From 6d5d6a87d512ab62c147e90675619db7f5d20064 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Thu, 20 Apr 2023 04:39:13 +0800 Subject: [PATCH 001/100] feat: init project 1. Use Vite and TypeScript 2. Custrom test via electron 3. API doc via typedoc --- .github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml | 62 +++ .github/ISSUE_TEMPLATE/bug---------.md | 38 ++ .github/ISSUE_TEMPLATE/bug_report.md | 38 ++ .github/ISSUE_TEMPLATE/feature_request.md | 20 + .gitignore | 23 ++ .npmrc | 2 + index.html | 78 ++++ package.json | 43 ++ pnpm-lock.yaml | 480 ++++++++++++++++++++++ script/typedoc-plugin-not-exported.js | 73 ++++ src/index.ts | 0 src/sample/index.ts | 77 ++++ test/ci/main.js | 73 ++++ test/ci/preload.js | 7 + test/index.html | 83 ++++ test/index.ts | 102 +++++ test/util.ts | 89 ++++ tsconfig.build.json | 35 ++ tsconfig.json | 29 ++ vite.config.js | 36 ++ 20 files changed, 1388 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml create mode 100644 .github/ISSUE_TEMPLATE/bug---------.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 index.html create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 script/typedoc-plugin-not-exported.js create mode 100644 src/index.ts create mode 100644 src/sample/index.ts create mode 100644 test/ci/main.js create mode 100644 test/ci/preload.js create mode 100644 test/index.html create mode 100644 test/index.ts create mode 100644 test/util.ts create mode 100644 tsconfig.build.json create mode 100644 tsconfig.json create mode 100644 vite.config.js diff --git a/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml b/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml new file mode 100644 index 00000000..9d0d058c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml @@ -0,0 +1,62 @@ +name: Bug Report +description: File a bug report +title: "[Bug]: " +labels: ["bug", "triage"] +assignees: + - octocat +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: input + id: contact + attributes: + label: Contact Details + description: How can we get in touch with you if we need more info? + placeholder: ex. email@example.com + validations: + required: false + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Also tell us, what did you expect to happen? + placeholder: Tell us what you see! + value: "A bug happened!" + validations: + required: true + - type: dropdown + id: version + attributes: + label: Version + description: What version of our software are you running? + options: + - 1.0.2 (Default) + - 1.0.3 (Edge) + validations: + required: true + - type: dropdown + id: browsers + attributes: + label: What browsers are you seeing the problem on? + multiple: true + options: + - Firefox + - Chrome + - Safari + - Microsoft Edge + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our [Code of Conduct](https://example.com) + options: + - label: I agree to follow this project's Code of Conduct + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug---------.md b/.github/ISSUE_TEMPLATE/bug---------.md new file mode 100644 index 00000000..a05203a2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug---------.md @@ -0,0 +1,38 @@ +--- +name: Bug 报告(中文模板) +about: 创建一个bug报告,帮助我们提升代码 +title: "[BUG]" +labels: bug +assignees: '' + +--- + +**Bug描述** +简单明晰的描述问题所在。 + +**Bug复现流程** +通过一下步骤产生bug: +1. 去目录/列表/文件 '...' +2. 点击 '....' +3. 向下滑动 '....' +4. 显示错误报告 + +**期待的结果** +简介明要的阐述你期待发生什么结果。 + +**报错截图** +如果可以,提供发生错误的截图。 + +**测试引擎版本:** +本地运行出错的Orillusion引擎版本。 + +**本机系统 (请填写完整):** + - OS: [e.g. win, mac, android] + - Browser [e.g. chrome] + - Version [e.g. 113] + +**Codepen链接** +如果有sandbox/codepen的代码示例链接,请提供。 + +**其他信息** +添加关于bug的其他描述信息。 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..8fd80a52 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[BUG]" +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Orillusion engine version:** +State the version you use for developement. + +**Desktop (please complete the following information):** + - OS: [e.g. win, mac, android] + - Browser [e.g. chrome] + - Version [e.g. 113] + +**Code demo link:** +If applicabla, please provide a sandbox/codepen/code snippet... to demonstrate the bug. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..bbcbbe7d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8bf04c36 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +node_modules +npm-debug.log* +yarn-error.log +yarn.lock +package-lock.json + +# production +/dist +/docs + +# misc +.DS_Store + +# idea +/.idea + +# others +/.env +/.env.local +/js diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..be310424 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +electron_mirror=https://npmmirror.com/mirrors/electron/ +electron_nightlyMirror=https://npmmirror.com/mirrors/electron-nightly/ \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..96c1214a --- /dev/null +++ b/index.html @@ -0,0 +1,78 @@ + + + + + + + Orillusion | Samples + + + + + + + + \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..efe8f945 --- /dev/null +++ b/package.json @@ -0,0 +1,43 @@ +{ + "name": "@orillusion/core", + "version": "0.5.0", + "author": "Orillusion", + "description": "Orillusion WebGPU Engine", + "main": "./dist/orillusion.umd.js", + "module": "./dist/orillusion.es.js", + "types": "./dist/src/index.d.ts", + "files": [ + "dist/src", + "dist/orillusion.umd.js", + "dist/orillusion.es.js", + "tsconfig.json" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/Orillusion/orillusion.git" + }, + "scripts": { + "dev": "vite", + "build": "tsc --p tsconfig.build.json && vite build && npm run build:types && npm run minify:es", + "build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json", + "minify:es": "uglifyjs dist/orillusion.es.js -o dist/orillusion.es.js -c -m", + "test": "electron test/ci/main.js", + "test:install": "npm i electron@npm:electron-nightly@latest --no-save", + "docs": "npm run docs:core && npm run docs:physics && npm run docs:media", + "docs:typedoc": "npx typedoc --plugin typedoc-plugin-markdown --plugin ./script/typedoc-plugin-not-exported.js --tsconfig tsconfig.build.json --gitRevision main --hideBreadcrumbs true --allReflectionsHaveOwnDocument true --readme none --excludeInternal --excludePrivate --excludeProtected --sort source-order --out", + "docs:core": "npm run docs:typedoc docs/api src/index.ts", + "docs:physics": "npm run docs:typedoc docs/physics src/libs/physics/index.ts", + "docs:media": "npm run docs:typedoc docs/media-extention src/libs/media-extention/index.ts", + "docs:stats": "npm run docs:typedoc docs/stats src/libs/stats/index.ts" + }, + "devDependencies": { + "@orillusion/core": "link:src", + "@orillusion/physics": "link:src/libs/physics", + "@webgpu/types": "^0.1.30", + "typedoc": "^0.24.4", + "typedoc-plugin-markdown": "^3.15.1", + "typescript": "^4.9.5", + "vite": "^4.2.2" + } +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000..5d7d9ad0 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,480 @@ +lockfileVersion: 5.4 + +specifiers: + '@orillusion/core': link:src + '@orillusion/physics': link:src/libs/physics + '@webgpu/types': ^0.1.30 + typedoc: ^0.24.4 + typedoc-plugin-markdown: ^3.15.1 + typescript: ^4.9.5 + vite: ^4.2.2 + +devDependencies: + '@orillusion/core': link:src + '@orillusion/physics': link:src/libs/physics + '@webgpu/types': 0.1.30 + typedoc: 0.24.4_typescript@4.9.5 + typedoc-plugin-markdown: 3.15.1_typedoc@0.24.4 + typescript: 4.9.5 + vite: 4.2.2 + +packages: + + /@esbuild/android-arm/0.17.17: + resolution: {integrity: sha512-E6VAZwN7diCa3labs0GYvhEPL2M94WLF8A+czO8hfjREXxba8Ng7nM5VxV+9ihNXIY1iQO1XxUU4P7hbqbICxg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64/0.17.17: + resolution: {integrity: sha512-jaJ5IlmaDLFPNttv0ofcwy/cfeY4bh/n705Tgh+eLObbGtQBK3EPAu+CzL95JVE4nFAliyrnEu0d32Q5foavqg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64/0.17.17: + resolution: {integrity: sha512-446zpfJ3nioMC7ASvJB1pszHVskkw4u/9Eu8s5yvvsSDTzYh4p4ZIRj0DznSl3FBF0Z/mZfrKXTtt0QCoFmoHA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64/0.17.17: + resolution: {integrity: sha512-m/gwyiBwH3jqfUabtq3GH31otL/0sE0l34XKpSIqR7NjQ/XHQ3lpmQHLHbG8AHTGCw8Ao059GvV08MS0bhFIJQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64/0.17.17: + resolution: {integrity: sha512-4utIrsX9IykrqYaXR8ob9Ha2hAY2qLc6ohJ8c0CN1DR8yWeMrTgYFjgdeQ9LIoTOfLetXjuCu5TRPHT9yKYJVg==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64/0.17.17: + resolution: {integrity: sha512-4PxjQII/9ppOrpEwzQ1b0pXCsFLqy77i0GaHodrmzH9zq2/NEhHMAMJkJ635Ns4fyJPFOlHMz4AsklIyRqFZWA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64/0.17.17: + resolution: {integrity: sha512-lQRS+4sW5S3P1sv0z2Ym807qMDfkmdhUYX30GRBURtLTrJOPDpoU0kI6pVz1hz3U0+YQ0tXGS9YWveQjUewAJw==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm/0.17.17: + resolution: {integrity: sha512-biDs7bjGdOdcmIk6xU426VgdRUpGg39Yz6sT9Xp23aq+IEHDb/u5cbmu/pAANpDB4rZpY/2USPhCA+w9t3roQg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64/0.17.17: + resolution: {integrity: sha512-2+pwLx0whKY1/Vqt8lyzStyda1v0qjJ5INWIe+d8+1onqQxHLLi3yr5bAa4gvbzhZqBztifYEu8hh1La5+7sUw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32/0.17.17: + resolution: {integrity: sha512-IBTTv8X60dYo6P2t23sSUYym8fGfMAiuv7PzJ+0LcdAndZRzvke+wTVxJeCq4WgjppkOpndL04gMZIFvwoU34Q==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64/0.17.17: + resolution: {integrity: sha512-WVMBtcDpATjaGfWfp6u9dANIqmU9r37SY8wgAivuKmgKHE+bWSuv0qXEFt/p3qXQYxJIGXQQv6hHcm7iWhWjiw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el/0.17.17: + resolution: {integrity: sha512-2kYCGh8589ZYnY031FgMLy0kmE4VoGdvfJkxLdxP4HJvWNXpyLhjOvxVsYjYZ6awqY4bgLR9tpdYyStgZZhi2A==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64/0.17.17: + resolution: {integrity: sha512-KIdG5jdAEeAKogfyMTcszRxy3OPbZhq0PPsW4iKKcdlbk3YE4miKznxV2YOSmiK/hfOZ+lqHri3v8eecT2ATwQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64/0.17.17: + resolution: {integrity: sha512-Cj6uWLBR5LWhcD/2Lkfg2NrkVsNb2sFM5aVEfumKB2vYetkA/9Uyc1jVoxLZ0a38sUhFk4JOVKH0aVdPbjZQeA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x/0.17.17: + resolution: {integrity: sha512-lK+SffWIr0XsFf7E0srBjhpkdFVJf3HEgXCwzkm69kNbRar8MhezFpkIwpk0qo2IOQL4JE4mJPJI8AbRPLbuOQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64/0.17.17: + resolution: {integrity: sha512-XcSGTQcWFQS2jx3lZtQi7cQmDYLrpLRyz1Ns1DzZCtn898cWfm5Icx/DEWNcTU+T+tyPV89RQtDnI7qL2PObPg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64/0.17.17: + resolution: {integrity: sha512-RNLCDmLP5kCWAJR+ItLM3cHxzXRTe4N00TQyQiimq+lyqVqZWGPAvcyfUBM0isE79eEZhIuGN09rAz8EL5KdLA==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64/0.17.17: + resolution: {integrity: sha512-PAXswI5+cQq3Pann7FNdcpSUrhrql3wKjj3gVkmuz6OHhqqYxKvi6GgRBoaHjaG22HV/ZZEgF9TlS+9ftHVigA==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64/0.17.17: + resolution: {integrity: sha512-V63egsWKnx/4V0FMYkr9NXWrKTB5qFftKGKuZKFIrAkO/7EWLFnbBZNM1CvJ6Sis+XBdPws2YQSHF1Gqf1oj/Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64/0.17.17: + resolution: {integrity: sha512-YtUXLdVnd6YBSYlZODjWzH+KzbaubV0YVd6UxSfoFfa5PtNJNaW+1i+Hcmjpg2nEe0YXUCNF5bkKy1NnBv1y7Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32/0.17.17: + resolution: {integrity: sha512-yczSLRbDdReCO74Yfc5tKG0izzm+lPMYyO1fFTcn0QNwnKmc3K+HdxZWLGKg4pZVte7XVgcFku7TIZNbWEJdeQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64/0.17.17: + resolution: {integrity: sha512-FNZw7H3aqhF9OyRQbDDnzUApDXfC1N6fgBhkqEO2jvYCJ+DxMTfZVqg3AX0R1khg1wHTBRD5SdcibSJ+XF6bFg==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@webgpu/types/0.1.30: + resolution: {integrity: sha512-9AXJSmL3MzY8ZL//JjudA//q+2kBRGhLBFpkdGksWIuxrMy81nFrCzj2Am+mbh8WoU6rXmv7cY5E3rdlyru2Qg==} + dev: true + + /ansi-sequence-parser/1.1.0: + resolution: {integrity: sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==} + dev: true + + /balanced-match/1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /brace-expansion/2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + + /esbuild/0.17.17: + resolution: {integrity: sha512-/jUywtAymR8jR4qsa2RujlAF7Krpt5VWi72Q2yuLD4e/hvtNcFQ0I1j8m/bxq238pf3/0KO5yuXNpuLx8BE1KA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.17.17 + '@esbuild/android-arm64': 0.17.17 + '@esbuild/android-x64': 0.17.17 + '@esbuild/darwin-arm64': 0.17.17 + '@esbuild/darwin-x64': 0.17.17 + '@esbuild/freebsd-arm64': 0.17.17 + '@esbuild/freebsd-x64': 0.17.17 + '@esbuild/linux-arm': 0.17.17 + '@esbuild/linux-arm64': 0.17.17 + '@esbuild/linux-ia32': 0.17.17 + '@esbuild/linux-loong64': 0.17.17 + '@esbuild/linux-mips64el': 0.17.17 + '@esbuild/linux-ppc64': 0.17.17 + '@esbuild/linux-riscv64': 0.17.17 + '@esbuild/linux-s390x': 0.17.17 + '@esbuild/linux-x64': 0.17.17 + '@esbuild/netbsd-x64': 0.17.17 + '@esbuild/openbsd-x64': 0.17.17 + '@esbuild/sunos-x64': 0.17.17 + '@esbuild/win32-arm64': 0.17.17 + '@esbuild/win32-ia32': 0.17.17 + '@esbuild/win32-x64': 0.17.17 + dev: true + + /fsevents/2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind/1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + dev: true + + /handlebars/4.7.7: + resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==} + engines: {node: '>=0.4.7'} + hasBin: true + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.17.4 + dev: true + + /has/1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + dev: true + + /is-core-module/2.12.0: + resolution: {integrity: sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==} + dependencies: + has: 1.0.3 + dev: true + + /jsonc-parser/3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + dev: true + + /lunr/2.3.9: + resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} + dev: true + + /marked/4.3.0: + resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} + engines: {node: '>= 12'} + hasBin: true + dev: true + + /minimatch/9.0.0: + resolution: {integrity: sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimist/1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /nanoid/3.3.6: + resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /neo-async/2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + dev: true + + /path-parse/1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /picocolors/1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /postcss/8.4.23: + resolution: {integrity: sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /resolve/1.22.2: + resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} + hasBin: true + dependencies: + is-core-module: 2.12.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /rollup/3.20.6: + resolution: {integrity: sha512-2yEB3nQXp/tBQDN0hJScJQheXdvU2wFhh6ld7K/aiZ1vYcak6N/BKjY1QrU6BvO2JWYS8bEs14FRaxXosxy2zw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /shiki/0.14.1: + resolution: {integrity: sha512-+Jz4nBkCBe0mEDqo1eKRcCdjRtrCjozmcbTUjbPTX7OOJfEbTZzlUWlZtGe3Gb5oV1/jnojhG//YZc3rs9zSEw==} + dependencies: + ansi-sequence-parser: 1.1.0 + jsonc-parser: 3.2.0 + vscode-oniguruma: 1.7.0 + vscode-textmate: 8.0.0 + dev: true + + /source-map-js/1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /source-map/0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /supports-preserve-symlinks-flag/1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /typedoc-plugin-markdown/3.15.1_typedoc@0.24.4: + resolution: {integrity: sha512-TaXE8gc8s5YepU1Ogyqfkh+khPE1/n4rV5vaoZCNyXvSLv62jWmHf443lHiQh7r07qAimUOKAndaaufAeIUSiQ==} + peerDependencies: + typedoc: '>=0.24.0' + dependencies: + handlebars: 4.7.7 + typedoc: 0.24.4_typescript@4.9.5 + dev: true + + /typedoc/0.24.4_typescript@4.9.5: + resolution: {integrity: sha512-vQuliyGhJEGeKzzCFHbkS3m0gHoIL6cfr0fHf6eX658iGELtq2J9mWe0b+X5McEYgFoMuHFt5Py3Zug6Sxjn/Q==} + engines: {node: '>= 14.14'} + hasBin: true + peerDependencies: + typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x + dependencies: + lunr: 2.3.9 + marked: 4.3.0 + minimatch: 9.0.0 + shiki: 0.14.1 + typescript: 4.9.5 + dev: true + + /typescript/4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + + /uglify-js/3.17.4: + resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} + engines: {node: '>=0.8.0'} + hasBin: true + requiresBuild: true + dev: true + optional: true + + /vite/4.2.2: + resolution: {integrity: sha512-PcNtT5HeDxb3QaSqFYkEum8f5sCVe0R3WK20qxgIvNBZPXU/Obxs/+ubBMeE7nLWeCo2LDzv+8hRYSlcaSehig==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.17.17 + postcss: 8.4.23 + resolve: 1.22.2 + rollup: 3.20.6 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /vscode-oniguruma/1.7.0: + resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} + dev: true + + /vscode-textmate/8.0.0: + resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==} + dev: true + + /wordwrap/1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + dev: true diff --git a/script/typedoc-plugin-not-exported.js b/script/typedoc-plugin-not-exported.js new file mode 100644 index 00000000..bf03675e --- /dev/null +++ b/script/typedoc-plugin-not-exported.js @@ -0,0 +1,73 @@ +"use strict"; +/** + * typedoc-plugin-not-exported + * TypeDoc plugin that forces inclusion of non-exported symbols (variables) + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const typedoc_1 = require("typedoc"); // version 0.20.16+ +const ModuleFlags = typedoc_1.TypeScript.SymbolFlags.ValueModule | typedoc_1.TypeScript.SymbolFlags.NamespaceModule; +exports.load = function (application) { + /** @type {Map>} */ + const checkedForModuleExports = new Map(); + let includeTag = 'notExported'; + application.options.addDeclaration({ + name: 'includeTag', + help: '[typedoc-plugin-not-exported] Specify the tag name for non-exported member to be imported under', + defaultValue: includeTag, + }); + application.converter.on(typedoc_1.Converter.EVENT_BEGIN, () => { + const includeTagTemp = application.options.getValue('includeTag'); + if (typeof includeTagTemp === 'string') { + includeTag = includeTagTemp.toLocaleLowerCase(); + } + }); + application.converter.on(typedoc_1.Converter.EVENT_CREATE_DECLARATION, lookForFakeExports); + application.converter.on(typedoc_1.Converter.EVENT_END, () => { + checkedForModuleExports.clear(); + }); + function lookForFakeExports(context, reflection) { + // Figure out where "not exports" will be placed, go up the tree until we get to + // the module where it belongs. + let targetModule = reflection; + while (!targetModule.kindOf(typedoc_1.ReflectionKind.Module | typedoc_1.ReflectionKind.Project)) { + targetModule = targetModule.parent; + } + const moduleContext = context.withScope(targetModule); + const reflSymbol = context.project.getSymbolFromReflection(reflection); + if (!reflSymbol) { + // Global file, no point in doing anything here. TypeDoc will already + // include everything declared in this file. + return; + } + for (const declaration of reflSymbol.declarations || []) { + checkFakeExportsOfFile(declaration.getSourceFile(), moduleContext); + } + } + function checkFakeExportsOfFile(file, context) { + const moduleSymbol = context.checker.getSymbolAtLocation(file); + // Make sure we are allowed to call getExportsOfModule + if (!moduleSymbol || (moduleSymbol.flags & ModuleFlags) === 0) { + return; + } + const checkedScopes = checkedForModuleExports.get(context.scope) || new Set(); + checkedForModuleExports.set(context.scope, checkedScopes); + if (checkedScopes.has(file)) + return; + checkedScopes.add(file); + const exportedSymbols = context.checker.getExportsOfModule(moduleSymbol); + const symbols = context.checker + .getSymbolsInScope(file, typedoc_1.TypeScript.SymbolFlags.ModuleMember) + .filter((symbol) => { + var _a; + return ((_a = symbol.declarations) === null || _a === void 0 ? void 0 : _a.some((d) => d.getSourceFile() === file)) && + !exportedSymbols.includes(symbol); + }); + for (const symbol of symbols) { + if (symbol + .getJsDocTags() + .some((tag) => tag.name.toLocaleLowerCase() === includeTag)) { + context.converter.convertSymbol(context, symbol); + } + } + } +}; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/sample/index.ts b/src/sample/index.ts new file mode 100644 index 00000000..62bd094f --- /dev/null +++ b/src/sample/index.ts @@ -0,0 +1,77 @@ +/******** Load all samples in /src/sample/ ********/ +function Menu() { + // load all modules in /sample + const modules = import.meta.glob(['./*/*.ts', '!./*/_*.ts']) + // create menu + let title = '', list = '' + for (const path in modules) { + const arr = path.split('/') + let _title = arr[1] + let _demo = arr[2].replace(/Sample_|Sample|\.ts/g, '') + if (_title != title) { + list += `

${_title}

` + title = _title + } + list += `${_demo}` + } + const menu = document.createElement('div') + menu.className = 'menu' + menu.innerHTML = list + document.body.appendChild(menu) + + // change sessionStorage.target on click, and reload iframe + menu.addEventListener('click', (e: Event) => { + let button = e.target as HTMLElement + if (!button.id) + return + // remove prev iframe to clear memory + document.querySelector('iframe')?.remove() + let target = button.id + if (target && modules[target]) { + addIframe() + document.querySelector('.active')?.classList.remove('active') + button.classList.add('active') + sessionStorage.top = menu.scrollTop + sessionStorage.target = target + } + }) + + // load target on refresh + if (sessionStorage.target) { + let target = sessionStorage.target + let a = document.querySelector(`[id="${target}"]`) + if (a) { + addIframe() + a.classList.add('active') + menu.scrollTop = sessionStorage.top + } + } else { + document.querySelector('a')?.click() + } + + // create an iframe inside page to load sample + function addIframe() { + const iframe = document.createElement('iframe') as HTMLIFrameElement + iframe.srcdoc = ` + + ` + document.body.appendChild(iframe) + } +} +Menu() + +// auto update index.ts, import all exports from /src/engine/ +const modules = import.meta.glob(['../engine/**/*.ts', '!../engine/**/*-back.ts', '!../engine/**/_*.ts']) +let content = '' +for (let path in modules) + content += `export * from "${path.slice(1, -3)}"\r\n` +import.meta.hot!.send('autoIndex', { content }) \ No newline at end of file diff --git a/test/ci/main.js b/test/ci/main.js new file mode 100644 index 00000000..79310a9a --- /dev/null +++ b/test/ci/main.js @@ -0,0 +1,73 @@ +const { app, BrowserWindow, ipcMain } = require('electron') +const path = require('path') +const {spawn} = require('child_process') + +app.commandLine.appendSwitch('log-level', 'silent') +const HOST = 'http://localhost:4000' + +const createWindow = async ()=>{ + const win = new BrowserWindow({ + width: 800, + height: 600, + // show: false, + // frame: false, + webPreferences: { + preload: path.join(__dirname, 'preload.js'), + nodeintegrationinsubframes: true, + webviewTag: true + } + }) + ipcMain.on('end', (_event, result) => { + let pass = true + for(let i in result){ + if(result[i].pass === false){ + pass = false + break + } + } + if(pass) + console.log('\x1b[32mCI pass\x1b[0m') + else + console.error('\x1b[31mCI not pass\x1b[0m') + console.table(result) + if(pass) + app.quit() + else{ + vite.kill() + process.exit(1) + } + }) + ipcMain.on('error', (_event, log) => { + console.error(`\x1b[31m${log.replaceAll(HOST + '/', '')}\x1b[0m\n-----------------`) + }) + ipcMain.on('test', (_event, log) => { + console.log(`\x1b[33m[${log.target}]\x1b[0m`) + console.table(log.result) + console.log('\n-----------------') + }) + + await win.loadURL(HOST + '/test/?auto') +} + +let vite +app.whenReady().then(() => { + vite = spawn('npx', ['vite', '--port', '4000', '--strictPort']) + vite.stdout.on('data', data=>{ + console.log(`\x1b[32m${data.toString()}\x1b[0m`) + if(data.toString().match(/vite.*.ready/i)){ + createWindow() + } + }) + vite.stderr.on('data', data=>{ + console.error(`\x1b[31m${data.toString()}\x1b[0m`) + vite.kill() + process.exit(1) + }) +}) +app.on('window-all-closed', () => { + app.quit() +}) +app.on('before-quit',()=>{ + if(vite) + vite.kill() +}) \ No newline at end of file diff --git a/test/ci/preload.js b/test/ci/preload.js new file mode 100644 index 00000000..b5f0f629 --- /dev/null +++ b/test/ci/preload.js @@ -0,0 +1,7 @@ +const { contextBridge, ipcRenderer } = require('electron') + +contextBridge.exposeInMainWorld('electron', { + test: (e) => ipcRenderer.send('test', e), + error: (e) => ipcRenderer.send('error', e), + end: (e) => ipcRenderer.send('end', e), +}) \ No newline at end of file diff --git a/test/index.html b/test/index.html new file mode 100644 index 00000000..8007542e --- /dev/null +++ b/test/index.html @@ -0,0 +1,83 @@ + + + + + + + Orillusion | Test + + + + + + + + \ No newline at end of file diff --git a/test/index.ts b/test/index.ts new file mode 100644 index 00000000..3b4348bd --- /dev/null +++ b/test/index.ts @@ -0,0 +1,102 @@ +// load all modules in /test +const modules = import.meta.glob(['./*/*.test.ts']) +// create menu +let title = '', list = '' +for (const path in modules) { + const arr = path.split('/') + let _title = arr[1] + let _demo = arr[2].replace(/Sample_|Sample|\.ts/g, '') + if (_title != title) { + list += `

${_title}

` + title = _title + } + list += `${_demo}` +} +list += '
' +const menu = document.createElement('div') +menu.className = 'menu' +menu.innerHTML = list +document.body.appendChild(menu) + +// change sessionStorage.target on click, and reload iframe +menu.addEventListener('click', (e: Event) => { + let button = e.target as HTMLElement + if (!button.id) + return + // remove prev iframe to clear memory + document.querySelector('iframe')?.remove() + let target = button.id + if (target && modules[target]) { + addIframe(target) + document.querySelector('.active')?.classList.remove('active') + button.classList.add('active') + sessionStorage.top = menu.scrollTop + sessionStorage.target = target + } +}) + +if (sessionStorage.target) { + let target = sessionStorage.target + let a = document.querySelector(`[id="${target}"]`) + if (a) { + addIframe(target) + a.classList.add('active') + menu.scrollTop = sessionStorage.top + } +} else { + document.querySelector('a')?.click() +} + +function addIframe(target: string) { + const iframe = document.createElement('iframe') as HTMLIFrameElement + iframe.srcdoc = ` + + + ` + document.body.appendChild(iframe) +} + +menu.querySelector('button')?.addEventListener('click', async (e: any) => { + e.target.innerHTML = 'RUNING' + e.target.disabled = true + try { + let links = menu.querySelectorAll('a') + let result: { [key: string]: any } = {} + for (let a of links as any) { + a.click() + await new Promise(res => { + window.addEventListener('message', e => { + if (e.data.type === 'end') { + result[a.id] = { + pass: e.data.fail > 0 ? false : true, + success: e.data.success, + fail: e.data.fail + } + res(true) + } + }, { once: true }) + }) + } + console.table(result) + window.electron?.end(result) + } catch (e) { + console.error(e) + } + e.target.innerHTML = 'TEST ALL' + e.target.disabled = false +}) + +if (location.search.match(/auto/)) { + menu.querySelector('button')?.click() +} + +declare global { + interface Window { + electron: { + test: (e: any) => void + error: (e: any) => void + end: (e: any) => void + } + } +} +export { } \ No newline at end of file diff --git a/test/util.ts b/test/util.ts new file mode 100644 index 00000000..ac1bfede --- /dev/null +++ b/test/util.ts @@ -0,0 +1,89 @@ +import { isEqual, isMatch } from 'https://unpkg.com/underscore@1.13.6/underscore-esm-min.js' + +let target = sessionStorage.target.split('/').pop() +let result: { [key: string]: any } = {} +let totalS = 0, totalF = 0 +console.group(`%c[${target}]`, 'color:yellow') +async function test(unit: string, run: () => Promise) { + result[unit] = { + success: 0, + fail: 0 + } + console.group(`%c[${unit}]`, 'color:green') + console.time('[time]') + let rej: any + try { + await Promise.race([ + run(), + new Promise((_, _rej) => { + rej = (e: any) => _rej(e.reason) + window.addEventListener('unhandledrejection', rej, { once: true }) + }) + ]) + result[unit].success++ + totalS++ + } catch (e: any) { + console.error('[TEST]', e.stack || e) + window.parent.electron?.error(e.stack || e.message) + result[unit].fail++ + totalF++ + } + window.removeEventListener('unhandledrejection', rej) + console.timeEnd('[time]') + console.groupEnd() +} + +class Compare { + src: any + constructor(obj: any) { + this.src = obj + } + toEqual(obj: any) { + if (!isEqual(this.src, obj)) { + //console.error('[TEST] toEqual', this.src, obj) + throw new Error('toEqual') + } + } + notEqual(obj: any) { + if (isEqual(this.src, obj)) { + //console.error('[TEST] notEqual', this.src, obj) + throw new Error('notEqual') + } + } + tobe(obj: any) { + if (this.src !== obj) { + //console.error('[TEST] tobe', this.src, obj) + throw new Error('tobe') + } + } + isMatch(obj: any) { + if (!isMatch(this.src, obj)) { + //console.error('[TEST] isMatch', this.src, obj) + throw new Error('isMatch') + } + } + // TODO +} +function expect(object: any) { + return new Compare(object) +} + +function end() { + console.table(result) + console.groupEnd() + window.parent.postMessage({ + type: 'end', + success: totalS, + fail: totalF + }, '*') + window.parent.electron?.test({ + target, result + }) +} + +function delay(time?: number) { + return new Promise(res => { + setTimeout(res, time || 200) + }) +} +export { test, expect, end, delay } \ No newline at end of file diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 00000000..39cace01 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "Node", + "sourceMap": false, + "resolveJsonModule": true, + "esModuleInterop": true, + "rootDir": "./", + "baseUrl": "./", + "paths": { + "../*": ["src/*"], + "@orillusion/*": ["src/libs/*"], + "@orillusion/core": ["src"] + }, + "types": ["vite/client", "@webgpu/types"], + // for build + // "noEmit": true, + "declaration": true, + "declarationDir": "dist", + "outDir": "dist", + "skipLibCheck": true, + "noImplicitAny": false, + "noUnusedLocals": false, + "noUnusedParameters":false, + "noImplicitReturns": false, + "strictPropertyInitialization": false, + "strictNullChecks": false, + "strict": false + }, + "include": ["src"], + "exclude": ["node_modules", "src/sample"] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..2ea60bef --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "Node", + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "noEmit": true, + "rootDir": "./", + "baseUrl": "./", + "paths": { + "../*": ["src/*"], + "@orillusion/*": ["src/libs/*"], + "@orillusion/core": ["src"] + }, + "types": ["vite/client", "@webgpu/types", "@types/jest"], + // for dev + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "allowJs": true, + "strict": true + }, + "include": ["src", "test", "config"], + "exclude": ["node_modules", "dist", "public"] +} \ No newline at end of file diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 00000000..704299dc --- /dev/null +++ b/vite.config.js @@ -0,0 +1,36 @@ +// vite.config.js +import { defineConfig } from 'vite' +import { readFile, writeFile } from 'fs/promises' +import {resolve} from 'path' + +module.exports = defineConfig({ + server: { + port: 3000, + // hmr: false // open this line if no auto hot-reload required + }, + resolve: { + alias: { + '@orillusion/core': resolve(__dirname, './src/index.ts'), + '@orillusion': resolve(__dirname, './src/libs') + }, + mainFields: ['module:dev', 'module'] + }, + plugins: [{ + name: 'autoIndex', + configureServer(server) { + server.ws.on('autoIndex', async (data) => { + let content = await readFile(resolve(__dirname, './src/index.ts'), 'utf-8') + if(data.content !== content) + writeFile(resolve(__dirname, './src/index.ts'), data.content) + }) + } + }], + build: { + lib: { + entry: resolve(__dirname, './src/index.ts'), + name: 'Orillusion', + fileName: (format) => `orillusion.${format}.js` + }, + // minify: 'terser' + } +}) From 3139051e2c7f91a5386f734ba14d29775a4c4677 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Thu, 20 Apr 2023 05:20:01 +0800 Subject: [PATCH 002/100] feat: enable github CI test Trigger CI on push/pr on [main] Run build & tests --- .github/workflows/ci.yml | 34 +++ package.json | 9 +- pnpm-lock.yaml | 576 ++++++++++++++++++++++++++++++++++++++- src/index.ts | 2 + test/base/base.test.ts | 8 + 5 files changed, 620 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 test/base/base.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..f3ad8681 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: CI auto test on push + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + test: + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + + - name: Install pnpm + uses: pnpm/action-setup@v2 + with: + version: 7 + + - name: Setup node 16 + uses: actions/setup-node@v3 + with: + node-version: 16 + cache: pnpm + + - name: Install deps + run: pnpm install + + - name: Test Build + run: pnpm run build + + - name: Test in Electron + run: pnpm run test:ci + \ No newline at end of file diff --git a/package.json b/package.json index efe8f945..2b313eb8 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,8 @@ "build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json", "minify:es": "uglifyjs dist/orillusion.es.js -o dist/orillusion.es.js -c -m", "test": "electron test/ci/main.js", - "test:install": "npm i electron@npm:electron-nightly@latest --no-save", + "test:ci": "xvfb-maybe -- electron test/ci/main.js", + "test:install": "pnpm i electron@npm:electron-nightly@latest xvfb-maybe -O", "docs": "npm run docs:core && npm run docs:physics && npm run docs:media", "docs:typedoc": "npx typedoc --plugin typedoc-plugin-markdown --plugin ./script/typedoc-plugin-not-exported.js --tsconfig tsconfig.build.json --gitRevision main --hideBreadcrumbs true --allReflectionsHaveOwnDocument true --readme none --excludeInternal --excludePrivate --excludeProtected --sort source-order --out", "docs:core": "npm run docs:typedoc docs/api src/index.ts", @@ -32,12 +33,14 @@ "docs:stats": "npm run docs:typedoc docs/stats src/libs/stats/index.ts" }, "devDependencies": { - "@orillusion/core": "link:src", - "@orillusion/physics": "link:src/libs/physics", "@webgpu/types": "^0.1.30", "typedoc": "^0.24.4", "typedoc-plugin-markdown": "^3.15.1", "typescript": "^4.9.5", "vite": "^4.2.2" + }, + "optionalDependencies": { + "electron": "npm:electron-nightly@latest", + "xvfb-maybe": "^0.2.1" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5d7d9ad0..ec953644 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,17 +1,19 @@ lockfileVersion: 5.4 specifiers: - '@orillusion/core': link:src - '@orillusion/physics': link:src/libs/physics '@webgpu/types': ^0.1.30 + electron: npm:electron-nightly@latest typedoc: ^0.24.4 typedoc-plugin-markdown: ^3.15.1 typescript: ^4.9.5 vite: ^4.2.2 + xvfb-maybe: ^0.2.1 + +optionalDependencies: + electron: /electron-nightly/26.0.0-nightly.20230418 + xvfb-maybe: 0.2.1 devDependencies: - '@orillusion/core': link:src - '@orillusion/physics': link:src/libs/physics '@webgpu/types': 0.1.30 typedoc: 0.24.4_typescript@4.9.5 typedoc-plugin-markdown: 3.15.1_typedoc@0.24.4 @@ -20,6 +22,24 @@ devDependencies: packages: + /@electron/get/2.0.2: + resolution: {integrity: sha512-eFZVFoRXb3GFGd7Ak7W4+6jBl9wBtiZ4AaYOse97ej6mKj5tkyO0dUnUChs1IhJZtx1BENo4/p4WUTXpi6vT+g==} + engines: {node: '>=12'} + dependencies: + debug: 4.3.4 + env-paths: 2.2.1 + fs-extra: 8.1.0 + got: 11.8.6 + progress: 2.0.3 + semver: 6.3.0 + sumchecker: 3.0.1 + optionalDependencies: + global-agent: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + /@esbuild/android-arm/0.17.17: resolution: {integrity: sha512-E6VAZwN7diCa3labs0GYvhEPL2M94WLF8A+czO8hfjREXxba8Ng7nM5VxV+9ihNXIY1iQO1XxUU4P7hbqbICxg==} engines: {node: '>=12'} @@ -218,6 +238,62 @@ packages: dev: true optional: true + /@sindresorhus/is/4.6.0: + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + dev: false + optional: true + + /@szmarczak/http-timer/4.0.6: + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + dependencies: + defer-to-connect: 2.0.1 + dev: false + optional: true + + /@types/cacheable-request/6.0.3: + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + dependencies: + '@types/http-cache-semantics': 4.0.1 + '@types/keyv': 3.1.4 + '@types/node': 18.15.11 + '@types/responselike': 1.0.0 + dev: false + optional: true + + /@types/http-cache-semantics/4.0.1: + resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==} + dev: false + optional: true + + /@types/keyv/3.1.4: + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + dependencies: + '@types/node': 18.15.11 + dev: false + optional: true + + /@types/node/18.15.11: + resolution: {integrity: sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==} + dev: false + optional: true + + /@types/responselike/1.0.0: + resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} + dependencies: + '@types/node': 18.15.11 + dev: false + optional: true + + /@types/yauzl/2.10.0: + resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} + requiresBuild: true + dependencies: + '@types/node': 18.15.11 + dev: false + optional: true + /@webgpu/types/0.1.30: resolution: {integrity: sha512-9AXJSmL3MzY8ZL//JjudA//q+2kBRGhLBFpkdGksWIuxrMy81nFrCzj2Am+mbh8WoU6rXmv7cY5E3rdlyru2Qg==} dev: true @@ -230,12 +306,134 @@ packages: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true + /boolean/3.2.0: + resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} + dev: false + optional: true + /brace-expansion/2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 dev: true + /buffer-crc32/0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + dev: false + optional: true + + /cacheable-lookup/5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + dev: false + optional: true + + /cacheable-request/7.0.2: + resolution: {integrity: sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==} + engines: {node: '>=8'} + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.1.1 + keyv: 4.5.2 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + dev: false + optional: true + + /clone-response/1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + dependencies: + mimic-response: 1.0.1 + dev: false + optional: true + + /debug/2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + dev: false + optional: true + + /debug/4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: false + optional: true + + /decompress-response/6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 + dev: false + optional: true + + /defer-to-connect/2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + dev: false + optional: true + + /define-properties/1.2.0: + resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} + engines: {node: '>= 0.4'} + dependencies: + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 + dev: false + optional: true + + /detect-node/2.1.0: + resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + dev: false + optional: true + + /electron-nightly/26.0.0-nightly.20230418: + resolution: {integrity: sha512-6hq27nwZd8DL5/s9TyOpIox9mqDNhAbrvHbuUvQGba8zQngu2OfFroP83LtrisaLLq7BEzAp11fvrvJvDThA+g==} + engines: {node: '>= 12.20.55'} + hasBin: true + requiresBuild: true + dependencies: + '@electron/get': 2.0.2 + '@types/node': 18.15.11 + extract-zip: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /end-of-stream/1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: false + optional: true + + /env-paths/2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + dev: false + optional: true + + /es6-error/4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + dev: false + optional: true + /esbuild/0.17.17: resolution: {integrity: sha512-/jUywtAymR8jR4qsa2RujlAF7Krpt5VWi72Q2yuLD4e/hvtNcFQ0I1j8m/bxq238pf3/0KO5yuXNpuLx8BE1KA==} engines: {node: '>=12'} @@ -266,6 +464,44 @@ packages: '@esbuild/win32-x64': 0.17.17 dev: true + /escape-string-regexp/4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: false + optional: true + + /extract-zip/2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + dependencies: + debug: 4.3.4 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.0 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /fd-slicer/1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + dependencies: + pend: 1.2.0 + dev: false + optional: true + + /fs-extra/8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: false + optional: true + /fsevents/2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -276,7 +512,68 @@ packages: /function-bind/1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - dev: true + + /get-intrinsic/1.2.0: + resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.3 + dev: false + optional: true + + /get-stream/5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + dependencies: + pump: 3.0.0 + dev: false + optional: true + + /global-agent/3.0.0: + resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} + engines: {node: '>=10.0'} + requiresBuild: true + dependencies: + boolean: 3.2.0 + es6-error: 4.1.1 + matcher: 3.0.0 + roarr: 2.15.4 + semver: 7.5.0 + serialize-error: 7.0.1 + dev: false + optional: true + + /globalthis/1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.0 + dev: false + optional: true + + /got/11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.0 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.2 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + dev: false + optional: true + + /graceful-fs/4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: false + optional: true /handlebars/4.7.7: resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==} @@ -291,12 +588,38 @@ packages: uglify-js: 3.17.4 dev: true + /has-property-descriptors/1.0.0: + resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + dependencies: + get-intrinsic: 1.2.0 + dev: false + optional: true + + /has-symbols/1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: false + optional: true + /has/1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} dependencies: function-bind: 1.1.1 - dev: true + + /http-cache-semantics/4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + dev: false + optional: true + + /http2-wrapper/1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + dev: false + optional: true /is-core-module/2.12.0: resolution: {integrity: sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==} @@ -304,10 +627,53 @@ packages: has: 1.0.3 dev: true + /isexe/2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: false + optional: true + + /json-buffer/3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: false + optional: true + + /json-stringify-safe/5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + dev: false + optional: true + /jsonc-parser/3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} dev: true + /jsonfile/4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + optionalDependencies: + graceful-fs: 4.2.11 + dev: false + optional: true + + /keyv/4.5.2: + resolution: {integrity: sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==} + dependencies: + json-buffer: 3.0.1 + dev: false + optional: true + + /lowercase-keys/2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + dev: false + optional: true + + /lru-cache/6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: false + optional: true + /lunr/2.3.9: resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} dev: true @@ -318,6 +684,26 @@ packages: hasBin: true dev: true + /matcher/3.0.0: + resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 4.0.0 + dev: false + optional: true + + /mimic-response/1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + dev: false + optional: true + + /mimic-response/3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: false + optional: true + /minimatch/9.0.0: resolution: {integrity: sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==} engines: {node: '>=16 || 14 >=14.17'} @@ -329,6 +715,16 @@ packages: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} dev: true + /ms/2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + dev: false + optional: true + + /ms/2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: false + optional: true + /nanoid/3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -339,10 +735,40 @@ packages: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} dev: true + /normalize-url/6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + dev: false + optional: true + + /object-keys/1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: false + optional: true + + /once/1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: false + optional: true + + /p-cancelable/2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + dev: false + optional: true + /path-parse/1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true + /pend/1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + dev: false + optional: true + /picocolors/1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} dev: true @@ -356,6 +782,31 @@ packages: source-map-js: 1.0.2 dev: true + /progress/2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + dev: false + optional: true + + /pump/3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: false + optional: true + + /quick-lru/5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + dev: false + optional: true + + /resolve-alpn/1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + dev: false + optional: true + /resolve/1.22.2: resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} hasBin: true @@ -365,6 +816,26 @@ packages: supports-preserve-symlinks-flag: 1.0.0 dev: true + /responselike/2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + dependencies: + lowercase-keys: 2.0.0 + dev: false + optional: true + + /roarr/2.15.4: + resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} + engines: {node: '>=8.0'} + dependencies: + boolean: 3.2.0 + detect-node: 2.1.0 + globalthis: 1.0.3 + json-stringify-safe: 5.0.1 + semver-compare: 1.0.0 + sprintf-js: 1.1.2 + dev: false + optional: true + /rollup/3.20.6: resolution: {integrity: sha512-2yEB3nQXp/tBQDN0hJScJQheXdvU2wFhh6ld7K/aiZ1vYcak6N/BKjY1QrU6BvO2JWYS8bEs14FRaxXosxy2zw==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} @@ -373,6 +844,34 @@ packages: fsevents: 2.3.2 dev: true + /semver-compare/1.0.0: + resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + dev: false + optional: true + + /semver/6.3.0: + resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true + dev: false + optional: true + + /semver/7.5.0: + resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: false + optional: true + + /serialize-error/7.0.1: + resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} + engines: {node: '>=10'} + dependencies: + type-fest: 0.13.1 + dev: false + optional: true + /shiki/0.14.1: resolution: {integrity: sha512-+Jz4nBkCBe0mEDqo1eKRcCdjRtrCjozmcbTUjbPTX7OOJfEbTZzlUWlZtGe3Gb5oV1/jnojhG//YZc3rs9zSEw==} dependencies: @@ -392,11 +891,32 @@ packages: engines: {node: '>=0.10.0'} dev: true + /sprintf-js/1.1.2: + resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==} + dev: false + optional: true + + /sumchecker/3.0.1: + resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} + engines: {node: '>= 8.0'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + /supports-preserve-symlinks-flag/1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} dev: true + /type-fest/0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + dev: false + optional: true + /typedoc-plugin-markdown/3.15.1_typedoc@0.24.4: resolution: {integrity: sha512-TaXE8gc8s5YepU1Ogyqfkh+khPE1/n4rV5vaoZCNyXvSLv62jWmHf443lHiQh7r07qAimUOKAndaaufAeIUSiQ==} peerDependencies: @@ -434,6 +954,12 @@ packages: dev: true optional: true + /universalify/0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + dev: false + optional: true + /vite/4.2.2: resolution: {integrity: sha512-PcNtT5HeDxb3QaSqFYkEum8f5sCVe0R3WK20qxgIvNBZPXU/Obxs/+ubBMeE7nLWeCo2LDzv+8hRYSlcaSehig==} engines: {node: ^14.18.0 || >=16.0.0} @@ -475,6 +1001,44 @@ packages: resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==} dev: true + /which/1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: false + optional: true + /wordwrap/1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} dev: true + + /wrappy/1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: false + optional: true + + /xvfb-maybe/0.2.1: + resolution: {integrity: sha512-9IyRz3l6Qyhl6LvnGRF5jMPB4oBEepQnuzvVAFTynP6ACLLSevqigICJ9d/+ofl29m2daeaVBChnPYUnaeJ7yA==} + hasBin: true + requiresBuild: true + dependencies: + debug: 2.6.9 + which: 1.3.1 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /yallist/4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: false + optional: true + + /yauzl/2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + dev: false + optional: true diff --git a/src/index.ts b/src/index.ts index e69de29b..ef2d8dd8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -0,0 +1,2 @@ +let foo = 1 +export { foo } \ No newline at end of file diff --git a/test/base/base.test.ts b/test/base/base.test.ts new file mode 100644 index 00000000..c6596f19 --- /dev/null +++ b/test/base/base.test.ts @@ -0,0 +1,8 @@ +import * as Orillusion from '../../src'; +import { test, end } from '../util' + +await test('Init', async () => { + console.log(Orillusion) +}) + +setTimeout(end, 500) \ No newline at end of file From d839d02298c5f69859e40850db10d9c49040714d Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Thu, 20 Apr 2023 05:25:39 +0800 Subject: [PATCH 003/100] fix: enable ci on dev --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f3ad8681..c6160944 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI auto test on push on: push: - branches: [ main ] + branches: [ main, dev ] pull_request: - branches: [ main ] + branches: [ main, dev ] jobs: test: From 98307e6fe2e939354e6d23310e91f6355e2a4f68 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Thu, 20 Apr 2023 05:32:39 +0800 Subject: [PATCH 004/100] fix: run build missing Dependencies --- package.json | 1 + pnpm-lock.yaml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b313eb8..d673679f 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ }, "optionalDependencies": { "electron": "npm:electron-nightly@latest", + "uglify-js": "^3.17.4", "xvfb-maybe": "^0.2.1" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ec953644..1de8baad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,11 +6,13 @@ specifiers: typedoc: ^0.24.4 typedoc-plugin-markdown: ^3.15.1 typescript: ^4.9.5 + uglify-js: ^3.17.4 vite: ^4.2.2 xvfb-maybe: ^0.2.1 optionalDependencies: electron: /electron-nightly/26.0.0-nightly.20230418 + uglify-js: 3.17.4 xvfb-maybe: 0.2.1 devDependencies: @@ -951,7 +953,6 @@ packages: engines: {node: '>=0.8.0'} hasBin: true requiresBuild: true - dev: true optional: true /universalify/0.1.2: From 6c322f7d85c68aeffa4c93d05b749fea594a73c8 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Thu, 20 Apr 2023 08:16:47 +0800 Subject: [PATCH 005/100] feat: upgrade ts@5 Use new moduleResolution option: bundler --- package.json | 2 +- pnpm-lock.yaml | 18 +++++++++--------- tsconfig.build.json | 2 +- tsconfig.json | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index d673679f..9c193bd4 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@webgpu/types": "^0.1.30", "typedoc": "^0.24.4", "typedoc-plugin-markdown": "^3.15.1", - "typescript": "^4.9.5", + "typescript": "^5.0.4", "vite": "^4.2.2" }, "optionalDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1de8baad..3e28cd21 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,7 @@ specifiers: electron: npm:electron-nightly@latest typedoc: ^0.24.4 typedoc-plugin-markdown: ^3.15.1 - typescript: ^4.9.5 + typescript: ^5.0.4 uglify-js: ^3.17.4 vite: ^4.2.2 xvfb-maybe: ^0.2.1 @@ -17,9 +17,9 @@ optionalDependencies: devDependencies: '@webgpu/types': 0.1.30 - typedoc: 0.24.4_typescript@4.9.5 + typedoc: 0.24.4_typescript@5.0.4 typedoc-plugin-markdown: 3.15.1_typedoc@0.24.4 - typescript: 4.9.5 + typescript: 5.0.4 vite: 4.2.2 packages: @@ -925,10 +925,10 @@ packages: typedoc: '>=0.24.0' dependencies: handlebars: 4.7.7 - typedoc: 0.24.4_typescript@4.9.5 + typedoc: 0.24.4_typescript@5.0.4 dev: true - /typedoc/0.24.4_typescript@4.9.5: + /typedoc/0.24.4_typescript@5.0.4: resolution: {integrity: sha512-vQuliyGhJEGeKzzCFHbkS3m0gHoIL6cfr0fHf6eX658iGELtq2J9mWe0b+X5McEYgFoMuHFt5Py3Zug6Sxjn/Q==} engines: {node: '>= 14.14'} hasBin: true @@ -939,12 +939,12 @@ packages: marked: 4.3.0 minimatch: 9.0.0 shiki: 0.14.1 - typescript: 4.9.5 + typescript: 5.0.4 dev: true - /typescript/4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} + /typescript/5.0.4: + resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} + engines: {node: '>=12.20'} hasBin: true dev: true diff --git a/tsconfig.build.json b/tsconfig.build.json index 39cace01..ff3ccc70 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -4,7 +4,7 @@ "useDefineForClassFields": true, "module": "ESNext", "lib": ["ESNext", "DOM"], - "moduleResolution": "Node", + "moduleResolution": "bundler", "sourceMap": false, "resolveJsonModule": true, "esModuleInterop": true, diff --git a/tsconfig.json b/tsconfig.json index 2ea60bef..fa5c0df4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "useDefineForClassFields": true, "module": "ESNext", "lib": ["ESNext", "DOM"], - "moduleResolution": "Node", + "moduleResolution": "bundler", "sourceMap": true, "resolveJsonModule": true, "esModuleInterop": true, @@ -16,7 +16,7 @@ "@orillusion/*": ["src/libs/*"], "@orillusion/core": ["src"] }, - "types": ["vite/client", "@webgpu/types", "@types/jest"], + "types": ["vite/client", "@webgpu/types"], // for dev "noUnusedLocals": true, "noUnusedParameters": true, @@ -24,6 +24,6 @@ "allowJs": true, "strict": true }, - "include": ["src", "test", "config"], + "include": ["src", "test"], "exclude": ["node_modules", "dist", "public"] } \ No newline at end of file From 630b0bfd5c6ef31789f12098d66063c52fef96a8 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Fri, 21 Apr 2023 01:28:23 +0800 Subject: [PATCH 006/100] refine: github issue templte --- .github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml | 62 ----------------------- .github/ISSUE_TEMPLATE/bug---------.md | 38 -------------- .github/ISSUE_TEMPLATE/bug_report.md | 39 +++++++------- .github/ISSUE_TEMPLATE/bug_report_zh.md | 37 ++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 13 +++-- 5 files changed, 62 insertions(+), 127 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml delete mode 100644 .github/ISSUE_TEMPLATE/bug---------.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report_zh.md diff --git a/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml b/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml deleted file mode 100644 index 9d0d058c..00000000 --- a/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Bug Report -description: File a bug report -title: "[Bug]: " -labels: ["bug", "triage"] -assignees: - - octocat -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report! - - type: input - id: contact - attributes: - label: Contact Details - description: How can we get in touch with you if we need more info? - placeholder: ex. email@example.com - validations: - required: false - - type: textarea - id: what-happened - attributes: - label: What happened? - description: Also tell us, what did you expect to happen? - placeholder: Tell us what you see! - value: "A bug happened!" - validations: - required: true - - type: dropdown - id: version - attributes: - label: Version - description: What version of our software are you running? - options: - - 1.0.2 (Default) - - 1.0.3 (Edge) - validations: - required: true - - type: dropdown - id: browsers - attributes: - label: What browsers are you seeing the problem on? - multiple: true - options: - - Firefox - - Chrome - - Safari - - Microsoft Edge - - type: textarea - id: logs - attributes: - label: Relevant log output - description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. - render: shell - - type: checkboxes - id: terms - attributes: - label: Code of Conduct - description: By submitting this issue, you agree to follow our [Code of Conduct](https://example.com) - options: - - label: I agree to follow this project's Code of Conduct - required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug---------.md b/.github/ISSUE_TEMPLATE/bug---------.md deleted file mode 100644 index a05203a2..00000000 --- a/.github/ISSUE_TEMPLATE/bug---------.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Bug 报告(中文模板) -about: 创建一个bug报告,帮助我们提升代码 -title: "[BUG]" -labels: bug -assignees: '' - ---- - -**Bug描述** -简单明晰的描述问题所在。 - -**Bug复现流程** -通过一下步骤产生bug: -1. 去目录/列表/文件 '...' -2. 点击 '....' -3. 向下滑动 '....' -4. 显示错误报告 - -**期待的结果** -简介明要的阐述你期待发生什么结果。 - -**报错截图** -如果可以,提供发生错误的截图。 - -**测试引擎版本:** -本地运行出错的Orillusion引擎版本。 - -**本机系统 (请填写完整):** - - OS: [e.g. win, mac, android] - - Browser [e.g. chrome] - - Version [e.g. 113] - -**Codepen链接** -如果有sandbox/codepen的代码示例链接,请提供。 - -**其他信息** -添加关于bug的其他描述信息。 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 8fd80a52..11618d65 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,38 +1,37 @@ --- name: Bug report about: Create a report to help us improve -title: "[BUG]" +title: "[BUG]: " labels: bug assignees: '' - --- -**Describe the bug** -A clear and concise description of what the bug is. +## Describe the bug +A clear and concise description of what the bug is -**To Reproduce** +## To Reproduce Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error +1. Create '...' +2. Click on '...' +3. Delete '...' +4. See error '...' -**Expected behavior** -A clear and concise description of what you expected to happen. +## Expected behavior +A clear and concise description of what you expected to happen -**Screenshots** -If applicable, add screenshots to help explain your problem. +## Screenshots +If applicable, add screenshots to help explain your problem -**Orillusion engine version:** -State the version you use for developement. +## Orillusion engine version +State the version you use for developement, e.g. 0.5.0 -**Desktop (please complete the following information):** +## Desktop (please complete the following information) - OS: [e.g. win, mac, android] - Browser [e.g. chrome] - Version [e.g. 113] -**Code demo link:** -If applicabla, please provide a sandbox/codepen/code snippet... to demonstrate the bug. +## Code demo link +If applicabla, please provide a sandbox/codepen/code snippet... to demonstrate the bug -**Additional context** -Add any other context about the problem here. +## Additional context +Add any other context about the problem here diff --git a/.github/ISSUE_TEMPLATE/bug_report_zh.md b/.github/ISSUE_TEMPLATE/bug_report_zh.md new file mode 100644 index 00000000..ba83488d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report_zh.md @@ -0,0 +1,37 @@ +--- +name: Bug 报告(中文模板) +about: 创建一个bug报告,帮助我们提升代码 +title: "[BUG]: " +labels: bug +assignees: '' +--- + +## Bug描述 +简单明晰的描述问题所在 + +## Bug复现流程 +通过以下步骤产生bug: +1. 创建 '...' +2. 点击 '...' +3. 删除 '...' +4. 出现错误 '...' + +## 期待的结果 +简介明要的阐述你期待发生什么结果 + +## 报错截图 +如果可以,提供发生错误的截图 + +## 测试引擎版本: +本地运行出错的Orillusion引擎版本, e.g. 0.5.0 + +## 本机系统 (请填写完整): + - OS: [e.g. win, mac, android] + - Browser [e.g. chrome] + - Version [e.g. 113] + +## Codepen链接 +如果有sandbox/codepen的代码示例链接,请提供 + +## 其他信息 +添加关于bug的其他描述信息 diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7d..35f4d7c4 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,20 +1,19 @@ --- name: Feature request about: Suggest an idea for this project -title: '' -labels: '' +title: '[FR]: ' +labels: 'feature' assignees: '' - --- -**Is your feature request related to a problem? Please describe.** +## Is your feature request related to a problem? Please describe A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -**Describe the solution you'd like** +## Describe the solution you'd like A clear and concise description of what you want to happen. -**Describe alternatives you've considered** +## Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered. -**Additional context** +## Additional context Add any other context or screenshots about the feature request here. From 2464aded7d28b375b790de802a75efea229a3d9e Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Fri, 21 Apr 2023 01:37:20 +0800 Subject: [PATCH 007/100] fix: delete old template --- .github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml | 62 ----------------------- .github/ISSUE_TEMPLATE/bug---------.md | 38 -------------- 2 files changed, 100 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml delete mode 100644 .github/ISSUE_TEMPLATE/bug---------.md diff --git a/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml b/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml deleted file mode 100644 index 9d0d058c..00000000 --- a/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Bug Report -description: File a bug report -title: "[Bug]: " -labels: ["bug", "triage"] -assignees: - - octocat -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report! - - type: input - id: contact - attributes: - label: Contact Details - description: How can we get in touch with you if we need more info? - placeholder: ex. email@example.com - validations: - required: false - - type: textarea - id: what-happened - attributes: - label: What happened? - description: Also tell us, what did you expect to happen? - placeholder: Tell us what you see! - value: "A bug happened!" - validations: - required: true - - type: dropdown - id: version - attributes: - label: Version - description: What version of our software are you running? - options: - - 1.0.2 (Default) - - 1.0.3 (Edge) - validations: - required: true - - type: dropdown - id: browsers - attributes: - label: What browsers are you seeing the problem on? - multiple: true - options: - - Firefox - - Chrome - - Safari - - Microsoft Edge - - type: textarea - id: logs - attributes: - label: Relevant log output - description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. - render: shell - - type: checkboxes - id: terms - attributes: - label: Code of Conduct - description: By submitting this issue, you agree to follow our [Code of Conduct](https://example.com) - options: - - label: I agree to follow this project's Code of Conduct - required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug---------.md b/.github/ISSUE_TEMPLATE/bug---------.md deleted file mode 100644 index a05203a2..00000000 --- a/.github/ISSUE_TEMPLATE/bug---------.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Bug 报告(中文模板) -about: 创建一个bug报告,帮助我们提升代码 -title: "[BUG]" -labels: bug -assignees: '' - ---- - -**Bug描述** -简单明晰的描述问题所在。 - -**Bug复现流程** -通过一下步骤产生bug: -1. 去目录/列表/文件 '...' -2. 点击 '....' -3. 向下滑动 '....' -4. 显示错误报告 - -**期待的结果** -简介明要的阐述你期待发生什么结果。 - -**报错截图** -如果可以,提供发生错误的截图。 - -**测试引擎版本:** -本地运行出错的Orillusion引擎版本。 - -**本机系统 (请填写完整):** - - OS: [e.g. win, mac, android] - - Browser [e.g. chrome] - - Version [e.g. 113] - -**Codepen链接** -如果有sandbox/codepen的代码示例链接,请提供。 - -**其他信息** -添加关于bug的其他描述信息。 From c607937e7cc3bdc8eb59296a757e2cf26c90655c Mon Sep 17 00:00:00 2001 From: shabai517 Date: Sun, 23 Apr 2023 09:14:54 +0100 Subject: [PATCH 008/100] feat(math): add polynomials module --- src/engine/math/Polynomials.ts | 97 ++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/engine/math/Polynomials.ts diff --git a/src/engine/math/Polynomials.ts b/src/engine/math/Polynomials.ts new file mode 100644 index 00000000..4533c869 --- /dev/null +++ b/src/engine/math/Polynomials.ts @@ -0,0 +1,97 @@ +/** + * @internal + * @group Math + */ +export class Polynomials { } + +// Returns the highest root for the cubic x^3 + px^2 + qx + r +/** + * @internal + */ +export function cubicPolynomialRoot(p: number, q: number, r: number) { + let rcp3 = 1.0 / 3.0; + let half = 0.5; + let po3 = p * rcp3; + let po3_2 = po3 * po3; + let po3_3 = po3_2 * po3; + let b = po3_3 - po3 * q * half + r * half; + let a = -po3_2 + q * rcp3; + let a3 = a * a * a; + let det = a3 + b * b; + + if (det >= 0) { + let r0 = Math.sqrt(det) - b; + r0 = r0 > 0 ? Math.pow(r0, rcp3) : -Math.pow(-r0, rcp3); + + return -po3 - a / r0 + r0; + } + + let abs = Math.sqrt(-a3); + let arg = Math.acos(-b / abs); + abs = Math.pow(abs, rcp3); + abs = abs - a / abs; + arg = -po3 + abs * Math.cos(arg * rcp3); + return arg; +} + +// Calculates all real roots of polynomial ax^2 + bx + c (and returns how many) +/** + * @internal + */ +export function quadraticPolynomialRootsGeneric(a, b, c, out: { r0; r1 }) { + let eps = 0.00001; + if (Math.abs(a) < eps) { + if (Math.abs(b) > eps) { + out.r0 = -c / b; + return 1; + } else { + return 0; + } + } + + let disc = b * b - 4 * a * c; + if (disc < 0.0) { + return 0; + } + + let halfRcpA = 0.5 / a; + let sqrtDisc = Math.sqrt(disc); + out.r0 = (sqrtDisc - b) * halfRcpA; + out.r1 = (-sqrtDisc - b) * halfRcpA; + return 2; +} + +// Calculates all the roots for the cubic ax^3 + bx^2 + cx + d. Max num roots is 3. +/** + * @internal + */ +export function cubicPolynomialRootsGeneric(roots: number[], a: number, b: number, c: number, d: number) { + let numRoots = 0; + if (Math.abs(a) >= 0.0001) { + let p = b / a; + let q = c / a; + let r = d / a; + roots[0] = cubicPolynomialRoot(p, q, r); + numRoots++; + + let la = a; + let lb = b + a * roots[0]; + let lc = c + b * roots[0] + a * roots[0] * roots[0]; + numRoots += quadraticPolynomialRootsGeneric(la, lb, lc, { r0: roots[1], r1: roots[2] }); + } else { + numRoots += quadraticPolynomialRootsGeneric(b, c, d, { r0: roots[1], r1: roots[2] }); + } + + return numRoots; +} + +// // Specialized version of QuadraticPolynomialRootsGeneric that returns the largest root +// /** +// * @internal +// */ +// export function quadraticPolynomialRoot(a, b, c) { +// let r0; +// let r1; +// quadraticPolynomialRootsGeneric(a, b, c, { r0: r0, r1: r1 }); +// return r0; +// } From 4f4d7492244ab9845ef89346e573d2c30b2cb4c5 Mon Sep 17 00:00:00 2001 From: shabai517 Date: Sun, 23 Apr 2023 09:15:06 +0100 Subject: [PATCH 009/100] feat(math): add polynomialCurve module --- src/engine/math/PolynomialCurve.ts | 255 +++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 src/engine/math/PolynomialCurve.ts diff --git a/src/engine/math/PolynomialCurve.ts b/src/engine/math/PolynomialCurve.ts new file mode 100644 index 00000000..47b1730a --- /dev/null +++ b/src/engine/math/PolynomialCurve.ts @@ -0,0 +1,255 @@ +import { AnimationCurve, FrameCache } from './AnimationCurve'; +import { cubicPolynomialRootsGeneric } from './Polynomials'; +import { Vector2 } from './Vector2'; + +/** + * @internal + * @group Math + */ +export class Polynomial { + public coeff: number[] = []; + public static EvalSegment(t: number, coeff: number[]) { + return t * (t * (t * coeff[0] + coeff[1]) + coeff[2]) + coeff[3]; + } +} + +/** + * @internal + * @group Math + */ +export class PolynomialCurve { + private static kMaxNumSegments = 8; + public segments: Polynomial[] = []; + public integrationCache: number[] = []; + public doubleIntegrationCache: number[] = []; + public times: number[] = []; + public segmentCount: number; + + constructor() { + this.segments[PolynomialCurve.kMaxNumSegments] = new Polynomial(); + this.integrationCache[PolynomialCurve.kMaxNumSegments] = 0; + this.doubleIntegrationCache[PolynomialCurve.kMaxNumSegments] = 0; + this.times[PolynomialCurve.kMaxNumSegments] = 0; + } + + public calculateMinMax(minmax: Vector2, value) { + minmax.x = Math.min(minmax.x, value); + minmax.y = Math.max(minmax.y, value); + } + + public findMinMaxDoubleIntegrated(): Vector2 { + let result = Vector2.ZERO.clone(); + let numSteps = 20; + let delta = 1.0 / numSteps; + let acc = delta; + for (let i = 0; i < numSteps; i++) { + this.calculateMinMax(result, this.evaluateDoubleIntegrated(acc)); + acc += delta; + } + return result; + } + + // Find the maximum of the integrated curve (x: min, y: max) + public findMinMaxIntegrated(): Vector2 { + let result = Vector2.ZERO.clone(); + let prevTimeValue = 0.0; + + let start: [] = []; + let end: [] = []; + for (let i = 0; i < this.segmentCount; i++) { + // Differentiate coefficients + let a = 4.0 * this.segments[i].coeff[0]; + let b = 3.0 * this.segments[i].coeff[1]; + let c = 2.0 * this.segments[i].coeff[2]; + let d = 1.0 * this.segments[i].coeff[3]; + + let roots: number[] = []; + let numRoots = cubicPolynomialRootsGeneric(roots, a, b, c, d); + for (let r = 0; r < numRoots; r++) { + let root = roots[r] + start[i]; + if (root >= start[i] && root < end[i]) { + this.calculateMinMax(result, this.evaluateIntegrated(root)); + } + } + + // TODO: Don't use eval integrated, use eval segment (and integrate in loop) + this.calculateMinMax(result, this.evaluateIntegrated(end[i])); + prevTimeValue = this.times[i]; + } + return result; + } + + public generateIntegrationCache(curve: PolynomialCurve) { + curve.integrationCache[0] = 0.0; + let prevTimeValue0 = curve.times[0]; + let prevTimeValue1 = 0.0; + for (let i = 1; i < curve.segmentCount; i++) { + let coeff = curve.segments[i - 1].coeff; + integrateSegment(coeff); + let time = prevTimeValue0 - prevTimeValue1; + curve.integrationCache[i] = curve.integrationCache[i - 1] + Polynomial.EvalSegment(time, coeff) * time; + prevTimeValue1 = prevTimeValue0; + prevTimeValue0 = curve.times[i]; + } + } + + public generateDoubleIntegrationCache(curve: PolynomialCurve) { + let sum = 0.0; + let prevTimeValue = 0.0; + for (let i = 0; i < curve.segmentCount; i++) { + curve.doubleIntegrationCache[i] = sum; + let time = curve.times[i] - prevTimeValue; + time = Math.max(time, 0.0); + sum += Polynomial.EvalSegment(time, curve.segments[i].coeff) * time * time + curve.integrationCache[i] * time; + prevTimeValue = curve.times[i]; + } + } + + // Integrates a velocity curve to be a position curve. + // You have to call EvaluateIntegrated to evaluate the curve + public integrate() { + this.generateIntegrationCache(this); + for (let i = 0; i < this.segmentCount; i++) { + integrateSegment(this.segments[i].coeff); + } + } + + // Integrates a velocity curve to be a position curve. + // You have to call EvaluateDoubleIntegrated to evaluate the curve + public doubleIntegrate() { + this.generateIntegrationCache(this); + for (let i = 0; i < this.segmentCount; i++) { + doubleIntegrateSegment(this.segments[i].coeff); + } + this.generateDoubleIntegrationCache(this); + } + + // Evaluates if it is possible to represent animation curve as PolynomialCurve + static isValidCurve(editorCurve: AnimationCurve): boolean { + let keyCount = editorCurve.getKeyCount(); + let segmentCount = keyCount - 1; + if (editorCurve.getKey(0).time != 0.0) { + segmentCount++; + } + if (editorCurve.getKey(keyCount - 1).time != 1.0) { + segmentCount++; + } + return segmentCount <= PolynomialCurve.kMaxNumSegments; + } + + public evaluateDoubleIntegrated(t) { + let prevTimeValue = 0.0; + for (let i = 0; i < this.segmentCount; i++) { + if (t <= this.times[i]) { + let time = t - prevTimeValue; + return this.doubleIntegrationCache[i] + this.integrationCache[i] * time + Polynomial.EvalSegment(time, this.segments[i].coeff) * time * time; + } + prevTimeValue = this.times[i]; + } + return 1.0; + } + + // Evaluate integrated Polynomial curve. + // Example: position = EvaluateIntegrated (normalizedTime) * startEnergy + // Use Integrate function to for example turn a velocity curve into a position curve. + // Expects that t is in the 0...1 range. + public evaluateIntegrated(t) { + let prevTimeValue = 0.0; + for (let i = 0; i < this.segmentCount; i++) { + if (t <= this.times[i]) { + let time = t - prevTimeValue; + return this.integrationCache[i] + Polynomial.EvalSegment(time, this.segments[i].coeff) * time; + } + prevTimeValue = this.times[i]; + } + return 1.0; + } + + // Evaluate the curve + // extects that t is in the 0...1 range + public evaluate(t): number { + let prevTimeValue = 0.0; + for (let i = 0; i < this.segmentCount; i++) { + if (t <= this.times[i]) { + return Polynomial.EvalSegment(t - prevTimeValue, this.segments[i].coeff); + + } + prevTimeValue = this.times[i]; + } + return 1.0; + } + + public buildCurve(editorCurve: AnimationCurve, scale: number) { + let keyCount = editorCurve.getKeyCount(); + this.segmentCount = 1; + + let kMaxTime = 1.01; + this.segments.length = 0; + this.integrationCache.length = 0; + this.doubleIntegrationCache.length = 0; + this.times.length = 0; + this.times[0] = kMaxTime; + + // Handle corner case 1 & 0 keyframes + if (keyCount == 0) { + } else if (keyCount == 1) { + this.segments[0] = new Polynomial(); + this.segments[0].coeff[3] = editorCurve.getKey(0).value * scale; + } else { + this.segmentCount = keyCount - 1; + let segmentOffset = 0; + + // Add extra key to start if it doesn't match up + if (editorCurve.getKey(0).time != 0.0) { + this.segments[0].coeff[3] = editorCurve.getKey(0).value; + this.times[0] = editorCurve.getKey(0).time; + segmentOffset = 1; + } + + for (let i = 0; i < this.segmentCount; i++) { + let cache: FrameCache; + editorCurve.calculateCacheData(cache, i, i + 1, 0.0); + this.segments[i + segmentOffset].coeff = cache.coeff.concat(); + this.times[i + segmentOffset] = editorCurve.getKey(i + 1).time; + } + this.segmentCount += segmentOffset; + + // Add extra key to start if it doesn't match up + if (editorCurve.getKey(keyCount - 1).time != 1.0) { + this.segments[this.segmentCount].coeff[3] = editorCurve.getKey(keyCount - 1).value; + this.segmentCount++; + } + + // Fixup last key time value + this.times[this.segmentCount - 1] = kMaxTime; + + for (let i = 0; i < this.segmentCount; i++) { + this.segments[i].coeff[0] *= scale; + this.segments[i].coeff[1] *= scale; + this.segments[i].coeff[2] *= scale; + this.segments[i].coeff[3] *= scale; + } + } + return true; + } +} + +/** + * @internal + */ +export function doubleIntegrateSegment(coeff) { + coeff[0] /= 20.0; + coeff[1] /= 12.0; + coeff[2] /= 6.0; + coeff[3] /= 2.0; +} + +/** + * @internal + */ +export function integrateSegment(coeff) { + coeff[0] /= 4.0; + coeff[1] /= 3.0; + coeff[2] /= 2.0; + coeff[3] /= 1.0; +} From 9b15e33dc037beac3e8a7030e10cdb5749764c73 Mon Sep 17 00:00:00 2001 From: shabai517 Date: Sun, 23 Apr 2023 09:15:16 +0100 Subject: [PATCH 010/100] feat(math): add line module --- src/engine/math/Line.ts | 285 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 src/engine/math/Line.ts diff --git a/src/engine/math/Line.ts b/src/engine/math/Line.ts new file mode 100644 index 00000000..80c504ca --- /dev/null +++ b/src/engine/math/Line.ts @@ -0,0 +1,285 @@ +import { Color } from './Color'; +import { Matrix4 } from './Matrix4'; +import { Ray } from './Ray'; +import { Vector3 } from './Vector3'; +import { repeat } from './MathUtil'; +/** + * @internal + */ +export enum LineClassification { + COLLINEAR, + LINES_INTERSECT, + SEGMENTS_INTERSECT, + A_BISECTS_B, + B_BISECTS_A, + PARALELL, +} +/** + * @internal + */ +export enum PointClassification { + ON_LINE, + LEFT_SIDE, + RIGHT_SIDE, +} +/** + * @internal + * @group Math + */ +export class Line { + static cacluteLine0: Line = new Line(null, null); + static cacluteLine1: Line = new Line(null, null); + + public start: Vector3; + public end: Vector3; + public color: Color = new Color(1, 1, 1, 1); + private _normal: Vector3; + private _normalCalculated: boolean = false; + + constructor(start?: Vector3, end?: Vector3) { + this.start = start; + this.end = end; + } + + public set(start: Vector3, end: Vector3) { + this.start = start; + this.end = end; + } + + public getCenter(): Vector3 { + let help = Vector3.HELP_0; + this.start.subtract(this.end, help); + help.scaleBy(0.5); + help.add(this.end); + return help; + } + + public inverse() { + let tmp = this.start; + this.start = this.end; + this.end = tmp; + } + + public equals(l: Line): boolean { + if ((this.start == l.start && this.end == l.end) || (this.start == l.end && this.end == l.start)) return true; + return false; + } + + /** + */ + public toArray() { + return [this.start.x, this.start.y, this.start.z, this.end.x, this.end.y, this.end.z]; + } + + /** + * @param ps + */ + public static getLines(ps: Vector3[]): Line[] { + let arr: Line[] = []; + for (let index = 0; index < ps.length; index++) { + let i0 = index; + let i1 = repeat(index + 1, ps.length); + let p0 = ps[i0]; + let p1 = ps[i1]; + arr.push(new Line(p0, p1)); + } + return arr; + } + + /** + * 判断两个直线关系 + * this line A = x0, y0 and B = x1, y1 + * other is A = x2, y2 and B = x3, y3 + * @param other 另一条直线 + * @param pIntersectPoint (out)返回两线段的交点 + * @return + */ + public intersection(other: Line, pIntersectPoint: Vector3 = null): LineClassification { + var denom: number = (other.end.z - other.start.z) * (this.end.x - this.start.x) - (other.end.x - other.start.x) * (this.end.z - this.start.z); + + var u0: number = (other.end.x - other.start.x) * (this.start.z - other.start.z) - (other.end.z - other.start.z) * (this.start.x - other.start.x); + + var u1: number = (other.start.x - this.start.x) * (this.end.z - this.start.z) - (other.start.z - this.start.z) * (this.end.x - this.start.x); + + //if parallel + if (denom == 0.0) { + if (u0 == 0.0 && u1 == 0.0) return LineClassification.COLLINEAR; + else return LineClassification.PARALELL; + } else { + u0 = u0 / denom; + u1 = u1 / denom; + + var x: number = this.start.x + u0 * (this.end.x - this.start.x); + var z: number = this.start.z + u0 * (this.end.z - this.start.z); + + if (pIntersectPoint != null) { + pIntersectPoint.x = x; + pIntersectPoint.y = 0; + pIntersectPoint.z = z; + } + + if (u0 >= 0.0 && u0 <= 1.0 && u1 >= 0.0 && u1 <= 1.0) { + return LineClassification.SEGMENTS_INTERSECT; + } else if (u1 >= 0.0 && u1 <= 1.0) { + return LineClassification.A_BISECTS_B; + } else if (u0 >= 0.0 && u0 <= 1.0) { + return LineClassification.B_BISECTS_A; + } + + return LineClassification.LINES_INTERSECT; + } + } + + /** + * 直线方向 + * @return + */ + public getDirection(): Vector3 { + var pt: Vector3 = this.end.subtract(this.start); + var direction: Vector3 = new Vector3(pt.x, pt.y); + return direction.normalize(); + } + + copyFrom(line: Line) { + if (!this.start) this.start = new Vector3(); + if (!this.end) this.end = new Vector3(); + this.start.copyFrom(line.start); + this.end.copyFrom(line.end); + } + + public static IsEqual(d1, d2) { + if (Math.abs(d1 - d2) < 1e-7) return true; + return false; + } + + public static squreDistanceSegmentToSegment(lineA: Line, lineB: Line, mat?: Matrix4) { + let a_po: Vector3 = lineA.start; + let a_p1: Vector3 = lineA.end; + + let b_po: Vector3 = lineB.start; + let b_p1: Vector3 = lineB.end; + + let x1 = a_po.x; + let y1 = a_po.y; + let z1 = a_po.z; + + let x2 = a_p1.x; + let y2 = a_p1.y; + let z2 = a_p1.z; + + let x3 = b_po.x; + let y3 = b_po.y; + let z3 = b_po.z; + + let x4 = b_p1.x; + let y4 = b_p1.y; + let z4 = b_p1.z; + + let ux = x2 - x1; + let uy = y2 - y1; + let uz = z2 - z1; + + let vx = x4 - x3; + let vy = y4 - y3; + let vz = z4 - z3; + + let wx = x1 - x3; + let wy = y1 - y3; + let wz = z1 - z3; + + let a = ux * ux + uy * uy + uz * uz; + let b = ux * vx + uy * vy + uz * vz; + let c = vx * vx + vy * vy + vz * vz; + let d = ux * wx + uy * wy + uz * wz; + let e = vx * wx + vy * wy + vz * wz; + let dt = a * c - b * b; + + let sd = dt; + let td = dt; + + let sn = 0.0; + let tn = 0.0; + + if (this.IsEqual(dt, 0.0)) { + sn = 0.0; + sd = 1.0; + + tn = e; + td = c; + } else { + sn = b * e - c * d; + tn = a * e - b * d; + if (sn < 0.0) { + sn = 0.0; + tn = e; + td = c; + } else if (sn > sd) { + sn = sd; + tn = e + b; + td = c; + } + } + if (tn < 0.0) { + tn = 0.0; + if (-d < 0.0) + sn = 0.0; + else if (-d > a) + sn = sd; + else { + sn = -d; + sd = a; + } + } else if (tn > td) { + tn = td; + if (-d + b < 0.0) sn = 0.0; + else if (-d + b > a) sn = sd; + else { + sn = -d + b; + sd = a; + } + } + + let sc = 0.0; + let tc = 0.0; + + if (this.IsEqual(sn, 0.0)) sc = 0.0; + else sc = sn / sd; + + if (this.IsEqual(tn, 0.0)) tc = 0.0; + else tc = tn / td; + + let dx = wx + sc * ux - tc * vx; + let dy = wy + sc * uy - tc * vy; + let dz = wz + sc * uz - tc * vz; + return dx * dx + dy * dy + dz * dz; + } + + /** + * isNearLine + */ + public isNear(ray: Ray, maxDistance: number = 0, mat?: Matrix4): boolean { + // //@task to-do + let tmpP0 = Vector3.HELP_0; + let tmpP1 = Vector3.HELP_1; + tmpP0.copyFrom(ray.origin); + tmpP1.copyFrom(ray.direction); + + tmpP1.scaleBy(9999); + tmpP1.add(tmpP0, tmpP1); + Line.cacluteLine0.set(tmpP0, tmpP1); + Line.cacluteLine1.copyFrom(this); + + if (mat) { + mat.perspectiveMultiplyPoint3(Line.cacluteLine1.start, Line.cacluteLine1.start); + mat.perspectiveMultiplyPoint3(Line.cacluteLine1.end, Line.cacluteLine1.end); + } + + let dis = Line.squreDistanceSegmentToSegment(Line.cacluteLine0, Line.cacluteLine1, mat); + if (dis + 1e-4 <= maxDistance) { + ray.length = dis; + return true; + } + ray.length = -999999; + return false; + } +} From cdd5019b7c0cb34a9c5a981b22749b6b08d54bd0 Mon Sep 17 00:00:00 2001 From: shabai517 Date: Sun, 23 Apr 2023 09:15:23 +0100 Subject: [PATCH 011/100] feat(math): add color module --- src/engine/math/Color.ts | 856 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 856 insertions(+) create mode 100644 src/engine/math/Color.ts diff --git a/src/engine/math/Color.ts b/src/engine/math/Color.ts new file mode 100644 index 00000000..09ac7493 --- /dev/null +++ b/src/engine/math/Color.ts @@ -0,0 +1,856 @@ +/** + * RGBA Color Object + * @group Math + */ +export class Color { + + /** + * red color + */ + public static COLOR_RED: Color = new Color(1, 0, 0, 1); + + /** + * green color + */ + public static COLOR_GREEN: Color = new Color(0, 1, 0, 1); + + /** + * blue color + */ + public static COLOR_BLUE: Color = new Color(0, 0, 1, 1); + + /** + * white color + */ + public static COLOR_WHITE: Color = new Color(1, 1, 1, 1); + + /** + * cache + * @internal + */ + public static COLOR_0: Color = new Color(); + /** + * cache + * @internal + */ + public static COLOR_1: Color = new Color(); + /** + * cache + * @internal + */ + public static COLOR_2: Color = new Color(); + + /** + * @internal + */ + private static HEX_CHARACTERS = 'a-f\\d'; + + /** + * @internal + */ + private static MATCH_3OR4_HEX = `#?[${Color.HEX_CHARACTERS}]{3}[${Color.HEX_CHARACTERS}]?`; + /** + * @internal + */ + private static MATCH_6OR8_HEX = `#?[${Color.HEX_CHARACTERS}]{6}([${Color.HEX_CHARACTERS}]{2})?`; + /** + * @internal + */ + private static NON_HEX_CHARS = new RegExp(`[^#${Color.HEX_CHARACTERS}]`, 'gi'); + /** + * @internal + */ + private static VALID_HEX_SIZE = new RegExp(`^${Color.MATCH_3OR4_HEX}$|^${Color.MATCH_6OR8_HEX}$`, 'i'); + + /** + * red channel + */ + public r: number = 0; + + /** + * green channel + */ + public g: number = 0; + + /** + * blue channel + */ + public b: number = 0; + + /** + * alpha channel + */ + public a: number = 0; + + /** + * create new color instance + * @param r red channel + * @param g green channel + * @param b blue channel + * @param a alpha channel + */ + constructor(r: number = 1.0, g: number = 1.0, b: number = 1.0, a: number = 1.0) { + this.setTo(r, g, b, a); + } + + /*** + * convert to hdr color , channel a is intensity + */ + convertToHDRRGB(): Color { + this.r = this.r * Math.pow(2.4, this.a); + this.g = this.g * Math.pow(2.4, this.a); + this.b = this.b * Math.pow(2.4, this.a); + return this; + } + + /** + * unSerialized color by data + * @param data + * @returns + */ + public unSerialized(data: any): this { + this.r = data['r']; + this.g = data['g']; + this.b = data['b']; + this.a = data['a']; + return this; + } + + /** + * update this color rgb form hexadecimal no alpha + * @param value + */ + public hexToRGB(value: number) { + //this.a = ((value >> 24) & 0xff ) / 255; + this.r = ((value >> 16) & 0xff) / 255; + this.g = ((value >> 8) & 0xff) / 255; + this.b = (value & 0xff) / 255; + } + + /** + * update this color rgb form hexadecimal has alpha + * @param value + */ + public hexToRGBA(value: number) { + this.a = ((value >> 24) & 0xff) / 255; + this.r = ((value >> 16) & 0xff) / 255; + this.g = ((value >> 8) & 0xff) / 255; + this.b = (value & 0xff) / 255; + } + + /** + * random on color + * @returns + */ + public static random(base: number = 1.0): Color { + let color = new Color(); + color.a = base; + color.r = base * Math.random(); + color.g = base * Math.random(); + color.b = base * Math.random(); + return color; + } + + /** + * set rgba to this color + * @param r red channel + * @param g green channel + * @param b blue channel + * @param a alpha channel + */ + public setTo(r: number, g: number, b: number, a: number) { + this.r = Math.max(r, 0.0); + this.g = Math.max(g, 0.0); + this.b = Math.max(b, 0.0); + this.a = Math.max(a, 0.0); + } + + /** + * update this color rgba form hexadecimal + * @param hex hex string。 + */ + public setHex(hex: string) { + if (typeof hex !== 'string' || Color.NON_HEX_CHARS.test(hex) || !Color.VALID_HEX_SIZE.test(hex)) { + throw new TypeError('Expected a valid hex string'); + } + hex = hex.replace(/^#/, ''); + let alphaFromHex = 1; + + if (hex.length === 8) { + alphaFromHex = Number.parseInt(hex.slice(6, 8), 16) / 255; + hex = hex.slice(0, 6); + } + + if (hex.length === 4) { + alphaFromHex = Number.parseInt(hex.slice(3, 4).repeat(2), 16) / 255; + hex = hex.slice(0, 3); + } + + if (hex.length === 3) { + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; + } + + const number = Number.parseInt(hex, 16); + const red = number >> 16; + const green = (number >> 8) & 255; + const blue = number & 255; + const alpha = alphaFromHex; + this.a = alpha; + this.r = red / 255; + this.g = green / 255; + this.b = blue / 255; + } + + /** + * convert this color to hex string code + * @returns + */ + public getHex(): string { + let getHexStr = (n: number) => { + n *= 255.0; + let str = n.toString(16); + if (str.length === 1) { + str = '0' + str; + } + return str; + }; + let hex = getHexStr(this.r) + getHexStr(this.g) + getHexStr(this.b) + getHexStr(this.a); + return hex; + } + + /** + * get rgb to array + */ + public get rgb(): number[] { + return [(this.r * 255) >>> 0, (this.g * 255) >>> 0, (this.b * 255) >>> 0]; + } + + /** + * set rgb by array + */ + public set rgb(c: number[]) { + this.setTo(c[0] / 255, c[1] / 255, c[2] / 255, this.a); + } + + /** + * get rgba to array + */ + public get rgba(): number[] { + return [(this.r * 255) >>> 0, (this.g * 255) >>> 0, (this.b * 255) >>> 0, (this.a * 255) >>> 0]; + } + + /** + * set rgb by array + */ + public set rgba(c: number[]) { + this.setTo(c[0] / 255, c[1] / 255, c[2] / 255, c[3] / 255); + } + + /** + * clone this color + * @returns + */ + public clone(): Color { + return new Color().copyForm(this); + } + + /** + * copy color form source color + * @returns + */ + public copyForm(src: Color): this { + this.r = src.r; + this.g = src.g; + this.b = src.b; + this.a = src.a; + return this; + } + + /** + * copy color form array + * @param arr [ 255 , 255 , 255 , 255 ] + * @param scalar + * @returns + */ + public copyFormArray(arr: number[], scalar: number = 255) { + this.r = arr[0] / scalar; + this.g = arr[1] / scalar; + this.b = arr[2] / scalar; + this.a = arr[3] / scalar; + return this; + } + + /** + * update this color rgb form hexadecimal no alpha + * @param hexColor rgb color + * @param dst ref out color + */ + public static hexRGBColor(hexColor: number, dst: Color = null): Color { + dst = dst || new Color(); + dst.hexToRGB(hexColor); + return dst; + } + + + + public static PRIMARY = 0x3f51b5; // + public static PRIMARYDARK = 0x303f9f; // + public static ACCENT = 0xff4081; // + /** + * 白色十六进制值 + */ + public static WHITE = 0xffffff; // + /** + * 象牙色十六进制值 + */ + public static IVORY = 0xfffff0; // + /** + * 亮黄色十六进制值 + */ + public static LIGHTYELLOW = 0xffffe0; // + /** + * 黄色十六进制值 + */ + public static YELLOW = 0xffff00; // + /** + * 雪白色十六进制值 + */ + public static SNOW = 0xfffafa; // + /** + * 花白色十六进制值 + */ + public static FLORALWHITE = 0xfffaf0; // + /** + * 柠檬绸十六进制值 + */ + public static LEMONCHIFFON = 0xfffacd; // + /** + * 米绸色十六进制值 + */ + public static CORNSILK = 0xfff8dc; // + /** + * 海贝色十六进制值 + */ + public static SEASHELL = 0xfff5ee; // + /** + * 淡紫红十六进制值 + */ + public static LAVENDERBLUSH = 0xfff0f5; // + /** + * 番木色十六进制值 + */ + public static PAPAYAWHIP = 0xffefd5; // + /** + * 白杏色十六进制值 + */ + public static BLANCHEDALMOND = 0xffebcd; // + /** + * 浅玫瑰色十六进制值 + */ + public static MISTYROSE = 0xffe4e1; // + /** + * 桔黄色十六进制值 + */ + public static BISQUE = 0xffe4c4; // + /** + * 鹿皮色十六进制值 + */ + public static MOCCASIN = 0xffe4b5; // + /** + * 纳瓦白十六进制值 + */ + public static NAVAJOWHITE = 0xffdead; // + /** + * 桃色十六进制值 + */ + public static PEACHPUFF = 0xffdab9; // + /** + * 金色十六进制值 + */ + public static GOLD = 0xffd700; // + /** + * 粉红色十六进制值 + */ + public static PINK = 0xffc0cb; // + /** + * 亮粉红色十六进制值 + */ + public static LIGHTPINK = 0xffb6c1; // + /** + * 橙色十六进制值 + */ + public static ORANGE = 0xffa500; // + /** + * 亮肉色十六进制值 + */ + public static LIGHTSALMON = 0xffa07a; // + /** + * 暗桔黄色十六进制值 + */ + public static DARKORANGE = 0xff8c00; // + /** + * 珊瑚色十六进制值 + */ + public static CORAL = 0xff7f50; // + /** + * 热粉红色十六进制值 + */ + public static HOTPINK = 0xff69b4; // + /** + * 西红柿色十六进制值 + */ + public static TOMATO = 0xff6347; // + /** + * 红橙色十六进制值 + */ + public static ORANGERED = 0xff4500; // + /** + * 深粉红色十六进制值 + */ + public static DEEPPINK = 0xff1493; // + /** + * 紫红色十六进制值 + */ + public static FUCHSIA = 0xff00ff; // + /** + * 红紫色十六进制值 + */ + public static MAGENTA = 0xff00ff; // + /** + * 红色十六进制值 + */ + public static RED = 0xff0000; // + /** + * 老花色十六进制值 + */ + public static OLDLACE = 0xfdf5e6; // + /** + * 亮金黄色十六进制值 + */ + public static LIGHTGOLDENRODYELLOW = 0xfafad2; // + /** + * 亚麻色十六进制值 + */ + public static LINEN = 0xfaf0e6; // + /** + * 古董白十六进制值 + */ + public static ANTIQUEWHITE = 0xfaebd7; // + /** + * 鲜肉色十六进制值 + */ + public static SALMON = 0xfa8072; // + /** + * 幽灵白十六进制值 + */ + public static GHOSTWHITE = 0xf8f8ff; // + /** + * 薄荷色十六进制值 + */ + public static MINTCREAM = 0xf5fffa; // + /** + * 烟白色十六进制值 + */ + public static WHITESMOKE = 0xf5f5f5; // + /** + * 米色十六进制值 + */ + public static BEIGE = 0xf5f5dc; // + /** + * 浅黄色十六进制值 + */ + public static WHEAT = 0xf5deb3; // + /** + * 沙褐色十六进制值 + */ + public static SANDYBROWN = 0xf4a460; // + /** + * 天蓝色十六进制值 + */ + public static AZURE = 0xf0ffff; // + /** + * 蜜色十六进制值 + */ + public static HONEYDEW = 0xf0fff0; // + /** + * 艾利斯兰色十六进制值 + */ + public static ALICEBLUE = 0xf0f8ff; // + /** + * 黄褐色十六进制值 + */ + public static KHAKI = 0xf0e68c; // + /** + * 亮珊瑚色十六进制值 + */ + public static LIGHTCORAL = 0xf08080; // + /** + * 苍麒麟色十六进制值 + */ + public static PALEGOLDENROD = 0xeee8aa; // + /** + * 紫罗兰色十六进制值 + */ + public static VIOLET = 0xee82ee; // + /** + * 暗肉色十六进制值 + */ + public static DARKSALMON = 0xe9967a; // + /** + * 淡紫色十六进制值 + */ + public static LAVENDER = 0xe6e6fa; // + /** + * 亮青色十六进制值 + */ + public static LIGHTCYAN = 0xe0ffff; // + /** + * 实木色十六进制值 + */ + public static BURLYWOOD = 0xdeb887; // + /** + * 洋李色十六进制值 + */ + public static PLUM = 0xdda0dd; // + /** + * 淡灰色十六进制值 + */ + public static GAINSBORO = 0xdcdcdc; // + /** + * 暗深红色十六进制值 + */ + public static CRIMSON = 0xdc143c; // + /** + * 苍紫罗兰色十六进制值 + */ + public static PALEVIOLETRED = 0xdb7093; // + /** + * 金麒麟色十六进制值 + */ + public static GOLDENROD = 0xdaa520; // + /** + * 淡紫色十六进制值 + */ + public static ORCHID = 0xda70d6; // + /** + * 蓟色十六进制值 + */ + public static THISTLE = 0xd8bfd8; // + /** + * 亮灰色十六进制值 + */ + public static LIGHTGREY = 0xd3d3d3; // + /** + * 茶色十六进制值 + */ + public static TAN = 0xd2b48c; // + /** + * 巧可力色十六进制值 + */ + public static CHOCOLATE = 0xd2691e; // + /** + * 秘鲁色十六进制值 + */ + public static PERU = 0xcd853f; // + /** + * 印第安红十六进制值 + */ + public static INDIANRED = 0xcd5c5c; // + /** + * 中紫罗兰色十六进制值 + */ + public static MEDIUMVIOLETRED = 0xc71585; // + /** + * 银色十六进制值 + */ + public static SILVER = 0xc0c0c0; // + /** + * 暗黄褐色十六进制值 + */ + public static DARKKHAKI = 0xbdb76b; // + /** + * 褐玫瑰红十六进制值 + */ + public static ROSYBROWN = 0xbc8f8f; // + /** + * 中粉紫色十六进制值 + */ + public static MEDIUMORCHID = 0xba55d3; // + /** + * 暗金黄色十六进制值 + */ + public static DARKGOLDENROD = 0xb8860b; // + /** + * 火砖色十六进制值 + */ + public static FIREBRICK = 0xb22222; // + /** + * 粉蓝色十六进制值 + */ + public static POWDERBLUE = 0xb0e0e6; // + /** + * 亮钢兰色十六进制值 + */ + public static LIGHTSTEELBLUE = 0xb0c4de; // + /** + * 苍宝石绿十六进制值 + */ + public static PALETURQUOISE = 0xafeeee; // + /** + * 黄绿色十六进制值 + */ + public static GREENYELLOW = 0xadff2f; // + /** + * 亮蓝色十六进制值 + */ + public static LIGHTBLUE = 0xadd8e6; // + /** + * 暗灰色十六进制值 + */ + public static DARKGRAY = 0xa9a9a9; // + /** + * 褐色十六进制值 + */ + public static BROWN = 0xa52a2a; // + /** + * 赭色十六进制值 + */ + public static SIENNA = 0xa0522d; // + /** + * 暗紫色十六进制值 + */ + public static DARKORCHID = 0x9932cc; // + /** + * 苍绿色十六进制值 + */ + public static PALEGREEN = 0x98fb98; // + /** + * 暗紫罗兰色十六进制值 + */ + public static DARKVIOLET = 0x9400d3; // + /** + * 中紫色十六进制值 + */ + public static MEDIUMPURPLE = 0x9370db; // + /** + * 亮绿色十六进制值 + */ + public static LIGHTGREEN = 0x90ee90; // + /** + * 暗海兰色十六进制值 + */ + public static DARKSEAGREEN = 0x8fbc8f; // + /** + * 重褐色十六进制值 + */ + public static SADDLEBROWN = 0x8b4513; // + /** + * 暗洋红十六进制值 + */ + public static DARKMAGENTA = 0x8b008b; // + /** + * 暗红色十六进制值 + */ + public static DARKRED = 0x8b0000; // + /** + * 紫罗兰蓝色十六进制值 + */ + public static BLUEVIOLET = 0x8a2be2; // + /** + * 亮天蓝色十六进制值 + */ + public static LIGHTSKYBLUE = 0x87cefa; // + /** + * 天蓝色十六进制值 + */ + public static SKYBLUE = 0x87ceeb; // + /** + * 灰色十六进制值 + */ + public static GRAY = 0x808080; // + /** + * 橄榄色十六进制值 + */ + public static OLIVE = 0x808000; // + /** + * 紫色十六进制值 + */ + public static PURPLE = 0x800080; // + /** + * 粟色十六进制值 + */ + public static MAROON = 0x800000; // + /** + * 碧绿色十六进制值 + */ + public static AQUAMARINE = 0x7fffd4; // + /** + * 黄绿色十六进制值 + */ + public static CHARTREUSE = 0x7fff00; // + /** + * 草绿色十六进制值 + */ + public static LAWNGREEN = 0x7cfc00; // + /** + * 中暗蓝色十六进制值 + */ + public static MEDIUMSLATEBLUE = 0x7b68ee; // + /** + * 亮蓝灰十六进制值 + */ + public static LIGHTSLATEGRAY = 0x778899; // + /** + * 灰石色十六进制值 + */ + public static SLATEGRAY = 0x708090; // + /** + * 深绿褐色十六进制值 + */ + public static OLIVEDRAB = 0x6b8e23; // + /** + * 石蓝色十六进制值 + */ + public static SLATEBLUE = 0x6a5acd; // + /** + * 暗灰色十六进制值 + */ + public static DIMGRAY = 0x696969; // + /** + * 中绿色十六进制值 + */ + public static MEDIUMAQUAMARINE = 0x66cdaa; // + /** + * 菊兰色十六进制值 + */ + public static CORNFLOWERBLUE = 0x6495ed; // + /** + * 军兰色十六进制值 + */ + public static CADETBLUE = 0x5f9ea0; // + /** + * 暗橄榄绿色十六进制值 + */ + public static DARKOLIVEGREEN = 0x556b2f; // + /** + * 靛青色十六进制值 + */ + public static INDIGO = 0x4b0082; // + /** + * 中绿宝石色十六进制值 + */ + public static MEDIUMTURQUOISE = 0x48d1cc; // + /** + * 暗灰蓝色十六进制值 + */ + public static DARKSLATEBLUE = 0x483d8b; // + /** + * 钢兰色十六进制值 + */ + public static STEELBLUE = 0x4682b4; // + /** + * 皇家蓝色十六进制值 + */ + public static ROYALBLUE = 0x4169e1; // + /** + * 青绿色十六进制值 + */ + public static TURQUOISE = 0x40e0d0; // + /** + * 中海蓝色十六进制值 + */ + public static MEDIUMSEAGREEN = 0x3cb371; // + /** + * 橙绿色十六进制值 + */ + public static LIMEGREEN = 0x32cd32; // + /** + * 暗瓦灰色十六进制值 + */ + public static DARKSLATEGRAY = 0x2f4f4f; // + /** + * 海绿色十六进制值 + */ + public static SEAGREEN = 0x2e8b57; // + /** + * 森林绿十六进制值 + */ + public static FORESTGREEN = 0x228b22; // + /** + * 亮海蓝色十六进制值 + */ + public static LIGHTSEAGREEN = 0x20b2aa; // + /** + * 闪兰色十六进制值 + */ + public static DODGERBLUE = 0x1e90ff; // + /** + * 中灰兰色十六进制值 + */ + public static MIDNIGHTBLUE = 0x191970; // + /** + * 浅绿色十六进制值 + */ + public static AQUA = 0x00ffff; // + /** + * 青色十六进制值 + */ + public static CYAN = 0x00ffff; // + /** + * 春绿色十六进制值 + */ + public static SPRINGGREEN = 0x00ff7f; // + /** + * 酸橙色十六进制值 + */ + public static LIME = 0x00ff00; // + /** + * 中春绿色十六进制值 + */ + public static MEDIUMSPRINGGREEN = 0x00fa9a; // + /** + * 暗宝石绿色十六进制值 + */ + public static DARKTURQUOISE = 0x00ced1; // + /** + * 深天蓝色十六进制值 + */ + public static DEEPSKYBLUE = 0x00bfff; // + /** + * 暗青色十六进制值 + */ + public static DARKCYAN = 0x008b8b; // + /** + * 水鸭色十六进制值 + */ + public static TEAL = 0x008080; // + /** + * 绿色十六进制值 + */ + public static GREEN = 0x008000; // + /** + * 暗绿色十六进制值 + */ + public static DARKGREEN = 0x006400; // + /** + * 蓝色十六进制值 + */ + public static BLUE = 0x0000ff; // + /** + * 中兰色十六进制值 + */ + public static MEDIUMBLUE = 0x0000cd; // + /** + * 暗蓝色十六进制值 + */ + public static DARKBLUE = 0x00008b; // + /** + * 海军色十六进制值 + */ + public static NAVY = 0x000080; // + /** + * 黑色十六进制值 + */ + public static BLACK = 0x000000; // + +} From f03adbed943eb6ca575f4524cd86b25103a35f55 Mon Sep 17 00:00:00 2001 From: shabai517 Date: Sun, 23 Apr 2023 09:15:35 +0100 Subject: [PATCH 012/100] feat(math): add Bezier3d module --- src/engine/math/Bezier3D.ts | 122 ++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/engine/math/Bezier3D.ts diff --git a/src/engine/math/Bezier3D.ts b/src/engine/math/Bezier3D.ts new file mode 100644 index 00000000..a869392e --- /dev/null +++ b/src/engine/math/Bezier3D.ts @@ -0,0 +1,122 @@ +import { Vector3 } from './Vector3'; +/** + * 3D Bezier Curve + * @group Math + */ +export class Bezier3D { + private static tmp_points: Vector3[] = []; + + /** + * get cubic curve point value form t at bezier data + * @param t interval value + * @param p0 start point + * @param c1 left control point + * @param c2 right control point + * @param p3 end point + * @returns cubic curve point + */ + public static calculateCubicBezierPoint(t: number, p0: Vector3, c1: Vector3, c2: Vector3, p3: Vector3): Vector3 { + if (t > 1) t = 1; + if (t < 0) t = 0; + let u = 1 - t; + let uu = u * u; + let uuu = u * u * u; + let tt = t * t; + let ttt = t * t * t; + let p = p0.mul(uuu); + let tp1 = c1.mul(3); + tp1 = tp1.mul(t); + tp1 = tp1.mul(uu); + + let tp2 = c2.mul(3); + tp2 = tp2.mul(tt); + tp2 = tp2.mul(u); + + let tp3 = p3.mul(ttt); + p = p.add(tp1); + p = p.add(tp2); + p = p.add(tp3); + return p; + } + + /** + * get curve point form three point bezier curve + * @param t interval value + * @param p0 start point + * @param c1 contrl point + * @param p1 end point + * @returns get bezier point at curve + */ + public static bezierPoint(t: number, p0: Vector3, c1: Vector3, p1: Vector3): Vector3 { + if (t > 1) t = 1; + if (t < 0) t = 0; + let u = 1 - t; + let uu = u * u; + let tt = t * t; + + let pp0 = p0.mul(uu); + + let cc1 = c1.mul(2); + cc1.scaleBy(u); + cc1.scaleBy(t); + + let pp1 = p1.mul(tt); + + pp0 = pp0.add(cc1); + pp0 = pp0.add(pp1); + + return pp0; + } + + private static calculateCubicBezierPoints(t: number, ps: Vector3[], skip: number): Vector3 { + if (t > 1) t = 1; + if (t < 0) t = 0; + let u = 1 - t; + let uu = u * u; + let uuu = u * u * u; + let tt = t * t; + let ttt = t * t * t; + let p = ps[skip].mul(uuu); + let tp1 = ps[skip + 1].mul(3); + tp1 = tp1.mul(t); + tp1 = tp1.mul(uu); + + let tp2 = ps[skip + 2].mul(3); + tp2 = tp2.mul(tt); + tp2 = tp2.mul(u); + + let tp3 = ps[skip + 3].mul(ttt); + p = p.add(tp1); + p = p.add(tp2); + p = p.add(tp3); + + return p; + } + + private static bezierPathValue(t: number, points: Vector3[]): Vector3 { + if (t > 1) t = 1; + if (t < 0) t = 0; + let count = points.length; + let tmp_points = this.tmp_points; + tmp_points.length = 0; + + for (let i = 1; i < count; ++i) { + for (let j = 0; j < count - i; ++j) { + if (i == 1) { + let v = new Vector3(); + v.x = points[j].x * (1 - t) + points[j + 1].x * t; + v.y = points[j].y * (1 - t) + points[j + 1].y * t; + v.z = points[j].z * (1 - t) + points[j + 1].z * t; + this.tmp_points.push(v); + continue; + } + let v2 = new Vector3(); + v2.x = tmp_points[j].x * (1 - t) + tmp_points[j + 1].x * t; + v2.y = tmp_points[j].y * (1 - t) + tmp_points[j + 1].y * t; + v2.z = tmp_points[j].z * (1 - t) + tmp_points[j + 1].z * t; + tmp_points.push(v2); + } + } + return tmp_points[0]; + } +} From bcaa0114d13c289a7e6d328155f870cf3615a662 Mon Sep 17 00:00:00 2001 From: shabai517 Date: Sun, 23 Apr 2023 09:15:41 +0100 Subject: [PATCH 013/100] feat(math): add Bezier2d module --- src/engine/math/Bezier2D.ts | 95 +++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 src/engine/math/Bezier2D.ts diff --git a/src/engine/math/Bezier2D.ts b/src/engine/math/Bezier2D.ts new file mode 100644 index 00000000..ecb3681c --- /dev/null +++ b/src/engine/math/Bezier2D.ts @@ -0,0 +1,95 @@ +import { MathUtil } from './MathUtil'; +import { Vector2 } from './Vector2'; +/** + * 2D Bezier Curve + * @group Math + */ +export class Bezier2D { + + private _points: Vector2[]; + + private _cacheValue: Vector2; + + /** + * instance bezier class + */ + constructor(vec2Ds: Vector2[] = []) { + this.points = vec2Ds; + this._cacheValue = new Vector2(); + } + + /** + * get all bezier 2d points + */ + public get points(): Vector2[] { + return this._points; + } + + /** + * set bezier 2d point[x,y] list must great 4 + */ + public set points(value: Vector2[]) { + this._points = value; + } + + /** + * get point2d at curve + * @param v 0.0 ~ 1.0 + * @returns return point2D at curve + */ + public getValue(v: number): Vector2 { + if (v < 0) v = 0; + if (v > 1) v = 1; + + let len = this.points.length - 1; + let ci = Math.floor(len * v); + let ni = ci + 1; + let w = MathUtil.fract((len + 1) * v); + if (ni >= len) { + ni = ci; + w = 0; + } + + this._cacheValue.x = this.points[ci].x + (this.points[ni].x - this.points[ci].x) * w; + this._cacheValue.y = this.points[ci].y + (this.points[ni].y - this.points[ci].y) * w; + return this._cacheValue; + } + + /** + * caclute bezier curve points at line [ 0.0 , 1.0 ] + * @param anchorpoints bezier anchor + * @param pointsAmount point count + * @returns get a bezier curve [Bezier2D] + */ + public static createBezierPoints(anchorpoints: Vector2[], pointsAmount: number): Bezier2D { + var bezier2d: Bezier2D = new Bezier2D(); + for (var i = 0; i < pointsAmount; i++) { + var point = Bezier2D.multiPointBezier(anchorpoints, i / pointsAmount); + bezier2d.points.push(point); + } + return bezier2d; + } + + private static multiPointBezier(points: Vector2[], t: number) { + var len = points.length; + var x = 0, + y = 0; + var erxiangshi = function (start: number, end: number) { + var cs = 1, + bcs = 1; + while (end > 0) { + cs *= start; + bcs *= end; + start--; + end--; + } + return cs / bcs; + }; + for (var i = 0; i < len; i++) { + var point = points[i]; + x += point.x * Math.pow(1 - t, len - 1 - i) * Math.pow(t, i) * erxiangshi(len - 1, i); + y += point.y * Math.pow(1 - t, len - 1 - i) * Math.pow(t, i) * erxiangshi(len - 1, i); + } + return new Vector2(x, y); + } +} From caf7974c0847620ead78d6d533329ab12233a8f5 Mon Sep 17 00:00:00 2001 From: shabai517 Date: Sun, 23 Apr 2023 09:15:52 +0100 Subject: [PATCH 014/100] feat(math): add animationCurve module --- src/engine/math/AnimationCurve.ts | 307 ++++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 src/engine/math/AnimationCurve.ts diff --git a/src/engine/math/AnimationCurve.ts b/src/engine/math/AnimationCurve.ts new file mode 100644 index 00000000..95340f51 --- /dev/null +++ b/src/engine/math/AnimationCurve.ts @@ -0,0 +1,307 @@ +import { PingPong, RepeatSE } from './MathUtil'; + +/** + * Time Warp Mode + * @PingPong value min -> max -> min + * @Repeat value = value % repeatSpace + * @Clamp value = max(min( value , 1 ) , 0 ) + */ +export enum WrapTimeMode { + PingPong = 0, + Repeat = 1, + Clamp = 2, +} + +/** + * @group Math + */ +export class Keyframe { + public serializedVersion: string = '2'; + public time: number; + public value: number; + public inSlope: number = 0; + public outSlope: number = 0; + public tangentMode: number = 0; + + constructor(time: number = 0, value: number = 0) { + this.time = time; + this.value = value; + } + + public unSerialized(data: any) { + this.serializedVersion = data['serializedVersion']; + this.time = data['time']; + this.value = data['value']; + this.tangentMode = data['tangentMode']; + this.inSlope = data['inSlope'] == 'Infinity' ? NaN : data['inSlope']; + this.outSlope = data['outSlope'] == 'Infinity' ? NaN : data['outSlope']; + } + + public unSerialized2(data: any) { + this.serializedVersion = data['serializedVersion']; + this.time = data['time']; + this.value = data['value']; + this.tangentMode = data['tangentMode']; + this.inSlope = data['inTangent'] == 'Infinity' ? NaN : data['inTangent']; + this.outSlope = data['outTangent'] == 'Infinity' ? NaN : data['outTangent']; + } +} + +/** + * @internal + * @group Math + */ +export class FrameCache { + public index: number; //= lhsIndex; + public time: number; // = lhs.time + timeOffset; + public timeEnd: number; // = rhs.time + timeOffset; + public coeff: number[] = []; //= lhsIndex; +} + +/** + * Animation Cureve + * has frame list data + * @group Math + */ +export class AnimationCurve { + private _totalTime: number = 1; + + private _cache: FrameCache = new FrameCache(); + + private _cacheOut: { lhsIndex: number; rhsIndex: number } = { + lhsIndex: 0, + rhsIndex: 0, + }; + + private _InvalidateCache: boolean = false; + + public curve: Keyframe[] = []; + + public serializedVersion: number; + + public preWarpMode: number; + + public postWarpMode: number; + + public rotationOrder: number; + + constructor(frames?: Keyframe[], preWarpMode: WrapTimeMode = WrapTimeMode.Repeat, postWarpMode: WrapTimeMode = WrapTimeMode.Repeat) { + if (frames) for (let i = 0; i < frames.length; i++) { + const frame = frames[i]; + this.addKeyFrame(frame); + } + this.preWarpMode = preWarpMode; + this.postWarpMode = postWarpMode; + } + + /** + * return this curve use total time + */ + public get totalTime() { + return this._totalTime; + } + + /** + * get curve first keframe time + */ + public get first(): Keyframe { + return this.curve[0]; + } + + /** + * get curve last keyframe time + */ + public get last(): Keyframe { + return this.curve[this.curve.length - 1]; + } + + /** + * add keyFrame to curve keyframe last and calcTotalTime + * @param keyFrame {@link Keyframe} sea: one key frame data + */ + public addKeyFrame(keyFrame: Keyframe) { + if (this.curve.indexOf(keyFrame) == -1) { + this.curve.push(keyFrame); + } + this.calcTotalTime(); + } + + /** + * remove keyframe form this curve + * @param keyFrame {@link Keyframe} + */ + public removeKeyFrame(keyFrame: Keyframe) { + let index = this.curve.indexOf(keyFrame); + if (index != -1) { + this.curve.splice(index, 1); + } + + this.calcTotalTime(); + } + + /** + * calculate keyframe list in to timeline + * @param cache {@link FrameCache} + * @param lhsIndex left frame index + * @param rhsIndex right frame index + * @param timeOffset offset time default 0.0 + */ + public calculateCacheData(cache: FrameCache, lhsIndex: number, rhsIndex: number, timeOffset: number = 0) { + let m_Curve = this.curve; + let lhs = m_Curve[lhsIndex]; + let rhs = m_Curve[rhsIndex]; + // DebugAssertIf (timeOffset < -0.001F || timeOffset - 0.001F > rhs.time - lhs.time); + cache.index = lhsIndex; + cache.time = lhs.time + timeOffset; + cache.timeEnd = rhs.time + timeOffset; + cache.index = lhsIndex; + + let dx, length; + let dy; + let m1, m2, d1, d2; + + dx = rhs.time - lhs.time; + dx = Math.max(dx, 0.0001); + dy = rhs.value - lhs.value; + length = 1.0 / (dx * dx); + + m1 = lhs.outSlope; + m2 = rhs.inSlope; + d1 = m1 * dx; + d2 = m2 * dx; + + cache.coeff[0] = ((d1 + d2 - dy - dy) * length) / dx; + cache.coeff[1] = (dy + dy + dy - d1 - d1 - d2) * length; + cache.coeff[2] = m1; + cache.coeff[3] = lhs.value; + this.setupStepped(cache.coeff, lhs, rhs); + } + + /** + * get caculate frames value + * @param time + * @returns + */ + public getValue(time: number): number { + time = this.wrapTime(time); + + this.findCurve(time, this._cacheOut); + + this.calculateCacheData(this._cache, this._cacheOut.lhsIndex, this._cacheOut.rhsIndex, 0); + + return this.evaluateCache(this._cache, time); + } + + /** + * get has Keyframe list count + * @returns int + */ + public getKeyCount(): number { + return this.curve.length; + } + + /** + * Get a Keyframe Data by Index + * @param index must int + * @returns Keyframe {@link Keyframe} + */ + public getKey(index: number): Keyframe { + return this.curve[index]; + } + + public unSerialized(data: any): this { + this.preWarpMode = data['m_PreInfinity']; + this.postWarpMode = data['m_PostInfinity']; + this.rotationOrder = data['m_RotationOrder']; + + let len = data['m_Curve'].length; + for (let i = 0; i < len; i++) { + this.curve[i] = new Keyframe(); + this.curve[i].unSerialized(data['m_Curve'][i.toString()]); + } + this.calcTotalTime(); + return this; + } + + public unSerialized2(data: Object): this { + this.preWarpMode = data['preWrapMode']; + this.postWarpMode = data['postWrapMode']; + + let keyFrames = data['keyFrames'] || data['keys']; + let len = keyFrames.length; + for (let i = 0; i < len; i++) { + this.curve[i] = new Keyframe(); + this.curve[i].unSerialized2(keyFrames[i.toString()]); + } + this.calcTotalTime(); + return this; + } + + private wrapTime(curveT: number) { + let m_Curve = this.curve; + let begTime = m_Curve[0].time; + let endTime = m_Curve[m_Curve.length - 1].time; + + if (curveT < begTime) { + if (this.preWarpMode == WrapTimeMode.Clamp) curveT = begTime; + else if (this.preWarpMode == WrapTimeMode.PingPong) curveT = PingPong(curveT, begTime, endTime); + else curveT = RepeatSE(curveT, begTime, endTime); + } else if (curveT > endTime) { + if (this.postWarpMode == WrapTimeMode.Clamp) curveT = endTime; + else if (this.postWarpMode == WrapTimeMode.PingPong) curveT = PingPong(curveT, begTime, endTime); + else curveT = RepeatSE(curveT, begTime, endTime); + } + return curveT; + } + + private evaluateCache(cache: FrameCache, curveT: number): number { + let t = curveT - cache.time; + let output = t * (t * (t * cache.coeff[0] + cache.coeff[1]) + cache.coeff[2]) + cache.coeff[3]; + return output; + } + + private findCurve(time: number, out: { lhsIndex: number; rhsIndex: number }) { + let frames = this.curve; + for (let i = 1; i < frames.length; i++) { + let left = frames[i - 1]; + let right = frames[i]; + if (left.time <= time && right.time > time) { + out.lhsIndex = i - 1; + out.rhsIndex = i; + } + } + } + + private setupStepped(coeff: number[], lhs: Keyframe, rhs: Keyframe) { + if (isNaN(lhs.outSlope) || isNaN(rhs.inSlope)) { + coeff[0] = 0.0; + coeff[1] = 0.0; + coeff[2] = 0.0; + coeff[3] = lhs.value; + } + } + + private invalidateCache() { + this._InvalidateCache = true; + } + + private calcTotalTime() { + let maxTime = 0; + for (let curve of this.curve) { + maxTime = Math.max(maxTime, curve.time); + } + this._totalTime = maxTime; + } + + public static scaleCurveValue(curve: AnimationCurve, scale: number) { + if (!curve._InvalidateCache) { + for (let i = 0; i < curve.curve.length; i++) { + let c = curve.curve[i]; + c.value *= scale; + c.inSlope *= scale; + c.outSlope *= scale; + } + } + curve.invalidateCache(); + } +} From a12345795769e9df2457302d07ec760952f8afe8 Mon Sep 17 00:00:00 2001 From: shabai517 Date: Sun, 23 Apr 2023 09:44:16 +0100 Subject: [PATCH 015/100] feat(gfx): add webgpu config --- .../gfx/graphics/webGpu/CanvasConfig.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/engine/gfx/graphics/webGpu/CanvasConfig.ts diff --git a/src/engine/gfx/graphics/webGpu/CanvasConfig.ts b/src/engine/gfx/graphics/webGpu/CanvasConfig.ts new file mode 100644 index 00000000..e95a3699 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/CanvasConfig.ts @@ -0,0 +1,40 @@ +import { Scene3D } from '../../../core/Scene3D'; + +/** + * config data for canvas + * @group engine3D + */ +export type CanvasConfig = { + /** + * reference of canvas + */ + canvas?: HTMLCanvasElement; + /** + * wheter use transparent background + * Pay attention to settings when using 3D transparent backgrounds{@link SkyRenderer} The enable of the sky rendering component is false + * skyRender.enable = false + */ + alpha?: boolean; + /** + * canvas styler zIndex + */ + zIndex?: number; + /** + * canvas pixel ratio + */ + devicePixelRatio?: number; + /** + * canvas background image + * need call scene.hideSky() and set CanvasConfig.alpha is true + */ + backgroundImage?: string; + /** + * canvas width + */ + width?: number; + /** + * canvas width + */ + height?: number, + +}; From 24697467e2e2d028884ec0789eeaf150bc2c1820 Mon Sep 17 00:00:00 2001 From: hellmor Date: Sun, 23 Apr 2023 17:34:34 +0800 Subject: [PATCH 016/100] feat(math): add math lib files (#16) Add some math libraries Update math libraries --- src/engine/math/HaltonSeq.ts | 51 ++++++++++++++++++++ src/engine/math/Orientation3D.ts | 9 ++++ src/engine/math/Plane.ts | 82 ++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 src/engine/math/HaltonSeq.ts create mode 100644 src/engine/math/Orientation3D.ts create mode 100644 src/engine/math/Plane.ts diff --git a/src/engine/math/HaltonSeq.ts b/src/engine/math/HaltonSeq.ts new file mode 100644 index 00000000..55c57871 --- /dev/null +++ b/src/engine/math/HaltonSeq.ts @@ -0,0 +1,51 @@ +/** + * https://en.wikipedia.org/wiki/Halton_sequence + * https://baike.baidu.com/item/Halton%20sequence/16697800 + * Class for generating the Halton low-discrepancy series for Quasi Monte Carlo integration. + */ +export class HaltonSeq { + private value = 0; + private inv_base = 0; + + public static get(index: number, radix: number): number { + let result = 0; + let fraction = 1 / radix; + + while (index > 0) { + result += (index % radix) * fraction; + + index /= radix; + fraction /= radix; + } + + return result; + } + + public getBase(index: number, base: number) { + let f = (this.inv_base = 1.0 / base); + + while (index > 0) { + this.value += f * (index % base); + index /= base; + f *= this.inv_base; + } + } + + public next() { + let r = 1.0 - this.value - 0.0000001; + if (this.inv_base < r) this.value += this.inv_base; + else { + let h = this.inv_base, + hh; + do { + hh = h; + h *= this.inv_base; + } while (h >= r); + this.value += hh + h - 1.0; + } + } + + public get() { + return this.value; + } +} diff --git a/src/engine/math/Orientation3D.ts b/src/engine/math/Orientation3D.ts new file mode 100644 index 00000000..556745fb --- /dev/null +++ b/src/engine/math/Orientation3D.ts @@ -0,0 +1,9 @@ +/** + * @internal + * @group Math + */ +export class Orientation3D { + public static AXIS_ANGLE: string = 'axisAngle'; + public static EULER_ANGLES: string = 'eulerAngles'; + public static QUATERNION: string = 'quaternion'; +} diff --git a/src/engine/math/Plane.ts b/src/engine/math/Plane.ts new file mode 100644 index 00000000..16ed621d --- /dev/null +++ b/src/engine/math/Plane.ts @@ -0,0 +1,82 @@ +import { Ray } from './Ray'; +import { Vector3 } from './Vector3'; + +/** + * Plane mathematics class + * @group Math + */ +export class Plane { + /** + * Center position of plane + */ + public point: Vector3 = new Vector3(); + + /** + * Plane normal vector + */ + public normal: Vector3 = Vector3.UP; + + /** + * @internal + */ + private _tmpVecA: Vector3 = new Vector3(); + + /** + * Constructs a new plane object + * @param pos Plane position + * @param normal Plane normal quantity + */ + constructor(pos: Vector3, normal: Vector3) { + this.point = pos; + this.normal = normal; + } + + /** + * Clones the current plane object + * @returns New plane object + */ + public clone(): Plane { + let plane: Plane = new Plane(this.point.clone(), this.normal.clone()); + return plane; + } + + /** + * Determine whether the plane intersects a line segment and calculate the intersection point + * @param start Starting point of line segment + * @param end End point of line segment + * @param point Point of output intersection + * @returns Returns whether it intersects + */ + public intersectsLine(start: Vector3, end: Vector3, point: Vector3) { + var d = -this.normal.dotProduct(this.point); + var d0 = this.normal.dotProduct(start) + d; + var d1 = this.normal.dotProduct(end) + d; + + var t = d0 / (d0 - d1); + var intersects = t >= 0 && t <= 1; + if (intersects && point) { + point.lerp(start, end, t); + } + + return intersects; + } + + /** + * Determine whether the plane intersects a ray and calculate the intersection point + * @param ray Ray of input + * @param outPoint Point of output intersection + * @returns Returns whether it intersects + */ + public intersectsRay(ray: Ray, targetPoint?: Vector3) { + targetPoint ||= this._tmpVecA; + targetPoint.copy(this.point).subtract(ray.origin, targetPoint); + var t = this.normal.dotProduct(targetPoint) / this.normal.dotProduct(ray.direction); + var intersects = t >= 0; + + if (intersects) { + targetPoint.copyFrom(ray.direction).multiplyScalar(t).add(ray.origin, targetPoint); + } + + return intersects; + } +} From cd36452dafcec41865aa3f9062667b2409ddab7c Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Sun, 23 Apr 2023 17:53:58 +0800 Subject: [PATCH 017/100] feat(memory): add MemoryDO (#19) add MemoryDO add MemoryInfo --- src/engine/core/pool/memory/MatrixDO.ts | 4 + src/engine/core/pool/memory/MemoryDO.ts | 55 ++++ src/engine/core/pool/memory/MemoryInfo.ts | 370 ++++++++++++++++++++++ 3 files changed, 429 insertions(+) create mode 100644 src/engine/core/pool/memory/MatrixDO.ts create mode 100644 src/engine/core/pool/memory/MemoryDO.ts create mode 100644 src/engine/core/pool/memory/MemoryInfo.ts diff --git a/src/engine/core/pool/memory/MatrixDO.ts b/src/engine/core/pool/memory/MatrixDO.ts new file mode 100644 index 00000000..b3b01fbf --- /dev/null +++ b/src/engine/core/pool/memory/MatrixDO.ts @@ -0,0 +1,4 @@ +export class MatrixDO { + constructor() { + } +} diff --git a/src/engine/core/pool/memory/MemoryDO.ts b/src/engine/core/pool/memory/MemoryDO.ts new file mode 100644 index 00000000..1e607496 --- /dev/null +++ b/src/engine/core/pool/memory/MemoryDO.ts @@ -0,0 +1,55 @@ +import { MemoryInfo } from './MemoryInfo'; + +/** + * @internal + * @group Core + */ +export class MemoryDO { + public shareDataBuffer: ArrayBuffer; + private _byteOffset: number = 0; + + public allocation(byteSize: number) { + if (this.shareDataBuffer && this.shareDataBuffer.byteLength < byteSize) { + this._byteOffset = 0; + } else { + this.shareDataBuffer = new ArrayBuffer(byteSize); + } + } + + public allocation_node(byteSize: number): MemoryInfo { + if (this._byteOffset + byteSize > this.shareDataBuffer.byteLength) { + console.error('memory not enough!', this._byteOffset, byteSize, this.shareDataBuffer.byteLength); + return null; + } + + let memoryInfo = new MemoryInfo(); + memoryInfo.byteOffset = this._byteOffset; + memoryInfo.byteSize = byteSize; + memoryInfo.dataBytes = new DataView(this.shareDataBuffer, this._byteOffset, memoryInfo.byteSize); + this._byteOffset += memoryInfo.byteSize; + return memoryInfo; + } + + public allocation_memory(memoryInfo: MemoryInfo): MemoryInfo { + if (this._byteOffset + memoryInfo.byteSize > this.shareDataBuffer.byteLength) { + console.error('memory not enough!', this._byteOffset, memoryInfo.byteSize, this.shareDataBuffer.byteLength); + return null; + } + + memoryInfo.byteOffset = this._byteOffset; + memoryInfo.dataBytes = new DataView(this.shareDataBuffer, this._byteOffset, memoryInfo.byteSize); + this._byteOffset += memoryInfo.byteSize; + return memoryInfo; + } + + public reset() { + this._byteOffset = 0; + } + + public destroy() { + this.shareDataBuffer = null; + this._byteOffset = 0; + } +} + +// export let MemoryPool = new _MemoryPool(); diff --git a/src/engine/core/pool/memory/MemoryInfo.ts b/src/engine/core/pool/memory/MemoryInfo.ts new file mode 100644 index 00000000..aff62e83 --- /dev/null +++ b/src/engine/core/pool/memory/MemoryInfo.ts @@ -0,0 +1,370 @@ +import { Color } from '../../../math/Color'; +import { Quaternion } from '../../../math/Quaternion'; +import { Vector2 } from '../../../math/Vector2'; +import { Vector3 } from '../../../math/Vector3'; +import { Vector4 } from '../../../math/Vector4'; + +/** + * @internal + * @group Core + */ +export class MemoryInfo { + public byteOffset: number; + public byteSize: number; + public offset: number = 0; + public dataBytes: DataView; + + public get x(): number { + return this.dataBytes.getFloat32(0 * Float32Array.BYTES_PER_ELEMENT, true); + } + + public set x(v: number) { + this.dataBytes.setFloat32(0 * Float32Array.BYTES_PER_ELEMENT, v, true); + } + + public get y(): number { + return this.dataBytes.getFloat32(1 * Float32Array.BYTES_PER_ELEMENT, true); + } + + public set y(v: number) { + this.dataBytes.setFloat32(1 * Float32Array.BYTES_PER_ELEMENT, v, true); + } + + public get z(): number { + return this.dataBytes.getFloat32(2 * Float32Array.BYTES_PER_ELEMENT, true); + } + + public set z(v: number) { + this.dataBytes.setFloat32(2 * Float32Array.BYTES_PER_ELEMENT, v, true); + } + + public get w(): number { + return this.dataBytes.getFloat32(3 * Float32Array.BYTES_PER_ELEMENT, true); + } + + public set w(v: number) { + this.dataBytes.setFloat32(3 * Float32Array.BYTES_PER_ELEMENT, v, true); + } + + public setX(x: number) { + this.x = x; + } + + public setXY(x: number, y: number) { + this.x = x; + this.y = y; + } + + public setXYZ(x: number, y: number, z: number) { + this.x = x; + this.y = y; + this.z = z; + } + + public setXYZW(x: number, y: number, z: number, w: number) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public setVector2Array(vs: Vector2[]) { + for (let i = 0; i < vs.length; i++) { + const element = vs[i]; + this.dataBytes.setFloat32((i * 2 + 0) * Float32Array.BYTES_PER_ELEMENT, element.x, true); + this.dataBytes.setFloat32((i * 2 + 1) * Float32Array.BYTES_PER_ELEMENT, element.y, true); + } + } + + public setVector3Array(vs: Vector3[]) { + for (let i = 0; i < vs.length; i++) { + const element = vs[i]; + this.dataBytes.setFloat32((i * 3 + 0) * Float32Array.BYTES_PER_ELEMENT, element.x, true); + this.dataBytes.setFloat32((i * 3 + 1) * Float32Array.BYTES_PER_ELEMENT, element.y, true); + this.dataBytes.setFloat32((i * 3 + 2) * Float32Array.BYTES_PER_ELEMENT, element.z, true); + } + } + + public setVector4Array(vs: Vector4[] | Quaternion[]) { + for (let i = 0; i < vs.length; i++) { + const element = vs[i]; + this.dataBytes.setFloat32((i * 4 + 0) * Float32Array.BYTES_PER_ELEMENT, element.x, true); + this.dataBytes.setFloat32((i * 4 + 1) * Float32Array.BYTES_PER_ELEMENT, element.y, true); + this.dataBytes.setFloat32((i * 4 + 2) * Float32Array.BYTES_PER_ELEMENT, element.z, true); + this.dataBytes.setFloat32((i * 4 + 3) * Float32Array.BYTES_PER_ELEMENT, element.w, true); + } + } + + public setColorArray(colorArray: Color[]) { + for (let i = 0; i < colorArray.length; i++) { + const element = colorArray[i]; + this.dataBytes.setFloat32((i * 4 + 0) * Float32Array.BYTES_PER_ELEMENT, element.r, true); + this.dataBytes.setFloat32((i * 4 + 1) * Float32Array.BYTES_PER_ELEMENT, element.g, true); + this.dataBytes.setFloat32((i * 4 + 2) * Float32Array.BYTES_PER_ELEMENT, element.b, true); + this.dataBytes.setFloat32((i * 4 + 3) * Float32Array.BYTES_PER_ELEMENT, element.a, true); + } + } + + public setInt8(v: number, index: number = 0) { + this.dataBytes.setInt8(index * Int8Array.BYTES_PER_ELEMENT, v); + } + + public getInt8(index: number = 0): number { + return this.dataBytes.getInt8(index * Int8Array.BYTES_PER_ELEMENT); + } + + public setInt16(v: number, index: number = 0) { + this.dataBytes.setInt16(index * Int16Array.BYTES_PER_ELEMENT, v, true); + } + + public getInt16(index: number = 0): number { + return this.dataBytes.getInt16(index * Int16Array.BYTES_PER_ELEMENT, true); + } + + public setInt32(v: number, index: number = 0) { + this.dataBytes.setInt32(index * Int32Array.BYTES_PER_ELEMENT, v, true); + } + + public getInt32(index: number = 0): number { + return this.dataBytes.getInt32(index * Int32Array.BYTES_PER_ELEMENT, true); + } + + public setFloat(v: number, index: number = 0) { + this.dataBytes.setFloat32(index * Float32Array.BYTES_PER_ELEMENT, v, true) + } + + public getFloat(index: number = 0): number { + return this.dataBytes.getFloat32(index * Float32Array.BYTES_PER_ELEMENT, true); + } + + public setUint8(v: number, index: number = 0) { + this.dataBytes.setUint8(index * Uint8Array.BYTES_PER_ELEMENT, v); + } + + public getUint8(index: number = 0): number { + return this.dataBytes.getUint8(index * Uint8Array.BYTES_PER_ELEMENT); + } + + public setUint16(v: number, index: number = 0) { + this.dataBytes.setUint16(index * Uint16Array.BYTES_PER_ELEMENT, v, true); + } + + + + public getUint16(index: number = 0): number { + return this.dataBytes.getUint16(index * Uint16Array.BYTES_PER_ELEMENT, true); + } + + public setUint32(v: number, index: number = 0) { + this.dataBytes.setUint32(index * Uint32Array.BYTES_PER_ELEMENT, v, true); + } + + public getUint32(index: number = 0): number { + return this.dataBytes.getUint32(index * Uint32Array.BYTES_PER_ELEMENT, true); + } + + public setArray(index: number, data: number[]) { + for (let i = 0; i < data.length; i++) { + const element = data[i]; + this.dataBytes.setFloat32((index + i) * Float32Array.BYTES_PER_ELEMENT, element, true); + } + } + + public setFloat32Array(index: number, data: Float32Array) { + // let buffer = this.dataBytes.buffer.slice(this.dataBytes.byteOffset, this.dataBytes.byteOffset + data.length * Float32Array.BYTES_PER_ELEMENT); + // let tmp = new Float32Array(buffer, index * Float32Array.BYTES_PER_ELEMENT); + // tmp.set(data); + + let tmp = new Float32Array(this.dataBytes.buffer, this.dataBytes.byteOffset + index * Float32Array.BYTES_PER_ELEMENT); + tmp.set(data); + } + + public setArrayBuffer(index: number, arrayBuffer: ArrayBuffer) { + if (arrayBuffer instanceof Uint8Array) { + this.setUint8Array(index, arrayBuffer); + } else if (arrayBuffer instanceof Uint16Array) { + this.setUint16Array(index, arrayBuffer); + } else if (arrayBuffer instanceof Uint32Array) { + this.setUint32Array(index, arrayBuffer); + } else if (arrayBuffer instanceof Int8Array) { + this.setInt8Array(index, arrayBuffer); + } else if (arrayBuffer instanceof Int16Array) { + this.setInt16Array(index, arrayBuffer); + } else if (arrayBuffer instanceof Int32Array) { + this.setInt32Array(index, arrayBuffer); + } else if (arrayBuffer instanceof Float32Array) { + this.setFloat32Array(index, arrayBuffer); + } else if (arrayBuffer instanceof Float64Array) { + + } + } + + public setInt8Array(index: number, data: Int8Array) { + let tmp = new Int8Array(this.dataBytes.buffer, this.dataBytes.byteOffset + index * Int8Array.BYTES_PER_ELEMENT); + tmp.set(data); + } + + public setInt16Array(index: number, data: Int16Array) { + let tmp = new Int16Array(this.dataBytes.buffer, this.dataBytes.byteOffset + index * Int16Array.BYTES_PER_ELEMENT); + tmp.set(data); + } + + public setInt32Array(index: number, data: Int32Array) { + let tmp = new Int32Array(this.dataBytes.buffer, this.dataBytes.byteOffset + index * Int32Array.BYTES_PER_ELEMENT); + tmp.set(data); + } + + public setUint8Array(index: number, data: Uint8Array) { + let tmp = new Uint8Array(this.dataBytes.buffer, this.dataBytes.byteOffset + index * Uint8Array.BYTES_PER_ELEMENT); + tmp.set(data); + } + + public setUint16Array(index: number, data: Uint16Array) { + let tmp = new Uint16Array(this.dataBytes.buffer, this.dataBytes.byteOffset + index * Uint16Array.BYTES_PER_ELEMENT); + tmp.set(data); + } + + public setUint32Array(index: number, data: Uint32Array) { + let tmp = new Uint32Array(this.dataBytes.buffer, this.dataBytes.byteOffset + index * Uint32Array.BYTES_PER_ELEMENT); + tmp.set(data); + } + + public setData(index: number, data: number) { + this.dataBytes.setFloat32(index * Float32Array.BYTES_PER_ELEMENT, data, true); + } + + public setVector2(index: number, data: Vector2) { + this.dataBytes.setFloat32((index) * Float32Array.BYTES_PER_ELEMENT, data.x, true); + this.dataBytes.setFloat32((index + 1) * Float32Array.BYTES_PER_ELEMENT, data.y, true); + } + + public setVector3(index: number, data: Vector3) { + this.dataBytes.setFloat32((index) * Float32Array.BYTES_PER_ELEMENT, data.x, true); + this.dataBytes.setFloat32((index + 1) * Float32Array.BYTES_PER_ELEMENT, data.y, true); + this.dataBytes.setFloat32((index + 2) * Float32Array.BYTES_PER_ELEMENT, data.z, true); + } + + public setVector4(index: number, data: Vector4) { + this.dataBytes.setFloat32((index) * Float32Array.BYTES_PER_ELEMENT, data.x, true); + this.dataBytes.setFloat32((index + 1) * Float32Array.BYTES_PER_ELEMENT, data.y, true); + this.dataBytes.setFloat32((index + 2) * Float32Array.BYTES_PER_ELEMENT, data.z, true); + this.dataBytes.setFloat32((index + 3) * Float32Array.BYTES_PER_ELEMENT, data.w, true); + } + + public setColor(index: number, data: Color) { + this.dataBytes.setFloat32((index) * Float32Array.BYTES_PER_ELEMENT, data.r, true); + this.dataBytes.setFloat32((index + 1) * Float32Array.BYTES_PER_ELEMENT, data.g, true); + this.dataBytes.setFloat32((index + 2) * Float32Array.BYTES_PER_ELEMENT, data.b, true); + this.dataBytes.setFloat32((index + 3) * Float32Array.BYTES_PER_ELEMENT, data.a, true); + } + + public getData(index: number): number { + return this.dataBytes.getFloat32(index * Float32Array.BYTES_PER_ELEMENT, true); + } + + public writeFloat(v: number) { + this.dataBytes.setFloat32(this.offset, v, true); + this.offset += Float32Array.BYTES_PER_ELEMENT; + } + + public writeInt8(v: number) { + this.dataBytes.setInt8(this.offset, v); + this.offset += Int8Array.BYTES_PER_ELEMENT; + } + + public writeInt16(v: number) { + this.dataBytes.setInt16(this.offset, v, true); + this.offset += Int16Array.BYTES_PER_ELEMENT; + } + + public writeInt32(v: number) { + this.dataBytes.setInt32(this.offset, v, true); + this.offset += Int32Array.BYTES_PER_ELEMENT; + } + + public writeUint8(v: number) { + this.dataBytes.setUint8(this.offset, v); + this.offset += Uint8Array.BYTES_PER_ELEMENT; + } + + public writeUint16(v: number) { + this.dataBytes.setUint16(this.offset, v, true); + this.offset += Uint16Array.BYTES_PER_ELEMENT; + } + + public writeUint32(v: number) { + this.dataBytes.setUint32(this.offset, v, true); + this.offset += Uint32Array.BYTES_PER_ELEMENT; + } + + public writeVector2(v: Vector2) { + this.writeFloat(v.x); + this.writeFloat(v.y); + } + + public writeVector3(v: Vector3) { + this.writeFloat(v.x); + this.writeFloat(v.y); + this.writeFloat(v.z); + } + + public writeVector4(v: Vector4) { + this.writeFloat(v.x); + this.writeFloat(v.y); + this.writeFloat(v.z); + this.writeFloat(v.w); + } + + public writeRGBColor(v: Color) { + this.writeFloat(v.r); + this.writeFloat(v.g); + this.writeFloat(v.b); + // this.writeFloat(v.a); + } + + public writeArray(v: number[]) { + for (let i = 0; i < v.length; i++) { + const d = v[i]; + this.writeFloat(d); + } + } + + public writeFloat32Array(v: Float32Array) { + new Float32Array(this.dataBytes.buffer, this.dataBytes.byteOffset + this.offset).set(v); + this.offset += v.byteLength; + } + + public writeInt8Array(v: Int8Array) { + new Int8Array(this.dataBytes.buffer, this.dataBytes.byteOffset + this.offset).set(v); + this.offset += v.byteLength; + } + + public writeInt16Array(v: Int16Array) { + new Int16Array(this.dataBytes.buffer, this.dataBytes.byteOffset + this.offset).set(v); + this.offset += v.byteLength; + } + + public writeInt32Array(v: Int32Array) { + new Int32Array(this.dataBytes.buffer, this.dataBytes.byteOffset + this.offset).set(v); + this.offset += v.byteLength; + } + + public writeUint8Array(v: Uint8Array) { + new Uint8Array(this.dataBytes.buffer, this.dataBytes.byteOffset + this.offset).set(v); + this.offset += v.byteLength; + } + + public writeUint16Array(v: Uint16Array) { + new Uint16Array(this.dataBytes.buffer, this.dataBytes.byteOffset + this.offset).set(v); + this.offset += v.byteLength; + } + + public writeUint32Array(v: Uint32Array) { + new Uint32Array(this.dataBytes.buffer, this.dataBytes.byteOffset + this.offset).set(v); + this.offset += v.byteLength; + } + + public reset() { + this.offset = 0; + } +} From 178336ac853ac850cdf84afad6a8983b458d38d7 Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Sun, 23 Apr 2023 17:54:30 +0800 Subject: [PATCH 018/100] feat(math): add math libs (#15) Add random numbers Add ray detection Add Triangle, Rect, UV, TimeInterpolator Add Vector2, Vector3, Vector4 --- src/engine/math/Rand.ts | 97 +++ src/engine/math/Random.ts | 588 +++++++++++++++ src/engine/math/Ray.ts | 477 ++++++++++++ src/engine/math/Rect.ts | 219 ++++++ src/engine/math/TimeInterpolator.ts | 520 +++++++++++++ src/engine/math/Triangle.ts | 146 ++++ src/engine/math/UV.ts | 23 + src/engine/math/Vector2.ts | 314 ++++++++ src/engine/math/Vector3.ts | 1091 +++++++++++++++++++++++++++ src/engine/math/Vector4.ts | 175 +++++ 10 files changed, 3650 insertions(+) create mode 100644 src/engine/math/Rand.ts create mode 100644 src/engine/math/Random.ts create mode 100644 src/engine/math/Ray.ts create mode 100644 src/engine/math/Rect.ts create mode 100644 src/engine/math/TimeInterpolator.ts create mode 100644 src/engine/math/Triangle.ts create mode 100644 src/engine/math/UV.ts create mode 100644 src/engine/math/Vector2.ts create mode 100644 src/engine/math/Vector3.ts create mode 100644 src/engine/math/Vector4.ts diff --git a/src/engine/math/Rand.ts b/src/engine/math/Rand.ts new file mode 100644 index 00000000..d9ab5596 --- /dev/null +++ b/src/engine/math/Rand.ts @@ -0,0 +1,97 @@ +import { getFloatFromInt } from './MathUtil'; + +/** + * 'Rand' is a random number generator based on an improved xorshift algorithm, + * which is a modification of the Linear Congruential Generator (LCG) method. + * @group Math + */ +export class Rand { + private _x: number = 0; + private _y: number = 0; + private _z: number = 0; + private _w: number = 0; + + /** + * Create a random number generator object with a specified seed. + * @param seed Random seed + */ + constructor(seed = 0) { + this.seed = seed; + } + + /** + * Random seed + */ + public get seed(): number { + return this._x; + } + + public set seed(value: number) { + this._x = value; + this._y = this._x * 1812433253 + 1; + this._z = this._y * 1812433253 + 1; + this._w = this._z * 1812433253 + 1; + } + + /** + * Convert an integer to a floating-point number + * @param value integer + * @returns + */ + public static getFloatFromInt(value) { + // take 23 bits of integer, and divide by 2^23-1 + return Math.floor((value & 0x007fffff) * (1.0 / 8388607.0)); + } + + /** + * Converts an integer to a single-byte integer + * @param value integer + * @returns + */ + public static getByteFromInt(value) { + // take the most significant byte from the 23-bit value + return value >> (23 - 8); + } + + /** + * Returns a new random number generator object with the same seed state as + * the current random number generator object + * @returns + */ + public clone(): Rand { + let result = new Rand(); + result._x = this._x; + result._y = this._y; + result._z = this._z; + result._w = this._w; + return result; + } + + /** + * Generate a random number + * @returns + */ + public get() { + let t = this._x ^ (this._x << 11); + this._x = this._y; + this._y = this._z; + this._z = this._w; + return (this._w = this._w ^ (this._w >> 19) ^ (t ^ (t >> 8))); + } + + /** + * Randomly generate a floating-point number 0.0 to 1.0 + * @returns + */ + public getFloat() { + return getFloatFromInt(this.get()); + } + + /** + * Randomly generates signed floating-point numbers -1.0 to 1.0 + * @returns + */ + public getSignedFloat() { + return this.getFloat() * 2.0 - 1.0; + } +} diff --git a/src/engine/math/Random.ts b/src/engine/math/Random.ts new file mode 100644 index 00000000..55f5e1a0 --- /dev/null +++ b/src/engine/math/Random.ts @@ -0,0 +1,588 @@ +/** + * @internal + */ +export function uniform_real_distribution(min, max) { + return Math.random() * max + Math.random() * min + (max - min) * Math.random(); +} + +/** + * @internal + */ +export function uniform_real_distribution2(min, max, rng) { + let rd = rng * Math.random(); + return Math.random() * max * rd + Math.random() * min * rd + (max - min) * Math.random() * rd; +} + +/** + * @internal + */ +export function normal_distribution(min, max, skew) { + let u = 0, v = 0; + while (u === 0) u = Math.random(); //Converting [0,1) to (0,1) + while (v === 0) v = Math.random(); + let num = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v); + + num = num / 10.0 + 0.5; // Translate to 0 -> 1 + if (num > 1 || num < 0) num = normal_distribution(min, max, skew); // resample between 0 and 1 if out of range + num = Math.pow(num, skew); // Skew + num *= max - min; // Stretch to fill range + num += min; // offset to min + return num; +} + +/* + * This implementation is "Simplex Noise" as presented by + * Ken Perlin at a relatively obscure and not often cited course + * session "Real-Time Shading" at Siggraph 2001 (before real + * time shading actually took on), under the title "hardware noise". + * The 3D function is numerically equivalent to his Java reference + * code available in the PDF course notes, although I re-implemented + * it from scratch to get more readable code. The 1D, 2D and 4D cases + * were implemented from scratch by me from Ken Perlin's text. + * + * This file has no dependencies on any other file, not even its own + * header file. The header file is made for use by external code only. + */ +/** + * @internal + */ +export function FASTFLOOR(x) { + return x > 0 ? Math.floor(x) : Math.floor(x) - 1; +} + +/* + * Permutation table. This is just a random jumble of all numbers 0-255, + * repeated twice to avoid wrapping the index at 255 for each lookup. + * This needs to be exactly the same for all instances on all platforms, + * so it's easiest to just keep it as static explicit data. + * This also removes the need for any initialisation of this class. + * + * Note that making this an int[] instead of a char[] might make the + * code run faster on platforms with a high penalty for unaligned single + * byte addressing. Intel x86 is generally single-byte-friendly, but + * some other CPUs are faster with 4-aligned reads. + * However, a char[] is smaller, which avoids cache trashing, and that + * is probably the most important aspect on most architectures. + * This array is accessed a *lot* by the noise functions. + * A vector-valued noise over 3D accesses it 96 times, and a + * float-valued 4D noise 64 times. We want this to fit in the cache! + */ +/** + * @internal + */ +export let perm = [ + 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, + 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, + 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, + 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180, 151, 160, + 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, + 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, + 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, + 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180, +]; + +/* + * Helper functions to compute gradients-dot-residualvectors (1D to 4D) + * Note that these generate gradients of more than unit length. To make + * a close match with the value range of classic Perlin noise, the final + * noise values need to be rescaled to fit nicely within [-1,1]. + * (The simplex noise functions as such also have different scaling.) + * Note also that these noise functions are the most practical and useful + * signed version of Perlin noise. To return values according to the + * RenderMan specification from the SL noise() and pnoise() functions, + * the noise values need to be scaled and offset to [0,1], like this: + * float SLnoise = (noise(x,y,z) + 1.0) * 0.5; + */ +/** + * @internal + */ +export function grad1(hash, x) { + let h = hash & 15; + let grad = 1.0 + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0 + if (h & 8) grad = -grad; // Set a random sign for the gradient + return grad * x; // Multiply the gradient with the distance +} + +/** + * @internal + */ +export function grad2(hash, x, y) { + let h = hash & 7; // Convert low 3 bits of hash code + let u = h < 4 ? x : y; // into 8 simple gradient directions, + let v = h < 4 ? y : x; // and compute the dot product with (x,y). + return (h & 1 ? -u : u) + (h & 2 ? -2.0 * v : 2.0 * v); +} + +/** + * @internal + */ +export function grad3(hash, x, y, z) { + let h = hash & 15; // Convert low 4 bits of hash code into 12 simple + let u = h < 8 ? x : y; // gradient directions, and compute dot product. + let v = h < 4 ? y : h == 12 || h == 14 ? x : z; // Fix repeats at h = 12 to 15 + return (h & 1 ? -u : u) + (h & 2 ? -v : v); +} + +/** + * @internal + */ +export function grad4(hash, x, y, z, t) { + let h = hash & 31; // Convert low 5 bits of hash code into 32 simple + let u = h < 24 ? x : y; // gradient directions, and compute dot product. + let v = h < 16 ? y : z; + let w = h < 8 ? z : t; + return (h & 1 ? -u : u) + (h & 2 ? -v : v) + (h & 4 ? -w : w); +} + +// A lookup table to traverse the simplex around a given point in 4D. +// Details can be found where this table is used, in the 4D noise method. +/* TODO: This should not be required, backport it from Bill's GLSL code! */ +/** + * @internal + */ +export let simplex = [ + [0, 1, 2, 3], + [0, 1, 3, 2], + [0, 0, 0, 0], + [0, 2, 3, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [1, 2, 3, 0], + [0, 2, 1, 3], + [0, 0, 0, 0], + [0, 3, 1, 2], + [0, 3, 2, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [1, 3, 2, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [1, 2, 0, 3], + [0, 0, 0, 0], + [1, 3, 0, 2], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [2, 3, 0, 1], + [2, 3, 1, 0], + [1, 0, 2, 3], + [1, 0, 3, 2], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [2, 0, 3, 1], + [0, 0, 0, 0], + [2, 1, 3, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [2, 0, 1, 3], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [3, 0, 1, 2], + [3, 0, 2, 1], + [0, 0, 0, 0], + [3, 1, 2, 0], + [2, 1, 0, 3], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [3, 1, 0, 2], + [0, 0, 0, 0], + [3, 2, 0, 1], + [3, 2, 1, 0], +]; + +/** + * @internal + */ +export function snoise1(x) { + let i0 = FASTFLOOR(x); + let i1 = i0 + 1; + let x0 = x - i0; + let x1 = x0 - 1.0; + + let n0, n1; + + let t0 = 1.0 - x0 * x0; + // if(t0 < 0.0f) t0 = 0.0f; // this never happens for the 1D case + t0 *= t0; + n0 = t0 * t0 * grad1(perm[i0 & 0xff], x0); + + let t1 = 1.0 - x1 * x1; + // if(t1 < 0.0f) t1 = 0.0f; // this never happens for the 1D case + t1 *= t1; + n1 = t1 * t1 * grad1(perm[i1 & 0xff], x1); + // The maximum value of this noise is 8*(3/4)^4 = 2.53125 + // A factor of 0.395 would scale to fit exactly within [-1,1], but + // we want to match PRMan's 1D noise, so we scale it down some more. + return 0.25 * (n0 + n1); +} + +// 2D simplex noise +/** + * @internal + */ +export function snoise2(x, y) { + const F2 = 0.366025403; // F2 = 0.5*(sqrt(3.0)-1.0) + const G2 = 0.211324865; // G2 = (3.0-Math.sqrt(3.0))/6.0 + + let n0, n1, n2; // Noise contributions from the three corners + + // Skew the input space to determine which simplex cell we're in + let s = (x + y) * F2; // Hairy factor for 2D + let xs = x + s; + let ys = y + s; + let i = FASTFLOOR(xs); + let j = FASTFLOOR(ys); + + let t = (i + j) * G2; + let X0 = i - t; // Unskew the cell origin back to (x,y) space + let Y0 = j - t; + let x0 = x - X0; // The x,y distances from the cell origin + let y0 = y - Y0; + + // For the 2D case, the simplex shape is an equilateral triangle. + // Determine which simplex we are in. + let i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords + if (x0 > y0) { + i1 = 1; + j1 = 0; + } // lower triangle, XY order: (0,0)->(1,0)->(1,1) + else { + i1 = 0; + j1 = 1; + } // upper triangle, YX order: (0,0)->(0,1)->(1,1) + + // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and + // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where + // c = (3-sqrt(3))/6 + + let x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords + let y1 = y0 - j1 + G2; + let x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords + let y2 = y0 - 1.0 + 2.0 * G2; + + // Wrap the integer indices at 256, to avoid indexing perm[] out of bounds + let ii = i & 0xff; + let jj = j & 0xff; + + // Calculate the contribution from the three corners + let t0 = 0.5 - x0 * x0 - y0 * y0; + if (t0 < 0.0) n0 = 0.0; + else { + t0 *= t0; + n0 = t0 * t0 * grad2(perm[ii + perm[jj]], x0, y0); + } + + let t1 = 0.5 - x1 * x1 - y1 * y1; + if (t1 < 0.0) n1 = 0.0; + else { + t1 *= t1; + n1 = t1 * t1 * grad2(perm[ii + i1 + perm[jj + j1]], x1, y1); + } + + let t2 = 0.5 - x2 * x2 - y2 * y2; + if (t2 < 0.0) n2 = 0.0; + else { + t2 *= t2; + n2 = t2 * t2 * grad2(perm[ii + 1 + perm[jj + 1]], x2, y2); + } + + // Add contributions from each corner to get the final noise value. + // The result is scaled to return values in the interval [-1,1]. + return 40.0 * (n0 + n1 + n2); // TODO: The scale factor is preliminary! +} + +// 3D simplex noise +/** + * @internal + */ +export function snoise3(x, y, z) { + // Simple skewing factors for the 3D case + const F3 = 0.333333333; + const G3 = 0.166666667; + + let n0, n1, n2, n3; // Noise contributions from the four corners + + // Skew the input space to determine which simplex cell we're in + let s = (x + y + z) * F3; // Very nice and simple skew factor for 3D + let xs = x + s; + let ys = y + s; + let zs = z + s; + let i = FASTFLOOR(xs); + let j = FASTFLOOR(ys); + let k = FASTFLOOR(zs); + + let t = (i + j + k) * G3; + let X0 = i - t; // Unskew the cell origin back to (x,y,z) space + let Y0 = j - t; + let Z0 = k - t; + let x0 = x - X0; // The x,y,z distances from the cell origin + let y0 = y - Y0; + let z0 = z - Z0; + + // For the 3D case, the simplex shape is a slightly irregular tetrahedron. + // Determine which simplex we are in. + let i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords + let i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords + + /* This code would benefit from a backport from the GLSL version! */ + if (x0 >= y0) { + if (y0 >= z0) { + i1 = 1; + j1 = 0; + k1 = 0; + i2 = 1; + j2 = 1; + k2 = 0; + } // X Y Z order + else if (x0 >= z0) { + i1 = 1; + j1 = 0; + k1 = 0; + i2 = 1; + j2 = 0; + k2 = 1; + } // X Z Y order + else { + i1 = 0; + j1 = 0; + k1 = 1; + i2 = 1; + j2 = 0; + k2 = 1; + } // Z X Y order + } else { + // x0 y0 ? 32 : 0; + let c2 = x0 > z0 ? 16 : 0; + let c3 = y0 > z0 ? 8 : 0; + let c4 = x0 > w0 ? 4 : 0; + let c5 = y0 > w0 ? 2 : 0; + let c6 = z0 > w0 ? 1 : 0; + let c = c1 + c2 + c3 + c4 + c5 + c6; + + let i1, j1, k1, l1; // The integer offsets for the second simplex corner + let i2, j2, k2, l2; // The integer offsets for the third simplex corner + let i3, j3, k3, l3; // The integer offsets for the fourth simplex corner + + // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order. + // Many values of c will never occur, since e.g. x>y>z>w makes x= 3 ? 1 : 0; + j1 = simplex[c][1] >= 3 ? 1 : 0; + k1 = simplex[c][2] >= 3 ? 1 : 0; + l1 = simplex[c][3] >= 3 ? 1 : 0; + // The number 2 in the "simplex" array is at the second largest coordinate. + i2 = simplex[c][0] >= 2 ? 1 : 0; + j2 = simplex[c][1] >= 2 ? 1 : 0; + k2 = simplex[c][2] >= 2 ? 1 : 0; + l2 = simplex[c][3] >= 2 ? 1 : 0; + // The number 1 in the "simplex" array is at the second smallest coordinate. + i3 = simplex[c][0] >= 1 ? 1 : 0; + j3 = simplex[c][1] >= 1 ? 1 : 0; + k3 = simplex[c][2] >= 1 ? 1 : 0; + l3 = simplex[c][3] >= 1 ? 1 : 0; + // The fifth corner has all coordinate offsets = 1, so no need to look that up. + + let x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords + let y1 = y0 - j1 + G4; + let z1 = z0 - k1 + G4; + let w1 = w0 - l1 + G4; + let x2 = x0 - i2 + 2.0 * G4; // Offsets for third corner in (x,y,z,w) coords + let y2 = y0 - j2 + 2.0 * G4; + let z2 = z0 - k2 + 2.0 * G4; + let w2 = w0 - l2 + 2.0 * G4; + let x3 = x0 - i3 + 3.0 * G4; // Offsets for fourth corner in (x,y,z,w) coords + let y3 = y0 - j3 + 3.0 * G4; + let z3 = z0 - k3 + 3.0 * G4; + let w3 = w0 - l3 + 3.0 * G4; + let x4 = x0 - 1.0 + 4.0 * G4; // Offsets for last corner in (x,y,z,w) coords + let y4 = y0 - 1.0 + 4.0 * G4; + let z4 = z0 - 1.0 + 4.0 * G4; + let w4 = w0 - 1.0 + 4.0 * G4; + + // Wrap the integer indices at 256, to avoid indexing perm[] out of bounds + let ii = i & 0xff; + let jj = j & 0xff; + let kk = k & 0xff; + let ll = l & 0xff; + + // Calculate the contribution from the five corners + let t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0; + if (t0 < 0.0) n0 = 0.0; + else { + t0 *= t0; + n0 = t0 * t0 * grad4(perm[ii + perm[jj + perm[kk + perm[ll]]]], x0, y0, z0, w0); + } + + let t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1; + if (t1 < 0.0) n1 = 0.0; + else { + t1 *= t1; + n1 = t1 * t1 * grad4(perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]]]], x1, y1, z1, w1); + } + + let t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2; + if (t2 < 0.0) n2 = 0.0; + else { + t2 *= t2; + n2 = t2 * t2 * grad4(perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]]]], x2, y2, z2, w2); + } + + let t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3; + if (t3 < 0.0) n3 = 0.0; + else { + t3 *= t3; + n3 = t3 * t3 * grad4(perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]]]], x3, y3, z3, w3); + } + + let t4 = 0.6 - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4; + if (t4 < 0.0) n4 = 0.0; + else { + t4 *= t4; + n4 = t4 * t4 * grad4(perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]]]], x4, y4, z4, w4); + } + + // Sum up and scale the result to cover the range [-1,1] + return 27.0 * (n0 + n1 + n2 + n3 + n4); // TODO: The scale factor is preliminary! +} +//--------------------------------------------------------------------- diff --git a/src/engine/math/Ray.ts b/src/engine/math/Ray.ts new file mode 100644 index 00000000..fd2290e0 --- /dev/null +++ b/src/engine/math/Ray.ts @@ -0,0 +1,477 @@ +import { IBound } from "../core/bound/IBound"; +import { Triangle } from "./Triangle"; +import { dot, sqrMagnitude } from "./MathUtil"; +import { Matrix4 } from "./Matrix4"; +import { Vector3 } from "./Vector3"; + +/** + * Ray + * @group Math + */ +export class Ray { + + /** + * Ray starting point + */ + public origin: Vector3 = new Vector3(); + + /** + * length + */ + public length: number = Number.MAX_VALUE; + + private static _rayl = 10e8; + private static _smallnum = 0.00000001; + private _vector: Vector3 = new Vector3(); + private _dir: Vector3 = new Vector3(); + + + /** + * Build a new ray object + * @param origin Ray starting point + * @param dir Ray direction + */ + constructor(origin?: Vector3, dir?: Vector3) { + this.origin.copyFrom(origin || new Vector3()); + this._dir.copyFrom(dir || new Vector3()); + this._dir.normalize(); + } + + /** + * Ray direction + */ + public get direction(): Vector3 { + return this._dir; + } + + public set direction(dir: Vector3) { + this._dir.copyFrom(dir); + this._dir.normalize(); + } + + /** + * Clone a new Ray object + * @returns + */ + public clone(): Ray { + return new Ray(this.origin, this.direction); + } + + /** + * Determine whether it intersects a bounding box + * @param box bounding box + * @returns whether intersect + */ + public intersectsBox(box: IBound): boolean { + return this.intersectBox(box, this._vector) !== null; + } + + /** + * Determine whether it intersects with a bounding box and + * calculate the intersection point + * @param box bounding box + * @param target Output intersection + * @returns whether intersect + */ + public intersectBox(box: IBound, target: Vector3): Vector3 { + let tmin, tmax, tymin, tymax, tzmin, tzmax; + + const invdirx = 1 / this.direction.x, + invdiry = 1 / this.direction.y, + invdirz = 1 / this.direction.z; + + const origin = this.origin; + + if (invdirx >= 0) { + tmin = (box.min.x - origin.x) * invdirx; + tmax = (box.max.x - origin.x) * invdirx; + } else { + tmin = (box.max.x - origin.x) * invdirx; + tmax = (box.min.x - origin.x) * invdirx; + } + + if (invdiry >= 0) { + tymin = (box.min.y - origin.y) * invdiry; + tymax = (box.max.y - origin.y) * invdiry; + } else { + tymin = (box.max.y - origin.y) * invdiry; + tymax = (box.min.y - origin.y) * invdiry; + } + + if (tmin > tymax || tymin > tmax) return null; + + // These lines also handle the case where tmin or tmax is NaN + // (result of 0 * Infinity). x !== x returns true if x is NaN + + if (tymin > tmin || tmin !== tmin) tmin = tymin; + + if (tymax < tmax || tmax !== tmax) tmax = tymax; + + if (invdirz >= 0) { + tzmin = (box.min.z - origin.z) * invdirz; + tzmax = (box.max.z - origin.z) * invdirz; + } else { + tzmin = (box.max.z - origin.z) * invdirz; + tzmax = (box.min.z - origin.z) * invdirz; + } + + if (tmin > tzmax || tzmin > tmax) return null; + + if (tzmin > tmin || tmin !== tmin) tmin = tzmin; + + if (tzmax < tmax || tmax !== tmax) tmax = tzmax; + + //return point closest to the ray (positive side) + + if (tmax < 0) return null; + + return this.at(tmin >= 0 ? tmin : tmax, target); + } + + /** + * Calculate a point on the ray + * @param t Length scalar + * @param target output target + * @returns result + */ + public at(t: number, target: Vector3) { + if (!target) { + console.warn('at() target is now required'); + target = new Vector3(); + } + return target.copy(this.direction).multiplyScalar(t).add(this.origin); + } + + /** + * Sets the ray to be a copy of the original ray + * @param src Ray object source + * @returns New ray object + */ + public copy(src: Ray): this { + this.origin.copy(src.origin); + this.direction.copy(src.direction); + this._dir.copy(src._dir); + this.length = src.length; + return this; + } + + /** + * Fast to the approximate ray direction + * @param dir direction + */ + public setApproxDirection(dir: Vector3) { + this._dir = dir.normalize(); + } + + /** + * Set ray origin + * @param origin ray origin + */ + public setOrigin(origin: Vector3) { + this.origin.copyFrom(origin); + } + + /** + * Get ray origin + */ + public getOrigin(): Vector3 { + return this.origin; + } + + /** + * Gets the point at the specified position on the ray + * @param t Length position + * @returns Returns a point at the specified location + */ + public getPoint(t: number): Vector3 { + this._dir.scaleBy(t); + return this.origin.add(this._dir); // + t * m_Direction; + } + + /** + * Calculate the distance from a point + * @param P Specify Point + * @returns result + */ + public sqrDistToPoint(P: Vector3): number { + let v = this._dir; + let w = P.subtract(this.origin); + + let c1 = dot(w, v); + let c2 = dot(v, v); + let b = c1 / c2; + + let Pb = this.getPoint(b); + return sqrMagnitude(P.subtract(Pb)); + } + + /** + * Applied matrix transformation + * @param mat4 matrix + */ + public applyMatrix(mat4: Matrix4) { + this.origin = mat4.transformPoint(this.origin); + this._dir = mat4.transformVector(this._dir); + } + + private _v0 = new Vector3(); + private _v1 = new Vector3(); + private _v2 = new Vector3(); + + /** + * Calculates whether a specified point is inside a triangle + * @param P point + * @param A Triangle vertex 1 + * @param B Triangle vertex 2 + * @param C Triangle vertex 3 + * @returns whether it is inside a triangle + */ + public pointInTriangle(P: Vector3, A: Vector3, B: Vector3, C: Vector3): boolean { + let v0 = this._v0; + let v1 = this._v1; + let v2 = this._v2; + + C.subtract(A, v0); + B.subtract(A, v1); + P.subtract(A, v2); + + // Compute dot products + let dot00 = Vector3.dot(v0, v0); + let dot01 = Vector3.dot(v0, v1); + let dot02 = Vector3.dot(v0, v2); + let dot11 = Vector3.dot(v1, v1); + let dot12 = Vector3.dot(v1, v2); + + // Compute barycentric coordinates + let invDenom = 1 / (dot00 * dot11 - dot01 * dot01); + let u = (dot11 * dot02 - dot01 * dot12) * invDenom; + let v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + // Check if point is in triangle + return u >= 0 && v >= 0 && u + v < 1; + } + + // Determine whether a ray intersect with a triangle + // Parameters + // orig: origin of the ray + // dir: direction of the ray + // v0, v1, v2: vertices of triangle + // t(out): weight of the intersection for the ray + // u(out), v(out): barycentric coordinate of intersection + private _E1: Vector3 = new Vector3(); + private _E2: Vector3 = new Vector3(); + private _P: Vector3 = new Vector3(); + private _T: Vector3 = new Vector3(); + private _Q: Vector3 = new Vector3(); + + /** + * Determine whether a ray intersects a triangle + * @param orig Ray starting point + * @param dir Ray direction + * @param face triangle + * @returns point of intersection + */ + public intersectTriangle(orig: Vector3, dir: Vector3, face: Triangle): Vector3 { + let v0: Vector3 = face.v1; + let v1: Vector3 = face.v2; + let v2: Vector3 = face.v3; + + // E1s + v1.subtract(v0, this._E1); + + // E2 + v2.subtract(v0, this._E2); + + // P + dir.cross(this._E2, this._P); + + // determinant + let det = this._E1.dotProduct(this._P); + + // keep det > 0, modify T accordingly + if (det > 0) { + orig.subtract(v0, this._T); + } else { + v0.subtract(orig, this._T); + det = -det; + } + + // If determinant is near zero, ray lies in plane of triangle + if (det < 0.0001) return null; + + // Calculate u and make sure u <= 1 + face.u = this._T.dotProduct(this._P); + if (face.u < 0.0 || face.u > det) return null; + + // Q + this._T.cross(this._E1, this._Q); + + // Calculate v and make sure u + v <= 1 + face.v = dir.dotProduct(this._Q); + if (face.v < 0.0 || face.u + face.v > det) return null; + + let hit = new Vector3(); + // Calculate t, scale parameters, ray intersects triangle + face.t0 = face.t = this._E2.dotProduct(this._Q); + + let fInvDet = 1.0 / det; + face.t *= fInvDet; + face.u *= fInvDet; + face.v *= fInvDet; + + hit.x = orig.x + face.t * dir.x; + hit.y = orig.y + face.t * dir.y; + hit.z = orig.z + face.t * dir.z; + + return hit; + } + + /** + * Determine whether a ray intersects the sphere + * @param o Ray starting point + * @param dir Ray direction + * @param center Sphere center + * @param radius radius of sphericity + * @returns point of intersection + */ + public intersectSphere(o: Vector3, dir: Vector3, center: Vector3, radius: number): Vector3 { + let oc = o.subtract(center); + let a = Vector3.dot(dir, dir); + let b = 2 * Vector3.dot(oc, dir); + let c = Vector3.dot(oc, oc) - radius * radius; + let dt = b * b - 4 * a * c; + + let hit: Vector3 = Vector3.HELP_3; + if (dt < 0) { + return null; + } else { + let t0 = (-b - Math.sqrt(dt)) / (a * 2); + if (t0 < 0) { + return null; + } + + hit.x = o.x + t0 * dir.x; + hit.y = o.y + t0 * dir.y; + hit.z = o.z + t0 * dir.z; + //let v = { hit.x - o.x, hit.y - o.y, hit.z - o.z }; + return hit; + } + } + + /** + * A test of the intersection between a ray and + * a given line segment within a given tolerance (threshold) + * @param sega The first point of a line segment used to test the intersection + * @param segb The second point of a line segment used to test the intersection + * @param threshold Margin, if the ray does not intersect the line segment but is close to the given threshold, the intersection is successful + * @return If there is an intersection, then the distance from the ray origin to the intersection, if there is no intersection, is -1 + */ + public intersectionSegment(sega: Vector3, segb: Vector3, threshold: number): { out: Vector3; length: number; } { + const o = this.origin; + const u = Vector3.HELP_0; + const rsegb = Vector3.HELP_1; + const v = Vector3.HELP_2; + const w = Vector3.HELP_3; + + segb.subtract(sega, u); + this._dir.scaleToRef(Ray._rayl, v); + o.add(v, rsegb); + + sega.subtract(o, w); + + var a = Vector3.dot(u, u); // always >= 0 + var b = Vector3.dot(u, v); + var c = Vector3.dot(v, v); // always >= 0 + var d = Vector3.dot(u, w); + var e = Vector3.dot(v, w); + var det = a * c - b * b; // always >= 0 + var sc: number, + sN: number, + sD = det; // sc = sN / sD, default sD = D >= 0 + var tc: number, + tN: number, + tD = det; // tc = tN / tD, default tD = D >= 0 + + // compute the line parameters of the two closest points + if (det < Ray._smallnum) { + // the lines are almost parallel + sN = 0.0; // force using point P0 on segment S1 + sD = 1.0; // to prevent possible division by 0.0 later + tN = e; + tD = c; + } else { + // get the closest points on the infinite lines + sN = b * e - c * d; + tN = a * e - b * d; + if (sN < 0.0) { + // sc < 0 => the s=0 edge is visible + sN = 0.0; + tN = e; + tD = c; + } else if (sN > sD) { + // sc > 1 => the s=1 edge is visible + sN = sD; + tN = e + b; + tD = c; + } + } + + if (tN < 0.0) { + // tc < 0 => the t=0 edge is visible + tN = 0.0; + // recompute sc for this edge + if (-d < 0.0) { + sN = 0.0; + } else if (-d > a) { + sN = sD; + } else { + sN = -d; + sD = a; + } + } else if (tN > tD) { + // tc > 1 => the t=1 edge is visible + tN = tD; + // recompute sc for this edge + if (-d + b < 0.0) { + sN = 0; + } else if (-d + b > a) { + sN = sD; + } else { + sN = -d + b; + sD = a; + } + } + // finally do the division to get sc and tc + sc = Math.abs(sN) < Ray._smallnum ? 0.0 : sN / sD; + tc = Math.abs(tN) < Ray._smallnum ? 0.0 : tN / tD; + + // get the difference of the two closest points + const qtc = Vector3.HELP_4; + v.scaleToRef(tc, qtc); + const qsc = Vector3.HELP_5; + u.scaleToRef(sc, qsc); + qsc.add(w, qsc); + const dP = Vector3.HELP_6; + qsc.subtract(qtc, dP); // = S1(sc) - S2(tc) + + var isIntersected = tc > 0 && tc <= this._dir.length && dP.lengthSquared < threshold * threshold; // return intersection result + + if (isIntersected) { + let dd0 = new Vector3(); + dd0.copyFrom(segb.subtract(sega)); + dd0.scaleBy(sc); + dd0.add(sega, dd0); + // let out = new Vector3(dx,dy,dz); + return { out: dd0, length: qsc.length }; + } + return { out: null, length: -1 }; + } + + private get_vec(p: Vector3, q: Vector3) { + let rc = Vector3.HELP_1; + rc.x = p.x - q.x; + rc.y = p.y - q.y; + rc.z = p.z - q.z; + return rc; + } +} diff --git a/src/engine/math/Rect.ts b/src/engine/math/Rect.ts new file mode 100644 index 00000000..e0dbed73 --- /dev/null +++ b/src/engine/math/Rect.ts @@ -0,0 +1,219 @@ + +/** + * Rectangular region + * @group Math + */ +export class Rect { + /** + * The x-coordinate of the rectangle + */ + public x: number; + + /** + * The y-coordinate of the rectangle + */ + public y: number; + + /** + * Width of a rectangle + */ + public w: number; + + /** + * Height of rectangle + */ + public h: number; + + /** + * Creates a new rectangular area object + * @param x The x-coordinate of the rectangle + * @param y The y coordinate of the rectangle + * @param width Width of a rectangle + * @param height Height of rectangle + */ + constructor(x: number = 0, y: number = 0, width: number = 0, height: number = 0) { + this.x = x; + this.y = y; + this.w = width; + this.h = height; + } + + /** + * Width of a rectangle + */ + public get width(): number { + return this.w; + } + + public set width(v) { + this.w = v; + } + + /** + * Height of rectangle + */ + public get height(): number { + return this.h; + } + + public set height(v) { + this.h = v; + } + + /** + * Whether the point is within the specified area + * @param x x value of point + * @param y y value of point + * @param lt_x The x value in the upper left corner + * @param lt_y The y value in the upper left corner + * @param rb_x The x value in the lower right corner + * @param rb_y The y value in the lower right corner + * @returns + */ + public static pointInRect(x: number, y: number, lt_x: number, lt_y: number, rb_x: number, rb_y: number): boolean { + if (x < lt_x || x > rb_x || y < lt_y || y > rb_y) { + return false; + } + + return true; + } + + /** + * Returns a new rectangular area object with the same properties as the current rectangular area + * @returns + */ + public clone(): Rect { + return new Rect(this.x, this.y, this.w, this.h); + } + + /** + * Copy the properties of the source object to this object + * @param v source object + * @returns + */ + public copyFrom(rect: Rect) { + this.x = rect.x; + this.y = rect.y; + this.w = rect.w; + this.h = rect.h; + } + + /** + * Copy the properties of this object to the target object + * @param v target object + * @returns + */ + public copyTo(rect: Rect): void { + rect.copyFrom(this); + } + + /** + * Whether the point is in this area + * @param x x value of point + * @param y y value of point + * @returns + */ + public inner(x: number, y: number): boolean { + if (x < this.x || x > this.x + this.width || y < this.y || y > this.y + this.height) { + return false; + } + return true; + } + + /** + * Whether the current rectangle is equal to the target rectangle + * @param rectangle Target rectangle + * @returns + */ + public equal(rectangle: Rect): boolean { + return !(this.x != rectangle.x || this.y != rectangle.y || this.width != rectangle.width || this.height != rectangle.height); + } + + /** + * Whether the current rectangle is equal to the target rectangle + * @param x The x value of the rectangle + * @param y The y value of the rectangle + * @param width Rectangle width + * @param height Rectangular height + * @returns + */ + public equalArea(x: number, y: number, width: number, height: number): boolean { + return !(this.x != x || this.y != y || this.width != width || this.height != height); + } + + /** + * Whether this rectangle overlaps with the target object + * @param source Source object + * @returns + */ + public equalInnerArea(source: Rect): boolean { + var aMinX = this.x; + var aMinY = this.y; + + var aMaxX = this.x + this.width; + var aMaxY = this.y + this.height; + + var bMinX = source.x; + var bMinY = source.y; + + var bMaxX = source.x + source.width; + var bMaxY = source.y + source.height; + + if (Math.max(aMinX, bMinX) <= Math.min(aMaxX, bMaxX) && Math.max(aMinY, bMinY) <= Math.min(aMaxY, bMaxY)) { + return true; + } + return false; + } + + /** + * Returns the overlap of two rectangles + * @param source source object + * @param target target object + * @returns + */ + public innerArea(source: Rect, target: Rect): Rect { + target = target || new Rect(); + var Xa1 = this.x; + var Ya1 = this.y; + + var Xa2 = this.x + this.width; + var Ya2 = this.y + this.height; + + var Xb1 = source.x; + var Yb1 = source.y; + + var Xb2 = source.x + source.width; + var Yb2 = source.y + source.height; + + var top: number = Math.max(Ya1, Yb1); + var bottom: number = Math.min(Ya2, Yb2); + var left: number = Math.max(Xa1, Xb1); + var right: number = Math.min(Xb2, Xa2); + if (top >= 0 && bottom >= 0 && bottom - top >= 0 && right - left > 0) { + target.x = left; + target.y = top; + target.width = right - left; + target.height = bottom - top; + } else { + target.x = 0; + target.y = 0; + target.width = 0; + target.height = 0; + } + return target; + } + + /** + * Sets the properties of the rectangle + * @param x x value + * @param y y value + * @param width Rectangle width + * @param height Rectangular height + */ + public setTo(x: number, y: number, width: number, height: number): void { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } +} diff --git a/src/engine/math/TimeInterpolator.ts b/src/engine/math/TimeInterpolator.ts new file mode 100644 index 00000000..60d39930 --- /dev/null +++ b/src/engine/math/TimeInterpolator.ts @@ -0,0 +1,520 @@ +/** + * Time Interpolator interface + * @internal + * @group Plugin + */ +export interface TimeInterpolator { + /** + * Maps a value representing the elapsed fraction of an animation to a value that represents + * the interpolated fraction. This interpolated value is then multiplied by the change in + * value of an animation to derive the animated value at the current elapsed animation time. + * + * @param input A value between 0 and 1.0 indicating our current point + * in the animation where 0 represents the start and 1.0 represents + * the end + * @return The interpolation value. This value can be more than 1.0 for + * interpolators which overshoot their targets, or less than 0 for + * interpolators that undershoot their targets. + */ + getInterpolation(input: number): number; +} + +/** + * An interpolator where the rate of change starts out slowly and + * and then accelerates. + * @internal + * @group Plugin + */ +export class AccelerateInterpolator implements TimeInterpolator { + private _factor: number; + private _doubleFactor: number; + + public constructor() { + this._factor = 1.0; + this._doubleFactor = 2.0; + } + + public get accelerateInterpolator(): number { + return this._factor + } + + public set accelerateInterpolator(factor: number) { + this._factor = factor; + this._doubleFactor = 2 * this._factor; + } + + public getInterpolation(input: number): number { + if (this._factor == 1.0) { + return input * input; + } else { + return Math.pow(input, this._doubleFactor); + } + } +} + +/** + * An interpolator where the rate of change starts out quickly and + * and then decelerates. + * @internal + * @group Plugin + */ +export class DecelerateInterpolator implements TimeInterpolator { + private _factor: number = 1.0; + + constructor() { + } + + public get decelerateInterpolator(): number { + return this._factor; + } + + public set decelerateInterpolator(factor: number) { + this._factor = factor; + } + + public getInterpolation(input: number): number { + let result; + if (this._factor == 1.0) { + result = 1.0 - (1.0 - input) * (1.0 - input); + } else { + result = 1.0 - Math.pow(1.0 - input, 2 * this._factor); + } + return result; + } +} + +/** + * An interpolator where the rate of change starts and ends slowly but + * accelerates through the middle. + * @internal + * @group Plugin + */ +export class AccelerateDecelerateInterpolator implements TimeInterpolator { + private _factor: number = 1.0; + + constructor() { + } + + public getInterpolation(input: number): number { + return Math.cos((input + 1) * Math.PI) / 2.0 + 0.5; + } +} + +/** + * An interpolator where the rate of change is constant + * @internal + * @group Plugin + */ +export class LinearInterpolator implements TimeInterpolator { + public getInterpolation(input: number): number { + return input; + } +} + +/** + * @internal + * @group Plugin + */ +export class JumperInterpolator implements TimeInterpolator { + public getInterpolation(t: number): number { + return 4.9 * t + 4.9 * t; + } +} + +/** + * An interpolator where the change bounces at the end. + * @internal + * @group Plugin + */ +export class BounceInterpolator implements TimeInterpolator { + constructor() { + } + + private static bounce(t): number { + return t * t * 9.8; + } + + public getInterpolation(t: number): number { + // _b(t) = t * t * 8 + // bs(t) = _b(t) for t < 0.3535 + // bs(t) = _b(t - 0.54719) + 0.7 for t < 0.7408 + // bs(t) = _b(t - 0.8526) + 0.9 for t < 0.9644 + // bs(t) = _b(t - 1.0435) + 0.95 for t <= 1.0 + // b(t) = bs(t * 1.1226) + t *= 1.1226; + if (t < 0.3535) return BounceInterpolator.bounce(t); + else if (t < 0.7408) return BounceInterpolator.bounce(t - 0.54719) + 0.7; + else if (t < 0.9644) return BounceInterpolator.bounce(t - 0.8526) + 0.9; + else return BounceInterpolator.bounce(t - 1.0435) + 0.95; + } + + public getBounceInterpolation(t: number): number { + if (t < 0.5) return BounceInterpolator.bounce(t); + else return BounceInterpolator.bounce(t - 1.0); + } + + public geJumpUp(v0: number, t: number): number { + // if (t < 0.5) { + // t = t / 0.5; + // return (v0 * t - BounceInterpolator.bounce(t)); + // } else if (t < 0.8) { + // t = (t - 0.5) / (0.8 - 0.5); + // return (v0 * t - BounceInterpolator.bounce(t)) * 0.5; + // } else if (t < 1) { + // t = (t - 0.8) / (1 - 0.8); + // return (v0 * t - BounceInterpolator.bounce(t)) * 0.2; + // } else + // return (v0 * t - BounceInterpolator.bounce(t)); + if (t < 0.5) { + t = t / 0.5; + return v0 * t - BounceInterpolator.bounce(t); + } else if (t < 0.8) { + t = (t - 0.5) / (0.8 - 0.5); + return (v0 * t - BounceInterpolator.bounce(t)) * 0.3; + } else if (t < 1) { + t = (t - 0.8) / (1 - 0.8); + return (v0 * t - BounceInterpolator.bounce(t)) * 0.15; + } else return v0 * t - BounceInterpolator.bounce(t); + } +} + +/** + * An interpolator where the change starts backward then flings forward. + * @internal + * @group Plugin + */ +export class AnticipateInterpolator implements TimeInterpolator { + private _tension: number; + + constructor() { + this._tension = 2.0; + } + + public get anticipateInterpolator(): number { + return this._tension + } + + public set anticipateInterpolator(tension: number) { + this._tension = tension; + } + + public getInterpolation(t: number): number { + // a(t) = t * t * ((tension + 1) * t - tension) + return t * t * ((this._tension + 1) * t - this._tension); + } +} + +/** + * An interpolator where the change starts backward then flings forward and overshoots + * the target value and finally goes back to the final value. + * @internal + * @group Plugin + */ +export class AnticipateOvershootInterpolator implements TimeInterpolator { + private _tension: number; + + constructor() { + this._tension = 1.0 * 1.5; + } + + public anticipateOvershootInterpolator(tension: number) { + this._tension = tension * 1.5; + } + + public anticipateOvershootInterpolator2(tension: number, extraTension: number) { + this._tension = tension * extraTension; + } + + public getInterpolation(t) { + // a(t, s) = t * t * ((s + 1) * t - s) + // o(t, s) = t * t * ((s + 1) * t + s) + // f(t) = 0.5 * a(t * 2, tension * extraTension), when t < 0.5 + // f(t) = 0.5 * (o(t * 2 - 2, tension * extraTension) + 2), when t <= 1.0 + if (t < 0.5) return 0.5 * AnticipateOvershootInterpolator.a(t * 2.0, this._tension); + else return 0.5 * (AnticipateOvershootInterpolator.o(t * 2.0 - 2.0, this._tension) + 2.0); + } + + private static a(t, s) { + return t * t * ((s + 1) * t - s); + } + + private static o(t, s) { + return t * t * ((s + 1) * t + s); + } +} + +/** + * Repeats the animation for a specified number of cycles. The + * rate of change follows a sinusoidal pattern. + * @internal + * @group Plugin + */ +export class CycleInterpolator implements TimeInterpolator { + private _cycles; + + constructor(cycles) { + this._cycles = cycles; + } + + public getInterpolation(t) { + return Math.sin(2 * this._cycles * Math.PI * t); + } +} + +/** + * An interpolator where the change flings forward and overshoots the last value + * then comes back. + * @internal + * @group Plugin + */ +export class OvershootInterpolator implements TimeInterpolator { + private _tension; + + constructor() { + this._tension = 2.0; + } + + public getInterpolation(t) { + // _o(t) = t * t * ((tension + 1) * t + tension) + // o(t) = _o(t - 1) + 1 + t -= 1.0; + return t * t * ((this._tension + 1) * t + this._tension) + 1.0; + //plot {(x-1)(x-1)((tension+1)(x-1)+tension)+1,(0= this.durtion) { + this.complete = true; + if (this.onComplete != null) { + this.onComplete(this.target); + } + } + this._ct += delta; + } else { + this.delayTime -= delta; + } + } + + /** + * @internal + */ + public dispose() { + this.onComplete = null; + this.onProgress = null; + this.target = null; + this.property = null; + this.targetProperty = null; + this.interpolatorEnum = null; + this._interpolator = null; + Interpolator.remove(this); + } +} diff --git a/src/engine/math/Triangle.ts b/src/engine/math/Triangle.ts new file mode 100644 index 00000000..5c4f0523 --- /dev/null +++ b/src/engine/math/Triangle.ts @@ -0,0 +1,146 @@ +import { Line } from './Line'; +import { Vector2 } from './Vector2'; +import { Vector3 } from './Vector3'; + +/** + * @internal + * @group Math + */ +export class Triangle { + public static ID: number = -1; + public v1: Vector3; + public v2: Vector3; + public v3: Vector3; + + public u1: Vector2; + public u2: Vector2; + public u3: Vector2; + + public n1: Vector3; + public n2: Vector3; + public n3: Vector3; + + public t0: number; + public t: number; + public u: number; + public v: number; + + public min = new Vector3(); + public max = new Vector3(); + public id: number = 0; + + constructor(v1?: Vector3, v2?: Vector3, v3?: Vector3) { + this.id = Triangle.ID++ + 200; + v1 && v2 && v3 && this.set(v1, v2, v3); + } + + public set(v1: Vector3, v2: Vector3, v3: Vector3): this { + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + + let min = this.min; + let max = this.max; + + min.x = Math.min(this.v1.x, this.v2.x, this.v3.x); + min.y = Math.min(this.v1.y, this.v2.y, this.v3.y); + min.z = Math.min(this.v1.z, this.v2.z, this.v3.z); + + max.x = Math.max(this.v1.x, this.v2.x, this.v3.x); + max.y = Math.max(this.v1.y, this.v2.y, this.v3.y); + max.z = Math.max(this.v1.z, this.v2.z, this.v3.z); + return this; + } + + public getNormal(): Vector3 { + let v1 = this.v1; + let v2 = this.v2; + let v3 = this.v3; + + let edge1 = new Vector3(v2.x - v1.x, v2.y - v1.y, v2.z - v1.z); + let edge2 = new Vector3(v3.x - v1.x, v3.y - v1.y, v3.z - v1.z); + + let normal = edge2.cross(edge1); + normal.normalize(); + return normal; + } + + public turnBack() { + let tmp = this.v3; + this.v3 = this.v1; + this.v1 = tmp; + } + + public getLines(): Line[] { + let v1 = this.v1; + let v2 = this.v2; + let v3 = this.v3; + let l = [new Line(v1, v2), new Line(v2, v3), new Line(v3, v1)]; + return l; + } + + public equals(t: Triangle): boolean { + let lines1: Line[] = this.getLines(); + let lines2: Line[] = t.getLines(); + + let cnt = 0; + for (let i = 0; i < lines1.length; i++) { + for (let j = 0; j < lines2.length; j++) { + if (lines1[i].equals(lines2[j])) cnt++; + } + } + if (cnt == 3) return true; + else return false; + } + + /** + * name + */ + public getCenter(): Vector3 { + let min = this.min; + let max = this.max; + let center = new Vector3(); + center.x = (min.x + max.x) * 0.5; + center.y = (min.y + max.y) * 0.5; + center.z = (min.z + max.z) * 0.5; + return center; + } + + /** + * @function + * @returns {Boolean} return intersection. + */ + public intersects(other: Triangle): boolean { + var aMax = this.max; + var aMin = this.min; + var bMax = other.max; + var bMin = other.min; + + return aMin.x <= bMax.x && aMax.x >= bMin.x && aMin.y <= bMax.y && aMax.y >= bMin.y && aMin.z <= bMax.z && aMax.z >= bMin.z; + } + + public sign2D(p1: Vector3, p2: Vector3, p3: Vector3) { + return (p1.x - p3.x) * (p2.z - p3.z) - (p2.x - p3.x) * (p1.z - p3.z); + } + + public pointInTriangle2D(pt: Vector3) { + let v1: Vector3 = this.v1; + let v2: Vector3 = this.v2; + let v3: Vector3 = this.v3; + let d1, d2, d3; + let has_neg, has_pos; + + d1 = this.sign2D(pt, v1, v2); + d2 = this.sign2D(pt, v2, v3); + d3 = this.sign2D(pt, v3, v1); + + has_neg = d1 < 0 || d2 < 0 || d3 < 0; + has_pos = d1 > 0 || d2 > 0 || d3 > 0; + + return !(has_neg && has_pos); + } + + public toArray() { + return [this.v1.x, this.v1.y, this.v1.z, this.v2.x, this.v2.y, this.v2.z, this.v3.x, this.v3.y, this.v3.z]; + } +} diff --git a/src/engine/math/UV.ts b/src/engine/math/UV.ts new file mode 100644 index 00000000..06de89c0 --- /dev/null +++ b/src/engine/math/UV.ts @@ -0,0 +1,23 @@ +import { Vector2 } from './Vector2'; + +/*** + * @internal + * @group Math + */ +export class UV extends Vector2 { + public static uv_0: UV = new UV(); + + public u: number = 0.0; + + public v: number = 0.0; + + constructor(x: number = 0, y: number = 0) { + super(x, y); + this.u = x; + this.v = y; + } + + public length(): number { + return 0; + } +} diff --git a/src/engine/math/Vector2.ts b/src/engine/math/Vector2.ts new file mode 100644 index 00000000..b2fb5889 --- /dev/null +++ b/src/engine/math/Vector2.ts @@ -0,0 +1,314 @@ + +/*** + * Vector 2D + * @group Math + */ +export class Vector2 { + + /** + * @internal + */ + public static HELP_0: Vector2 = new Vector2(); + + /** + * @internal + */ + public static HELP_1: Vector2 = new Vector2(); + + public static readonly ZERO: Vector2 = new Vector2(0, 0); + + public static readonly SAFE_MAX: Vector2 = new Vector2(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); + + public static readonly SAFE_MIN: Vector2 = new Vector2(Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER); + + /** + * The x component of the vector, the default value is 0. + */ + public x: number = 0.0; + + /** + * The y component of the vector, the default value is 0. + */ + public y: number = 0.0; + + /** + * Create a new Vector2. + * @param x The x component of the vector, which defaults to 0. + * @param y The y component of the vector, which defaults to 0. + */ + constructor(x: number = 0, y: number = 0) { + this.x = x; + this.y = y; + } + + /** + * Returns the Angle, in radians, between two vectors. + * @param a Vector a + * @param b Vector b + * @returns result + */ + public static getAngle(a: Vector2, b: Vector2): number { + return Math.atan2(b.y - a.y, b.x - a.x); + } + + /** + * Computes linear interpolation between two vectors. + * @param from starting vector + * @param to The vector in which you interpolate + * @param t + */ + public static slerp(from: Vector2, to: Vector2, t: number): Vector2 { + let v = new Vector2(); + let dot = from.dot(to); + if (dot < 0) { + to.x = -to.x; + to.y = -to.y; + dot = -dot; + } + if (dot > 0.9995) { + v.x = from.x + t * (to.x - from.x); + v.y = from.y + t * (to.y - from.y); + return v; + } + let theta = Math.acos(dot); + let sinTheta = Math.sin(theta); + let scale0 = Math.sin((1 - t) * theta) / sinTheta; + let scale1 = Math.sin(t * theta) / sinTheta; + v.x = scale0 * from.x + scale1 * to.x; + v.y = scale0 * from.y + scale1 * to.y; + return v; + } + + /** + * Linear interpolation between two vectors. + * @param from starting vector + * @param to The vector in which you interpolate + * @param t + * @returns + */ + public static lerp(from: Vector2, to: Vector2, t: number) { + Vector2.HELP_0.copyFrom(from); + Vector2.HELP_1.copyFrom(to); + Vector2.HELP_0.scale(t); + Vector2.HELP_1.scale(1.0 - t); + return new Vector2(Vector2.HELP_0.x + Vector2.HELP_1.x, Vector2.HELP_0.y + Vector2.HELP_1.y); + } + + /** + * Sets the x and y components of this vector. + * @param x The x component of the vector, which defaults to 0. + * @param y The y component of the vector, which defaults to 0. + */ + public set(x: number = 0, y: number = 0) { + this.x = x; + this.y = y; + } + + /** + * Calculate the distance between this vector and the incoming vector. + * @param a Target vector + * @returns + */ + public distance(a: Vector2): number { + return Math.sqrt(Math.pow(this.x - a.x, 2) + Math.pow(this.y - a.y, 2)); + } + + /** + * Add the vectors. + * @param a + * @param target + * @returns + */ + public add(a: Vector2, target?: Vector2): Vector2 { + target = target || new Vector2(); + target.x = this.x + a.x; + target.y = this.y + a.y; + return target; + } + + /** + * Vector subtraction + * @param a + * @param target + * + */ + public sub(a: Vector2, target?: Vector2): Vector2 { + target = target || new Vector2(); + target.x = this.x - a.x; + target.y = this.y - a.y; + return target; + } + + /** + * Let's multiply the x and y values of this vector times v. + * @param v + */ + public scale(v: number) { + this.x = this.x * v; + this.y = this.y * v; + } + + /** + * Let's multiply the x and y values of this vector by a. + * @param a + * @param target + * @returns + */ + public multiply(a: number, target?: Vector2) { + target = target || new Vector2(); + target.x = this.x * a; + target.y = this.y * a; + return target; + } + + /** + * We're going to divide the x and y values of this vector by v. + * @param v + * @param target + * @returns + */ + public divide(v: number, target?: Vector2) { + target = target || new Vector2(); + target.x = this.x / v; + target.y = this.y / v; + return target; + } + + /** + * Vector inversion + * @param target + * @returns + */ + public neg(target?: Vector2): Vector2 { + if (!target) target = new Vector2(); + target.x = -target.x; + target.y = -target.y; + return target; + } + + public abs() { + return Math.sqrt(this.x * this.x + this.y * this.y); + } + + /** + * Length of vector + * @returns + */ + public length(): number { + return Math.sqrt(this.x * this.x + this.y * this.y); + } + + /** + * Returns the Angle, in radians, between the current vector and the target vector. + * @param target Target vector + * @returns + */ + public getAngle(target: Vector2): number { + return Math.atan2(target.y - this.y, target.x - this.x); + } + + public unt(target?: Vector2): Vector2 { + target = target || new Vector2(); + let d = this.abs(); + target.x = this.x / d; + target.y = this.y / d; + return target; + } + + public angleTo(v: Vector2): number { + let dx = v.x - this.x; + let dy = v.y - this.y; + return Math.atan2(dy, dx); + } + + /** + * Whether two vectors are equal + * @param a Vector of comparison + * @returns + */ + public equals(a: Vector2): boolean { + if (Math.abs(this.x - a.x) < 1e-6 && Math.abs(this.y - a.y) < 1e-6) return true; + return false; + } + + public pal(a: Vector2): number { + let u1 = this.unt(); + let u2 = a.unt(); + if (u1.equals(u2)) return 1; + if (u1.equals(u2.neg())) return -1; + return 0; + } + + /** + * Returns a new vector that has the same x and y as the current vector. + * @returns + */ + public clone(): Vector2 { + return new Vector2(this.x, this.y); + } + + /** + * Copy the x and y properties of the source vector to this vector + * @param v Source vector + * @returns + */ + public copyFrom(v: Vector2): Vector2 { + this.x = v.x; + this.y = v.y; + return this; + } + + /** + * Take the dot product of two vectors. + * @param value Target vector + * @returns + */ + public dot(value: Vector2): number { + return this.x * value.x + this.y * value.y; + } + + /** + * Convert this vector to a unit vector. + */ + public normalize() { + let d = this.abs(); + this.x = this.x / d; + this.y = this.y / d; + } + + /** + * Add two vectors + * @param otherVector Additive vector + * @returns + */ + public addInPlace(otherVector: Vector2): Vector2 { + this.x += otherVector.x; + this.y += otherVector.y; + return this; + } + + /** + * Add the scalar to the x and y of this vector. + * @param s Additive scalar + * @returns + */ + public addScalar(s: number) { + this.x += s; + this.y += s; + + return this; + } + + /** + * + * @param minVal Component will be limited to the minimum value of + * @param maxVal The component will be limited to the maximum value of + * @returns + */ + public clampScalar(minVal: number, maxVal: number) { + this.x = Math.max(minVal, Math.min(maxVal, this.x)); + this.y = Math.max(minVal, Math.min(maxVal, this.y)); + + return this; + } +} diff --git a/src/engine/math/Vector3.ts b/src/engine/math/Vector3.ts new file mode 100644 index 00000000..a2f6cc4d --- /dev/null +++ b/src/engine/math/Vector3.ts @@ -0,0 +1,1091 @@ + +/** + * Vector 3D + * @group Math + */ +export class Vector3 { + + /** + * Vector maximum + */ + public static readonly MAX: Vector3 = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); + + /** + * Vector minimum + */ + public static readonly MIN: Vector3 = new Vector3(Number.MIN_VALUE, Number.MIN_VALUE, Number.MIN_VALUE); + + /** + * Vector maximum integer value + */ + public static readonly SAFE_MAX: Vector3 = new Vector3(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); + + /** + * Vector minimum integer value + */ + public static readonly SAFE_MIN: Vector3 = new Vector3(Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER); + + /** + * X axis positive axis coordinate (1, 0, 0). + */ + public static readonly X_AXIS: Vector3 = new Vector3(1, 0, 0); + + /** + * The X-axis is negative (-1, 0, 0). + */ + public static readonly neg_X_AXIS: Vector3 = new Vector3(-1, 0, 0); + + /** + * The y axis defined as a Vector3 object with coordinates (0,1,0). + */ + public static readonly Y_AXIS: Vector3 = new Vector3(0, 1, 0); + + /** + * The z axis defined as a Vector3 object with coordinates (0,0,1). + */ + public static readonly Z_AXIS: Vector3 = new Vector3(0, 0, 1); + + /** + * @internal + */ + public static HELP_0: Vector3 = new Vector3(); + + /** + * @internal + */ + public static HELP_1: Vector3 = new Vector3(); + + /** + * @internal + */ + public static HELP_2: Vector3 = new Vector3(); + + /** + * @internal + */ + public static readonly EPSILON: number = 0.00001; + + /** + * @internal + */ + public static HELP_3: Vector3 = new Vector3(); + + /** + * @internal + */ + public static HELP_4: Vector3 = new Vector3(); + + /** + * @internal + */ + public static HELP_5: Vector3 = new Vector3(); + + /** + * @internal + */ + public static HELP_6: Vector3 = new Vector3(); + + /** + * Returns a new vector with zero x, y, and z components + */ + public static get ZERO(): Vector3 { + return new Vector3(0, 0, 0); + } + + /** + * Returns a new vector whose x, y, and z components are all 1 + */ + public static get ONE(): Vector3 { + return new Vector3(1, 1, 1); + }; + + /** + * Returns a new vector pointing to the left, x is -1, y is 0, and z is 0 + */ + public static get LEFT(): Vector3 { + return new Vector3(-1, 0, 0); + }; + + /** + * Returns a new vector pointing in the right direction, where x is 1, y is 0, and z is 0 + */ + public static get RIGHT(): Vector3 { + return new Vector3(1, 0, 0); + }; + + /** + * Returns a new vector pointing upwards, that is, x equals 0, y equals 1, and z equals 0 + */ + public static get UP(): Vector3 { + return new Vector3(0, 1, 0); + }; + + /** + * Returns a new vector pointing down, where x is 0, y is -1, and z is 0 + */ + public static get DOWN(): Vector3 { + return new Vector3(0, -1, 0); + }; + + /** + * Returns a new backward vector, x equals 0, y equals 0, and z equals negative 1 + */ + public static get BACK(): Vector3 { + return new Vector3(0, 0, -1); + }; + + /** + * Returns a new forward-pointing vector, that is, x is 0, y is 0, and z is 1 + */ + public static get FORWARD(): Vector3 { + return new Vector3(0, 0, 1); + }; + + /** + * The first element of a Vector3 object, such as the x coordinate of + * a point in the three-dimensional space. The default value is 0. + */ + public x: number = 0; + + /** + * The second element of a Vector3 object, such as the y coordinate of + * a point in the three-dimensional space. The default value is 0. + */ + public y: number = 0; + + /** + * The third element of a Vector3 object, such as the y coordinate of + * a point in the three-dimensional space. The default value is 0. + */ + public z: number = 0; + + /** + * The z component of the vector, + * A three-dimensional position or projection that can be used as a perspective projection + * We can also do w in the quaternion + */ + public w: number = 1; + + /** + * @internal + */ + public index: number = 0; + + /** + * @internal + */ + private static _index: number = 0; + + + /** + * Creates an instance of a Vector3 object. If you do not specify a。 + * parameter for the constructor, a Vector3 object is created with + * the elements (0,0,0,0). + * + * @param x The first element, such as the x coordinate. + * @param y The second element, such as the y coordinate. + * @param z The third element, such as the z coordinate. + * @param w An optional element for additional data such as the angle + * of rotation. + */ + constructor(x: number = 0, y: number = 0, z: number = 0, w: number = 0) { + this.set(x, y, z, w); + + this.index = Vector3._index++; + } + + /** + * Set w component + * @param value + */ + public set a(value: number) { + this.w = value; + } + + /** + * Set x component + * @param value + */ + public set r(value: number) { + this.x = value; + } + + /** + * Set the y component + * @param value + */ + public set g(value: number) { + this.y = value; + } + + /** + * Set z component + * @param value + */ + public set b(value: number) { + this.z = value; + } + + /** + * get the w component + * @returns value of w + */ + public get a(): number { + return this.w; + } + + /** + * get the x component + * @returns value of x + */ + public get r(): number { + return this.x; + } + + /** + * get the y component + * @returns value of y + */ + public get g(): number { + return this.y; + } + + /** + * get the z component + * @returns value of z + */ + public get b(): number { + return this.z; + } + + /** + * The length of the vector, the distance from the origin (0, 0, 0) to (x, y, z) + */ + public get length(): number { + return Math.sqrt(this.lengthSquared); + } + + /** + * You get the square of the length of the vector + * @returns + */ + public get lengthSquared(): number { + return this.x * this.x + this.y * this.y + this.z * this.z; + } + + /** + * Get the current vector + */ + public get position() { + return this; + } + + /** + * Obtain a vertical line segment with width through an orientation + * @param dir + * @param tp1 + * @param tp2 + * @param width + */ + public static getTowPointbyDir(dir: Vector3, tp1: Vector3, tp2: Vector3, width: number, aix: Vector3) { + if (aix == Vector3.Z_AXIS) { + tp1.x = dir.y; + tp1.y = -dir.x; + + tp2.x = -dir.y; + tp2.y = dir.x; + + tp1.scaleBy(width * 0.5); + tp2.scaleBy(width * 0.5); + } else if (aix == Vector3.Y_AXIS) { + tp1.x = dir.z; + tp1.z = -dir.x; + + tp2.x = -dir.z; + tp2.z = dir.x; + + tp1.scaleBy(width * 0.5); + tp2.scaleBy(width * 0.5); + } + } + + /** + * Calculate the distance from the point to the line + * @param point1 Starting point of line segment + * @param point2 End point of line segment + * @param position Point position + * @returns Distance from a point to a line segment + */ + public static pointToLine(point1: Vector3, point2: Vector3, position: Vector3) { + let space = 0; + let a, b, c; + a = Vector3.distance(point1, point2); + b = Vector3.distance(point1, position); + c = Vector3.distance(point2, position); + if (c <= 0.000001 || b <= 0.000001) { + space = 0; + return space; + } + if (a <= 0.000001) { + space = b; + return space; + } + if (c * c >= a * a + b * b) { + space = b; + return space; + } + if (b * b >= a * a + c * c) { + space = c; + return space; + } + let p = (a + b + c) / 2; + let s = Math.sqrt(p * (p - a) * (p - b) * (p - c)); + space = (2 * s) / a; + return space; + } + + public static cross(a: Vector3, b: Vector3, target: Vector3 = null): Vector3 { + target = target || new Vector3(); + target.x = a.y * b.z - a.z * b.y; + target.y = a.z * b.x - a.x * b.z; + target.z = a.x * b.y - a.y * b.x; + target.w = 1; + return target; + } + + /** + * Take the dot product of two vectors. + * @param a Vector a + * @param b Vector b + * @returns + */ + public static dot(a: Vector3, b: Vector3): number { + return a.x * b.x + a.y * b.y + a.z * b.z; + } + + public static getPoints(total: number, randSeed: number) { + let points = []; + for (let index = 0; index < total; index++) { + const element = new Vector3(Math.random() * randSeed - randSeed * 0.5, Math.random() * randSeed - randSeed * 0.5, Math.random() * randSeed - randSeed * 0.5); + points.push(element); + } + return points; + } + + public static getPointNumbers(total: number, randSeed: number) { + let points = []; + for (let index = 0; index < total; index++) { + points.push(Math.random() * randSeed - randSeed * 0.5, Math.random() * randSeed - randSeed * 0.5, Math.random() * randSeed - randSeed * 0.5); + } + return points; + } + + /** + * Returns the Angle, in degrees, between the source vector and the target vector. + * @param from source vector. + * @param to target vector. + * @returns + */ + public static getAngle(from: Vector3, to: Vector3): number { + let t = from.dotProduct(to) / (from.length * to.length); + return (Math.acos(t) * 180) / Math.PI; + } + + public static sqrMagnitude(arg0: Vector3): number { + return arg0.x * arg0.x + arg0.y * arg0.y + arg0.z * arg0.z; + } + + public static getZYAngle(zd: Vector3, yd: Vector3) { + return this.calAngle(zd.y, zd.z, yd.y, yd.z); + } + /** + * Subtract two vectors + * @param a Vector a + * @param b Vector b + * @param target output vector + * @returns + */ + public static sub(a: Vector3, b: Vector3, target: Vector3 = null): Vector3 { + target = target || new Vector3(); + target.x = a.x - b.x; + target.y = a.y - b.y; + target.z = a.z - b.z; + + return target; + } + + /** + * Add two vectors + * @param a Vector a + * @param b Vector b + * @param target output vector + * @returns + */ + public static add(a: Vector3, b: Vector3, target: Vector3 = null): Vector3 { + target = target || new Vector3(); + target.x = a.x + b.x; + target.y = a.y + b.y; + target.z = a.z + b.z; + return target; + } + + /** + * @internal + * @param current + * @param target + * @param currentVelocity + * @param smoothTime + * @param maxSpeed + * @param deltaTime + * @returns + */ + public static smoothDamp(current: Vector3, target: Vector3, currentVelocity: Vector3, smoothTime: number, maxSpeed: number, deltaTime: number) { + // smoothTime = Math.max(0.0001, smoothTime); + // let num = 2 / smoothTime; + // let num2 = num * deltaTime; + // let num3 = 1 / (1 + num2 + 0.48 * num2 * num2 + 0.235 * num2 * num2 * num2); + // let vector = Vector3.Sub(current, target); + // let vector2 = target; + // let maxLength = maxSpeed * smoothTime; + // vector.clampLength(-maxLength, maxLength); + // target = Vector3.Sub(current, vector, target); + // let vector3 = Vector3.Add(currentVelocity, vector.scaleBy(num)); + // vector3.x = vector3.x + (vector.x - vector3.x) * num3; + // vector3.y = vector3.y + (vector.y - vector3.y) * num3; + // vector3.z = vector3.z + (vector.z - vector3.z) * num3; + // currentVelocity = Vector3.Sub( vector3 , vector); + // return target + (vector - vector2) * num3; + return null; + } + + /** + * Calculate the distance between two vectors + * @param pt1 Vector 1 + * @param pt2 Vector 2 + * @returns number The distance between two vectors + */ + public static distance(pt1: Vector3, pt2: Vector3): number { + var x: number = pt1.x - pt2.x; + var y: number = pt1.y - pt2.y; + var z: number = pt1.z - pt2.z; + return Math.sqrt(x * x + y * y + z * z); + } + + /** + * Calculate the distance between two vectors XZ axes + * @param pt1 Vector 1 + * @param pt2 Vector 2 + * @returns number The distance between two vectors + */ + public static distanceXZ(pt1: Vector3, pt2: Vector3): number { + var x: number = pt1.x - pt2.x; + var y: number = 0; + var z: number = pt1.z - pt2.z; + return Math.sqrt(x * x + y * y + z * z); + } + + /** + * Sets the current vector x, y, z, and w components + * @param x + * @param y + * @param z + * @param w + * @returns + */ + public set(x: number, y: number, z: number, w: number = 1) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + return this; + } + + /** + * The vector is added to the vector + * @param a Additive vector + * @param target Return vector + * @returns result + */ + public add(a: Vector3, target: Vector3 = null): Vector3 { + if (!target) { + target = new Vector3(); + } + + var a0x: number = this.x; + var a0y: number = this.y; + var a0z: number = this.z; + var a0w: number = this.w; + var a1x: number = a.x; + var a1y: number = a.y; + var a1z: number = a.z; + var a1w: number = a.w; + target.setTo(a0x + a1x, a0y + a1y, a0z + a1z, a0w + a1w); + return target; + } + + public addXYZW(x: number, y: number, z: number, w: number, target: Vector3 = null): Vector3 { + if (!target) { + target = new Vector3(); + } + var a0x: number = this.x; + var a0y: number = this.y; + var a0z: number = this.z; + var a0w: number = this.w; + var a1x: number = x; + var a1y: number = y; + var a1z: number = z; + var a1w: number = w; + target.setTo(a0x + a1x, a0y + a1y, a0z + a1z, a0w + a1w); + return target; + } + + /** + * Clone a vector with the same components as the current vector + */ + public clone(): Vector3 { + return new Vector3(this.x, this.y, this.z, this.w); + } + + /** + * The components of the source vector are set to the current vector + * @param src Original vector + * @returns + */ + public copyFrom(src: Vector3): Vector3 { + var v = this; + v.x = src.x; + v.y = src.y; + v.z = src.z; + v.w = src.w; + return v; + } + + /** + * You take the cross product of two vectors, + * The cross product is going to be the perpendicular vector between these two vectors + * @param a Take the cross product of another vector + * @returns Vector3 returns the cross product vector + */ + public crossProduct(a: Vector3, target: Vector3 = null): Vector3 { + target = target || new Vector3(); + target.x = this.y * a.z - this.z * a.y; + target.y = this.z * a.x - this.x * a.z; + target.z = this.x * a.y - this.y * a.x; + target.w = 1; + return target; + } + + /** + * Subtract two vectors and assign the result to yourself + * @param a Minus vector + */ + public decrementBy(a: Vector3): void { + this.x -= a.x; + this.y -= a.y; + this.z -= a.z; + } + + /** + * + * Calculate the dot product of two vectors and return the Angle relationship between the two vectors + * @param a The vector that you need to compute + * @returns number Returns the Angle relationship between two vectors + */ + public dotProduct(a: Vector3): number { + return this.x * a.x + this.y * a.y + this.z * a.z; + } + + // /** + // * @language en_US + // * @param toCompare The Vector3 object to be compared with the current + // * Vector3 object. + // * @param allFour An optional parameter that specifies whether the w + // * property of the Vector3 objects is used in the + // * comparison. + // * @returns + // * to the current Vector3 object; false if it is not equal. + // */ + + /** + * + * Find whether the values of two vectors are identical + * @param toCompare The vector to compare + * @param allFour The default parameter is 1, whether to compare the w component + * @returns A value of true if the specified Vector3 object is equal to the current Vector3 object; false if it is not equal. + */ + public equals(toCompare: Vector3, allFour: boolean = false): boolean { + return this.x == toCompare.x && this.y == toCompare.y && this.z == toCompare.z && (!allFour || this.w == toCompare.w); + } + + // /** + // * @language en_US + // * Increments the value of the x, y, and z elements of the current + // * Vector3 object by the values of the x, y, and z elements of a + // * specified Vector3 object. Unlike the Vector3.add() + // * method, the incrementBy() method changes the current + // * Vector3 object and does not return a new Vector3 object. + // * + // * @param a The Vector3 object to be added to the current Vector3 + // * object. + // */ + + /** + * The current vector plus is equal to the vector, plus just the x, y, and z components + * @param a vector + */ + public incrementBy(a: Vector3) { + this.x += a.x; + this.y += a.y; + this.z += a.z; + } + + + /** + * The current vector divided by the vector or component + * @param v The vector or component that you want to divide + * @returns Vector3 Returns the result of the calculation + */ + public divide(v): Vector3 { + if (v instanceof Vector3) return new Vector3(this.x / v.x, this.y / v.y, this.z / v.z); + else { + this.x = this.x / v; + this.y = this.y / v; + this.z = this.z / v; + } + return this; + } + + + /** + * Sets the current Vector3 object to its inverse. The inverse object + * is also considered the opposite of the original object. The value of + * the x, y, and z properties of the current Vector3 object is changed + * to -x, -y, and -z. + */ + public negate() { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z; + return this; + } + + /** + * Scales the line segment between(0,0) and the current point to a set + * length. + * + * @param thickness The scaling value. For example, if the current + * Vector3 object is (0,3,4), and you normalize it to + * 1, the point returned is at(0,0.6,0.8). + */ + public normalize(thickness: number = 1): Vector3 { + let self = this; + if (this.length != 0) { + var invLength = thickness / this.length; + this.x *= invLength; + this.y *= invLength; + this.z *= invLength; + return self; + } + return self; + } + + /** + * Apply the rotation quaternion + * @param q quaternion + * @returns + */ + public applyQuaternion(q) { + const x = this.x, + y = this.y, + z = this.z; + const qx = q.x, + qy = q.y, + qz = q.z, + qw = q.w; + + // calculate quat * vector + + const ix = qw * x + qy * z - qz * y; + const iy = qw * y + qz * x - qx * z; + const iz = qw * z + qx * y - qy * x; + const iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + + this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + + return this; + } + + /** + * Scales the current Vector3 object by a scalar, a magnitude. The + * Vector3 object's x, y, and z elements are multiplied by the scalar + * number specified in the parameter. For example, if the vector is + * scaled by ten, the result is a vector that is ten times longer. The + * scalar can also change the direction of the vector. Multiplying the + * vector by a negative number reverses its direction. + * + * @param s A multiplier (scalar) used to scale a Vector3 object. + */ + public scaleBy(s: number): Vector3 { + this.x *= s; + this.y *= s; + this.z *= s; + return this; + } + + /** + * The current vector times the scalar s + * @param s scalar s + * @returns + */ + public mul(s: number): Vector3 { + let v = new Vector3(); + v.x = this.x * s; + v.y = this.y * s; + v.z = this.z * s; + return v; + } + + public scale(s: Vector3): Vector3 { + this.x *= s.x; + this.y *= s.y; + this.z *= s.z; + return this; + } + + public scaleToRef(s: number, ref: Vector3): Vector3 { + if (!ref) { + ref = new Vector3(); + } + + ref.x = this.x * s; + ref.y = this.y * s; + ref.z = this.z * s; + return ref; + } + + /** + * @language en_US + * Sets the members of Vector3 to the specified values + * + * @param xa The first element, such as the x coordinate. + * @param ya The second element, such as the y coordinate. + * @param za The third element, such as the z coordinate. + */ + public setTo(xa: number, ya: number, za: number, wa: number = 1): void { + this.x = xa; + this.y = ya; + this.z = za; + this.w = wa; + } + + /** + * Copy the components of the source vector to this vector + * @param src Source vector + * @returns + */ + public copy(src: Vector3): this { + this.x = src.x; + this.y = src.y; + this.z = src.z; + this.w = src.w; + return this; + } + + /** + * @language en_US + * Subtracts the value of the x, y, and z elements of the current + * Vector3 object from the values of the x, y, and z elements of + * another Vector3 object. The subtract() method does not + * change the current Vector3 object. Instead, this method returns a + * new Vector3 object with the new values. + * + * @param a The Vector3 object to be subtracted from the current + * Vector3 object. + * @returns A new Vector3 object that is the difference between the + * current Vector3 and the specified Vector3 object. + */ + public subtract(a: Vector3, target: Vector3 = null): Vector3 { + if (!target) { + target = new Vector3(); + } + target.setTo(this.x - a.x, this.y - a.y, this.z - a.z); + return target; + } + + /** + * Let's multiply that vector times that vector. + * @param other Multiplied vectors + * @param target Returned vector + * @returns + */ + public multiply(other: Vector3, target: Vector3 = null): Vector3 { + if (!target) { + target = new Vector3(); + } + + var x0: number = this.x; + var y0: number = this.y; + var z0: number = this.z; + + var x1: number = other.x; + var y1: number = other.y; + var z1: number = other.z; + + target.setTo(x0 * x1, y0 * y1, z0 * z1); + return target; + } + + /** + * Let's divide this vector by this vector. + * @param other The vector that divides + * @param target Returned vector + * @returns + */ + public divided(other: Vector3, target: Vector3 = null): Vector3 { + if (!target) { + target = new Vector3(); + } + + var x0: number = this.x; + var y0: number = this.y; + var z0: number = this.z; + + var x1: number = other.x; + var y1: number = other.y; + var z1: number = other.z; + + target.setTo(x0 / x1, y0 / y1, z0 / z1); + return target; + } + + /** + * Divide that vector by the scalar + * @param v The scalar that divides + * @param target Output a Vector3 vector + * @returns + */ + public div(v: number, target?: Vector3): Vector3 { + if (!target) { + target = new Vector3(); + } + + var x0: number = this.x; + var y0: number = this.y; + var z0: number = this.z; + var w0: number = this.w; + + target.setTo(x0 / v, y0 / v, z0 / v, w0 / v); + return target; + } + + /** + * Computes the linear interpolation between two Vector3, and the result is the current object + * @param v0 Vector 1 + * @param v1 Vector 2 + * @param t Interpolation factor + */ + public lerp(v0: Vector3, v1: Vector3, t: number): void { + var v0x: number = v0.x, + v0y: number = v0.y, + v0z: number = v0.z, + v0w: number = v0.w; + var v1x: number = v1.x, + v1y: number = v1.y, + v1z: number = v1.z, + v1w: number = v1.w; + + this.x = (v1x - v0x) * t + v0x; + this.y = (v1y - v0y) * t + v0y; + this.z = (v1z - v0z) * t + v0z; + this.w = (v1w - v0w) * t + v0w; + } + + /** + * The x, y, and z components of this vector are rounded upward to the nearest integers. + * @param min minimum value + * @param max maximum value + * @returns + */ + public clamp(min: Vector3, max: Vector3): Vector3 { + // assumes min < max, componentwise + + this.x = Math.max(min.x, Math.min(max.x, this.x)); + this.y = Math.max(min.y, Math.min(max.y, this.y)); + this.z = Math.max(min.z, Math.min(max.z, this.z)); + + return this; + } + + // /** + // * + // * Computes the linear interpolation between two Vector3, and the result is the current object + // * @param lhs Vector3 1 + // * @param rhs Vector3 2 + // * @param t Interpolation factor + // */ + // public slerp(lhs: Vector3, rhs: Vector3, t: number): void { + // var lhsMag: number = Math.sqrt(this.Dot(lhs, lhs)); + // var rhsMag: number = Math.sqrt(this.Dot(rhs, rhs)); + + // if (lhsMag < 0.00001 || rhsMag < 0.00001) { + // return this.lerp(lhs, rhs, t); + // } + + // var lerpedMagnitude: number = lhsMag + t * (rhsMag - lhsMag); + + // var dot: number = this.Dot(lhs, rhs) / (lhsMag * rhsMag); + + // // direction is almost the same + // if (dot > 1.0 - 0.00001) { + // return this.lerp(lhs, rhs, t); + // } + // // directions are almost opposite + // else if (dot < -1.0 + 0.00001) { + // Vector3.HELP_0.copyFrom(lhs); + // var lhsNorm: Vector3 = Vector3.HELP_0.divide(lhsMag); + // this.OrthoNormalVectorFast(lhsNorm, Vector3.HELP_1); + // var axis: Vector3 = Vector3.HELP_1; + // Quaternion.HELP_0.fromAxisAngle(Vector3.HELP_1, 3.1415926 * t * MathConfig.RADIANS_TO_DEGREES); + // var m: Matrix4 = Quaternion.HELP_0.toMatrix3D(Matrix4.helpMatrix); + // m.transformVector4(lhsNorm, this); + // this.scaleBy(lerpedMagnitude); + // return; + // } + // // normal case + // else { + // lhs.dotProduct; + // this.Cross(lhs, rhs, Vector3.HELP_0); + // var axis: Vector3 = Vector3.HELP_0; + // Vector3.HELP_1.copyFrom(lhs); + // var lhsNorm: Vector3 = Vector3.HELP_1.divide(lhsMag); + // axis.normalize(); + // var angle: number = Math.acos(dot) * t; + // Quaternion.HELP_0.fromAxisAngle(axis, angle * MathConfig.RADIANS_TO_DEGREES); + // var m: Matrix4 = Quaternion.HELP_0.toMatrix3D(Matrix4.helpMatrix); + // m.transformVector4(lhsNorm, this); + // this.scaleBy(lerpedMagnitude); + // return; + // } + // } + + /** + * Returns the string form of the current vector + * @returns + */ + public toString(): string { + return '<' + this.x + ', ' + this.y + ', ' + this.z + '>'; + } + + // */ + // public vertical(a: Vector3, dir: Vector3, target: Vector3) { + // let DoT = Vector3.dot(dir, target); + // if (DoT > 0) { + // target.x = a.y; + // target.y = -a.x; + // } else { + // target.x = -a.y; + // target.y = a.x; + // } + // } + + public normalizeToWay2D_XY() { + let tx = Math.abs(this.x); + let ty = Math.abs(this.y); + if (tx > ty) { + if (this.x > 0) { + this.copyFrom(Vector3.RIGHT); + } else { + this.copyFrom(Vector3.LEFT); + } + } else { + if (this.y > 0) { + this.copyFrom(Vector3.DOWN); + } else { + this.copyFrom(Vector3.UP); + } + } + } + + public toArray() { + return [this.x, this.y, this.z]; + } + + public copyToBytes(byte: DataView) { + byte.setFloat32(0 * Float32Array.BYTES_PER_ELEMENT, this.x, true); + byte.setFloat32(1 * Float32Array.BYTES_PER_ELEMENT, this.y, true); + byte.setFloat32(2 * Float32Array.BYTES_PER_ELEMENT, this.z, true); + } + + /** + * The cross product of two Vector3s is this cross product of a + * The cross product is going to be the perpendicular vector between these two vectors + * @param a Take the cross product of another vector + * @returns Vector3 Returns the cross product vector + */ + public cross(a: Vector3, target: Vector3 = null): Vector3 { + target = target || new Vector3(); + target.x = this.y * a.z - this.z * a.y; + target.y = this.z * a.x - this.x * a.z; + target.z = this.x * a.y - this.y * a.x; + target.w = 1; + return target; + } + + public multiplyScalar(scalar: number) { + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + + return this; + } + + public setFromArray(array: number[], firstElementPos: number = 0) { + this.x = array[firstElementPos]; + this.y = array[firstElementPos + 1]; + this.z = array[firstElementPos + 2]; + } + + public divideScalar(scalar) { + return this.multiplyScalar(1 / scalar); + } + + public clampLength(min: number, max: number) { + let length = this.length; + return this.divideScalar(length || 1).multiplyScalar(Math.max(min, Math.min(max, length))); + } + + public setScalar(value: number) { + this.x = value; + this.y = value; + this.z = value; + return this; + } + + private static calAngle(cx, cy, x, y) { + const radian = getCosBy2pt(x, y, cx, cy); + let angle = (Math.acos(radian) * 180) / Math.PI; + + if (x < cx) angle = -angle; + // console.log(angle) + return angle; + + // Calculate the vector formed by point 1 and point 2 + function getCosBy2pt(x, y, cx, cy) { + // Dot product formula + let a = [x - cx, y - cy]; + let b = [0, -1]; + return calCos(a, b); + } + function calCos(a, b) { + let dotProduct = a[0] * b[0] + a[1] * b[1]; + let d = Math.sqrt(a[0] * a[0] + a[1] * a[1]) * Math.sqrt(b[0] * b[0] + b[1] * b[1]); + return dotProduct / d; + } + } +} + + diff --git a/src/engine/math/Vector4.ts b/src/engine/math/Vector4.ts new file mode 100644 index 00000000..4fc56e92 --- /dev/null +++ b/src/engine/math/Vector4.ts @@ -0,0 +1,175 @@ + +/*** + * Vector 4D + * @internal + * @group Math + */ +export class Vector4 { + + /** + * The x axis defined as a Vector4 object with coordinates (1,0,0). + */ + public static X_AXIS: Vector4 = new Vector4(1, 0, 0); + + /** + * The y axis defined as a Vector4 object with coordinates (0,1,0). + */ + public static Y_AXIS: Vector4 = new Vector4(0, 1, 0); + + /** + * The z axis defined as a Vector4 object with coordinates (0,0,1). + */ + public static Z_AXIS: Vector4 = new Vector4(0, 0, 1); + + /** + * @internal + */ + public static HELP_0: Vector4 = new Vector4(); + + /** + * @internal + */ + public static HELP_1: Vector4 = new Vector4(); + + /** + * @internal + */ + public static HELP_2: Vector4 = new Vector4(); + + /** + * @internal + */ + public static EPSILON: number = 0.00001; + + /** + * @internal + */ + public static HELP_3: Vector4 = new Vector4(); + + /** + * @internal + */ + public static HELP_4: Vector4 = new Vector4(); + + /** + * @internal + */ + public static HELP_5: Vector4 = new Vector4(); + + /** + * @internal + */ + public static HELP_6: Vector4 = new Vector4(); + + public static ZERO: Vector4 = new Vector4(); + + public static ONE: Vector4 = new Vector4(1, 1, 1, 1); + + public static LEFT: Vector4 = new Vector4(-1, 0, 0); + + public static RIGHT: Vector4 = new Vector4(1, 0, 0); + + public static UP: Vector4 = new Vector4(0, -1, 0); + + public static DOWN: Vector4 = new Vector4(0, 1, 0); + + public static BACK: Vector4 = new Vector4(0, 0, -1); + + public static FORWARD: Vector4 = new Vector4(0, 0, 1); + + /** + * @language en_US + * The first element of a Vector4 object, such as the x coordinate of + * a point in the three-dimensional space. The default value is 0. + */ + public x: number = 0; + + /** + * @language en_US + * The second element of a Vector4 object, such as the y coordinate of + * a point in the three-dimensional space. The default value is 0. + */ + public y: number = 0; + + /** + * @language en_US + * The third element of a Vector4 object, such as the y coordinate of + * a point in the three-dimensional space. The default value is 0. + */ + public z: number = 0; + + + /** + * A three-dimensional position or projection that can be used as + * a perspective projection can also be a w in a quaternion + * @version Orillusion3D 0.5.1 + */ + public w: number = 1; + + constructor(x: number = 0, y: number = 0, z: number = 0, w: number = 0) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public get width() { + return this.z; + } + + public get height() { + return this.w; + } + + public static crossVectors(a: Vector4, b: Vector4, target?: Vector4) { + target = target || new Vector4(); + var ax = a.x, + ay = a.y, + az = a.z; + var bx = b.x, + by = b.y, + bz = b.z; + + target.x = ay * bz - az * by; + target.y = az * bx - ax * bz; + target.z = ax * by - ay * bx; + + return target; + } + + public static distance(pt1: Vector4, pt2: Vector4): number { + let x: number = pt1.x - pt2.x; + let y: number = pt1.y - pt2.y; + let z: number = pt1.z - pt2.z; + let w: number = pt1.w - pt2.w; + return Math.sqrt(x * x + y * y + z * z + w * w); + } + + public set(x: number, y: number, z: number, w: number): this { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + return this; + } + + public multiplyScalar(scalar: number): this { + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + this.w *= scalar; + return this; + } + + public copyFrom(v: Vector4): this { + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.w = v.w; + return this; + } + + public clone(): Vector4 { + return new Vector4(this.x, this.y, this.z, this.w); + } +} From b3647e03abff5381312203c19467a250de70efe9 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Sun, 23 Apr 2023 17:55:15 +0800 Subject: [PATCH 019/100] feat(math): base math (#13) Adding Mathematical Matrix4*4 for 3D Computing Adding Mathematical Matrix3*3 for 2D Computing Adding Mathematical Quaternion for 2D/3D Rotation Computing --- src/engine/math/Matrix3.ts | 579 ++++++++ src/engine/math/Matrix4.ts | 2638 +++++++++++++++++++++++++++++++++ src/engine/math/Quaternion.ts | 596 ++++++++ 3 files changed, 3813 insertions(+) create mode 100644 src/engine/math/Matrix3.ts create mode 100644 src/engine/math/Matrix4.ts create mode 100644 src/engine/math/Quaternion.ts diff --git a/src/engine/math/Matrix3.ts b/src/engine/math/Matrix3.ts new file mode 100644 index 00000000..a0b65f4d --- /dev/null +++ b/src/engine/math/Matrix3.ts @@ -0,0 +1,579 @@ +import { DEGREES_TO_RADIANS } from './MathUtil'; +import { Rect } from './Rect'; +import { Vector3 } from './Vector3'; + +/** + * @internal + */ +let PI = Math.PI; + +/** + * @internal + */ +let TwoPI = PI * 2; + +/** + * ////************** + * ////****a b tx**** + * ////****c d ty**** + * ////****u v w **** + * ////************** + */ +/** + * 3*3 Matrix + * @group Math + */ +export class Matrix3 { + + /** + * The width of x + */ + public a: number; + + /** + * The slope of y + */ + public b: number; + + /** + * The slope of x + */ + public c: number; + + /** + * The height of y + */ + public d: number; + + /** + * The position of the x coordinate + */ + public tx: number; + + /** + * The position of the y coordinate + */ + public ty: number; + + /** + * Create a Matrix3 + * @param a The width of x + * @param b The slope of y + * @param c The slope of x + * @param d The height of y + * @param tx The position of the x coordinate + * @param ty The position of the y coordinate + */ + constructor(a: number = 1, b: number = 0, c: number = 0, d: number = 1, tx: number = 0, ty: number = 0) { + this.a = a; + this.b = b; + this.c = c; + this.d = d; + this.tx = tx; + this.ty = ty; + } + + /** + * Clone an Matrix3 object + * @returns New Matrix3 object + */ + public clone(): Matrix3 { + return new Matrix3(this.a, this.b, this.c, this.d, this.tx, this.ty); + } + + /** + * Merges the current matrix with the target matrix + * @param matrix target matrix + */ + public concat(matrix: Matrix3): void { + let a: number = this.a; + let c: number = this.c; + let tx: number = this.tx; + this.a = a * matrix.a + this.b * matrix.c; + this.b = a * matrix.b + this.b * matrix.d; + this.c = c * matrix.a + this.d * matrix.c; + this.d = c * matrix.b + this.d * matrix.d; + this.tx = tx * matrix.a + this.ty * matrix.c + matrix.tx; + this.ty = tx * matrix.b + this.ty * matrix.d + matrix.ty; + } + + /** + * The current matrix value is overwritten by the target matrix value + * @param other target matrix value + * @returns current matrix + */ + public copyFrom(other: Matrix3): Matrix3 { + this.a = other.a; + this.b = other.b; + this.c = other.c; + this.d = other.d; + this.tx = other.tx; + this.ty = other.ty; + return this; + } + + /** + * Reset to the identity matrix + */ + public identity(): this { + this.a = this.d = 1; + this.b = this.c = this.tx = this.ty = 0; + return this; + } + + /** + * Invert this matrix + */ + public invert(): void { + this._invertInto(this); + } + + /** + * Rotate according to Angle + * @param angle rotation angle + */ + public rotate(angle: number): void { + angle = +angle; + if (angle !== 0) { + angle = angle * DEGREES_TO_RADIANS; + let u = Math.cos(angle); + let v = Math.sin(angle); + let ta = this.a; + let tb = this.b; + let tc = this.c; + let td = this.d; + let ttx = this.tx; + let tty = this.ty; + this.a = ta * u - tb * v; + this.b = ta * v + tb * u; + this.c = tc * u - td * v; + this.d = tc * v + td * u; + this.tx = ttx * u - tty * v; + this.ty = ttx * v + tty * u; + } + } + + /** + * Scale by offset + * @param sx x axis scaling + * @param sy y axis scaling + */ + public scale(sx: number, sy: number): void { + if (sx !== 1) { + this.a *= sx; + this.c *= sx; + this.tx *= sx; + } + if (sy !== 1) { + this.b *= sy; + this.d *= sy; + this.ty *= sy; + } + } + + /** + * Reset the matrix value + * @param a Matrix element a + * @param b Matrix element b + * @param c Matrix element c + * @param d Matrix element d + * @param tx Matrix element tx + * @param ty Matrix element ty + * @returns The modified matrix + */ + public setTo(a: number, b: number, c: number, d: number, tx: number, ty: number): Matrix3 { + this.a = a; + this.b = b; + this.c = c; + this.d = d; + this.tx = tx; + this.ty = ty; + return this; + } + + /** + * transformation of coordinates + * @param pointX x coordinate + * @param pointY y coordinate + * @param resultPoint Vector of results + * @returns Vector of results + */ + public transformPoint(pointX: number, pointY: number, resultPoint?: Vector3): Vector3 { + let x = this.a * pointX + this.c * pointY + this.tx; + let y = this.b * pointX + this.d * pointY + this.ty; + if (resultPoint) { + resultPoint.setTo(x, y, 0, 1); + return resultPoint; + } + return new Vector3(x, y, 0, 1); + } + + /** + * translation + * @param x x coordinate + * @param y y coordinate + */ + public setTranslate(x: number, y: number) { + this.tx = x; + this.ty = y; + } + + /** + * Translates the specified offset + * @param dx The x-coordinate offset + * @param dy The y-coordinate offset + */ + public translate(dx: number, dy: number): void { + this.tx += dx; + this.ty += dy; + } + + /** + * multiply + * @param t target matrix + */ + public mul(t: Matrix3) { + let m1 = this; + let m2 = t; + let aa: number = m1.a; + let ab: number = m1.b; + let ac: number = m1.c; + let ad: number = m1.d; + let atx: number = m1.tx; + let aty: number = m1.ty; + let ba: number = m2.a; + let bb: number = m2.b; + let bc: number = m2.c; + let bd: number = m2.d; + let btx: number = m2.tx; + let bty: number = m2.ty; + + if (bb !== 0 || bc !== 0) { + this.a = aa * ba + ab * bc; + this.b = aa * bb + ab * bd; + this.c = ac * ba + ad * bc; + this.d = ac * bb + ad * bd; + this.tx = ba * atx + bc * aty + btx; + this.ty = bb * atx + bd * aty + bty; + } else { + this.a = aa * ba; + this.b = ab * bd; + this.c = ac * ba; + this.d = ad * bd; + this.tx = ba * atx + btx; + this.ty = bd * aty + bty; + } + } + + /** + * Is equal to the given matrix + * @param other matrix + * @returns + */ + public equals(other: Matrix3): boolean { + return this.a == other.a && this.b == other.b && this.c == other.c && this.d == other.d && this.tx == other.tx && this.ty == other.ty; + } + + /** + * get a front matrix by multiplication + * @param a Multiply by a + * @param b Multiply by b + * @param c Multiply by c + * @param d Multiply by d + * @param tx Multiply by tx + * @param ty Multiply by ty + * @returns prematrix + */ + public prepend(a: number, b: number, c: number, d: number, tx: number, ty: number): Matrix3 { + let tx1 = this.tx; + if (a != 1 || b != 0 || c != 0 || d != 1) { + let a1 = this.a; + let c1 = this.c; + this.a = a1 * a + this.b * c; + this.b = a1 * b + this.b * d; + this.c = c1 * a + this.d * c; + this.d = c1 * b + this.d * d; + } + this.tx = tx1 * a + this.ty * c + tx; + this.ty = tx1 * b + this.ty * d + ty; + return this; + } + + /** + * Obtain a post-multiplication matrix by multiplication. + * @param mat Matrix + * @returns result + */ + public append(mat: Matrix3): Matrix3 { + let a1 = this.a; + let b1 = this.b; + let c1 = this.c; + let d1 = this.d; + if (mat.a != 1 || mat.b != 0 || mat.c != 0 || mat.d != 1) { + this.a = mat.a * a1 + mat.b * c1; + this.b = mat.a * b1 + mat.b * d1; + this.c = mat.c * a1 + mat.d * c1; + this.d = mat.c * b1 + mat.d * d1; + } + this.tx = mat.tx * a1 + mat.ty * c1 + this.tx; + this.ty = mat.tx * b1 + mat.ty * d1 + this.ty; + + return this; + } + + /** + * Use the given point for the transformation, ignoring the x, y coordinates + * @param point A given point + * @returns + */ + public deltaTransformPoint(point: Vector3): Vector3 { + let self = this; + let x = self.a * point.x + self.c * point.y; + let y = self.b * point.x + self.d * point.y; + return new Vector3(x, y); + } + + /** + * Converts the current matrix to string form + * @returns + */ + public toString(): string { + return '(a=' + this.a + ', b=' + this.b + ', c=' + this.c + ', d=' + this.d + ', tx=' + this.tx + ', ty=' + this.ty + ')'; + } + + /** + * Set the matrix scaling, rotation, and conversion parameters + * @param scaleX x axis scaling + * @param scaleY y axis scaling + * @param rotation rotation + * @param tx x-coordinate + * @param ty y-coordinate + */ + public createBox(scaleX: number, scaleY: number, rotation: number = 0, tx: number = 0, ty: number = 0): void { + let self = this; + if (rotation !== 0) { + rotation = rotation * DEGREES_TO_RADIANS; + let u = Math.cos(rotation); + let v = Math.sin(rotation); + self.a = u * scaleX; + self.b = v * scaleY; + self.c = -v * scaleX; + self.d = u * scaleY; + } else { + self.a = scaleX; + self.b = 0; + self.c = 0; + self.d = scaleY; + } + self.tx = tx; + self.ty = ty; + } + + /** + * Create a gradient box + * @param width width + * @param height height + * @param rotation rotation + * @param tx x-coordinate + * @param ty y-coordinate + */ + public createGradientBox(width: number, height: number, rotation: number = 0, tx: number = 0, ty: number = 0): void { + this.createBox(width / 1638.4, height / 1638.4, rotation, tx + width / 2, ty + height / 2); + } + + + /** + * Invert the given matrix + * @param target matrix + * @returns + */ + private _invertInto(target: Matrix3): void { + let a = this.a; + let b = this.b; + let c = this.c; + let d = this.d; + let tx = this.tx; + let ty = this.ty; + if (b == 0 && c == 0) { + target.b = target.c = 0; + if (a == 0 || d == 0) { + target.a = target.d = target.tx = target.ty = 0; + } else { + a = target.a = 1 / a; + d = target.d = 1 / d; + target.tx = -a * tx; + target.ty = -d * ty; + } + + return; + } + let determinant = a * d - b * c; + if (determinant == 0) { + target.identity(); + return; + } + determinant = 1 / determinant; + let k = (target.a = d * determinant); + b = target.b = -b * determinant; + c = target.c = -c * determinant; + d = target.d = a * determinant; + target.tx = -(k * tx + c * ty); + target.ty = -(b * tx + d * ty); + } + + /** + * @private + */ + public getScaleX(): number { + let m = this; + if (m.a == 1 && m.b == 0) { + return 1; + } + let result = Math.sqrt(m.a * m.a + m.b * m.b); + return this.getDeterminant() < 0 ? -result : result; + } + + /** + * @private + */ + public getScaleY(): number { + let m = this; + if (m.c == 0 && m.d == 1) { + return 1; + } + let result = Math.sqrt(m.c * m.c + m.d * m.d); + return this.getDeterminant() < 0 ? -result : result; + } + + /** + * @private + */ + public getSkewX(): number { + return Math.atan2(this.d, this.c) - Math.PI / 2; + } + + /** + * @private + */ + public getSkewY(): number { + return Math.atan2(this.b, this.a); + } + + /** + * @private + */ + public updateScaleAndRotation(scaleX: number, scaleY: number, skewX: number, skewY: number) { + if ((skewX == 0 || skewX == TwoPI) && (skewY == 0 || skewY == TwoPI)) { + this.a = scaleX; + this.b = this.c = 0; + this.d = scaleY; + return; + } + skewX = skewX * DEGREES_TO_RADIANS; + skewY = skewY * DEGREES_TO_RADIANS; + let u = Math.cos(skewX); + let v = Math.sin(skewX); + if (skewX == skewY) { + this.a = u * scaleX; + this.b = v * scaleX; + } else { + this.a = Math.cos(skewY) * scaleX; + this.b = Math.sin(skewY) * scaleX; + } + this.c = -v * scaleY; + this.d = u * scaleY; + } + + /** + * @private + * target = other * this + */ + public preMultiplyInto(other: Matrix3, target: Matrix3): void { + let a = other.a * this.a; + let b = 0.0; + let c = 0.0; + let d = other.d * this.d; + let tx = other.tx * this.a + this.tx; + let ty = other.ty * this.d + this.ty; + + if (other.b !== 0.0 || other.c !== 0.0 || this.b !== 0.0 || this.c !== 0.0) { + a += other.b * this.c; + d += other.c * this.b; + b += other.a * this.b + other.b * this.d; + c += other.c * this.a + other.d * this.c; + tx += other.ty * this.c; + ty += other.tx * this.b; + } + + target.a = a; + target.b = b; + target.c = c; + target.d = d; + target.tx = tx; + target.ty = ty; + } + + + /** + * @private + */ + private $transformBounds(bounds: Rect): void { + let a = this.a; + let b = this.b; + let c = this.c; + let d = this.d; + let tx = this.tx; + let ty = this.ty; + + let x = bounds.x; + let y = bounds.y; + let xMax = x + bounds.width; + let yMax = y + bounds.height; + + let x0 = a * x + c * y + tx; + let y0 = b * x + d * y + ty; + let x1 = a * xMax + c * y + tx; + let y1 = b * xMax + d * y + ty; + let x2 = a * xMax + c * yMax + tx; + let y2 = b * xMax + d * yMax + ty; + let x3 = a * x + c * yMax + tx; + let y3 = b * x + d * yMax + ty; + + let tmp = 0; + + if (x0 > x1) { + tmp = x0; + x0 = x1; + x1 = tmp; + } + if (x2 > x3) { + tmp = x2; + x2 = x3; + x3 = tmp; + } + + bounds.x = Math.floor(x0 < x2 ? x0 : x2); + bounds.width = Math.ceil((x1 > x3 ? x1 : x3) - bounds.x); + + if (y0 > y1) { + tmp = y0; + y0 = y1; + y1 = tmp; + } + if (y2 > y3) { + tmp = y2; + y2 = y3; + y3 = tmp; + } + + bounds.y = Math.floor(y0 < y2 ? y0 : y2); + bounds.height = Math.ceil((y1 > y3 ? y1 : y3) - bounds.y); + } + + /** + * @private + */ + private getDeterminant() { + return this.a * this.d - this.b * this.c; + } +} diff --git a/src/engine/math/Matrix4.ts b/src/engine/math/Matrix4.ts new file mode 100644 index 00000000..4db4eb0e --- /dev/null +++ b/src/engine/math/Matrix4.ts @@ -0,0 +1,2638 @@ +import { clamp, DEGREES_TO_RADIANS, RADIANS_TO_DEGREES } from './MathUtil'; +import { Orientation3D } from './Orientation3D'; +import { kPI } from './ParticleMath'; +import { Quaternion } from './Quaternion'; +import { Vector3 } from './Vector3'; + +const EPSILON: number = 0.000001; + +/** + * math 4*4 matrix + * @group Math + */ +export class Matrix4 { + + /** + * matrix44 bytes block size + */ + public static blockBytes: number = 16 * 4; + + /** + * @internal + */ + public static block: number = 16; + + /** + * matrix do total count + */ + public static totalCount: number = 0; + + /** + * matrix has max limit count + */ + public static maxCount: number = 300000; + + /** + * current matrix use count + */ + public static useCount: number = 0; + + /** + * @internal + */ + public static buffer: ArrayBuffer; + + /** + * @internal + * wasm use memory use first ptr + */ + public static wasmMatrixPtr: number = 0; + + /** + * matrix do use share bytesArray + */ + public static matrixBytes: Float32Array; + + /** + * cache all use do matrix + */ + public static globalMatrixRef: Matrix4[]; + + /** + * @internal + */ + public static wasm: any; + + /** + * help fix global matrix 0 + */ + public static help_matrix_0: Matrix4; + + /** + * help fix global matrix 1 + */ + public static help_matrix_1: Matrix4; + + /** + * help fix global matrix 2 + */ + public static help_matrix_2: Matrix4; + + /** + * help fix global matrix 3 + */ + public static helpMatrix: Matrix4; + + /** + * help fix global matrix 4 + */ + public static helpMatrix2: Matrix4; + + private static _getEulerMatrix: Matrix4; + private static _zero: Vector3 = new Vector3(0, 0, 0); + private static _one: Vector3 = new Vector3(1, 1, 1); + private static _prs: Vector3[] = [new Vector3(), new Vector3(), new Vector3()]; + + + /** + * matrix index at global matrix list + */ + public index: number = 0; + + /** + * @internal + */ + public offset: number = 0; + + /** + * matrix raw data format Float32Array + * @see {@link Float32Array} + * @version Orillusion3D 0.5.1 + */ + public rawData: Float32Array; + + private _position: Vector3; + + + /** + * alloc web runtime cpu memory totalCount * 4(float) * 4 + * init matrix memory by totalCount * 4(float) * 4 + * @param count every alloc matrix count + * @version Orillusion3D 0.5.1 + */ + public static allocMatrix(totalCount: number) { + this.totalCount = totalCount; + + Matrix4.matrixBytes = new Float32Array(totalCount * 16); + Matrix4.buffer = Matrix4.matrixBytes.buffer; + Matrix4.wasmMatrixPtr = 0; + + this.globalMatrixRef ||= []; + this.globalMatrixRef.forEach((m) => { + let rawData = m.rawData; + m.rawData = new Float32Array(Matrix4.matrixBytes.buffer, m.offset, 16); + for (let i = 0; i < rawData.length; i++) { + m.rawData[i] = rawData[i]; + } + }); + + Matrix4.help_matrix_0 ||= new Matrix4(); + Matrix4.help_matrix_1 ||= new Matrix4(); + Matrix4.help_matrix_2 ||= new Matrix4(); + Matrix4.helpMatrix ||= new Matrix4(); + Matrix4.helpMatrix2 ||= new Matrix4(); + Matrix4._getEulerMatrix ||= new Matrix4(); + Matrix4._getEulerMatrix.identity(); + } + + /** + * create matrix from two direction + * @param fromDirection first direction + * @param toDirection second direction + * @param target ref matrix + * @returns return new one matrix + * @version Orillusion3D 0.5.1 + */ + public static fromToRotation(fromDirection: Vector3, toDirection: Vector3, target?: Matrix4): Matrix4 { + target ||= new Matrix4(); + target.transformDir(fromDirection, toDirection); + return target; + } + + /** + * Generate a matrix (rotate degrees with x,y,z as the center axis) + * @param x x on the central axis + * @param y y on the central axis + * @param z z on the central axis + * @param degrees rotation angle + * @returns Matrix4 result + * @version Orillusion3D 0.5.1 + */ + public static getAxisRotation(x: number, y: number, z: number, degrees: number): Matrix4 { + let m: Matrix4 = new Matrix4(); + + let rad = degrees * (Math.PI / 180); + let c: number = Math.cos(rad); + let s: number = Math.sin(rad); + let t: number = 1 - c; + let tmp1: number, tmp2: number; + + m.rawData[0] = c + x * x * t; + m.rawData[5] = c + y * y * t; + m.rawData[10] = c + z * z * t; + + tmp1 = x * y * t; + tmp2 = z * s; + m.rawData[1] = tmp1 + tmp2; + m.rawData[4] = tmp1 - tmp2; + tmp1 = x * z * t; + tmp2 = y * s; + m.rawData[8] = tmp1 + tmp2; + m.rawData[2] = tmp1 - tmp2; + tmp1 = y * z * t; + tmp2 = x * s; + m.rawData[9] = tmp1 - tmp2; + m.rawData[6] = tmp1 + tmp2; + + return m; + } + + + /** + * Arrange the Euler values + * @param euler Euler values + */ + public static sanitizeEuler(euler: Vector3): void { + Matrix4.makePositive(euler); + } + + /** + * + * @param euler + */ + public static makePositive(euler: Vector3): void { + let negativeFlip = -0.0001; + let positiveFlip = kPI * 2.0 - 0.0001; + + if (euler.x < negativeFlip) { + euler.x += 2.0 * kPI; + } + else if (euler.x > positiveFlip) { + euler.x -= 2.0 * kPI; + } + + if (euler.y < negativeFlip) { + euler.y += 2.0 * kPI; + } + else if (euler.y > positiveFlip) { + euler.y -= 2.0 * kPI; + } + + if (euler.z < negativeFlip) { + euler.z += 2.0 * kPI; + } + else if (euler.z > positiveFlip) { + euler.z -= 2.0 * kPI; + } + } + + /** + * Convert the matrix to Euler angles + * @param matrix Matrix to be transformed + * @param v euler angle + * @returns + */ + public static matrixToEuler(matrix: Matrix4, v: Vector3) { + // from http://www.geometrictools.com/Documentation/EulerAngles.pdf + // YXZ order + if (matrix.get(1, 2) < 0.999) { + // some fudge for imprecision + if (matrix.get(1, 2) > -0.999) { + // some fudge for imprecision + v.x = Math.asin(-matrix.get(1, 2)); + v.y = Math.atan2(matrix.get(0, 2), matrix.get(2, 2)); + v.z = Math.atan2(matrix.get(1, 0), matrix.get(1, 1)); + Matrix4.sanitizeEuler(v); + return true; + } else { + // WARNING. Not unique. YA - ZA = atan2(r01,r00) + v.x = kPI * 0.5; + v.y = Math.atan2(matrix.get(0, 1), matrix.get(0, 0)); + v.z = 0.0; + Matrix4.sanitizeEuler(v); + return false; + } + } else { + // WARNING. Not unique. YA + ZA = atan2(-r01,r00) + v.x = -kPI * 0.5; + v.y = Math.atan2(-matrix.get(0, 1), matrix.get(0, 0)); + v.z = 0.0; + Matrix4.sanitizeEuler(v); + return false; + } + } + + + /** + * Multiply the world matrix, specifying parameters and results according to the index + * @param aMat Matrix to be multiplied (please specify index) + * @param bMat Matrix to be multiplied (please specify index) + * @param target_Mat Result matrix (get results based on index) + */ + public static matrixMultiply(aMat: Matrix4, bMat: Matrix4, target_Mat: Matrix4): void { + Matrix4.wasm.Matrix_Multiply(aMat.index, bMat.index, target_Mat.index); + } + + /** + * World matrix extension, according to the index to specify parameters and results + * @param aMat Matrix to be multiplied (please specify index) + * @param bMat Matrix to be multiplied (please specify index) + * @param target_Mat Result matrix (get results based on index) + */ + public static matrixAppend(aMat: Matrix4, bMat: Matrix4, target_Mat: Matrix4): void { + Matrix4.wasm.Matrix_Append(aMat.index, bMat.index, target_Mat.index); + } + + /** + * The Y-axis is rotated between the world matrix, and the parameters and results are specified according to the index + * @param aMat Matrix to be multiplied (please specify index) + * @param bMat Matrix to be multiplied (please specify index) + * @param target_Mat Result matrix (get results based on index) + */ + public static matrixRotateY(rad: number, target_Mat: Matrix4): void { + Matrix4.wasm.Matrix_Append(rad, target_Mat.index); + } + + /** + * Rotate the world matrix, specifying parameters and results according to the index + * @param aMat Matrix to be multiplied (please specify index) + * @param bMat Matrix to be multiplied (please specify index) + * @param target_Mat Result matrix (get results based on index) + */ + public static matrixRotate(rad: number, axis: Vector3, target_Mat: Matrix4): void { + Matrix4.wasm.Matrix_Rotate(rad, axis, target_Mat.index); + } + + + /** + * + * @param local -- + */ + constructor(local: boolean = true) { + // if (!local) { + if (Matrix4.useCount >= Matrix4.totalCount) { + Matrix4.allocMatrix(Matrix4.totalCount + 1000); + } + + this.index = Matrix4.useCount; + this.offset = Matrix4.useCount * Matrix4.blockBytes + Matrix4.wasmMatrixPtr; + + Matrix4.globalMatrixRef[this.index] = this; + Matrix4.useCount++; + + this.rawData = new Float32Array(Matrix4.matrixBytes.buffer, this.offset, 16); + + this._position = new Vector3(); + + this.identity(); + } + + /** + * current matrix move position and rotation to target + * @param eye eye position + * @param at target position + * @param up normalize axis way + * @version Orillusion3D 0.5.1 + */ + public lookAt(eye: Vector3, at: Vector3, up: Vector3 = Vector3.Y_AXIS): void { + let data = this.rawData; + at.subtract(eye, Vector3.HELP_0); + let zAxis: Vector3 = Vector3.HELP_0; + if (zAxis.length < 0.0001) { + zAxis.z = 1; + } + zAxis.normalize(); + let xAxis: Vector3 = up.crossProduct(zAxis, Vector3.HELP_1); + + if (xAxis.length < 0.0001) { + if (Math.abs(up.z) > 0.9999) { + zAxis.x += 0.0001; + } else { + zAxis.z += 0.0001; + } + } + + zAxis.normalize(); + up.cross(zAxis, xAxis); + + + xAxis.normalize(); // + let yAxis = zAxis.crossProduct(xAxis, Vector3.HELP_2); + + data[0] = xAxis.x; + data[1] = yAxis.x; + data[2] = zAxis.x; + data[3] = 0; + + data[4] = xAxis.y; + data[5] = yAxis.y; + data[6] = zAxis.y; + data[7] = 0; + + data[8] = xAxis.z; + data[9] = yAxis.z; + data[10] = zAxis.z; + data[11] = 0; + + data[12] = -xAxis.dotProduct(eye); + data[13] = -yAxis.dotProduct(eye); + data[14] = -zAxis.dotProduct(eye); + + data[15] = 1; + } + + /** + * matrix multiply + * @param mat4 multiply target + * @version Orillusion3D 0.5.1 + */ + public multiply(mat4: Matrix4): void { + let a = this.rawData; + let b = mat4.rawData; + let r = Matrix4.helpMatrix; + + r[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12]; + r[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13]; + r[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14]; + r[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15]; + + r[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12]; + r[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13]; + r[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14]; + r[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15]; + + r[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12]; + r[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13]; + r[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14]; + r[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15]; + + r[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12]; + r[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13]; + r[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14]; + r[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15]; + + a[0] = r[0]; + a[1] = r[1]; + a[2] = r[2]; + a[3] = r[3]; + a[4] = r[4]; + a[5] = r[5]; + a[6] = r[6]; + a[7] = r[7]; + a[8] = r[8]; + a[9] = r[9]; + a[10] = r[10]; + a[11] = r[11]; + a[12] = r[12]; + a[13] = r[13]; + a[14] = r[14]; + a[15] = r[15]; + } + + /** + * + * @param a + * @param b + * @returns + */ + public multiplyMatrices(a: Matrix4, b: Matrix4) { + + const ae = a.rawData; + const be = b.rawData; + const te = this.rawData; + + const a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12]; + const a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13]; + const a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14]; + const a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15]; + + const b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12]; + const b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13]; + const b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14]; + const b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15]; + + te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; + te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; + te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; + te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; + + te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; + te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; + te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; + te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; + + te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; + te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; + te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; + te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; + + te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; + te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; + te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; + te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; + + return this; + + } + + /** + * convert a vector3 to this matrix space + * if output not set , return a new one + * @param v target vector3 + * @param output save target + * @returns save target + */ + public multiplyPoint3(v: Vector3, output?: Vector3): Vector3 { + output ||= new Vector3(); + let rawData = this.rawData; + output.x = rawData[0] * v.x + rawData[4] * v.y + rawData[8] * v.z + rawData[12]; + output.y = rawData[1] * v.x + rawData[5] * v.y + rawData[9] * v.z + rawData[13]; + output.z = rawData[2] * v.x + rawData[6] * v.y + rawData[10] * v.z + rawData[14]; + return output; + } + + public multiplyVector4(a: Vector3, out?: Vector3) { + out ||= new Vector3(); + let m = this.rawData; + let x = a.x; + let y = a.y; + let z = a.z; + let w = m[3] * x + m[7] * y + m[11] * z + m[15]; + w = w || 1.0; + out.x = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; + out.y = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; + out.z = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; + out.w = 1; + return out; + } + + /** + * @private + */ + public perspectiveB(fov: number, aspect: number, near: number, far: number): Matrix4 { + let y = Math.tan((fov * Math.PI) / 360) * near; + let x = y * aspect; + return this.frustum(-x, x, -y, y, near, far); + } + + /** + * convert a vector3 to this matrix space + * if output not set , return a new one + * @param v convert target + * @param target ref one vector3 + * @returns Vector3 + * @version Orillusion3D 0.5.1 + */ + public transformVector4(v: Vector3, target?: Vector3): Vector3 { + let data: Float32Array = this.rawData; + + target ||= new Vector3(); + + let x: number = v.x; + let y: number = v.y; + let z: number = v.z; + let w: number = v.w; + + target.x = x * data[0] + y * data[4] + z * data[8] + w * data[12]; + target.y = x * data[1] + y * data[5] + z * data[9] + w * data[13]; + target.z = x * data[2] + y * data[6] + z * data[10] + w * data[14]; + target.w = x * data[3] + y * data[7] + z * data[11] + w * data[15]; + + return target; + } + + /** + * Convert projection coordinates to 3D coordinates + * @param v vector3 target + * @param output ref vector3d + * @returns + */ + public perspectiveMultiplyPoint3(v: Vector3, output: Vector3): boolean { + let res: Vector3 = Vector3.HELP_2; + let w: number; + let rawData = this.rawData; + res.x = rawData[0] * v.x + rawData[4] * v.y + rawData[8] * v.z + rawData[12]; + res.y = rawData[1] * v.x + rawData[5] * v.y + rawData[9] * v.z + rawData[13]; + res.z = rawData[2] * v.x + rawData[6] * v.y + rawData[10] * v.z + rawData[14]; + w = rawData[3] * v.x + rawData[7] * v.y + rawData[11] * v.z + rawData[15]; + if (Math.abs(w) > 1.0e-7) { + let invW = 1.0 / w; + output.x = res.x * invW; + output.y = res.y * invW; + output.z = res.z * invW; + return true; + } else { + output.x = 0.0; + output.y = 0.0; + output.z = 0.0; + return false; + } + } + + /** + * set matrix perspective + * @param fov perspective angle 0 ~ 90 + * @param aspect aspect ratio + * @param zn near plane + * @param zf far plane + * @version Orillusion3D 0.5.1 + */ + public perspective(fov: number, aspect: number, zn: number, zf: number) { + let data = this.rawData; + // let angle: number = (Math.PI - fov * DEGREES_TO_RADIANS) / 2.0; + // let yScale: number = Math.tan(angle); + // let xScale: number = yScale / aspect; + + let angle: number = (fov * DEGREES_TO_RADIANS) / 2.0; + let f = Math.cos(angle) / Math.sin(angle); + // 0.5 / tan + data[0] = -f / aspect; + // data[0] = xScale; + data[1] = 0; + data[2] = 0; + data[3] = 0; + + data[4] = 0; + data[5] = f; + data[6] = 0; + data[7] = 0; + + data[8] = 0; + data[9] = 0; + data[10] = zf / (zf - zn); + data[11] = 1; + + data[12] = 0; + data[13] = 0; + data[14] = (-zn * zf) / (zf - zn); + data[15] = 0; + } + + /** + * @version Orillusion3D 0.5.1 + * set matrix orthogonal projection + * @param w screen width + * @param h screen height + * @param zn camera near plane + * @param zf camera far plane + * @returns this matrix + */ + public ortho(w: number, h: number, zn: number, zf: number) { + let data = this.rawData; + + data[0] = 2 / w; + data[1] = 0; + data[2] = 0; + data[3] = 0; + + data[4] = 0; + data[5] = 2 / h; + data[6] = 0; + data[7] = 0; + + data[8] = 0; + data[9] = 0; + data[10] = 1 / (zf - zn); + data[11] = 0; + + data[12] = 0; + data[13] = 0; + data[14] = zn / (zn - zf); + data[15] = 1; + + return this + } + + /** + * set matrix orthogonal projection by view side + * @param left orthogonal view left + * @param right orthogonal view right + * @param bottom orthogonal view bottom + * @param top orthogonal view top + * @param near camera near plane + * @param far camera far plane + * @returns this matrix + */ + public orthoZO(left: number, right: number, bottom: number, top: number, near: number, far: number) { + let data = this.rawData; + let lr = 1 / (left - right); + let bt = 1 / (bottom - top); + let nf = 1 / (near - far); + data[0] = -2 * lr; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; + data[5] = -2 * bt; + data[6] = 0; + data[7] = 0; + data[8] = 0; + data[9] = 0; + data[10] = nf; + data[11] = 0; + data[12] = (left + right) * lr; + data[13] = (top + bottom) * bt; + data[14] = near * nf; + data[15] = 1; + return this; + } + + /** + * set matrix orthogonal projection by view center + */ + public orthoOffCenter(l: number, r: number, b: number, t: number, zn: number, zf: number) { + let data = this.rawData; + + data[0] = 2 / (r - l); + data[1] = 0; + data[2] = 0; + data[3] = 0; + + data[4] = 0; + data[5] = 2 / (t - b); + data[6] = 0; + data[7] = 0; + + data[8] = 0; + data[9] = 0; + data[10] = 1.0 / (zf - zn); + data[11] = 0; + + data[12] = (l + r) / (l - r); + data[13] = (t + b) / (b - t); + data[14] = zn / (zn - zf); + data[15] = 1; + } + + /** + * set matrix form two direction + * @param fromDirection first direction + * @param toDirection second direction + * @version Orillusion3D 0.5.1 + */ + public transformDir(fromDirection: Vector3, toDirection: Vector3) { + let data = this.rawData; + + let EPSILON: number = 0.000001; + let v: Vector3 = Vector3.HELP_0; + toDirection.crossProduct(fromDirection, v); + let e: number = toDirection.dotProduct(fromDirection); + + if (e > 1.0 - EPSILON) { + this.identity(); + } else if (3 < -1.0 + EPSILON) { + let up: Vector3 = Vector3.HELP_1; + let left: Vector3 = Vector3.HELP_2; // + let invLen: number = 0; + + let fxx; + let fyy; + let fzz; + let fxy; + let fxz; + let fyz; + let uxx; + let uyy; + let uzz; + let uxy; + let uxz; + let uyz; + let lxx; + let lyy; + let lzz; + let lxy; + let lxz; + let lyz; + + left.x = 0.0; + left.y = fromDirection.z; + left.z = -fromDirection.y; + if (left.dotProduct(left) < EPSILON) { + left.x = -fromDirection.z; + left.y = 0.0; + left.z = fromDirection.x; + } + /* normalize "left" */ + invLen = 1.0 / Math.sqrt(left.dotProduct(left)); + left[0] *= invLen; + left[1] *= invLen; + left[2] *= invLen; + + left.crossProduct(fromDirection, up); + + fxx = -fromDirection.x * fromDirection.x; + fyy = -fromDirection.y * fromDirection.y; + fzz = -fromDirection.z * fromDirection.z; + fxy = -fromDirection.x * fromDirection.y; + fxz = -fromDirection.x * fromDirection.z; + fyz = -fromDirection.y * fromDirection.z; + + uxx = up.x * up.x; + uyy = up.y * up.y; + uzz = up.z * up.z; + uxy = up.x * up.y; + uxz = up.x * up.z; + uyz = up.y * up.z; + + lxx = -left.x * left.x; + lyy = -left.y * left.y; + lzz = -left.z * left.z; + lxy = -left.x * left.y; + lxz = -left.x * left.z; + lyz = -left.y * left.z; + + data[0] = fxx + uxx + lxx; + data[1] = fxy + uxy + lxy; + data[2] = fxz + uxz + lxz; + data[4] = data[1]; + data[5] = fyy + uyy + lyy; + data[6] = fyz + uyz + lyz; + data[8] = data[2]; + data[9] = data[6]; + data[10] = fzz + uzz + lzz; + + data[3] = 0; + data[7] = 0; + data[11] = 0; + data[15] = 1; + } else { + let hvx; + let hvz; + let hvxy; + let hvxz; + let hvyz; + + let h = (1.0 - e) / v.dotProduct(v); + hvx = h * v.x; + hvz = h * v.z; + hvxy = hvx * v.y; + hvxz = hvx * v.z; + hvyz = hvz * v.y; + data[0] = e + hvx * v.x; + data[1] = hvxy - v.z; + data[2] = hvxz + v.y; + data[4] = hvxy + v.z; + data[5] = e + h * v.y * v.y; + data[6] = hvyz - v.x; + data[8] = hvxz - v.y; + data[9] = hvyz + v.x; + data[10] = e + hvz * v.z; + + data[3] = 0; + data[7] = 0; + data[11] = 0; + data[15] = 1; + } + } + + /** + * multiply matrix a b + * @param lhs target matrix + * @version Orillusion3D 0.5.1 + */ + public append(lhs: Matrix4): void { + let data = this.rawData; + let m111: number = data[0]; + let m121: number = data[4]; + let m131: number = data[8]; + let m141: number = data[12]; + let m112: number = data[1]; + let m122: number = data[5]; + let m132: number = data[9]; + let m142: number = data[13]; + let m113: number = data[2]; + let m123: number = data[6]; + let m133: number = data[10]; + let m143: number = data[14]; + let m114: number = data[3]; + let m124: number = data[7]; + let m134: number = data[11]; + let m144: number = data[15]; + + data[0] = m111 * lhs.rawData[0] + m112 * lhs.rawData[4] + m113 * lhs.rawData[8] + m114 * lhs.rawData[12]; + data[1] = m111 * lhs.rawData[1] + m112 * lhs.rawData[5] + m113 * lhs.rawData[9] + m114 * lhs.rawData[13]; + data[2] = m111 * lhs.rawData[2] + m112 * lhs.rawData[6] + m113 * lhs.rawData[10] + m114 * lhs.rawData[14]; + data[3] = m111 * lhs.rawData[3] + m112 * lhs.rawData[7] + m113 * lhs.rawData[11] + m114 * lhs.rawData[15]; + + data[4] = m121 * lhs.rawData[0] + m122 * lhs.rawData[4] + m123 * lhs.rawData[8] + m124 * lhs.rawData[12]; + data[5] = m121 * lhs.rawData[1] + m122 * lhs.rawData[5] + m123 * lhs.rawData[9] + m124 * lhs.rawData[13]; + data[6] = m121 * lhs.rawData[2] + m122 * lhs.rawData[6] + m123 * lhs.rawData[10] + m124 * lhs.rawData[14]; + data[7] = m121 * lhs.rawData[3] + m122 * lhs.rawData[7] + m123 * lhs.rawData[11] + m124 * lhs.rawData[15]; + + data[8] = m131 * lhs.rawData[0] + m132 * lhs.rawData[4] + m133 * lhs.rawData[8] + m134 * lhs.rawData[12]; + data[9] = m131 * lhs.rawData[1] + m132 * lhs.rawData[5] + m133 * lhs.rawData[9] + m134 * lhs.rawData[13]; + data[10] = m131 * lhs.rawData[2] + m132 * lhs.rawData[6] + m133 * lhs.rawData[10] + m134 * lhs.rawData[14]; + data[11] = m131 * lhs.rawData[3] + m132 * lhs.rawData[7] + m133 * lhs.rawData[11] + m134 * lhs.rawData[15]; + + data[12] = m141 * lhs.rawData[0] + m142 * lhs.rawData[4] + m143 * lhs.rawData[8] + m144 * lhs.rawData[12]; + data[13] = m141 * lhs.rawData[1] + m142 * lhs.rawData[5] + m143 * lhs.rawData[9] + m144 * lhs.rawData[13]; + data[14] = m141 * lhs.rawData[2] + m142 * lhs.rawData[6] + m143 * lhs.rawData[10] + m144 * lhs.rawData[14]; + data[15] = m141 * lhs.rawData[3] + m142 * lhs.rawData[7] + m143 * lhs.rawData[11] + m144 * lhs.rawData[15]; + } + + /** + * matrix a add matrix b + * @param lhs target matrix. + * @returns Matrix4 result. + * @version Orillusion3D 0.5.1 + */ + public add(lhs: Matrix4): Matrix4 { + let data = this.rawData; + let m111: number = data[0]; + let m121: number = data[4]; + let m131: number = data[8]; + let m141: number = data[12]; + let m112: number = data[1]; + let m122: number = data[5]; + let m132: number = data[9]; + let m142: number = data[13]; + let m113: number = data[2]; + let m123: number = data[6]; + let m133: number = data[10]; + let m143: number = data[14]; + let m114: number = data[3]; + let m124: number = data[7]; + let m134: number = data[11]; + let m144: number = data[15]; + let m211: number = lhs.rawData[0]; + let m221: number = lhs.rawData[4]; + let m231: number = lhs.rawData[8]; + let m241: number = lhs.rawData[12]; + let m212: number = lhs.rawData[1]; + let m222: number = lhs.rawData[5]; + let m232: number = lhs.rawData[9]; + let m242: number = lhs.rawData[13]; + let m213: number = lhs.rawData[2]; + let m223: number = lhs.rawData[6]; + let m233: number = lhs.rawData[10]; + let m243: number = lhs.rawData[14]; + let m214: number = lhs.rawData[3]; + let m224: number = lhs.rawData[7]; + let m234: number = lhs.rawData[11]; + let m244: number = lhs.rawData[15]; + + data[0] = m111 + m211; + data[1] = m112 + m212; + data[2] = m113 + m213; + data[3] = m114 + m214; + + data[4] = m121 + m221; + data[5] = m122 + m222; + data[6] = m123 + m223; + data[7] = m124 + m224; + + data[8] = m131 + m231; + data[9] = m132 + m232; + data[10] = m133 + m233; + data[11] = m134 + m234; + + data[12] = m141 + m241; + data[13] = m142 + m242; + data[14] = m143 + m243; + data[15] = m144 + m244; + return this; + } + + /** + * matrix a sub matrix b + * @param lhs target matrix b. + * @returns Matrix4 . + * @version Orillusion3D 0.5.1 + */ + public sub(lhs: Matrix4): Matrix4 { + let data = this.rawData; + + let m111: number = data[0]; + let m121: number = data[4]; + let m131: number = data[8]; + let m141: number = data[12]; + let m112: number = data[1]; + let m122: number = data[5]; + let m132: number = data[9]; + let m142: number = data[13]; + let m113: number = data[2]; + let m123: number = data[6]; + let m133: number = data[10]; + let m143: number = data[14]; + let m114: number = data[3]; + let m124: number = data[7]; + let m134: number = data[11]; + let m144: number = data[15]; + let m211: number = lhs.rawData[0]; + let m221: number = lhs.rawData[4]; + let m231: number = lhs.rawData[8]; + let m241: number = lhs.rawData[12]; + let m212: number = lhs.rawData[1]; + let m222: number = lhs.rawData[5]; + let m232: number = lhs.rawData[9]; + let m242: number = lhs.rawData[13]; + let m213: number = lhs.rawData[2]; + let m223: number = lhs.rawData[6]; + let m233: number = lhs.rawData[10]; + let m243: number = lhs.rawData[14]; + let m214: number = lhs.rawData[3]; + let m224: number = lhs.rawData[7]; + let m234: number = lhs.rawData[11]; + let m244: number = lhs.rawData[15]; + + data[0] = m111 - m211; + data[1] = m112 - m212; + data[2] = m113 - m213; + data[3] = m114 - m214; + + data[4] = m121 - m221; + data[5] = m122 - m222; + data[6] = m123 - m223; + data[7] = m124 - m224; + + data[8] = m131 - m231; + data[9] = m132 - m232; + data[10] = m133 - m233; + data[11] = m134 - m234; + + data[12] = m141 - m241; + data[13] = m142 - m242; + data[14] = m143 - m243; + data[15] = m144 - m244; + return this; + } + + /** + * Matrix times components. + * @param v This matrix is going to be multiplied by this value + * @returns Matrix4 Returns a multiplicative result matrix. + * @version Orillusion3D 0.5.1 + */ + public mult(v: number): Matrix4 { + let data = this.rawData; + + data[0] *= v; + data[1] *= v; + data[2] *= v; + data[3] *= v; + + data[4] *= v; + data[5] *= v; + data[6] *= v; + data[7] *= v; + + data[8] *= v; + data[9] *= v; + data[10] *= v; + data[11] *= v; + + data[12] *= v; + data[13] *= v; + data[14] *= v; + data[15] *= v; + return this; + } + + // /** + // * Create an Euler rotation matrix. + // * @param x Angle of rotation around the x axis. + // * @param y Angle of rotation around the y axis. + // * @param z Angle of rotation around the z axis. + // * @version Orillusion3D 0.5.1 + // */ + // public rotation(x: number, y: number, z: number) { + // Quaternion.CALCULATION_QUATERNION.fromEulerAngles(x, y, z); + // this.makeTransform( + // Matrix4.position_000, + // Matrix4.scale_111, + // Quaternion.CALCULATION_QUATERNION, + // ); + // } + + /** + Add a direction Angle rotation to the current matrix (the matrix created by rotating degrees according to axis) + @param degrees Angle of rotation. + @param axis Angle of rotation around axis axis + @version Orillusion3D 0.5.1 + */ + public appendRotation(degrees: number, axis: Vector3): void { + let m: Matrix4 = Matrix4.getAxisRotation(axis.x, axis.y, axis.z, degrees); + this.append(m); + } + + /** + * Create a matrix based on the axis and rotation Angle (the matrix created by rotating the degrees according to the axis) + * @param degrees Angle of rotation. + * @param axis Rotation Angle around axis axis. Axis needs to be specified as the orientation of an axis between x/y/z + * @version Orillusion3D 0.5.1 + */ + public createByRotation(degrees: number, axis: Vector3): void { + let tmp: Matrix4 = Matrix4.helpMatrix; + let s: number; + let c: number; + + let angle: number = degrees * DEGREES_TO_RADIANS; + s = Math.sin(angle); + c = Math.cos(angle); + + if (axis.x == 1) { + tmp.rawData[0] = 1.0; + tmp.rawData[1] = 0.0; + tmp.rawData[2] = 0.0; + tmp.rawData[3] = 0.0; + tmp.rawData[4] = 0.0; + tmp.rawData[5] = c; + tmp.rawData[6] = s; + tmp.rawData[7] = 0.0; + tmp.rawData[8] = 0.0; + tmp.rawData[9] = -s; + tmp.rawData[10] = c; + tmp.rawData[11] = 0.0; + tmp.rawData[12] = 0.0; + tmp.rawData[13] = 0.0; + tmp.rawData[14] = 0.0; + tmp.rawData[15] = 1.0; + } + + if (axis.y == 1) { + tmp.rawData[0] = c; + tmp.rawData[1] = 0.0; + tmp.rawData[2] = -s; + tmp.rawData[3] = 0.0; + tmp.rawData[4] = 0.0; + tmp.rawData[5] = 1.0; + tmp.rawData[6] = 0.0; + tmp.rawData[7] = 0.0; + tmp.rawData[8] = s; + tmp.rawData[9] = 0.0; + tmp.rawData[10] = c; + tmp.rawData[11] = 0.0; + tmp.rawData[12] = 0.0; + tmp.rawData[13] = 0.0; + tmp.rawData[14] = 0.0; + tmp.rawData[15] = 1.0; + } + + if (axis.z == 1) { + tmp.rawData[0] = c; + tmp.rawData[1] = s; + tmp.rawData[2] = 0.0; + tmp.rawData[3] = 0.0; + tmp.rawData[4] = -s; + tmp.rawData[5] = c; + tmp.rawData[6] = 0.0; + tmp.rawData[7] = 0.0; + tmp.rawData[8] = 0.0; + tmp.rawData[9] = 0.0; + tmp.rawData[10] = 1.0; + tmp.rawData[11] = 0.0; + tmp.rawData[12] = 0.0; + tmp.rawData[13] = 0.0; + tmp.rawData[14] = 0.0; + tmp.rawData[15] = 1.0; + } + + this.append(tmp); + } + + /** + * Append the triaxial scaling value + * @param xScale x axis scaling + * @param yScale y axis scaling + * @param zScale z axis scaling + * @version Orillusion3D 0.5.1 + */ + public appendScale(xScale: number, yScale: number, zScale: number) { + Matrix4.helpMatrix.createByScale(xScale, yScale, zScale); + this.append(Matrix4.helpMatrix); + } + + /** + * A scaling matrix is generated and other properties are reset + * @param xScale x axis scaling + * @param yScale y axis scaling + * @param zScale z axis scaling + * @version Orillusion3D 0.5.1 + */ + public createByScale(xScale: number, yScale: number, zScale: number): void { + let data = this.rawData; + data[0] = xScale; + data[1] = 0.0; + data[2] = 0.0; + data[3] = 0.0; + data[4] = 0.0; + data[5] = yScale; + data[6] = 0.0; + data[7] = 0.0; + data[8] = 0.0; + data[9] = 0.0; + data[10] = zScale; + data[11] = 0.0; + data[12] = 0.0; + data[13] = 0.0; + data[14] = 0.0; + data[15] = 1.0; + } + + /** + * Plus a translation matrix + * @param x x axis scaling + * @param y y axis scaling + * @param z z axis scaling + * @version Orillusion3D 0.5.1 + */ + public appendTranslation(x: number, y: number, z: number) { + let data = this.rawData; + data[12] += x; + data[13] += y; + data[14] += z; + } + + /** + * Returns a clone of the current matrix + * @returns Matrix4 The cloned matrix + * @version Orillusion3D 0.5.1 + */ + public clone(): Matrix4 { + let ret: Matrix4 = new Matrix4(); + ret.copyFrom(this); + return ret; + } + + /** + * Assigns a value to one row of the current matrix + * @param row Row of copy + * @param Vector3 Value of copy + * @version Orillusion3D 0.5.1 + */ + public copyRowFrom(row: number, Vector3: Vector3) { + let data = this.rawData; + switch (row) { + case 0: + data[0] = Vector3.x; + data[1] = Vector3.y; + data[2] = Vector3.z; + data[3] = Vector3.w; + break; + case 1: + data[4] = Vector3.x; + data[5] = Vector3.y; + data[6] = Vector3.z; + data[7] = Vector3.w; + break; + case 2: + data[8] = Vector3.x; + data[9] = Vector3.y; + data[10] = Vector3.z; + data[11] = Vector3.w; + break; + case 3: + data[12] = Vector3.x; + data[13] = Vector3.y; + data[14] = Vector3.z; + data[15] = Vector3.w; + break; + default: + ///throw new ArgumentError("ArgumentError, Column " + column + " out of bounds [0, ..., 3]"); + } + } + + /** + * One of the rows in the copy matrix stores the values in Vector3. + * @param row Row of copy + * @param Vector3 Copy the storage target + * @version Orillusion3D 0.5.1 + */ + public copyRowTo(row: number, Vector3: Vector3) { + let data = this.rawData; + switch (row) { + case 0: + Vector3.x = data[0]; + Vector3.y = data[1]; + Vector3.z = data[2]; + Vector3.w = data[3]; + break; + case 1: + Vector3.x = data[4]; + Vector3.y = data[5]; + Vector3.z = data[6]; + Vector3.w = data[7]; + break; + case 2: + Vector3.x = data[8]; + Vector3.y = data[9]; + Vector3.z = data[10]; + Vector3.w = data[11]; + break; + case 3: + Vector3.x = data[12]; + Vector3.y = data[13]; + Vector3.z = data[14]; + Vector3.w = data[15]; + break; + default: + /// throw new ArgumentError("ArgumentError, Column " + column + " out of bounds [0, ..., 3]"); + } + } + + /** + * Assigns the value of a matrix to the current matrix. + * @param sourceMatrix3D source Matrix + * @returns Returns the current matrix + * @version Orillusion3D 0.5.1 + */ + public copyFrom(sourceMatrix3D: Matrix4): Matrix4 { + let data: Float32Array = this.rawData; + data[0] = sourceMatrix3D.rawData[0]; + data[1] = sourceMatrix3D.rawData[1]; + data[2] = sourceMatrix3D.rawData[2]; + data[3] = sourceMatrix3D.rawData[3]; + data[4] = sourceMatrix3D.rawData[4]; + data[5] = sourceMatrix3D.rawData[5]; + data[6] = sourceMatrix3D.rawData[6]; + data[7] = sourceMatrix3D.rawData[7]; + data[8] = sourceMatrix3D.rawData[8]; + data[9] = sourceMatrix3D.rawData[9]; + data[10] = sourceMatrix3D.rawData[10]; + data[11] = sourceMatrix3D.rawData[11]; + data[12] = sourceMatrix3D.rawData[12]; + data[13] = sourceMatrix3D.rawData[13]; + data[14] = sourceMatrix3D.rawData[14]; + data[15] = sourceMatrix3D.rawData[15]; + return this; + } + + /** + * Copies the value of the current matrix to a float array. + * @param vector The target array. + * @param index copy from the index of the array. + * @param transpose Whether to transpose the current matrix. + * @version Orillusion3D 0.5.1 + */ + public copyRawDataTo(vector: Float32Array, index: number = 0, transpose: boolean = false) { + let data: Float32Array = this.rawData; + vector[0 + index] = data[0]; + vector[1 + index] = data[1]; + vector[2 + index] = data[2]; + vector[3 + index] = data[3]; + vector[4 + index] = data[4]; + vector[5 + index] = data[5]; + vector[6 + index] = data[6]; + vector[7 + index] = data[7]; + vector[8 + index] = data[8]; + vector[9 + index] = data[9]; + vector[10 + index] = data[10]; + vector[11 + index] = data[11]; + vector[12 + index] = data[12]; + vector[13 + index] = data[13]; + vector[14 + index] = data[14]; + vector[15 + index] = data[15]; + } + + /** + * Assigns a value to a column of the current matrix + * @param col column + * @param Vector3 Source of value + * @version Orillusion3D 0.5.1 + */ + public copyColFrom(col: number, Vector3: Vector3) { + let data: Float32Array = this.rawData; + switch (col) { + case 0: + data[0] = Vector3.x; + data[4] = Vector3.y; + data[8] = Vector3.z; + data[12] = Vector3.w; + break; + case 1: + data[1] = Vector3.x; + data[5] = Vector3.y; + data[9] = Vector3.z; + data[13] = Vector3.w; + break; + case 2: + data[2] = Vector3.x; + data[6] = Vector3.y; + data[10] = Vector3.z; + data[14] = Vector3.w; + break; + case 3: + data[3] = Vector3.x; + data[7] = Vector3.y; + data[11] = Vector3.z; + data[15] = Vector3.w; + break; + default: + new Error('no more raw!'); + } + } + + /** + * Copy a column of the current matrix + * @param col column + * @param Vector3 Target of copy + * @version Orillusion3D 0.5.1 + */ + public copyColTo(col: number, Vector3: Vector3) { + let data: Float32Array = this.rawData; + switch (col) { + case 0: + Vector3.x = data[0]; + Vector3.y = data[4]; + Vector3.z = data[8]; + Vector3.w = data[12]; + break; + case 1: + Vector3.x = data[1]; + Vector3.y = data[5]; + Vector3.z = data[9]; + Vector3.w = data[13]; + break; + case 2: + Vector3.x = data[2]; + Vector3.y = data[6]; + Vector3.z = data[10]; + Vector3.w = data[14]; + break; + case 3: + Vector3.x = data[3]; + Vector3.y = data[7]; + Vector3.z = data[11]; + Vector3.w = data[15]; + break; + default: + new Error('no more raw!'); + } + } + + /** + * Copy the current matrix + * @param dest Target of copy + * @version Orillusion3D 0.5.1 + */ + public copyToMatrix3D(dest: Matrix4) { + dest.rawData = this.rawData.slice(0); + } + + /** + * Calculate rotation matrix + * @param quaternion Rotate the quaternion + * @returns + */ + public makeRotationFromQuaternion(quaternion: Quaternion): Matrix4 { + this.compose(Matrix4._zero, quaternion, Matrix4._one); + return this; + } + + /** + * Decompose the current matrix + * @param orientationStyle The default decomposition type is Orientation3D.EULER_ANGLES + * @see Orientation3D.AXIS_ANGLE + * @see Orientation3D.EULER_ANGLES + * @see Orientation3D.QUATERNION + * @returns Vector3[3] pos rot scale + * @version Orillusion3D 0.5.1 + */ + public decompose(orientationStyle: string = 'eulerAngles', target?: Vector3[]): Vector3[] { + let q: Quaternion = Quaternion.CALCULATION_QUATERNION; + let vec: Vector3[] = target ? target : Matrix4._prs; + this.copyRawDataTo(Matrix4.helpMatrix.rawData); + let mr = Matrix4.helpMatrix.rawData; + + let pos: Vector3 = vec[0]; + pos.x = mr[12]; + pos.y = mr[13]; + pos.z = mr[14]; + mr[12] = 0; + mr[13] = 0; + mr[14] = 0; + + let scale: Vector3 = vec[2]; + + scale.x = Math.sqrt(mr[0] * mr[0] + mr[1] * mr[1] + mr[2] * mr[2]); + scale.y = Math.sqrt(mr[4] * mr[4] + mr[5] * mr[5] + mr[6] * mr[6]); + scale.z = Math.sqrt(mr[8] * mr[8] + mr[9] * mr[9] + mr[10] * mr[10]); + + if (mr[0] * (mr[5] * mr[10] - mr[6] * mr[9]) + - mr[1] * (mr[4] * mr[10] - mr[6] * mr[8]) + + mr[2] * (mr[4] * mr[9] - mr[5] * mr[8]) < 0) { + scale.z = -scale.z; + } + + mr[0] /= scale.x; + mr[1] /= scale.x; + mr[2] /= scale.x; + mr[4] /= scale.y; + mr[5] /= scale.y; + mr[6] /= scale.y; + mr[8] /= scale.z; + mr[9] /= scale.z; + mr[10] /= scale.z; + + let rot = vec[1]; + + switch (orientationStyle) { + case Orientation3D.AXIS_ANGLE: + rot.w = Math.acos((mr[0] + mr[5] + mr[10] - 1) / 2); + + let len: number = Math.sqrt((mr[6] - mr[9]) * (mr[6] - mr[9]) + (mr[8] - mr[2]) * (mr[8] - mr[2]) + (mr[1] - mr[4]) * (mr[1] - mr[4])); + rot.x = (mr[6] - mr[9]) / len; + rot.y = (mr[8] - mr[2]) / len; + rot.z = (mr[1] - mr[4]) / len; + + break; + case Orientation3D.QUATERNION: + let tr = mr[0] + mr[5] + mr[10]; + + if (tr > 0) { + rot.w = Math.sqrt(1 + tr) / 2; + + rot.x = (mr[6] - mr[9]) / (4 * rot.w); + rot.y = (mr[8] - mr[2]) / (4 * rot.w); + rot.z = (mr[1] - mr[4]) / (4 * rot.w); + } else if (mr[0] > mr[5] && mr[0] > mr[10]) { + rot.x = Math.sqrt(1 + mr[0] - mr[5] - mr[10]) / 2; + + rot.w = (mr[6] - mr[9]) / (4 * rot.x); + rot.y = (mr[1] + mr[4]) / (4 * rot.x); + rot.z = (mr[8] + mr[2]) / (4 * rot.x); + } else if (mr[5] > mr[10]) { + rot.y = Math.sqrt(1 + mr[5] - mr[0] - mr[10]) / 2; + + rot.x = (mr[1] + mr[4]) / (4 * rot.y); + rot.w = (mr[8] - mr[2]) / (4 * rot.y); + rot.z = (mr[6] + mr[9]) / (4 * rot.y); + } else { + rot.z = Math.sqrt(1 + mr[10] - mr[0] - mr[5]) / 2; + + rot.x = (mr[8] + mr[2]) / (4 * rot.z); + rot.y = (mr[6] + mr[9]) / (4 * rot.z); + rot.w = (mr[1] - mr[4]) / (4 * rot.z); + } + + break; + case Orientation3D.EULER_ANGLES: + tr = mr[0] + mr[5] + mr[10]; + + if (tr > 0) { + q.w = Math.sqrt(1 + tr) / 2; + + q.x = (mr[6] - mr[9]) / (4 * q.w); + q.y = (mr[8] - mr[2]) / (4 * q.w); + q.z = (mr[1] - mr[4]) / (4 * q.w); + } else if (mr[0] > mr[5] && mr[0] > mr[10]) { + q.x = Math.sqrt(1 + mr[0] - mr[5] - mr[10]) / 2; + + q.w = (mr[6] - mr[9]) / (4 * q.x); + q.y = (mr[1] + mr[4]) / (4 * q.x); + q.z = (mr[8] + mr[2]) / (4 * q.x); + } else if (mr[5] > mr[10]) { + rot.y = Math.sqrt(1 + mr[5] - mr[0] - mr[10]) / 2; + + q.x = (mr[1] + mr[4]) / (4 * q.y); + q.w = (mr[8] - mr[2]) / (4 * q.y); + q.z = (mr[6] + mr[9]) / (4 * q.y); + } else { + q.z = Math.sqrt(1 + mr[10] - mr[0] - mr[5]) / 2; + + q.x = (mr[8] + mr[2]) / (4 * q.z); + q.y = (mr[6] + mr[9]) / (4 * q.z); + q.w = (mr[1] - mr[4]) / (4 * q.z); + } + q.toEulerAngles(rot); + + break; + } + + vec[0] = pos; + vec[1] = rot; + vec[2] = scale; + + return vec; + } + + + + /** + * Get the Euler vector + * @param target Vector of results + * @param quaternion Rotate the quaternion + * @param isDegree Whether to convert to Angle + * @param order convert order + * @returns + */ + static getEuler(target: Vector3, quaternion: Quaternion, isDegree: boolean = true, order?: string) { + target ||= new Vector3(); + Matrix4._getEulerMatrix.makeRotationFromQuaternion(quaternion).makeEuler(target, isDegree, order); + return target; + } + + /** + * Calculate the combined matrix of displacement, rotation and scaling + * @param position translation + * @param quaternion rotation + * @param scale scale + * @returns + */ + public compose(position: Vector3, quaternion: Quaternion, scale: Vector3) { + const te = this.rawData; + + const x = quaternion.x; + const y = quaternion.y; + const z = quaternion.z; + const w = quaternion.w; + const x2 = x + x; + const y2 = y + y; + const z2 = z + z; + const xx = x * x2; + const xy = x * y2; + const xz = x * z2; + const yy = y * y2; + const yz = y * z2; + const zz = z * z2; + const wx = w * x2; + const wy = w * y2; + const wz = w * z2; + + const sx = scale.x; + const sy = scale.y; + const sz = scale.z; + + te[0] = (1 - (yy + zz)) * sx; + te[1] = (xy + wz) * sx; + te[2] = (xz - wy) * sx; + te[3] = 0; + + te[4] = (xy - wz) * sy; + te[5] = (1 - (xx + zz)) * sy; + te[6] = (yz + wx) * sy; + te[7] = 0; + + te[8] = (xz + wy) * sz; + te[9] = (yz - wx) * sz; + te[10] = (1 - (xx + yy)) * sz; + te[11] = 0; + + te[12] = position.x; + te[13] = position.y; + te[14] = position.z; + te[15] = 1; + + return this; + } + + /** + * The current matrix transforms a vector + * @param v Vector to transform + * @param target The default is null and if the current argument is null then a new Vector3 will be returned + * @returns Vector3 The transformed vector + * @version Orillusion3D 0.5.1 + */ + public deltaTransformVector(v: Vector3, target?: Vector3): Vector3 { + target ||= new Vector3(); + + let data: Float32Array = this.rawData; + let x: number = v.x; + let y: number = v.y; + let z: number = v.z; + + target.x = x * data[0] + y * data[4] + z * data[8]; + target.y = x * data[1] + y * data[5] + z * data[9]; + target.z = x * data[2] + y * data[6] + z * data[10]; + target.w = x * data[3] + y * data[7] + z * data[11]; + return target; + } + + /** + * Unifies the current matrix + * @version Orillusion3D 0.5.1 + */ + public identity() { + let data: Float32Array = this.rawData; + //1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 + data[0] = 1; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; + data[5] = 1; + data[6] = 0; + data[7] = 0; + data[8] = 0; + data[9] = 0; + data[10] = 1; + data[11] = 0; + data[12] = 0; + data[13] = 0; + data[14] = 0; + data[15] = 1; + return this; + } + + /** + * Fill the current matrix + * @param value The filled value + * @version Orillusion3D 0.5.1 + */ + public fill(value: number) { + let data: Float32Array = this.rawData; + data[1] = value; + data[2] = value; + data[3] = value; + data[4] = value; + data[6] = value; + data[7] = value; + data[8] = value; + data[9] = value; + data[11] = value; + data[12] = value; + data[13] = value; + data[14] = value; + data[0] = value; + data[5] = value; + data[10] = value; + data[15] = value; + } + + /** + * Invert the current matrix + * @version Orillusion3D 0.5.1 + */ + public invers33() { + /// Invert a 3x3 using cofactors. This is about 8 times faster than + /// the Numerical Recipes code which uses Gaussian elimination. + let data: Float32Array = this.rawData; + + let rkInverse_00 = data[5] * data[10] - data[9] * data[6]; + let rkInverse_01 = data[8] * data[6] - data[4] * data[10]; + let rkInverse_02 = data[4] * data[9] - data[8] * data[5]; + let rkInverse_10 = data[9] * data[2] - data[1] * data[10]; + let rkInverse_11 = data[0] * data[10] - data[8] * data[2]; + let rkInverse_12 = data[8] * data[1] - data[0] * data[9]; + let rkInverse_20 = data[1] * data[6] - data[5] * data[2]; + let rkInverse_21 = data[4] * data[2] - data[0] * data[6]; + let rkInverse_22 = data[0] * data[5] - data[4] * data[1]; + + let fDet: number = data[0] * rkInverse_00 + data[4] * rkInverse_10 + data[8] * rkInverse_20; + + if (Math.abs(fDet) > 0.00000000001) { + let fInvDet: number = 1.0 / fDet; + + data[0] = fInvDet * rkInverse_00; + data[4] = fInvDet * rkInverse_01; + data[8] = fInvDet * rkInverse_02; + data[1] = fInvDet * rkInverse_10; + data[5] = fInvDet * rkInverse_11; + data[9] = fInvDet * rkInverse_12; + data[2] = fInvDet * rkInverse_20; + data[6] = fInvDet * rkInverse_21; + data[10] = fInvDet * rkInverse_22; + } + } + + /** + * Invert the current matrix + * @returns boolean Whether can invert it + * @version Orillusion3D 0.5.1 + */ + public invert(): boolean { + let d = this.determinant; + let invertable = Math.abs(d) > 0.00000000001; + let data: Float32Array = this.rawData; + + if (invertable) { + d = 1 / d; + let m11: number = data[0]; + let m21: number = data[4]; + let m31: number = data[8]; + let m41: number = data[12]; + let m12: number = data[1]; + let m22: number = data[5]; + let m32: number = data[9]; + let m42: number = data[13]; + let m13: number = data[2]; + let m23: number = data[6]; + let m33: number = data[10]; + let m43: number = data[14]; + let m14: number = data[3]; + let m24: number = data[7]; + let m34: number = data[11]; + let m44: number = data[15]; + + data[0] = d * (m22 * (m33 * m44 - m43 * m34) - m32 * (m23 * m44 - m43 * m24) + m42 * (m23 * m34 - m33 * m24)); + data[1] = -d * (m12 * (m33 * m44 - m43 * m34) - m32 * (m13 * m44 - m43 * m14) + m42 * (m13 * m34 - m33 * m14)); + data[2] = d * (m12 * (m23 * m44 - m43 * m24) - m22 * (m13 * m44 - m43 * m14) + m42 * (m13 * m24 - m23 * m14)); + data[3] = -d * (m12 * (m23 * m34 - m33 * m24) - m22 * (m13 * m34 - m33 * m14) + m32 * (m13 * m24 - m23 * m14)); + data[4] = -d * (m21 * (m33 * m44 - m43 * m34) - m31 * (m23 * m44 - m43 * m24) + m41 * (m23 * m34 - m33 * m24)); + data[5] = d * (m11 * (m33 * m44 - m43 * m34) - m31 * (m13 * m44 - m43 * m14) + m41 * (m13 * m34 - m33 * m14)); + data[6] = -d * (m11 * (m23 * m44 - m43 * m24) - m21 * (m13 * m44 - m43 * m14) + m41 * (m13 * m24 - m23 * m14)); + data[7] = d * (m11 * (m23 * m34 - m33 * m24) - m21 * (m13 * m34 - m33 * m14) + m31 * (m13 * m24 - m23 * m14)); + data[8] = d * (m21 * (m32 * m44 - m42 * m34) - m31 * (m22 * m44 - m42 * m24) + m41 * (m22 * m34 - m32 * m24)); + data[9] = -d * (m11 * (m32 * m44 - m42 * m34) - m31 * (m12 * m44 - m42 * m14) + m41 * (m12 * m34 - m32 * m14)); + data[10] = d * (m11 * (m22 * m44 - m42 * m24) - m21 * (m12 * m44 - m42 * m14) + m41 * (m12 * m24 - m22 * m14)); + data[11] = -d * (m11 * (m22 * m34 - m32 * m24) - m21 * (m12 * m34 - m32 * m14) + m31 * (m12 * m24 - m22 * m14)); + data[12] = -d * (m21 * (m32 * m43 - m42 * m33) - m31 * (m22 * m43 - m42 * m23) + m41 * (m22 * m33 - m32 * m23)); + data[13] = d * (m11 * (m32 * m43 - m42 * m33) - m31 * (m12 * m43 - m42 * m13) + m41 * (m12 * m33 - m32 * m13)); + data[14] = -d * (m11 * (m22 * m43 - m42 * m23) - m21 * (m12 * m43 - m42 * m13) + m41 * (m12 * m23 - m22 * m13)); + data[15] = d * (m11 * (m22 * m33 - m32 * m23) - m21 * (m12 * m33 - m32 * m13) + m31 * (m12 * m23 - m22 * m13)); + } + return invertable; + } + + /** + * Converts the current coordinates to the world coordinates + * @param v Current coordinates + * @param target world coordinate + * @returns world coordinate + */ + public transformPoint(v: Vector3, target?: Vector3): Vector3 { + let data: Float32Array = this.rawData; + target ||= new Vector3(); + + let x: number = v.x; + let y: number = v.y; + let z: number = v.z; + + target.x = x * data[0] + y * data[4] + z * data[8] + data[12]; + target.y = x * data[1] + y * data[5] + z * data[9] + data[13]; + target.z = x * data[2] + y * data[6] + z * data[10] + data[14]; + + return target; + } + + /** + * Transforming a 3D vector with the current matrix does not deal with displacement + * @param v Vector of transformation + * @param target If the current argument is null then a new Vector3 will be returned + * @returns Vector3 The transformed vector + * @version Orillusion3D 0.5.1 + */ + public transformVector(v: Vector3, target?: Vector3): Vector3 { + let data: Float32Array = this.rawData; + + target ||= new Vector3(); + + let x: number = v.x; + let y: number = v.y; + let z: number = v.z; + + target.x = x * data[0] + y * data[4] + z * data[8]; + target.y = x * data[1] + y * data[5] + z * data[9]; + target.z = x * data[2] + y * data[6] + z * data[10]; + + return target; + } + + /** + * The current matrix transpose + * @version Orillusion3D 0.5.1 + */ + public transpose() { + let data: Float32Array = this.rawData; + + for (let i: number = 0; i < Matrix4.helpMatrix.rawData.length; i++) { + Matrix4.helpMatrix.rawData[i] = data[i]; + } + + data[1] = Matrix4.helpMatrix.rawData[4]; + data[2] = Matrix4.helpMatrix.rawData[8]; + data[3] = Matrix4.helpMatrix.rawData[12]; + data[4] = Matrix4.helpMatrix.rawData[1]; + data[6] = Matrix4.helpMatrix.rawData[9]; + data[7] = Matrix4.helpMatrix.rawData[13]; + data[8] = Matrix4.helpMatrix.rawData[2]; + data[9] = Matrix4.helpMatrix.rawData[6]; + data[11] = Matrix4.helpMatrix.rawData[14]; + data[12] = Matrix4.helpMatrix.rawData[3]; + data[13] = Matrix4.helpMatrix.rawData[7]; + data[14] = Matrix4.helpMatrix.rawData[11]; + } + + /** + * Returns the matrix determinant + * @returns number determinant + * @version Orillusion3D 0.5.1 + */ + public get determinant(): number { + let data: Float32Array = this.rawData; + return ( + (data[0] * data[5] - data[4] * data[1]) * (data[10] * data[15] - data[14] * data[11]) - + (data[0] * data[9] - data[8] * data[1]) * (data[6] * data[15] - data[14] * data[7]) + + (data[0] * data[13] - data[12] * data[1]) * (data[6] * data[11] - data[10] * data[7]) + + (data[4] * data[9] - data[8] * data[5]) * (data[2] * data[15] - data[14] * data[3]) - + (data[4] * data[13] - data[12] * data[5]) * (data[2] * data[11] - data[10] * data[3]) + + (data[8] * data[13] - data[12] * data[9]) * (data[2] * data[7] - data[6] * data[3]) + ); + } + + /** + * Return matrix displacement + * @param out Position of translation + * @returns Position of translation + */ + public getPosition(out?: Vector3): Vector3 { + out ||= new Vector3(); + let data: Float32Array = this.rawData; + out.x = data[12]; + out.y = data[13]; + out.z = data[14]; + return out; + } + + /** + * Return translation + * @returns Vector3 Position of translation + * @version Orillusion3D 0.5.1 + */ + public get position(): Vector3 { + this._position.set(this.rawData[12], this.rawData[13], this.rawData[14]); + return this._position; + } + + /** + * Set Position of translation + * @param value Position of translation + * @version Orillusion3D 0.5.1 + */ + public set position(value: Vector3) { + let data: Float32Array = this.rawData; + data[12] = value.x; + data[13] = value.y; + data[14] = value.z; + } + + /** + * get Component of scale + * + * @returns Vector3 缩放 + * @version Orillusion3D 0.5.1 + */ + public get scale(): Vector3 { + let data: Float32Array = this.rawData; + return new Vector3(data[0], data[5], data[10]); + } + + /** + * Set component of scale + */ + public set scale(value: Vector3) { + let data: Float32Array = this.rawData; + data[0] = value.x; + data[5] = value.y; + data[10] = value.z; + } + + // public setWorldTrans( pos:Vector3 , rotQ:Quaternion,scale:Vector3 = Vector3.SCALE){ + // this.makeTransform(pos,scale,rotQ); + // } + + /** + * Returns the value of the matrix as a string + * + * @returns string 字符 + * @version Orillusion3D 0.5.1 + */ + public toString(): string { + let data = this.rawData; + return ( + 'matrix3d(' + + Math.round(data[0] * 1000) / 1000 + + ',' + + Math.round(data[1] * 1000) / 1000 + + ',' + + Math.round(data[2] * 1000) / 1000 + + ',' + + Math.round(data[3] * 1000) / 1000 + + ',' + + Math.round(data[4] * 1000) / 1000 + + ',' + + Math.round(data[5] * 1000) / 1000 + + ',' + + Math.round(data[6] * 1000) / 1000 + + ',' + + Math.round(data[7] * 1000) / 1000 + + ',' + + Math.round(data[8] * 1000) / 1000 + + ',' + + Math.round(data[9] * 1000) / 1000 + + ',' + + Math.round(data[10] * 1000) / 1000 + + ',' + + Math.round(data[11] * 1000) / 1000 + + ',' + + Math.round(data[12] * 1000) / 1000 + + ',' + + Math.round(data[13] * 1000) / 1000 + + ',' + + Math.round(data[14] * 1000) / 1000 + + ',' + + Math.round(data[15] * 1000) / 1000 + + ')' + ); + } + + /** + * Interpolate between two matrices + * @param m0 Matrix 0 + * @param m1 Matrix 1 + * @param t Factor of interpolation 0.0 - 1.0 + * @version Orillusion3D 0.5.1 + */ + public lerp(m0: Matrix4, m1: Matrix4, t: number): void { + ///t(m1 - m0) + m0 + this.copyFrom(m1).sub(m0).mult(t).add(m0); + } + + /** + * Read matrix element values + * @param row row + * @param column column + * @returns + */ + public get(row: number, column: number) { + return this.rawData[row + column * 4]; + } + + /** + * Sets the matrix element values + * @param row row + * @param column column + * @param v value + */ + public set(row: number, column: number, v: number) { + this.rawData[row + column * 4] = v; + } + + /** + * Get the maximum value of the matrix scaled on each axis + * @version Orillusion3D 0.5.1 4.0 + */ + public getMaxScaleOnAxis(): number { + let te = this.rawData; + + let scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2]; + let scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6]; + let scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10]; + + return Math.sqrt(Math.max(scaleXSq, scaleYSq, scaleZSq)); + } + + /** + * Calculate the displacement from the vector + * @param inTrans Vector + * @returns current matrix + */ + public translate(inTrans: Vector3) { + // let Get = this.Get ; + let x = this.get(0, 0) * inTrans.x + this.get(0, 1) * inTrans.y + this.get(0, 2) * inTrans.z + this.get(0, 3); + let y = this.get(1, 0) * inTrans.x + this.get(1, 1) * inTrans.y + this.get(1, 2) * inTrans.z + this.get(1, 3); + let z = this.get(2, 0) * inTrans.x + this.get(2, 1) * inTrans.y + this.get(2, 2) * inTrans.z + this.get(2, 3); + let w = this.get(3, 0) * inTrans.x + this.get(3, 1) * inTrans.y + this.get(3, 2) * inTrans.z + this.get(3, 3); + + this.set(0, 3, x); + this.set(1, 3, y); + this.set(2, 3, z); + this.set(3, 3, w); + return this; + } + + /** + * form unity API + */ + public setTRInverse(pos: Vector3, q: Quaternion) { + q = q.inverse(); + Quaternion.quaternionToMatrix(q, this); + this.translate(new Vector3(-pos.x, -pos.y, -pos.z)); + } + + /** + * Set scale value + * @param inScale scale value + * @returns this matrix + */ + public setScale(inScale: Vector3) { + this.set(0, 0, inScale.x); + this.set(0, 1, 0.0); + this.set(0, 2, 0.0); + this.set(0, 3, 0.0); + this.set(1, 0, 0.0); + this.set(1, 1, inScale.y); + this.set(1, 2, 0.0); + this.set(1, 3, 0.0); + this.set(2, 0, 0.0); + this.set(2, 1, 0.0); + this.set(2, 2, inScale.z); + this.set(2, 3, 0.0); + this.set(3, 0, 0.0); + this.set(3, 1, 0.0); + this.set(3, 2, 0.0); + this.set(3, 3, 1.0); + return this; + } + + /** + * Generate the matrix according to the three axes + * @param xAxis + * @param yAxis + * @param zAxis + */ + public makeBasis(xAxis: Vector3, yAxis: Vector3, zAxis: Vector3) { + this.setElements( + xAxis.x, yAxis.x, zAxis.x, 0, + xAxis.y, yAxis.y, zAxis.y, 0, + xAxis.z, yAxis.z, zAxis.z, 0, + 0, 0, 0, 1 + ); + return this; + } + + public makeRotationAxis(axis: Vector3, angle: number) { + + const c = Math.cos(angle); + const s = Math.sin(angle); + const t = 1 - c; + const x = axis.x, y = axis.y, z = axis.z; + const tx = t * x, ty = t * y; + + this.setElements( + tx * x + c, tx * y - s * z, tx * z + s * y, 0, + tx * y + s * z, ty * y + c, ty * z - s * x, 0, + tx * z - s * y, ty * z + s * x, t * z * z + c, 0, + 0, 0, 0, 1 + ); + + return this; + + } + + + /** + * private + */ + private static transpose(matrix: Matrix4, result: Matrix4) { + result ||= new Matrix4(); + let m = matrix.rawData; + let r = result.rawData; + r[0] = m[0]; + r[1] = m[4]; + r[2] = m[8]; + r[3] = m[12]; + r[4] = m[1]; + r[5] = m[5]; + r[6] = m[9]; + r[7] = m[13]; + r[8] = m[2]; + r[9] = m[6]; + r[10] = m[10]; + r[11] = m[14]; + r[12] = m[3]; + r[13] = m[7]; + r[14] = m[11]; + r[15] = m[15]; + return result; + } + + /** + * private + */ + private static inverse(matrix: Matrix4, result: Matrix4) { + result ||= new Matrix4(); + let m = matrix.rawData; + let r = result.rawData; + + r[0] = m[5] * m[10] * m[15] - m[5] * m[14] * m[11] - m[6] * m[9] * m[15] + m[6] * m[13] * m[11] + m[7] * m[9] * m[14] - m[7] * m[13] * m[10]; + r[1] = -m[1] * m[10] * m[15] + m[1] * m[14] * m[11] + m[2] * m[9] * m[15] - m[2] * m[13] * m[11] - m[3] * m[9] * m[14] + m[3] * m[13] * m[10]; + r[2] = m[1] * m[6] * m[15] - m[1] * m[14] * m[7] - m[2] * m[5] * m[15] + m[2] * m[13] * m[7] + m[3] * m[5] * m[14] - m[3] * m[13] * m[6]; + r[3] = -m[1] * m[6] * m[11] + m[1] * m[10] * m[7] + m[2] * m[5] * m[11] - m[2] * m[9] * m[7] - m[3] * m[5] * m[10] + m[3] * m[9] * m[6]; + + r[4] = -m[4] * m[10] * m[15] + m[4] * m[14] * m[11] + m[6] * m[8] * m[15] - m[6] * m[12] * m[11] - m[7] * m[8] * m[14] + m[7] * m[12] * m[10]; + r[5] = m[0] * m[10] * m[15] - m[0] * m[14] * m[11] - m[2] * m[8] * m[15] + m[2] * m[12] * m[11] + m[3] * m[8] * m[14] - m[3] * m[12] * m[10]; + r[6] = -m[0] * m[6] * m[15] + m[0] * m[14] * m[7] + m[2] * m[4] * m[15] - m[2] * m[12] * m[7] - m[3] * m[4] * m[14] + m[3] * m[12] * m[6]; + r[7] = m[0] * m[6] * m[11] - m[0] * m[10] * m[7] - m[2] * m[4] * m[11] + m[2] * m[8] * m[7] + m[3] * m[4] * m[10] - m[3] * m[8] * m[6]; + + r[8] = m[4] * m[9] * m[15] - m[4] * m[13] * m[11] - m[5] * m[8] * m[15] + m[5] * m[12] * m[11] + m[7] * m[8] * m[13] - m[7] * m[12] * m[9]; + r[9] = -m[0] * m[9] * m[15] + m[0] * m[13] * m[11] + m[1] * m[8] * m[15] - m[1] * m[12] * m[11] - m[3] * m[8] * m[13] + m[3] * m[12] * m[9]; + r[10] = m[0] * m[5] * m[15] - m[0] * m[13] * m[7] - m[1] * m[4] * m[15] + m[1] * m[12] * m[7] + m[3] * m[4] * m[13] - m[3] * m[12] * m[5]; + r[11] = -m[0] * m[5] * m[11] + m[0] * m[9] * m[7] + m[1] * m[4] * m[11] - m[1] * m[8] * m[7] - m[3] * m[4] * m[9] + m[3] * m[8] * m[5]; + + r[12] = -m[4] * m[9] * m[14] + m[4] * m[13] * m[10] + m[5] * m[8] * m[14] - m[5] * m[12] * m[10] - m[6] * m[8] * m[13] + m[6] * m[12] * m[9]; + r[13] = m[0] * m[9] * m[14] - m[0] * m[13] * m[10] - m[1] * m[8] * m[14] + m[1] * m[12] * m[10] + m[2] * m[8] * m[13] - m[2] * m[12] * m[9]; + r[14] = -m[0] * m[5] * m[14] + m[0] * m[13] * m[6] + m[1] * m[4] * m[14] - m[1] * m[12] * m[6] - m[2] * m[4] * m[13] + m[2] * m[12] * m[5]; + r[15] = m[0] * m[5] * m[10] - m[0] * m[9] * m[6] - m[1] * m[4] * m[10] + m[1] * m[8] * m[6] + m[2] * m[4] * m[9] - m[2] * m[8] * m[5]; + + let det = m[0] * r[0] + m[1] * r[4] + m[2] * r[8] + m[3] * r[12]; + for (let i = 0; i < 16; i++) { + r[i] /= det; + } + return result; + } + + private makeEuler(target: Vector3, toDegree: boolean, order: string = 'XYZ'): Vector3 { + const te = this.rawData; + const m11 = te[0]; + const m12 = te[4]; + const m13 = te[8]; + const m21 = te[1]; + const m22 = te[5]; + const m23 = te[9]; + const m31 = te[2]; + const m32 = te[6]; + const m33 = te[10]; + + switch (order) { + case 'XYZ': + target.y = Math.asin(clamp(m13, -1, 1)); + + if (Math.abs(m13) < 0.9999999) { + target.x = Math.atan2(-m23, m33); + target.z = Math.atan2(-m12, m11); + } else { + target.x = Math.atan2(m32, m22); + target.z = 0; + } + + break; + + case 'YXZ': + target.x = Math.asin(-clamp(m23, -1, 1)); + + if (Math.abs(m23) < 0.9999999) { + target.y = Math.atan2(m13, m33); + target.z = Math.atan2(m21, m22); + } else { + target.y = Math.atan2(-m31, m11); + target.z = 0; + } + + break; + + case 'ZXY': + target.x = Math.asin(clamp(m32, -1, 1)); + + if (Math.abs(m32) < 0.9999999) { + target.y = Math.atan2(-m31, m33); + target.z = Math.atan2(-m12, m22); + } else { + target.y = 0; + target.z = Math.atan2(m21, m11); + } + + break; + + case 'ZYX': + target.y = Math.asin(-clamp(m31, -1, 1)); + + if (Math.abs(m31) < 0.9999999) { + target.x = Math.atan2(m32, m33); + target.z = Math.atan2(m21, m11); + } else { + target.x = 0; + target.z = Math.atan2(-m12, m22); + } + + break; + + case 'YZX': + target.z = Math.asin(clamp(m21, -1, 1)); + + if (Math.abs(m21) < 0.9999999) { + target.x = Math.atan2(-m23, m22); + target.y = Math.atan2(-m31, m11); + } else { + target.x = 0; + target.y = Math.atan2(m13, m33); + } + + break; + + case 'XZY': + target.z = Math.asin(-clamp(m12, -1, 1)); + + if (Math.abs(m12) < 0.9999999) { + target.x = Math.atan2(m32, m22); + target.y = Math.atan2(m13, m11); + } else { + target.x = Math.atan2(-m23, m33); + target.y = 0; + } + + break; + + default: { + } + } + if (toDegree) { + target.multiplyScalar(RADIANS_TO_DEGREES); + } + return target; + } + + private frustum(l: number, r: number, b: number, t: number, n: number, f: number): Matrix4 { + let m = this.rawData; + + m[0] = (2 * n) / (r - l); + m[1] = 0; + m[2] = (r + l) / (r - l); + m[3] = 0; + + m[4] = 0; + m[5] = (2 * n) / (t - b); + m[6] = (t + b) / (t - b); + m[7] = 0; + + m[8] = 0; + m[9] = 0; + m[10] = -(f + n) / (f - n); + m[11] = (-2 * f * n) / (f - n); + + m[12] = 0; + m[13] = 0; + m[14] = -1; + m[15] = 0; + + return this; + } + + private setElements(n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44) { + + const te = this.rawData; + + te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14; + te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24; + te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34; + te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44; + + return this; + + } +} + +/** + * @internal + */ +export function multiplyMatrices4x4REF(lhs: Matrix4, rhs: Matrix4, res: Matrix4) { + for (let i = 0; i < 4; i++) { + res.rawData[i] = lhs.rawData[i] * rhs.rawData[0] + lhs.rawData[i + 4] * rhs.rawData[1] + lhs.rawData[i + 8] * rhs.rawData[2] + lhs.rawData[i + 12] * rhs.rawData[3]; + res.rawData[i + 4] = lhs.rawData[i] * rhs.rawData[4] + lhs.rawData[i + 4] * rhs.rawData[5] + lhs.rawData[i + 8] * rhs.rawData[6] + lhs.rawData[i + 12] * rhs.rawData[7]; + res.rawData[i + 8] = lhs.rawData[i] * rhs.rawData[8] + lhs.rawData[i + 4] * rhs.rawData[9] + lhs.rawData[i + 8] * rhs.rawData[10] + lhs.rawData[i + 12] * rhs.rawData[11]; + res.rawData[i + 12] = lhs.rawData[i] * rhs.rawData[12] + lhs.rawData[i + 4] * rhs.rawData[13] + lhs.rawData[i + 8] * rhs.rawData[14] + lhs.rawData[i + 12] * rhs.rawData[15]; + } +} + +/** + * @internal + */ +export function makeMatrix44ByQuaternion(pos: Vector3, scale: Vector3, rot: Quaternion) { + this.identity(); + Quaternion.quaternionToMatrix(rot, this); + this.appendTranslation(pos.x, pos.y, pos.z); + this.appendScale(scale.x, scale.y, scale.z); +} + +/** + * @internal + */ +export function makeMatrix44(r: Vector3, p: Vector3, s: Vector3, outMat: Matrix4) { + // Quaternion.CALCULATION_QUATERNION.fromEulerAngles(r.x, r.y, r.z); + + let rawData = outMat.rawData; + + let x: number = r.x * DEGREES_TO_RADIANS; + let y: number = r.y * DEGREES_TO_RADIANS; + let z: number = r.z * DEGREES_TO_RADIANS; + let w: number = 0; + + let halfX: number = x * 0.5; + let halfY: number = y * 0.5; + let halfZ: number = z * 0.5; + + let cosX: number = Math.cos(halfX); + let sinX: number = Math.sin(halfX); + let cosY: number = Math.cos(halfY); + let sinY: number = Math.sin(halfY); + let cosZ: number = Math.cos(halfZ); + let sinZ: number = Math.sin(halfZ); + + w = cosX * cosY * cosZ + sinX * sinY * sinZ; + x = sinX * cosY * cosZ - cosX * sinY * sinZ; + y = cosX * sinY * cosZ + sinX * cosY * sinZ; + z = cosX * cosY * sinZ - sinX * sinY * cosZ; + + let x2 = x + x; + let y2 = y + y; + let z2 = z + z; + + let xx = x * x2; + let xy = x * y2; + let xz = x * z2; + let yy = y * y2; + let yz = y * z2; + let zz = z * z2; + let wx = w * x2; + let wy = w * y2; + let wz = w * z2; + let sx = s.x; + let sy = s.y; + let sz = s.z; + + rawData[0] = (1 - (yy + zz)) * sx; + rawData[1] = (xy + wz) * sx; + rawData[2] = (xz - wy) * sx; + rawData[3] = 0; + rawData[4] = (xy - wz) * sy; + rawData[5] = (1 - (xx + zz)) * sy; + rawData[6] = (yz + wx) * sy; + rawData[7] = 0; + rawData[8] = (xz + wy) * sz; + rawData[9] = (yz - wx) * sz; + rawData[10] = (1 - (xx + yy)) * sz; + rawData[11] = 0; + rawData[12] = p.x; + rawData[13] = p.y; + rawData[14] = p.z; + rawData[15] = 1; +} + +/** + * @internal + */ +export function append(src: Matrix4, lhs: Matrix4, target: Matrix4): void { + let data = src.rawData; + let targetData = target.rawData; + let m111: number = data[0]; + let m121: number = data[4]; + let m131: number = data[8]; + let m141: number = data[12]; + let m112: number = data[1]; + let m122: number = data[5]; + let m132: number = data[9]; + let m142: number = data[13]; + let m113: number = data[2]; + let m123: number = data[6]; + let m133: number = data[10]; + let m143: number = data[14]; + let m114: number = data[3]; + let m124: number = data[7]; + let m134: number = data[11]; + let m144: number = data[15]; + + targetData[0] = m111 * lhs.rawData[0] + m112 * lhs.rawData[4] + m113 * lhs.rawData[8] + m114 * lhs.rawData[12]; + targetData[1] = m111 * lhs.rawData[1] + m112 * lhs.rawData[5] + m113 * lhs.rawData[9] + m114 * lhs.rawData[13]; + targetData[2] = m111 * lhs.rawData[2] + m112 * lhs.rawData[6] + m113 * lhs.rawData[10] + m114 * lhs.rawData[14]; + targetData[3] = m111 * lhs.rawData[3] + m112 * lhs.rawData[7] + m113 * lhs.rawData[11] + m114 * lhs.rawData[15]; + + targetData[4] = m121 * lhs.rawData[0] + m122 * lhs.rawData[4] + m123 * lhs.rawData[8] + m124 * lhs.rawData[12]; + targetData[5] = m121 * lhs.rawData[1] + m122 * lhs.rawData[5] + m123 * lhs.rawData[9] + m124 * lhs.rawData[13]; + targetData[6] = m121 * lhs.rawData[2] + m122 * lhs.rawData[6] + m123 * lhs.rawData[10] + m124 * lhs.rawData[14]; + targetData[7] = m121 * lhs.rawData[3] + m122 * lhs.rawData[7] + m123 * lhs.rawData[11] + m124 * lhs.rawData[15]; + + targetData[8] = m131 * lhs.rawData[0] + m132 * lhs.rawData[4] + m133 * lhs.rawData[8] + m134 * lhs.rawData[12]; + targetData[9] = m131 * lhs.rawData[1] + m132 * lhs.rawData[5] + m133 * lhs.rawData[9] + m134 * lhs.rawData[13]; + targetData[10] = m131 * lhs.rawData[2] + m132 * lhs.rawData[6] + m133 * lhs.rawData[10] + m134 * lhs.rawData[14]; + targetData[11] = m131 * lhs.rawData[3] + m132 * lhs.rawData[7] + m133 * lhs.rawData[11] + m134 * lhs.rawData[15]; + + targetData[12] = m141 * lhs.rawData[0] + m142 * lhs.rawData[4] + m143 * lhs.rawData[8] + m144 * lhs.rawData[12]; + targetData[13] = m141 * lhs.rawData[1] + m142 * lhs.rawData[5] + m143 * lhs.rawData[9] + m144 * lhs.rawData[13]; + targetData[14] = m141 * lhs.rawData[2] + m142 * lhs.rawData[6] + m143 * lhs.rawData[10] + m144 * lhs.rawData[14]; + targetData[15] = m141 * lhs.rawData[3] + m142 * lhs.rawData[7] + m143 * lhs.rawData[11] + m144 * lhs.rawData[15]; +} + +/** + * @internal + */ +export function rotMatrix(mat: Matrix4, q: Quaternion) { + let x: number = q.x; + let y: number = q.y; + let z: number = q.z; + let w: number = q.w; + + let rawData: Float32Array = mat.rawData; + let xy2: number = 2.0 * x * y; + let xz2: number = 2.0 * x * z; + let xw2: number = 2.0 * x * w; + let yz2: number = 2.0 * y * z; + let yw2: number = 2.0 * y * w; + let zw2: number = 2.0 * z * w; + let xx: number = x * x; + let yy: number = y * y; + let zz: number = z * z; + let ww: number = w * w; + + rawData[0] = xx - yy - zz + ww; + rawData[4] = xy2 - zw2; + rawData[8] = xz2 + yw2; + rawData[12] = 0; + rawData[1] = xy2 + zw2; + rawData[5] = -xx + yy - zz + ww; + rawData[9] = yz2 - xw2; + rawData[13] = 0; + rawData[2] = xz2 - yw2; + rawData[6] = yz2 + xw2; + rawData[10] = -xx - yy + zz + ww; + rawData[14] = 0; + rawData[3] = 0.0; + rawData[7] = 0.0; + rawData[11] = 0; + rawData[15] = 1; + return mat; +} + +/** + * @internal + */ +export function matrixRotateY(rad: number, target: Matrix4) { + let out = target.rawData; + let s = Math.sin(rad); + let c = Math.cos(rad); + out[0] = c; + out[1] = 0; + out[2] = -s; + out[3] = 0; + out[8] = s; + out[9] = 0; + out[10] = c; + out[11] = 0; + return out; +} + +/** + * Rotates a mat4 by the given angle around the given axis + * @internal + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @param {ReadonlyVec3} axis the axis to rotate around + * @returns {mat4} out + */ +export function matrixRotate(rad: number, axis: Vector3, target: Matrix4) { + let x = axis.x; + let y = axis.y; + let z = axis.z; + let len = Math.hypot(x, y, z); + let s; + let c; + let t; + let a23; + let b00; + let b01; + let b02; + let b10; + let b11; + let b12; + let b20; + let b21; + let b22; + + if (len < EPSILON) { + return null; + } + + len = 1 / len; + x *= len; + y *= len; + z *= len; + s = Math.sin(rad); + c = Math.cos(rad); + t = 1 - c; + a23 = 0; // Construct the elements of the rotation matrix + + b00 = x * x * t + c; + b01 = y * x * t + z * s; + b02 = z * x * t - y * s; + b10 = x * y * t - z * s; + b11 = y * y * t + c; + b12 = z * y * t + x * s; + b20 = x * z * t + y * s; + b21 = y * z * t - x * s; + b22 = z * z * t + c; // Perform rotation-specific matrix multiplication + + let out = target.rawData; + out[0] = b00; + out[1] = b01; + out[2] = b02; + out[3] = 0; + out[4] = b10; + out[5] = b11; + out[6] = b12; + out[7] = 0; + out[8] = b20; + out[9] = b21; + out[10] = b22; + out[11] = 0; + + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + + return out; +} + +/** + * @internal + */ +export function matrixMultiply(aMat: Matrix4, bMat: Matrix4, target: Matrix4) { + let a = aMat.rawData; + let a00 = a[0]; + let a01 = a[1]; + let a02 = a[2]; + let a03 = a[3]; + let a10 = a[4]; + let a11 = a[5]; + let a12 = a[6]; + let a13 = a[7]; + let a20 = a[8]; + let a21 = a[9]; + let a22 = a[10]; + let a23 = a[11]; + let a30 = a[12]; + let a31 = a[13]; + let a32 = a[14]; + let a33 = a[15]; // Cache only the current line of the second matrix + + let b = bMat.rawData; + let out = target.rawData; + + let b0 = b[0]; + let b1 = b[1]; + let b2 = b[2]; + let b3 = b[3]; + out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + b0 = b[4]; + b1 = b[5]; + b2 = b[6]; + b3 = b[7]; + out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + b0 = b[8]; + b1 = b[9]; + b2 = b[10]; + b3 = b[11]; + out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + b0 = b[12]; + b1 = b[13]; + b2 = b[14]; + b3 = b[15]; + out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + return out; +} diff --git a/src/engine/math/Quaternion.ts b/src/engine/math/Quaternion.ts new file mode 100644 index 00000000..a051b0aa --- /dev/null +++ b/src/engine/math/Quaternion.ts @@ -0,0 +1,596 @@ +import { DEGREES_TO_RADIANS, RADIANS_TO_DEGREES } from './MathUtil'; +import { Orientation3D } from './Orientation3D'; +import { Vector3 } from './Vector3'; + +/** + * Quaternions are used to represent rotations. + * @group Math + */ +export class Quaternion { + public static HELP_0: Quaternion = new Quaternion(); + public static HELP_1: Quaternion = new Quaternion(); + public static HELP_2: Quaternion = new Quaternion(); + public static _zero: Quaternion = new Quaternion(0, 0, 0, 1); + public static CALCULATION_QUATERNION: Quaternion = new Quaternion(); + /** + * @internal + */ + public x: number = 0; + /** + * @internal + */ + public y: number = 0; + /** + * @internal + */ + public z: number = 0; + /** + * @internal + */ + public w: number = 1; + + /** + * Create a new quaternion object + * @param x The X component of a quaternion. + * @param y The Y component of a quaternion. + * @param z The Z component of a quaternion. + * @param w The W component of a quaternion. + */ + constructor(x: number = 0, y: number = 0, z: number = 0, w: number = 1) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + /** + * Identity quaternion + * @returns + */ + public static identity() { + return Quaternion._zero; + } + + /** + * Converts quaternions to matrices + * @param q Quaternion + * @param m Matrix + */ + public static quaternionToMatrix(q: Quaternion, m: any) { + // If q is guaranteed to be a unit quaternion, s will always + // be 1. In that case, this calculation can be optimized out. + //float norm = GetNorm (q); + //float s = (norm > 0.0) ? 2.0/norm : 0; + + // Precalculate coordinate products + let x = q.x * 2.0; + let y = q.y * 2.0; + let z = q.z * 2.0; + let xx = q.x * x; + let yy = q.y * y; + let zz = q.z * z; + let xy = q.x * y; + let xz = q.x * z; + let yz = q.y * z; + let wx = q.w * x; + let wy = q.w * y; + let wz = q.w * z; + + // Calculate 3x3 matrix from orthonormal basis + m.rawData[0] = 1.0 - (yy + zz); + m.rawData[1] = xy + wz; + m.rawData[2] = xz - wy; + m.rawData[3] = 0.0; + + m.rawData[4] = xy - wz; + m.rawData[5] = 1.0 - (xx + zz); + m.rawData[6] = yz + wx; + m.rawData[7] = 0.0; + + m.rawData[8] = xz + wy; + m.rawData[9] = yz - wx; + m.rawData[10] = 1.0 - (xx + yy); + m.rawData[11] = 0.0; + + m.rawData[12] = 0.0; + m.rawData[13] = 0.0; + m.rawData[14] = 0.0; + m.rawData[15] = 1.0; + } + + public get magnitude(): number { + return Math.sqrt(this.w * this.w + this.x * this.x + this.y * this.y + this.z * this.z); + } + + /** + * Set the x, y, z, and w components of the existing quaternions. + * @param x The X component of a quaternion. + * @param y The Y component of a quaternion. + * @param z The Z component of a quaternion. + * @param w The W component of a quaternion. + */ + public set(x: number = 0, y: number = 0, z: number = 0, w: number = 1) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public divide(v): Quaternion { + if (v instanceof Quaternion) { + return new Quaternion(this.x / v.x, this.y / v.y, this.z / v.z); + } + else { + this.x = this.x / v; + this.y = this.y / v; + this.z = this.z / v; + } + return this; + } + + /** + * @internal + */ + public setFromArray(d: Float32Array | number[]) { + this.x = d[0]; + this.y = d[1]; + this.z = d[2]; + this.w = d[3]; + return this; + } + + /** + * Multiply two quaternions + * @param qa Quaternion 1 + * @param qb Quaternion 2 + */ + public multiply(qa: Quaternion, qb: Quaternion) { + var w1: number = qa.w; + var x1: number = qa.x; + var y1: number = qa.y; + var z1: number = qa.z; + var w2: number = qb.w; + var x2: number = qb.x; + var y2: number = qb.y; + var z2: number = qb.z; + + this.w = w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2; + this.x = w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2; + this.y = w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2; + this.z = w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2; + } + + public multiplyVector(vector: Vector3, target: Quaternion = null): Quaternion { + target ||= new Quaternion(); + var x2: number = vector.x; + var y2: number = vector.y; + var z2: number = vector.z; + + target.w = -this.x * x2 - this.y * y2 - this.z * z2; + target.x = this.w * x2 + this.y * z2 - this.z * y2; + target.y = this.w * y2 - this.x * z2 + this.z * x2; + target.z = this.w * z2 + this.x * y2 - this.y * x2; + + return target; + } + + /** + * Set the quaternion with a given rotation of the axis and Angle. + * @param axis axis + * @param angle angle + */ + public fromAxisAngle(axis: Vector3, angle: number) { + angle *= Math.PI / 180.0; + var halfAngle: number = angle * 0.5; + var sinA: number = Math.sin(halfAngle); + + this.w = Math.cos(halfAngle); + this.x = axis.x * sinA; + this.y = axis.y * sinA; + this.z = axis.z * sinA; + + this.normalize(); + } + + /** + * Turn quaternions into angles + * @param axis axis + * @returns + */ + public toAxisAngle(axis: Vector3): number { + var sqrLength: number = this.x * this.x + this.y * this.y + this.z * this.z; + var angle: number = 0; + if (sqrLength > 0.0) { + angle = 2.0 * Math.acos(this.w); + sqrLength = 1.0 / Math.sqrt(sqrLength); + axis.x = this.x * sqrLength; + axis.y = this.y * sqrLength; + axis.z = this.z * sqrLength; + } else { + angle = 0; + axis.x = 1.0; + axis.y = 0; + axis.z = 0; + } + // angle /= Math.PI / 180.0; + return angle; + } + + /** + * Spherically interpolates between two quaternions, providing an interpolation between rotations with constant angle change rate. + * @param qa The first quaternion to interpolate. + * @param qb The second quaternion to interpolate. + * @param t The interpolation weight, a value between 0 and 1. + */ + public slerp(qa: Quaternion, qb: Quaternion, t: number) { + var w1: number = qa.w; + var x1: number = qa.x; + var y1: number = qa.y; + var z1: number = qa.z; + var w2: number = qb.w; + var x2: number = qb.x; + var y2: number = qb.y; + var z2: number = qb.z; + var dot: number = w1 * w2 + x1 * x2 + y1 * y2 + z1 * z2; + + // shortest direction + if (dot < 0) { + dot = -dot; + w2 = -w2; + x2 = -x2; + y2 = -y2; + z2 = -z2; + } + + if (dot < 0.95) { + // interpolate angle linearly + var angle: number = Math.acos(dot); + var s: number = 1 / Math.sin(angle); + var s1: number = Math.sin(angle * (1 - t)) * s; + var s2: number = Math.sin(angle * t) * s; + this.w = w1 * s1 + w2 * s2; + this.x = x1 * s1 + x2 * s2; + this.y = y1 * s1 + y2 * s2; + this.z = z1 * s1 + z2 * s2; + } else { + // nearly identical angle, interpolate linearly + this.w = w1 + t * (w2 - w1); + this.x = x1 + t * (x2 - x1); + this.y = y1 + t * (y2 - y1); + this.z = z1 + t * (z2 - z1); + var len: number = 1.0 / Math.sqrt(this.w * this.w + this.x * this.x + this.y * this.y + this.z * this.z); + this.w *= len; + this.x *= len; + this.y *= len; + this.z *= len; + } + } + + /** + * Linearly interpolates between two quaternions. + * @param qa The first quaternion to interpolate. + * @param qb The second quaternion to interpolate. + * @param t The interpolation weight, a value between 0 and 1. + */ + public lerp(qa: Quaternion, qb: Quaternion, t: number) { + var w1: number = qa.w; + var x1: number = qa.x; + var y1: number = qa.y; + var z1: number = qa.z; + var w2: number = qb.w; + var x2: number = qb.x; + var y2: number = qb.y; + var z2: number = qb.z; + var len: number; + + // shortest direction + if (w1 * w2 + x1 * x2 + y1 * y2 + z1 * z2 < 0) { + w2 = -w2; + x2 = -x2; + y2 = -y2; + z2 = -z2; + } + + this.w = w1 + t * (w2 - w1); + this.x = x1 + t * (x2 - x1); + this.y = y1 + t * (y2 - y1); + this.z = z1 + t * (z2 - z1); + + len = 1.0 / Math.sqrt(this.w * this.w + this.x * this.x + this.y * this.y + this.z * this.z); + this.w *= len; + this.x *= len; + this.y *= len; + this.z *= len; + } + + /** + * Fills the quaternion object with values representing the given euler rotation. + * @param ax The angle in radians of the rotation around the ax axis. + * @param ay The angle in radians of the rotation around the ay axis. + * @param az The angle in radians of the rotation around the az axis. + */ + public fromEulerAngles(ax: number, ay: number, az: number): Quaternion { + ax *= DEGREES_TO_RADIANS; + ay *= DEGREES_TO_RADIANS; + az *= DEGREES_TO_RADIANS; + + var halfX: number = ax * 0.5; + var halfY: number = ay * 0.5; + var halfZ: number = az * 0.5; + var cosX: number = Math.cos(halfX); + var sinX: number = Math.sin(halfX); + var cosY: number = Math.cos(halfY); + var sinY: number = Math.sin(halfY); + var cosZ: number = Math.cos(halfZ); + var sinZ: number = Math.sin(halfZ); + + this.w = cosX * cosY * cosZ + sinX * sinY * sinZ; + this.x = sinX * cosY * cosZ - cosX * sinY * sinZ; + this.y = cosX * sinY * cosZ + sinX * cosY * sinZ; + this.z = cosX * cosY * sinZ - sinX * sinY * cosZ; + + return this; + } + + /** + * Fills a target Vector3D object with the Euler angles that form the rotation represented by this quaternion. + * @param target An optional Vector3D object to contain the Euler angles. If not provided, a new object is created. + * @returns The Vector3D containing the Euler angles. + */ + public toEulerAngles(target: Vector3 = null): Vector3 { + target ||= new Vector3(); + target.x = Math.atan2(2.0 * (this.w * this.x + this.y * this.z), 1.0 - 2.0 * (this.x * this.x + this.y * this.y)); + + var temp: number = 2.0 * (this.w * this.y - this.z * this.x); + temp = this.clampf(temp, -1.0, 1.0); + target.y = Math.asin(temp); + target.z = Math.atan2(2.0 * (this.w * this.z + this.x * this.y), 1.0 - 2.0 * (this.y * this.y + this.z * this.z)); + + target.x /= DEGREES_TO_RADIANS; + target.y /= DEGREES_TO_RADIANS; + target.z /= DEGREES_TO_RADIANS; + return target; + } + + /** + * Sets the current quaternion from the rotation matrix + * @param m + * @returns + */ + public setFromRotationMatrix(m: any) { + const te = m.rawData; + const m11 = te[0]; + const m12 = te[4]; + const m13 = te[8]; + const m21 = te[1]; + const m22 = te[5]; + const m23 = te[9]; + const m31 = te[2]; + const m32 = te[6]; + const m33 = te[10]; + const trace = m11 + m22 + m33; + + if (trace > 0) { + const s = 0.5 / Math.sqrt(trace + 1.0); + + this.w = 0.25 / s; + this.x = (m32 - m23) * s; + this.y = (m13 - m31) * s; + this.z = (m21 - m12) * s; + } else if (m11 > m22 && m11 > m33) { + const s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33); + + this.w = (m32 - m23) / s; + this.x = 0.25 * s; + this.y = (m12 + m21) / s; + this.z = (m13 + m31) / s; + } else if (m22 > m33) { + const s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33); + + this.w = (m13 - m31) / s; + this.x = (m12 + m21) / s; + this.y = 0.25 * s; + this.z = (m23 + m32) / s; + } else { + const s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22); + + this.w = (m21 - m12) / s; + this.x = (m13 + m31) / s; + this.y = (m23 + m32) / s; + this.z = 0.25 * s; + } + + return this; + } + + /** + * Get the Euler Angle + * @param eulers + * @returns + */ + public getEulerAngles(eulers?: Vector3) { + var x; + var y; + var z; + var qx; + var qy; + var qz; + var qw; + var a2; + + eulers = eulers === undefined ? new Vector3() : eulers; + + qx = this.x; + qy = this.y; + qz = this.z; + qw = this.w; + + a2 = 2 * (qw * qy - qx * qz); + if (a2 <= -0.99999) { + x = 2 * Math.atan2(qx, qw); + y = -Math.PI / 2; + z = 0; + } else if (a2 >= 0.99999) { + x = 2 * Math.atan2(qx, qw); + y = Math.PI / 2; + z = 0; + } else { + x = Math.atan2(2 * (qw * qx + qy * qz), 1 - 2 * (qx * qx + qy * qy)); + y = Math.asin(a2); + z = Math.atan2(2 * (qw * qz + qx * qy), 1 - 2 * (qy * qy + qz * qz)); + } + + return eulers.set(x, y, z).scaleBy(RADIANS_TO_DEGREES); + } + + /** + * The normalize of the quaternion. Convert this quaternion to a normalize coefficient. + * @param val normalize coefficient, which is 1 by default + */ + public normalize(val: number = 1): void { + var mag: number = val / Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); + + this.x *= mag; + this.y *= mag; + this.z *= mag; + this.w *= mag; + } + + /** + * Returns the value of a quaternion as a string + * @returns + */ + public toString(): string { + return '{x:' + this.x + ' y:' + this.y + ' z:' + this.z + ' w:' + this.w + '}'; + } + + /** + * Extracts a quaternion rotation matrix out of a given Matrix3D object. + * @param matrix The Matrix3D out of which the rotation will be extracted. + */ + public fromMatrix(matrix: any) { + var v: Vector3 = matrix.decompose(Orientation3D.QUATERNION)[1]; + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.w = v.w; + } + + /** + * Returns a quaternion that inverts the current quaternion + * @param target The default parameter is null. If the current parameter is null, a new quaternion object is returned + * @returns Quaternion Result + */ + public inverse(target: Quaternion = null): Quaternion { + target ||= new Quaternion(); + + var norm: number = this.w * this.w + this.x * this.x + this.y * this.y + this.z * this.z; + + if (norm > 0.0) { + var invNorm = 1.0 / norm; + target.w = this.w * invNorm; + target.x = -this.x * invNorm; + target.y = -this.y * invNorm; + target.z = -this.z * invNorm; + } + + return target; + } + + /** + * Clones the quaternion. + * @returns An exact duplicate of the current Quaternion. + */ + public clone(): Quaternion { + return new Quaternion(this.x, this.y, this.z, this.w); + } + + /** + * Rotates a point. + * @param vector The Vector3D object to be rotated. + * @param target An optional Vector3D object that will contain the rotated coordinates. If not provided, a new object will be created. + * @returns A Vector3D object containing the rotated point. + */ + public transformVector(vector: Vector3, target: Vector3 = null): Vector3 { + var x1: number; + var y1: number; + var z1: number; + var w1: number; + var x2: number = vector.x; + var y2: number = vector.y; + var z2: number = vector.z; + + target ||= new Vector3(); + + // p*q' + w1 = -this.x * x2 - this.y * y2 - this.z * z2; + x1 = this.w * x2 + this.y * z2 - this.z * y2; + y1 = this.w * y2 - this.x * z2 + this.z * x2; + z1 = this.w * z2 + this.x * y2 - this.y * x2; + + target.x = -w1 * this.x + x1 * this.w - y1 * this.z + z1 * this.y; + target.y = -w1 * this.y + x1 * this.z + y1 * this.w - z1 * this.x; + target.z = -w1 * this.z - x1 * this.y + y1 * this.x + z1 * this.w; + return target; + } + + /** + * Copies the data from a quaternion into this instance. + * @param q The quaternion to copy from. + */ + public copyFrom(q: Quaternion | Vector3) { + var v = this; + v.x = q.x; + v.y = q.y; + v.z = q.z; + v.w = q.w; + } + + /** + * from untiy API + * op + */ + public mul(lhs: Quaternion, rhs: Quaternion, target?: Quaternion) { + let ret = target || new Quaternion(); + ret.x = lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y; + ret.y = lhs.w * rhs.y + lhs.y * rhs.w + lhs.z * rhs.x - lhs.x * rhs.z; + ret.z = lhs.w * rhs.z + lhs.z * rhs.w + lhs.x * rhs.y - lhs.y * rhs.x; + ret.w = lhs.w * rhs.w - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z; + return ret; + } + + private clampf(value: number, minInclusive: number, maxInclusive: number): number { + if (minInclusive > maxInclusive) { + var temp: number = minInclusive; + minInclusive = maxInclusive; + maxInclusive = temp; + } + return value < minInclusive ? minInclusive : value < maxInclusive ? value : maxInclusive; + } +} + +/** + * @internal + */ +export function rotateVectorByQuat(lhs: Quaternion, rhs: Vector3, target: Vector3) { + let x = lhs.x * 2.0; + let y = lhs.y * 2.0; + let z = lhs.z * 2.0; + let xx = lhs.x * x; + let yy = lhs.y * y; + let zz = lhs.z * z; + let xy = lhs.x * y; + let xz = lhs.x * z; + let yz = lhs.y * z; + let wx = lhs.w * x; + let wy = lhs.w * y; + let wz = lhs.w * z; + + let res = target ? target : new Vector3(); + res.x = (1.0 - (yy + zz)) * rhs.x + (xy - wz) * rhs.y + (xz + wy) * rhs.z; + res.y = (xy + wz) * rhs.x + (1.0 - (xx + zz)) * rhs.y + (yz - wx) * rhs.z; + res.z = (xz - wy) * rhs.x + (yz + wx) * rhs.y + (1.0 - (xx + yy)) * rhs.z; + + // AssertIf (!CompareApproximately (restest, res)); + return res; +} From 4bc0446b9a7fe30f37a0994ce46c45b07cbe74c7 Mon Sep 17 00:00:00 2001 From: JingwenBai <98864137+JingwenBai@users.noreply.github.com> Date: Sun, 23 Apr 2023 10:58:18 +0100 Subject: [PATCH 020/100] feat(event): add event lib (#21) add mouseCode module add keyCode module add CResizeEvent module add CResizeListener module add CResizeDispatcher module add CEvent module --- src/engine/event/CEvent.ts | 122 ++++++++++++++++ src/engine/event/CEventDispatcher.ts | 210 +++++++++++++++++++++++++++ src/engine/event/CEventListener.ts | 61 ++++++++ src/engine/event/CResizeEvent.ts | 13 ++ src/engine/event/KeyCode.ts | 112 ++++++++++++++ src/engine/event/MouseCode.ts | 26 ++++ 6 files changed, 544 insertions(+) create mode 100644 src/engine/event/CEvent.ts create mode 100644 src/engine/event/CEventDispatcher.ts create mode 100644 src/engine/event/CEventListener.ts create mode 100644 src/engine/event/CResizeEvent.ts create mode 100644 src/engine/event/KeyCode.ts create mode 100644 src/engine/event/MouseCode.ts diff --git a/src/engine/event/CEvent.ts b/src/engine/event/CEvent.ts new file mode 100644 index 00000000..65e2503b --- /dev/null +++ b/src/engine/event/CEvent.ts @@ -0,0 +1,122 @@ +import { Object3D, View3D } from '../..'; +import { TouchData } from '../io/TouchData'; +import { CEventListener } from './CEventListener'; +/** + * Basic class of Event + * @group Events + */ +export class CEvent { + /** + * Event target, it's usually event dispatcher + */ + public target: Object3D; + + /** + * Current event target, it's current bubble object + */ + public currentTarget: CEventListener; + + /** + * event type, it's registered string of key + */ + public type: string; + + /** + * extra data.Used for the transmission process of events, carrying data + */ + public data: any; + + /** + * + * The param data when event is registered + */ + public param: any; + + /** + * + * the time when event is + */ + public time: number = 0; + + /** + * + *the delay time when event is dispatched. + */ + public delay: number = 0; + + /** + * + * mouse code, see @MouseCode {@link MouseCode} + */ + public mouseCode: number = 0; + + /** + * Is Ctrl key pressed when the event occurs + */ + public ctrlKey: boolean; + + /** + * Is Alt key pressed when the event occurs + */ + public altKey: boolean; + + /** + * Is Shift key pressed when the event occurs + */ + public shiftKey: boolean; + + /** + * Collection of finger touch points, which registered + */ + public targetTouches: Array; + + /** + * Collection of finger touch points changed + */ + public changedTouches: Array; + + /** + * Collection of finger touch points + */ + public touches: Array; + + private _stopImmediatePropagation: boolean = false; + + /** + * binded view3D object in event. + */ + public view: View3D; + + /** + * + * Create a new event, with type and data + * @param eventType {any} eventType + * @param data {any} param + */ + constructor(eventType: string = null, data: any = null) { + this.type = eventType; + this.data = data; + } + /** + * + * Prevent bubbling of all event listeners in subsequent nodes of the current node in the event flow. + */ + public stopImmediatePropagation() { + this._stopImmediatePropagation = true; + } + + /** + * @internal + * set stopImmediatePropagation as false + */ + public reset() { + this._stopImmediatePropagation = false; + } + + /** + * Returns stopImmediatePropagation value + */ + public get isStopImmediatePropagation(): boolean { + return this._stopImmediatePropagation; + } +} diff --git a/src/engine/event/CEventDispatcher.ts b/src/engine/event/CEventDispatcher.ts new file mode 100644 index 00000000..3ed52d44 --- /dev/null +++ b/src/engine/event/CEventDispatcher.ts @@ -0,0 +1,210 @@ +import { CEvent } from './CEvent'; +import { CEventListener } from './CEventListener'; + +/** + * Basic class of event diapatcher. + * It includes the implementation of functions such as event registration, + * deregistration, distribution, and unregister. + * @group Events + */ +export class CEventDispatcher { + /** + * @internal + */ + protected listeners: any = {}; + /** + * @internal + */ + public data: any; + /** + * + * Dispatch an event to all registered objects with a specific type of listener. + * @param event3D the event is dispatched. + */ + public dispatchEvent(event: CEvent) { + var list: any = this.listeners[event.type]; + if (list != null) { + list = list.slice(); + for (var i: number = 0; i < list.length; i++) { + var listener: CEventListener = list[i]; + if (listener.handler) { + try { + event.param = listener.param; + event.currentTarget = listener; + if (!listener.thisObject) { + // log("nullListener thisObject"); + } + listener.handler.call(listener.thisObject, event); + } catch (error) { + // if (window.//console) { + //console.error(error.stack); + // } + } + if (event.isStopImmediatePropagation) { + break; + } + } + } + } + } + + /** + * + * release all registered event. + */ + public dispose() { + for (var key in this.listeners) { + var list: any = this.listeners[key]; + while (list.length > 0) { + var listener: CEventListener = list[0]; + listener.handler = null; + listener.thisObject = null; + list.splice(0, 1); + } + } + } + + /** + * + * register an event listener to event distancher. + * @param type {string} event type. + * @param callback {Function} The callback function that handles events. + * This function must accept an Event3D object as its unique parameter and cannot return any result. + * for example:function(evt:Event3D):void。 + * @param thisObject {any} Current registration object, it'll call callback function。 + * @param param {any} the data binded to registered event, the default value is null。 + * @param priority {number} The priority of callback function execution, with a larger set value having priority to call + * @returns {number} Returns register event id + */ + public addEventListener(type: string | number, callback: Function, thisObject: any, param: any = null, priority: number = 0): number { + if (this.listeners[type] == null) { + this.listeners[type] = []; + } + + if (!this.hasEventListener(type, callback, thisObject)) { + var listener: CEventListener = new CEventListener(type, thisObject, callback, param, priority); + listener.id = ++CEventListener.event_id_count; + listener.current = this; + this.listeners[type].push(listener); + this.listeners[type].sort(function (listener1: CEventListener, listener2: CEventListener) { + return listener2.priority - listener1.priority; + }); + + return listener.id; + } + + for (let i = 0; i < this.listeners[type].length; i++) { + let listener: CEventListener = this.listeners[type][i]; + if (listener.equalCurrentListener(type, callback, thisObject, param)) { + return listener.id; + } + } + + return 0; + } + + /** + * + * Remove Event Listening + * @param type {string} event type + * @param callback {Function} callback function of event register + * @param thisObject {any} The current registered object. + */ + public removeEventListener(type: string | number, callback: Function, thisObject: any): void { + if (this.hasEventListener(type, callback, thisObject)) { + for (var i: number = 0; i < this.listeners[type].length; i++) { + var listener: CEventListener = this.listeners[type][i]; + if (listener.equalCurrentListener(type, callback, thisObject, listener.param)) { + listener.handler = null; + listener.thisObject = null; + this.listeners[type].splice(i, 1); + return; + } + } + } + } + + /** + * + * Remove an event Listening with id + * @param register event id, see {@link addEventListener} + * Returns true when removed success. + */ + public removeEventListenerAt(id: number): boolean { + for (var key in this.listeners) { + for (var i: number = 0; i < this.listeners[key].length; i++) { + var listener = this.listeners[key][i]; + if (listener.id == id) { + listener.handler = null; + listener.thisObject = null; + this.listeners[key].splice(i, 1); + return true; + } + } + } + return false; + } + + /** + * + * Specify a event type to remove all related event listeners + * eventType event type, set null to remove all event listeners + */ + public removeAllEventListener(eventType: string | number = null): void { + let listener: CEventListener; + + if (eventType) { + if (this.listeners[eventType]) { + for (var i: number = 0; i < this.listeners[eventType].length; i++) { + listener = this.listeners[eventType][i]; + listener.dispose(); + this.listeners[eventType].splice(i, 1); + } + + delete this.listeners[eventType]; + } + } else { + for (let key in this.listeners) { + for (var i: number = 0; i < this.listeners[key].length; i++) { + listener = this.listeners[key][i]; + listener.dispose(); + this.listeners[key].splice(i, 1); + } + + delete this.listeners[key]; + } + } + } + + /** + * + * whether the target presence of a listener with event type. + * @param type {string} event type. + * @returns {boolean} Returns a boolean. + */ + public containEventListener(type: string): boolean { + if (this.listeners[type] == null) return false; + return this.listeners[type].length > 0; + } + + /** + * + * whether the target presence of a listener with event type. it associate more registration parameters. + * @param type {string} event name. + * @param callback {Function} callback function of event register. + * @param thisObject {any} The registered object. + * @returns {boolean} Returns a boolean. + */ + public hasEventListener(type: string | number, callback: Function = null, thisObject: any = null): boolean { + if (this.listeners[type] == null) return false; + if (thisObject && callback) { + for (var i: number = 0; i < this.listeners[type].length; i++) { + var listener: CEventListener = this.listeners[type][i]; + if (listener.equalCurrentListener(type, callback, thisObject, listener.param)) { + return true; + } + } + } + return false; + } +} diff --git a/src/engine/event/CEventListener.ts b/src/engine/event/CEventListener.ts new file mode 100644 index 00000000..c5f17328 --- /dev/null +++ b/src/engine/event/CEventListener.ts @@ -0,0 +1,61 @@ +/** + * The EventListener class is used to add or remove event listeners. + * @internal + * @group Events + */ +export class CEventListener { + /** + * @private + */ + public static event_id_count = 0; + + /** + * + * Record a id. When registering a listening event, the value will increase automatically + */ + public id: number = 0; + + /** + * + * Returns current event dispatcher + */ + public current: any; + + /** + * + * @param type {string} event type + * @param thisObject {any} the object is registerd + * @param handler {Function} The callback function that handles events. + * @param param {any} Parameters bound when registering events + * @param priority {number} The priority of callback function execution, with a larger set value having priority to call + */ + constructor(public type: string | number = null, public thisObject: any = null, public handler: Function = null, public param: any = null, public priority: number = 0) { } + + /** + * + * Compare whether two events are the same + * @param type {string} event type + * @param handler {Function} The callback function that handles events. + * @param thisObject {any} the object is registerd + * @param param {any} Parameters bound when registering events + * @returns {boolean} Returns a boolean + */ + public equalCurrentListener(type: string | number, handler: Function, thisObject: any, param: any): boolean { + if (this.type == type && this.thisObject == thisObject && this.handler == handler && this.param == param) { + return true; + } + return false; + } + + /** + * + * release all registered event. + */ + + public dispose() { + this.handler = null; + this.thisObject = null; + this.param = null; + this.priority = 0; + } +} diff --git a/src/engine/event/CResizeEvent.ts b/src/engine/event/CResizeEvent.ts new file mode 100644 index 00000000..e3ee17f0 --- /dev/null +++ b/src/engine/event/CResizeEvent.ts @@ -0,0 +1,13 @@ +import { CEvent } from './CEvent'; +/** + * size change event when canvas resized + * @internal + * @group Events + */ +export class CResizeEvent extends CEvent { + /** + * + * RESIZE:enum event type + */ + static RESIZE: string = 'resize'; +} diff --git a/src/engine/event/KeyCode.ts b/src/engine/event/KeyCode.ts new file mode 100644 index 00000000..3cb5c69f --- /dev/null +++ b/src/engine/event/KeyCode.ts @@ -0,0 +1,112 @@ +/** + * Represents a unique identifier corresponding to a keyboard button. see {@link KeyboardEvent.keyCode} + * @group Events + */ +export enum KeyCode { + Key_BackSpace = 8, + Key_Tab = 9, + Key_Clear = 12, + Key_Enter = 13, + Key_Shift_L = 16, + Key_Control_L = 17, + Key_Alt_L = 18, + Key_Pause = 19, + Key_CapsLock = 20, + Key_Escape = 21, + Key_Esc = 27, + Key_Space = 32, + Key_Prior = 33, + Key_Next = 34, + Key_End = 35, + Key_Home = 36, + Key_Left = 37, + Key_Up = 38, + Key_Right = 39, + Key_Down = 40, + Key_Select = 41, + Key_Print = 42, + Key_Execute = 43, + Key_Insert = 45, + Key_Delete = 46, + Key_Help = 47, + Key_0 = 48, + Key_1 = 49, + Key_2 = 50, + Key_3 = 51, + Key_4 = 52, + Key_5 = 53, + Key_6 = 54, + Key_7 = 55, + Key_8 = 56, + Key_9 = 57, + + Key_A = 65, + Key_B = 66, + Key_C = 67, + Key_D = 68, + Key_E = 69, + Key_F = 70, + Key_G = 71, + Key_H = 72, + Key_I = 73, + Key_J = 74, + Key_K = 75, + Key_L = 76, + Key_M = 77, + Key_N = 78, + Key_O = 79, + Key_P = 80, + Key_Q = 81, + Key_R = 82, + Key_S = 83, + Key_T = 84, + Key_U = 85, + Key_V = 86, + Key_W = 87, + Key_X = 88, + Key_Y = 89, + Key_Z = 90, + Key_KP_0 = 96, + Key_KP_1 = 97, + Key_KP_2 = 98, + Key_KP_3 = 99, + Key_KP_4 = 100, + Key_KP_5 = 101, + Key_KP_6 = 102, + Key_KP_7 = 103, + Key_KP_8 = 104, + Key_KP_9 = 105, + Key_Multiply = 106, + Key_Add = 107, + Key_Separator = 108, + Key_Subtract = 109, + Key_Decimal = 110, + Key_Divide = 111, + Key_F1 = 112, + Key_F2 = 113, + Key_F3 = 114, + Key_F4 = 115, + Key_F5 = 116, + Key_F6 = 117, + Key_F7 = 118, + Key_F8 = 119, + Key_F9 = 120, + Key_F10 = 121, + Key_F11 = 122, + Key_F12 = 123, + Key_F13 = 124, + Key_F14 = 125, + Key_F15 = 126, + Key_F16 = 127, + Key_F17 = 128, + Key_F18 = 129, + Key_F19 = 130, + Key_F20 = 131, + Key_F21 = 132, + Key_F22 = 133, + Key_F23 = 134, + Key_F24 = 135, + + Key_Num_Lock = 136, + Key_Scroll_Lock = 137, +} diff --git a/src/engine/event/MouseCode.ts b/src/engine/event/MouseCode.ts new file mode 100644 index 00000000..dabc3640 --- /dev/null +++ b/src/engine/event/MouseCode.ts @@ -0,0 +1,26 @@ +/** + * Mouse Key Code + * @group Events + */ +export enum MouseCode { + /** + * + * key code of mouse left + * + */ + MOUSE_LEFT = 0, + + /** + * + * key code of mouse middle + * + */ + MOUSE_MID = 1, + + /** + * + * key code of mouse right + * + */ + MOUSE_RIGHT = 2, +} From f1464416c2ff6805a78919bdf834a25292dc9a76 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Sun, 23 Apr 2023 18:07:40 +0800 Subject: [PATCH 021/100] feat(WebGPU): Add WebGPU Context (#18) create webgpu context , connect webgpu add material pass create add rgba image merage for computer compute IBL env map for PBR Material --- src/engine/gfx/generate/BrdfLUTGenerate.ts | 34 ++ src/engine/gfx/generate/PassGenerate.ts | 205 +++++++++++++ .../gfx/generate/convert/IBLEnvMapCreator.ts | 127 ++++++++ .../gfx/generate/convert/MergeRGBACreator.ts | 41 +++ .../gfx/generate/graphic/webgpu/Context3D.ts | 138 +++++++++ .../generate/graphic/webgpu/WebGPUConst.ts | 279 +++++++++++++++++ .../webgpu/core/bindGroups/GlobalBindGroup.ts | 59 ++++ .../core/bindGroups/GlobalBindGroupLayout.ts | 28 ++ .../core/bindGroups/GlobalUniformGroup.ts | 152 +++++++++ .../webgpu/core/bindGroups/MatrixBindGroup.ts | 44 +++ .../core/bindGroups/TexturesBindGroup.ts | 97 ++++++ .../core/bindGroups/groups/LightEntries.ts | 68 ++++ .../core/bindGroups/groups/ProbeEntries.ts | 53 ++++ .../gfx/generate/renderJob/GPUContext.ts | 290 ++++++++++++++++++ src/engine/math/Matrix4.ts | 2 +- 15 files changed, 1616 insertions(+), 1 deletion(-) create mode 100644 src/engine/gfx/generate/BrdfLUTGenerate.ts create mode 100644 src/engine/gfx/generate/PassGenerate.ts create mode 100644 src/engine/gfx/generate/convert/IBLEnvMapCreator.ts create mode 100644 src/engine/gfx/generate/convert/MergeRGBACreator.ts create mode 100644 src/engine/gfx/generate/graphic/webgpu/Context3D.ts create mode 100644 src/engine/gfx/generate/graphic/webgpu/WebGPUConst.ts create mode 100644 src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalBindGroup.ts create mode 100644 src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalBindGroupLayout.ts create mode 100644 src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalUniformGroup.ts create mode 100644 src/engine/gfx/generate/graphic/webgpu/core/bindGroups/MatrixBindGroup.ts create mode 100644 src/engine/gfx/generate/graphic/webgpu/core/bindGroups/TexturesBindGroup.ts create mode 100644 src/engine/gfx/generate/graphic/webgpu/core/bindGroups/groups/LightEntries.ts create mode 100644 src/engine/gfx/generate/graphic/webgpu/core/bindGroups/groups/ProbeEntries.ts create mode 100644 src/engine/gfx/generate/renderJob/GPUContext.ts diff --git a/src/engine/gfx/generate/BrdfLUTGenerate.ts b/src/engine/gfx/generate/BrdfLUTGenerate.ts new file mode 100644 index 00000000..d93c5651 --- /dev/null +++ b/src/engine/gfx/generate/BrdfLUTGenerate.ts @@ -0,0 +1,34 @@ +import BRDFLUT from '../../assets/shader/utils/BRDFLUT.wgsl?raw'; +import { VirtualTexture } from '../../textures/VirtualTexture'; +import { ComputeShader } from '../graphics/webGpu/shader/ComputeShader'; +import { GPUTextureFormat } from '../graphics/webGpu/WebGPUConst'; +import { GPUContext } from '../renderJob/GPUContext'; +/** + * @internal + * @group GFX + */ +export class BRDFLUTGenerate { + compute: ComputeShader; + + constructor() { + this.compute = new ComputeShader(BRDFLUT); + } + public generateBRDFLUTTexture() { + //create virtual texture + let texture = new VirtualTexture(256, 256, GPUTextureFormat.rgba8unorm, false, GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING); + + //set storageTexture + this.compute.setStorageTexture('brdflutTexture', texture); + + //set worker size + this.compute.workerSizeX = 256 / 8; + this.compute.workerSizeY = 256 / 8; + + //active + let commandEncoder = GPUContext.beginCommandEncoder(); + GPUContext.computeCommand(commandEncoder, [this.compute]); + GPUContext.endCommandEncoder(commandEncoder); + + return texture; + } +} diff --git a/src/engine/gfx/generate/PassGenerate.ts b/src/engine/gfx/generate/PassGenerate.ts new file mode 100644 index 00000000..7b037461 --- /dev/null +++ b/src/engine/gfx/generate/PassGenerate.ts @@ -0,0 +1,205 @@ +import { RenderNode } from '../../components/renderer/RenderNode'; +import { DepthMaterialPass } from '../../materials/multiPass/DepthMaterialPass'; +import { CastShadowMaterialPass } from '../../materials/multiPass/CastShadowMaterialPass'; +import { RendererType } from '../renderJob/passRenderer/state/RendererType'; +import { RendererMask, RendererMaskUtil } from '../renderJob/passRenderer/state/RendererMask'; +import { GLTFParser } from '../../loader/parser/gltf/GLTFParser'; +import { SkyGBufferPass } from '../../materials/multiPass/SkyGBufferPass'; +import { Color, ColorLitMaterial, GBufferPass, MaterialBase, RenderShader } from '../../..'; +import { CastPointShadowMaterialPass } from '../../materials/multiPass/CastPointShadowMaterialPass'; +/** + * @internal + * @group GFX + */ +export class PassGenerate { + public static createGIPass(renderNode: RenderNode, material: MaterialBase) { + if (RendererMaskUtil.hasMask(renderNode.rendererMask, RendererMask.Sky)) { + let pass = new SkyGBufferPass(); + pass.baseMap = material.baseMap; + + let baseMat = material; + let shader = pass.getShader(); + shader.shaderState.cullMode = baseMat.getShader().cullMode; + shader.shaderState.frontFace = baseMat.getShader().frontFace; + + material.addPass(RendererType.GI, pass, 0); + pass.renderShader.preCompile(renderNode.geometry); + } else { + this.castGBufferPass(renderNode, material); + } + } + + public static castGBufferPass(renderNode: RenderNode, material: MaterialBase) { + for (let i = 0; i < renderNode.materials.length; i++) { + const mat = renderNode.materials[i]; + let pass = mat.renderShader.getPassShader(RendererType.GI); + if (!pass) { + pass = new GBufferPass(); + let renderShader = pass.renderShader; + pass.baseColor = mat.baseColor; + pass.baseMap = mat.baseMap; + pass.normalMap = mat.normalMap; + pass.envIntensity = mat.envIntensity; + + pass.emissiveMap = mat.emissiveMap; + pass.emissiveColor = mat.emissiveColor; + pass.emissiveIntensity = mat.emissiveIntensity; + + pass.alphaCutoff = mat.alphaCutoff; + + let baseMat = renderNode.materials[0]; + let shader = pass.getShader(); + shader.shaderState.cullMode = baseMat.getShader().cullMode; + shader.shaderState.frontFace = baseMat.getShader().frontFace; + renderShader.preCompile(renderNode.geometry); + mat.renderShader.setPassShader(RendererType.GI, pass); + } + material.addPass(RendererType.GI, pass, i); + } + } + + public static createShadowPass(renderNode: RenderNode, material: MaterialBase) { + let use_skeleton = RendererMaskUtil.hasMask(renderNode.rendererMask, RendererMask.SkinnedMesh); + let useTangent = renderNode.geometry.hasAttribute('TANGENT'); + let useMorphTargets = renderNode.geometry.hasAttribute(GLTFParser.MORPH_POSITION_PREFIX + '0'); + let useMorphNormals = renderNode.geometry.hasAttribute(GLTFParser.MORPH_NORMAL_PREFIX + '0'); + + let shadowMaterialPass = material.renderShader.getPassShader(RendererType.SHADOW); + if (!shadowMaterialPass) { + shadowMaterialPass = new CastShadowMaterialPass(); + shadowMaterialPass.baseMap = renderNode.materials[0].baseMap; + shadowMaterialPass.alphaCutoff = renderNode.materials[0].alphaCutoff; + shadowMaterialPass.setDefine("USE_ALPHACUT", renderNode.materials[0].alphaCutoff < 1.0); + // shadowMaterialPass.doubleSide = false ; + for (let j = 0; j < 1; j++) { + const renderShader = shadowMaterialPass.renderShader; + if (useTangent) { + renderShader.setDefine(`USE_TANGENT`, useTangent); + } + if (use_skeleton) { + renderShader.setDefine(`USE_SKELETON`, use_skeleton); + } + if (useMorphTargets) { + renderShader.setDefine(`USE_MORPHTARGETS`, useMorphTargets); + } + if (useMorphNormals) { + renderShader.setDefine(`USE_MORPHNORMALS`, useMorphNormals); + } + // renderShader.shaderState.cullMode = baseMat.getShader().cullMode ; + renderShader.shaderState.cullMode = `front`; + renderShader.preCompile(renderNode.geometry); + } + material.renderShader.setPassShader(RendererType.SHADOW, shadowMaterialPass); + } + material.addPass(RendererType.SHADOW, shadowMaterialPass, 0); + + let castPointShadowMaterialPass = material.renderShader.getPassShader(RendererType.POINT_SHADOW); + if (!castPointShadowMaterialPass) { + castPointShadowMaterialPass = new CastPointShadowMaterialPass(); + castPointShadowMaterialPass.baseMap = renderNode.materials[0].baseMap; + castPointShadowMaterialPass.alphaCutoff = renderNode.materials[0].alphaCutoff; + castPointShadowMaterialPass.setDefine("USE_ALPHACUT", renderNode.materials[0].alphaCutoff < 1.0); + // castPointShadowMaterialPass.doubleSide = false ; + for (let j = 0; j < 1; j++) { + const renderShader = castPointShadowMaterialPass.renderShader; + if (useTangent) { + renderShader.setDefine(`USE_TANGENT`, useTangent); + } + if (use_skeleton) { + renderShader.setDefine(`USE_SKELETON`, use_skeleton); + } + if (useMorphTargets) { + renderShader.setDefine(`USE_MORPHTARGETS`, useMorphTargets); + } + if (useMorphNormals) { + renderShader.setDefine(`USE_MORPHNORMALS`, useMorphNormals); + } + // renderShader.shaderState.cullMode = baseMat.getShader().cullMode ; + renderShader.shaderState.cullMode = `front`; + renderShader.preCompile(renderNode.geometry); + } + material.renderShader.setPassShader(RendererType.POINT_SHADOW, castPointShadowMaterialPass); + } + material.addPass(RendererType.POINT_SHADOW, castPointShadowMaterialPass, 0); + } + + public static createReflectionPass(renderNode: RenderNode, material: MaterialBase) { + // let reflectionPass = material.renderShader.getPassShader(RendererType.REFLECTION); + // if (!reflectionPass) { + // reflectionPass = new ColorLitMaterial(); + // let baseMat = renderNode.materials[0]; + // reflectionPass.baseMap = baseMat.baseMap; + // let useTangent = renderNode.geometry.hasVertexAttribute('TANGENT'); + // let useMorphTargets = renderNode.geometry.hasVertexAttribute(GLTFParser.MORPH_POSITION_PREFIX + '0'); + // let useMorphNormals = renderNode.geometry.hasVertexAttribute(GLTFParser.MORPH_NORMAL_PREFIX + '0'); + + // let use_skeleton = RendererMaskUtil.hasMask(renderNode.rendererMask, RendererMask.SkinnedMesh); + + // let shader = reflectionPass.getShader(); + // shader.shaderState.cullMode = baseMat.getShader().cullMode; + // shader.shaderState.frontFace = baseMat.getShader().frontFace; + + // for (let j = 0; j < 1; j++) { + // const renderShader = reflectionPass.getShader(); + + // if (!useTangent) { + // renderShader.setDefine(`USE_TANGENT`, useTangent); + // } + // if (use_skeleton) { + // renderShader.setDefine(`USE_SKELETON`, use_skeleton); + // } + // if (useMorphTargets) { + // renderShader.setDefine(`USE_MORPHTARGETS`, useMorphTargets); + // } + // if (useMorphNormals) { + // renderShader.setDefine(`USE_MORPHNORMALS`, useMorphNormals); + // } + + // renderShader.preCompile(renderNode.geometry, reflectionPass); + // } + + // material.renderShader.setPassShader(RendererType.REFLECTION, reflectionPass); + // } + // material.addPass(RendererType.REFLECTION, reflectionPass, 0); + } + + public static createDepthPass(renderNode: RenderNode, material: MaterialBase) { + let depthMaterialPass = material.renderShader.getPassShader(RendererType.DEPTH); + if (!depthMaterialPass) { + let depthMaterialPass = new DepthMaterialPass(); + let baseMat = renderNode.materials[0]; + depthMaterialPass.baseMap = baseMat.baseMap; + let useTangent = renderNode.geometry.hasAttribute('TANGENT'); + let useMorphTargets = renderNode.geometry.hasAttribute(GLTFParser.MORPH_POSITION_PREFIX + '0'); + let useMorphNormals = renderNode.geometry.hasAttribute(GLTFParser.MORPH_NORMAL_PREFIX + '0'); + + let use_skeleton = RendererMaskUtil.hasMask(renderNode.rendererMask, RendererMask.SkinnedMesh); + + let shader = depthMaterialPass.getShader(); + shader.shaderState.cullMode = baseMat.getShader().cullMode; + shader.shaderState.frontFace = baseMat.getShader().frontFace; + + for (let j = 0; j < 1; j++) { + const renderShader = depthMaterialPass.getShader(); + + if (!useTangent) { + renderShader.setDefine(`USE_TANGENT`, useTangent); + } + if (use_skeleton) { + renderShader.setDefine(`USE_SKELETON`, use_skeleton); + } + if (useMorphTargets) { + renderShader.setDefine(`USE_MORPHTARGETS`, useMorphTargets); + } + if (useMorphNormals) { + renderShader.setDefine(`USE_MORPHNORMALS`, useMorphNormals); + } + + renderShader.preCompile(renderNode.geometry); + } + + material.renderShader.setPassShader(RendererType.DEPTH, depthMaterialPass); + } + material.addPass(RendererType.DEPTH, depthMaterialPass, 0); + } +} diff --git a/src/engine/gfx/generate/convert/IBLEnvMapCreator.ts b/src/engine/gfx/generate/convert/IBLEnvMapCreator.ts new file mode 100644 index 00000000..60bc52b0 --- /dev/null +++ b/src/engine/gfx/generate/convert/IBLEnvMapCreator.ts @@ -0,0 +1,127 @@ +import { Texture } from '../../graphics/webGpu/core/texture/Texture'; +import { webGPUContext } from '../../graphics/webGpu/Context3D'; +import IBLEnvMapCreator_compute from '../../../assets/shader/compute/IBLEnvMapCreator_compute.wgsl?raw'; +import { TextureCubeUtils } from './TextureCubeUtils'; +import { GPUContext } from '../../../..'; +/** + * @internal + * @group GFX + */ +export class IBLEnvMapCreator { + private static configBuffer: GPUBuffer = null; + private static quaternionBuffer: GPUBuffer = null; + private static blurSettingBuffer: GPUBuffer = null; + private static pipeline: GPUComputePipeline; + + static importantSample(image: { width: number; height: number; erpTexture: Texture }, dstSize: number, roughness: number, dstView: GPUTextureView): void { + const device = webGPUContext.device; + if (this.pipeline == null) { + this.pipeline = device.createComputePipeline({ + layout: `auto`, + compute: { + module: device.createShaderModule({ + code: IBLEnvMapCreator_compute, + }), + entryPoint: 'main', + }, + }); + } + const computePipeline = this.pipeline; + + //config + const configStride = 4 * 4; //4 float + this.configBuffer ||= device.createBuffer({ + size: configStride, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + device.queue.writeBuffer(this.configBuffer, 0, new Uint32Array([image.width, image.height, dstSize, dstSize])); + + const quaternionSize = 4 * 6; ////xyzw * float + //quaternion + if (!this.quaternionBuffer) { + this.quaternionBuffer = device.createBuffer({ + size: quaternionSize * 4 * 6, + usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, + }); + + let qArray = new Float32Array(4 * 6); + for (let i = 0; i < 6; i++) { + let q = TextureCubeUtils.getRotationToFace(i); + qArray[i * 4 + 0] = q.x; + qArray[i * 4 + 1] = q.y; + qArray[i * 4 + 2] = q.z; + qArray[i * 4 + 3] = q.w; + } + device.queue.writeBuffer(this.quaternionBuffer, 0, qArray); + } + + //roughness + this.blurSettingBuffer ||= device.createBuffer({ + size: configStride, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + device.queue.writeBuffer(this.blurSettingBuffer, 0, new Float32Array([roughness, 0, 0, 0])); + + //image + const inputImageBuffer = image.erpTexture; + + let entries0 = [ + { + binding: 0, + resource: { + buffer: this.configBuffer, + size: 4 * 4, + }, + }, + { + binding: 1, + resource: { + buffer: this.quaternionBuffer, + size: quaternionSize * 4, + }, + }, + { + binding: 2, + resource: inputImageBuffer.gpuSampler, + }, + { + binding: 3, + resource: inputImageBuffer.getGPUView(), + }, + ]; + + let entries1 = [ + { + binding: 0, + resource: { + buffer: this.blurSettingBuffer, + size: 4 * 4, + }, + }, + { + binding: 1, + resource: dstView, + }, + ]; + + const computeBindGroup0 = device.createBindGroup({ + layout: computePipeline.getBindGroupLayout(0), + entries: entries0, + }); + + const computeBindGroup1 = device.createBindGroup({ + layout: computePipeline.getBindGroupLayout(1), + entries: entries1, + }); + + const commandEncoder = GPUContext.beginCommandEncoder(); + const computePass = commandEncoder.beginComputePass(); + computePass.setPipeline(computePipeline); + computePass.setBindGroup(0, computeBindGroup0); + computePass.setBindGroup(1, computeBindGroup1); + computePass.dispatchWorkgroups(dstSize / 8, dstSize / 8, 6); + + computePass.end(); + GPUContext.endCommandEncoder(commandEncoder); + } +} diff --git a/src/engine/gfx/generate/convert/MergeRGBACreator.ts b/src/engine/gfx/generate/convert/MergeRGBACreator.ts new file mode 100644 index 00000000..142ecd1c --- /dev/null +++ b/src/engine/gfx/generate/convert/MergeRGBACreator.ts @@ -0,0 +1,41 @@ +import MergeRGBA_Cs from '../../../assets/shader/compute/MergeRGBA_Cs.wgsl?raw'; +import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { Texture } from '../../graphics/webGpu/core/texture/Texture'; +import { ComputeShader } from '../../graphics/webGpu/shader/ComputeShader'; +import { GPUTextureFormat } from '../../graphics/webGpu/WebGPUConst'; +import { GPUContext } from '../../renderJob/GPUContext'; +/** + * @internal + * @group GFX + */ +export class MergeRGBACreator { + public static merge(textureR: Texture, textureG: Texture, textureB: Texture, textureA: Texture) { + let w = 0; + let h = 0; + w = Math.max(textureR.width, w); + w = Math.max(textureG.width, w); + w = Math.max(textureB.width, w); + w = Math.max(textureA.width, w); + + h = Math.max(textureR.height, h); + h = Math.max(textureG.height, h); + h = Math.max(textureB.height, h); + h = Math.max(textureA.height, h); + let outTex = new VirtualTexture(w, h, GPUTextureFormat.rgba8unorm); + + let compute = new ComputeShader(MergeRGBA_Cs); + compute.setSamplerTexture('textureR', textureR); + compute.setSamplerTexture('textureG', textureG); + compute.setSamplerTexture('textureB', textureB); + compute.setSamplerTexture('textureA', textureA); + compute.setStorageTexture('outTex', outTex); + + compute.workerSizeX = Math.ceil(w / 8); + compute.workerSizeY = Math.ceil(h / 8); + + let command = GPUContext.beginCommandEncoder(); + GPUContext.computeCommand(command, [compute]); + GPUContext.endCommandEncoder(command); + return outTex; + } +} diff --git a/src/engine/gfx/generate/graphic/webgpu/Context3D.ts b/src/engine/gfx/generate/graphic/webgpu/Context3D.ts new file mode 100644 index 00000000..9c7b53e6 --- /dev/null +++ b/src/engine/gfx/generate/graphic/webgpu/Context3D.ts @@ -0,0 +1,138 @@ +import { CanvasConfig } from './CanvasConfig'; +/** + * @internal + */ +class Context3D { + public adapter: GPUAdapter; + public device: GPUDevice; + public context: GPUCanvasContext; + public aspect: number; + public presentationSize: number[] = [0, 0]; + public presentationFormat: GPUTextureFormat; + public canvas: HTMLCanvasElement; + + public windowWidth: number; + public windowHeight: number; + + + public sourceWidth: number; + public sourceHeight: number; + + public canvasConfig: CanvasConfig; + + public super: number = 1.0; + // initSize: number[]; + public get pixelRatio() { + return this.canvasConfig?.devicePixelRatio || window.devicePixelRatio || 1 + } + /** + * Configure canvas by CanvasConfig + * @param canvasConfig + * @returns + */ + async init(canvasConfig?: CanvasConfig): Promise { + this.canvasConfig = canvasConfig; + if (canvasConfig && canvasConfig.canvas) { + this.canvas = canvasConfig.canvas; + if (this.canvas === null) + throw new Error('no Canvas') + } else { + this.canvas = document.createElement('canvas'); + // this.canvas.style.position = 'fixed'; + this.canvas.style.position = `absolute`; + this.canvas.style.top = '0px'; + this.canvas.style.left = '0px'; + this.canvas.style.width = '100%'; + this.canvas.style.height = '100%'; + + // this.canvas.style.width = canvasConfig.width ? `${canvasConfig.width}px` : '100%'; + // this.canvas.style.height = canvasConfig.height ? `${canvasConfig.height}px` : '100%'; + + this.canvas.style.zIndex = canvasConfig?.zIndex ? canvasConfig.zIndex.toString() : '0'; + document.body.appendChild(this.canvas); + } + + this.resize(this.canvas.clientWidth, this.canvas.clientHeight) + if (canvasConfig && canvasConfig.backgroundImage) { + this.canvas.style.background = `url(${canvasConfig.backgroundImage})` + this.canvas.style['background-size'] = 'cover' + this.canvas.style['background-position'] = 'center' + } else + this.canvas.style.background = 'transparent'; + this.canvas.style['touch-action'] = 'none' + this.canvas.style['object-fit'] = 'cover' + + this.context = this.canvas.getContext('webgpu'); + + this.sourceWidth = Math.floor(this.canvas.clientWidth * this.pixelRatio * this.super) + this.sourceHeight = Math.floor(this.canvas.clientHeight * this.pixelRatio * this.super) + + if (`gpu` in navigator) { + //TODO add webgpu event + // console.log( `${navigator.platform} this chrom not support webgpu!` ); + } + + this.adapter = await navigator.gpu.requestAdapter({ + powerPreference: 'high-performance', + // powerPreference: 'low-power', + }); + + if (this.adapter == null) { + //TODO add webgpu event + // console.log( `${navigator.platform} this chrom not support webgpu!` ); + } + + this.device = await this.adapter.requestDevice({ + requiredFeatures: [`texture-compression-bc`], + requiredLimits: { + minUniformBufferOffsetAlignment: 256, + maxStorageBufferBindingSize: this.adapter.limits.maxStorageBufferBindingSize + } + }); + + if (this.device == null) { + //TODO add webgpu event + // console.log( `${navigator.platform} this chrom not support webgpu!` ); + } + + + this.device.label = 'device'; + this.presentationFormat = navigator.gpu.getPreferredCanvasFormat(); //this.context.getPreferredFormat(this.adapter); + this.context.configure({ + device: this.device, + format: this.presentationFormat, + usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT, + alphaMode: 'premultiplied', + colorSpace: `display-p3` + }); + this.resize(this.canvas.clientWidth, this.canvas.clientHeight) + + let timer: any + const resizeObserver = new ResizeObserver(() => { + clearTimeout(timer) + timer = setTimeout(() => { + this.resize(this.canvas.clientWidth, this.canvas.clientHeight) + }, 50) + }); + resizeObserver.observe(this.canvas); + + return true; + } + + public resize(width: number, height: number) { + this.canvas.width = this.windowWidth = Math.floor(width * this.pixelRatio * this.super) + this.canvas.height = this.windowHeight = Math.floor(height * this.pixelRatio * this.super) + + // this.canvas.width = this.windowWidth = Math.floor(this.canvasConfig.width ? this.canvasConfig.width : width * this.pixelRatio) + // this.canvas.height = this.windowHeight = Math.floor(this.canvasConfig.height ? this.canvasConfig.height : height * this.pixelRatio) + + this.presentationSize[0] = this.windowWidth; + this.presentationSize[1] = this.windowHeight; + this.aspect = this.windowWidth / this.windowHeight; + } +} + +/** + * @internal + */ +export let webGPUContext = new Context3D(); diff --git a/src/engine/gfx/generate/graphic/webgpu/WebGPUConst.ts b/src/engine/gfx/generate/graphic/webgpu/WebGPUConst.ts new file mode 100644 index 00000000..f92084e6 --- /dev/null +++ b/src/engine/gfx/generate/graphic/webgpu/WebGPUConst.ts @@ -0,0 +1,279 @@ +/** + * @internal + */ +export let GPUAddressMode = { + clamp_to_edge: 'clamp-to-edge' as GPUAddressMode, + repeat: 'repeat' as GPUAddressMode, + mirror_repeat: 'mirror-repeat' as GPUAddressMode, +}; +/** + * @internal + */ +export let GPUBlendFactor = { + zero: 'zero' as GPUBlendFactor, + one: 'one' as GPUBlendFactor, + src: 'src' as GPUBlendFactor, + one_minus_src: 'one-minus-src' as GPUBlendFactor, + src_alpha: 'src-alpha' as GPUBlendFactor, + one_minus_src_alpha: 'one-minus-src-alpha' as GPUBlendFactor, + dst: 'dst' as GPUBlendFactor, + one_minus_dst: 'one-minus-dst' as GPUBlendFactor, + dst_alpha: 'dst-alpha' as GPUBlendFactor, + one_minus_dst_alpha: 'one-minus-dst-alpha' as GPUBlendFactor, + src_alpha_saturated: 'src-alpha-saturated' as GPUBlendFactor, + constant: 'constant' as GPUBlendFactor, + one_minus_constant: 'one-minus-constant' as GPUBlendFactor, +}; +/** + * @internal + */ +export const blendComponent = { + srcFactor: 'one', + dstFactor: 'zero', + operation: 'add', +}; +/** + * @internal + */ +export const stencilStateFace = { + compare: 'always', + failOp: 'keep', + depthFailOp: 'keep', + passOp: 'keep', +}; +/** + * @internal + */ +type GPUBlendOperation = 'add' | 'subtract' | 'reverse-subtract' | 'min' | 'max'; +/** + * @internal + */ +type GPUBufferBindingType = 'uniform' | 'storage' | 'read-only-storage'; +/** + * @internal + */ +type GPUCanvasCompositingAlphaMode = 'opaque' | 'premultiplied'; +/** + * @internal + */ +export let GPUCompareFunction = { + never: 'never' as GPUCompareFunction, + less: 'less' as GPUCompareFunction, + equal: 'equal' as GPUCompareFunction, + less_equal: 'less-equal' as GPUCompareFunction, + greater: 'greater' as GPUCompareFunction, + not_equal: 'not-equal' as GPUCompareFunction, + greater_equal: 'greater-equal' as GPUCompareFunction, + always: 'always' as GPUCompareFunction, +}; +/** + * @internal + */ +type GPUCompilationMessageType = 'error' | 'warning' | 'info'; +/** + * @internal + */ +export let GPUCullMode = { + none: 'none' as GPUCullMode, + front: 'front' as GPUCullMode, + back: 'back' as GPUCullMode, +}; +/** + * @internal + */ +type GPUDeviceLostReason = 'destroyed'; +/** + * @internal + */ +type GPUErrorFilter = 'out-of-memory' | 'validation'; +/** + * @internal + */ + export type GPUFeatureName = 'depth-clamping' | 'depth24unorm-stencil8' | 'depth32float-stencil8' | 'pipeline-statistics-query' | 'texture-compression-bc' | 'timestamp-query'; +/** + * @internal + */ +export let GPUFilterMode = { + nearest : "nearest" as GPUFilterMode, + linear : "linear" as GPUFilterMode, +} +/** + * @internal + */ + export type GPUFrontFace = 'ccw' | 'cw'; +/** + * @internal + */ +type GPUIndexFormat = 'uint16' | 'uint32'; +/** + * @internal + */ +type GPULoadOp = 'load' | `clear`; +type GPUPipelineStatisticName = 'vertex-shader-invocations' | 'clipper-invocations' | 'clipper-primitives-out' | 'fragment-shader-invocations' | 'compute-shader-invocations'; +/** + * @internal + */ +type GPUPowerPreference = 'low-power' | 'high-performance'; +/** + * @internal + */ +type GPUPredefinedColorSpace = 'srgb'; +/** + * @internal + */ +export let GPUPrimitiveTopology = { + point_list: 'point-list' as GPUPrimitiveTopology, + line_list: 'line-list' as GPUPrimitiveTopology, + line_strip: 'line-strip' as GPUPrimitiveTopology, + triangle_list: 'triangle-list' as GPUPrimitiveTopology, + triangle_strip: 'triangle-strip' as GPUPrimitiveTopology, +}; +/** + * @internal + */ +type GPUQueryType = 'occlusion' | 'pipeline-statistics' | 'timestamp'; +/** + * @internal + */ +type GPUSamplerBindingType = 'filtering' | 'non-filtering' | 'comparison'; +/** + * @internal + */ +type GPUStencilOperation = 'keep' | 'zero' | 'replace' | 'invert' | 'increment-clamp' | 'decrement-clamp' | 'increment-wrap' | 'decrement-wrap'; +/** + * @internal + */ +type GPUStorageTextureAccess = GPUStorageTextureAccessNew | GPUStorageTextureAccessOld; +/** + * @internal + */ +type GPUStorageTextureAccessNew = 'write-only'; +/** + * @internal + */ +/** @deprecated */ +type GPUStorageTextureAccessOld = 'read-only' | 'write-only'; +/** + * @internal + */ +type GPUStoreOp = 'store' | 'discard'; +/** + * @internal + */ +type GPUTextureAspect = 'all' | 'stencil-only' | 'depth-only'; +/** + * @internal + */ +type GPUTextureDimension = '1d' | '2d' | '3d'; +/** + * @internal + */ +export let GPUTextureFormat = { + r8unorm: 'r8unorm' as GPUTextureFormat, + r8snorm: 'r8snorm' as GPUTextureFormat, + r8uint: 'r8uint' as GPUTextureFormat, + r8sint: 'r8sint' as GPUTextureFormat, + r16uint: 'r16uint' as GPUTextureFormat, + r16sint: 'r16sint' as GPUTextureFormat, + r16float: 'r16float' as GPUTextureFormat, + rg8unorm: 'rg8unorm' as GPUTextureFormat, + rg8snorm: 'rg8snorm' as GPUTextureFormat, + rg8uint: 'rg8uint' as GPUTextureFormat, + rg8sint: 'rg8sint' as GPUTextureFormat, + r32uint: 'r32uint' as GPUTextureFormat, + r32sint: 'r32sint' as GPUTextureFormat, + r32float: 'r32float' as GPUTextureFormat, + rg16uint: 'rg16uint' as GPUTextureFormat, + rg16sint: 'rg16sint' as GPUTextureFormat, + rg16float: 'rg16float' as GPUTextureFormat, + rgba8unorm: 'rgba8unorm' as GPUTextureFormat, + rgba8unorm_srgb: 'rgba8unorm-srgb' as GPUTextureFormat, + rgba8snorm: 'rgba8snorm' as GPUTextureFormat, + rgba8uint: 'rgba8uint' as GPUTextureFormat, + rgba8sint: 'rgba8sint' as GPUTextureFormat, + bgra8unorm: 'bgra8unorm' as GPUTextureFormat, + bgra8unorm_srgb: 'bgra8unorm-srgb' as GPUTextureFormat, + rgb9e5ufloat: 'rgb9e5ufloat' as GPUTextureFormat, + rgb10a2unorm: 'rgb10a2unorm' as GPUTextureFormat, + rg11b10ufloat: 'rg11b10ufloat' as GPUTextureFormat, + rg32uint: 'rg32uint' as GPUTextureFormat, + rg32sint: 'rg32sint' as GPUTextureFormat, + rg32float: 'rg32float' as GPUTextureFormat, + rgba16uint: 'rgba16uint' as GPUTextureFormat, + rgba16sint: 'rgba16sint' as GPUTextureFormat, + rgba16float: 'rgba16float' as GPUTextureFormat, + rgba32uint: 'rgba32uint' as GPUTextureFormat, + rgba32sint: 'rgba32sint' as GPUTextureFormat, + rgba32float: 'rgba32float' as GPUTextureFormat, + stencil8: 'stencil8' as GPUTextureFormat, + depth16unorm: 'depth16unorm' as GPUTextureFormat, + depth24plus: 'depth24plus' as GPUTextureFormat, + depth24plus_stencil8: 'depth24plus-stencil8' as GPUTextureFormat, + depth32float: 'depth32float' as GPUTextureFormat, + bc1_rgba_unorm: 'bc1-rgba-unorm' as GPUTextureFormat, + bc1_rgba_unorm_srgb: 'bc1-rgba-unorm-srgb' as GPUTextureFormat, + bc2_rgba_unorm: 'bc2-rgba-unorm' as GPUTextureFormat, + bc2_rgba_unorm_srgb: 'bc2-rgba-unorm-srgb' as GPUTextureFormat, + bc3_rgba_unorm: 'bc3-rgba-unorm' as GPUTextureFormat, + bc3_rgba_unorm_srgb: 'bc3-rgba-unorm-srgb' as GPUTextureFormat, + bc4_r_unorm: 'bc4-r-unorm' as GPUTextureFormat, + bc4_r_snorm: 'bc4-r-snorm' as GPUTextureFormat, + bc5_rg_unorm: 'bc5-rg-unorm' as GPUTextureFormat, + bc5_rg_snorm: 'bc5-rg-snorm' as GPUTextureFormat, + bc6h_rgb_ufloat: 'bc6h-rgb-ufloat' as GPUTextureFormat, + bc6h_rgb_float: 'bc6h-rgb-float' as GPUTextureFormat, + bc7_rgba_unorm: 'bc7-rgba-unorm' as GPUTextureFormat, + bc7_rgba_unorm_srgb: 'bc7-rgba-unorm-srgb' as GPUTextureFormat, + depth24unorm_stencil8: 'depth24unorm-stencil8' as GPUTextureFormat, + depth32float_stencil8: 'depth32float-stencil8' as GPUTextureFormat, +}; +/** + * @internal + */ +type GPUTextureSampleType = 'float' | 'unfilterable-float' | 'depth' | 'sint' | 'uint'; +/** + * @internal + */ +type GPUTextureViewDimension = '1d' | '2d' | '2d-array' | 'cube' | 'cube-array' | '3d'; +/** + * @internal + */ +export let GPUVertexFormat = { + uint8x2: 'uint8x2' as GPUVertexFormat, + uint8x4: 'uint8x4' as GPUVertexFormat, + sint8x2: 'sint8x2' as GPUVertexFormat, + sint8x4: 'sint8x4' as GPUVertexFormat, + unorm8x2: 'unorm8x2' as GPUVertexFormat, + unorm8x4: 'unorm8x4' as GPUVertexFormat, + snorm8x2: 'snorm8x2' as GPUVertexFormat, + snorm8x4: 'snorm8x4' as GPUVertexFormat, + uint16x2: 'uint16x2' as GPUVertexFormat, + uint16x4: 'uint16x4' as GPUVertexFormat, + sint16x2: 'sint16x2' as GPUVertexFormat, + sint16x4: 'sint16x4' as GPUVertexFormat, + unorm16x2: 'unorm16x2' as GPUVertexFormat, + unorm16x4: 'unorm16x4' as GPUVertexFormat, + snorm16x2: 'snorm16x2' as GPUVertexFormat, + snorm16x4: 'snorm16x4' as GPUVertexFormat, + float16x2: 'float16x2' as GPUVertexFormat, + float16x4: 'float16x4' as GPUVertexFormat, + float32: 'float32' as GPUVertexFormat, + float32x2: 'float32x2' as GPUVertexFormat, + float32x3: 'float32x3' as GPUVertexFormat, + float32x4: 'float32x4' as GPUVertexFormat, + uint32: 'uint32' as GPUVertexFormat, + uint32x2: 'uint32x2' as GPUVertexFormat, + uint32x3: 'uint32x3' as GPUVertexFormat, + uint32x4: 'uint32x4' as GPUVertexFormat, + sint32: 'sint32' as GPUVertexFormat, + sint32x2: 'sint32x2' as GPUVertexFormat, + sint32x3: 'sint32x3' as GPUVertexFormat, + sint32x4: 'sint32x4' as GPUVertexFormat, +}; +/** + * @internal + */ +export let GPUVertexStepMode = { + vertex: 'vertex' as GPUVertexStepMode, + instance: 'instance' as GPUVertexStepMode, +}; diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalBindGroup.ts b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalBindGroup.ts new file mode 100644 index 00000000..e267840a --- /dev/null +++ b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalBindGroup.ts @@ -0,0 +1,59 @@ +import { Camera3D } from '../../../../../core/Camera3D'; +import { LightEntries } from './groups/LightEntries'; +import { MatrixBindGroup } from './MatrixBindGroup'; +import { GlobalUniformGroup } from './GlobalUniformGroup'; +import { Scene3D } from '../../../../../core/Scene3D'; +/** + * @internal + * Use Global DO Matrix ArrayBuffer Descriptor + * @group GFX + */ +export class GlobalBindGroup { + private static _cameraBindGroups: Map; + private static _lightEntriesMap: Map; + // public static probeEntries: ProbeEntries; + public static modelMatrixBindGroup: MatrixBindGroup; + + public static initCommon() { + this.modelMatrixBindGroup = new MatrixBindGroup(); + this._cameraBindGroups = new Map(); + this._lightEntriesMap = new Map(); + } + + public static getCameraGroup(camera: Camera3D) { + let cameraBindGroup = this._cameraBindGroups.get(camera); + if (!cameraBindGroup) { + cameraBindGroup = new GlobalUniformGroup(this.modelMatrixBindGroup); + this._cameraBindGroups.set(camera, cameraBindGroup); + } + + if (camera.isShadowCamera) { + cameraBindGroup.setShadowCamera(camera); + } else { + cameraBindGroup.setCamera(camera); + } + return cameraBindGroup; + } + + public static getLightEntries(scene: Scene3D): LightEntries { + if (!scene) { + console.log(`getLightEntries scene is null`); + } + + let lightEntries = this._lightEntriesMap.get(scene); + if (!lightEntries) { + lightEntries = new LightEntries(); + this._lightEntriesMap.set(scene, lightEntries); + } + return this._lightEntriesMap.get(scene); + } + + // static updateProbes(probes: Probe[]) { + // if (!this.probeEntries) { + // this.probeEntries = new ProbeEntries(); + // this.probeEntries.initDataUniform(probes); + // } + // } + + +} diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalBindGroupLayout.ts b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalBindGroupLayout.ts new file mode 100644 index 00000000..10f6835d --- /dev/null +++ b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalBindGroupLayout.ts @@ -0,0 +1,28 @@ +import { webGPUContext } from "../../Context3D"; + +export class GlobalBindGroupLayout { + + private static _globalDataBindGroupLayout: GPUBindGroupLayout; + public static getGlobalDataBindGroupLayout(): GPUBindGroupLayout { + if (this._globalDataBindGroupLayout) return this._globalDataBindGroupLayout; + let entries: GPUBindGroupLayoutEntry[] = []; + entries.push({ + binding: 0, + visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE, + buffer: { + type: 'uniform', + }, + }); + + entries.push({ + binding: 1, + visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE, + buffer: { + type: 'read-only-storage', + }, + }); + + this._globalDataBindGroupLayout = webGPUContext.device.createBindGroupLayout({ entries }); + return this._globalDataBindGroupLayout; + } +} diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalUniformGroup.ts b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalUniformGroup.ts new file mode 100644 index 00000000..eed1502a --- /dev/null +++ b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalUniformGroup.ts @@ -0,0 +1,152 @@ +import { ShadowLightsCollect } from '../../../../renderJob/collect/ShadowLightsCollect'; +import { Camera3D } from '../../../../../core/Camera3D'; +import { CubeCamera } from '../../../../../core/CubeCamera'; +import { PointShadowCubeCamera } from '../../../../../core/PointShadowCubeCamera'; +import { Engine3D } from '../../../../../Engine3D'; +import { Matrix4 } from '../../../../../math/Matrix4'; + +import { UUID } from '../../../../../util/Global'; +import { Time } from '../../../../../util/Time'; +import { WebGPUDescriptorCreator } from '../../descriptor/WebGPUDescriptorCreator'; +import { webGPUContext } from '../../Context3D'; +import { StorageGPUBuffer } from '../buffer/StorageGPUBuffer'; +import { UniformGPUBuffer } from '../buffer/UniformGPUBuffer'; +import { GlobalBindGroup } from './GlobalBindGroup'; +import { GlobalBindGroupLayout } from './GlobalBindGroupLayout'; +import { MatrixBindGroup } from './MatrixBindGroup'; + +/** + * @internal + * @author sirxu + * @group GFX + */ +export class GlobalUniformGroup { + public uuid: string; + public usage: number; + public globalBindGroup: GPUBindGroup; + public uniformGPUBuffer: UniformGPUBuffer; + private matrixBindGroup: MatrixBindGroup; + private uniformByteLength: number; + private matrixesByteLength: number; + + /** + * + * @param matrixBindGroup 全局矩阵绑定group,通用统一 + */ + constructor(matrixBindGroup: MatrixBindGroup) { + this.uuid = UUID(); + this.usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST; + this.uniformGPUBuffer = new UniformGPUBuffer(32 * 4 * 4 + (3 * 4 * 4) + 8 * 16); + this.uniformGPUBuffer.visibility = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE + this.matrixBindGroup = matrixBindGroup; + + this.createBindGroup(); + } + + createBindGroup() { + this.uniformByteLength = this.uniformGPUBuffer.memory.shareDataBuffer.byteLength; + this.matrixesByteLength = Matrix4.blockBytes * Matrix4.totalCount; + + this.globalBindGroup = webGPUContext.device.createBindGroup({ + label: `global_bindGroupLayout`, + layout: GlobalBindGroupLayout.getGlobalDataBindGroupLayout(), + entries: [ + { + binding: 0, + resource: { + buffer: this.uniformGPUBuffer.buffer, + offset: 0, // this.uniformGPUBuffer.memory.shareDataBuffer.byteOffset, + size: this.uniformByteLength, + }, + }, + { + binding: 1, + resource: { + buffer: this.matrixBindGroup.matrixBufferDst.buffer, + offset: 0, + size: this.matrixesByteLength, + }, + }, + ], + }); + } + + // public check() { + // if (this.uniformByteLength != this.uniformGPUBuffer.memory.shareDataBuffer.byteLength + // || this.matrixesByteLength != Matrix4.blockBytes * Matrix4.totalCount) { + // this.createBindGroup(); + // } + // } + + public setCamera(camera: Camera3D) { + camera.transform.updateWorldMatrix(true); + this.uniformGPUBuffer.setMatrix(`_projectionMatrix`, camera.projectionMatrix); + this.uniformGPUBuffer.setMatrix(`_viewMatrix`, camera.viewMatrix); + this.uniformGPUBuffer.setMatrix(`_cameraWorldMatrix`, camera.transform.worldMatrix); + this.uniformGPUBuffer.setMatrix(`_projectionMatrixInv`, camera.projectionMatrixInv); + let raw = new Float32Array(8 * 16); + for (let i = 0; i < 8; i++) { + let shadowLightList = ShadowLightsCollect.getDirectShadowLightWhichScene(camera.transform.scene3D); + if (i < shadowLightList.length) { + let mat = shadowLightList[i].shadowCamera.pvMatrix.rawData; + raw.set(mat, i * 16); + } else { + raw.set(camera.transform.worldMatrix.rawData, i * 16); + } + } + this.uniformGPUBuffer.setFloat32Array(`_shadowCamera`, raw); + this.uniformGPUBuffer.setVector3(`CameraPos`, camera.transform.worldPosition); + + this.uniformGPUBuffer.setFloat(`Time.frame`, Time.frame); + this.uniformGPUBuffer.setFloat(`Time.time`, Time.frame); + this.uniformGPUBuffer.setFloat(`Time.detail`, Time.delta); + this.uniformGPUBuffer.setFloat(`EngineSetting.Shadow.shadowBias`, Engine3D.setting.shadow.shadowBias); + this.uniformGPUBuffer.setFloat(`skyExposure`, Engine3D.setting.sky.skyExposure); + this.uniformGPUBuffer.setFloat(`EngineSetting.Render.renderPassState`, Engine3D.setting.render.renderPassState); + this.uniformGPUBuffer.setFloat(`EngineSetting.Render.quadScale`, Engine3D.setting.render.quadScale); + this.uniformGPUBuffer.setFloat(`EngineSetting.Render.hdrExposure`, Engine3D.setting.render.hdrExposure); + + this.uniformGPUBuffer.setInt32(`renderState_left`, Engine3D.setting.render.renderState_left); + this.uniformGPUBuffer.setInt32(`renderState_right`, Engine3D.setting.render.renderState_right); + this.uniformGPUBuffer.setFloat(`renderState_split`, Engine3D.setting.render.renderState_split); + + let mouseX = Engine3D.inputSystem.mouseX * webGPUContext.pixelRatio * webGPUContext.super; + let mouseY = Engine3D.inputSystem.mouseY * webGPUContext.pixelRatio * webGPUContext.super; + this.uniformGPUBuffer.setFloat(`mouseX`, mouseX); + this.uniformGPUBuffer.setFloat(`mouseY`, mouseY); + this.uniformGPUBuffer.setFloat(`windowWidth`, webGPUContext.windowWidth); + this.uniformGPUBuffer.setFloat(`windowHeight`, webGPUContext.windowHeight); + this.uniformGPUBuffer.setFloat(`near`, camera.near); + this.uniformGPUBuffer.setFloat(`far`, camera.far); + + this.uniformGPUBuffer.setFloat(`EngineSetting.Shadow.pointShadowBias`, Engine3D.setting.shadow.pointShadowBias); + this.uniformGPUBuffer.setFloat(`shadowMapSize`, Engine3D.setting.shadow.shadowSize); + this.uniformGPUBuffer.setFloat(`shadowSoft`, Engine3D.setting.shadow.shadowSoft); + this.uniformGPUBuffer.apply(); + } + + setShadowCamera(camera: Camera3D) { + camera.transform.updateWorldMatrix(true); + this.uniformGPUBuffer.setMatrix(`_projectionMatrix`, camera.projectionMatrix); + this.uniformGPUBuffer.setMatrix(`_viewMatrix`, camera.viewMatrix); + this.uniformGPUBuffer.setMatrix(`_pvMatrix`, camera.pvMatrix); + this.uniformGPUBuffer.apply(); + } + + public addUniformNode() { } + + writeBuffer() { + const matBytes = Matrix4.matrixBytes; + let totalBytes = matBytes.byteLength; + let offsetBytes = 0; + + // webGPUContext.device.queue.writeBuffer(this.matrixBufferDst, offsetBytes, matBytes.buffer, matBytes.byteOffset, matBytes.byteLength); + + const space = 5000 * 64; // 5000 * 16 * 4 + while (offsetBytes < totalBytes) { + let len = Math.min(space, totalBytes - offsetBytes); + webGPUContext.device.queue.writeBuffer(this.matrixBindGroup.matrixBufferDst.buffer, offsetBytes, matBytes.buffer, matBytes.byteOffset + offsetBytes, len); + offsetBytes += len; + } + } +} diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/MatrixBindGroup.ts b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/MatrixBindGroup.ts new file mode 100644 index 00000000..32eecb67 --- /dev/null +++ b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/MatrixBindGroup.ts @@ -0,0 +1,44 @@ +import { Matrix4 } from '../../../../../math/Matrix4'; +import { UUID } from '../../../../../util/Global'; +import { Time } from '../../../../../util/Time'; +import { WebGPUDescriptorCreator } from '../../descriptor/WebGPUDescriptorCreator'; +import { webGPUContext } from '../../Context3D'; +import { StorageGPUBuffer } from '../buffer/StorageGPUBuffer'; +/** + * @author sirxu + * @internal + * @group GFX + */ +export class MatrixBindGroup { + public uuid: string; + public index: number; + public usage: number; + public groupBufferSize: number; + public matrixBufferDst: StorageGPUBuffer; + constructor() { + this.uuid = UUID(); + this.groupBufferSize = 0; + this.usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST; + this.cacheWorldMatrix(); + } + + private cacheWorldMatrix() { + this.groupBufferSize = Matrix4.maxCount * Matrix4.blockBytes; + this.matrixBufferDst = new StorageGPUBuffer(this.groupBufferSize / 4); + this.matrixBufferDst.visibility = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE + this.matrixBufferDst.buffer.label = this.groupBufferSize.toString(); + } + + writeBuffer() { + const matBytes = Matrix4.matrixBytes; + let totalBytes = matBytes.byteLength; + let offsetBytes = 0; + + const space = 5000 * 64; + while (offsetBytes < totalBytes) { + let len = Math.min(space, totalBytes - offsetBytes); + webGPUContext.device.queue.writeBuffer(this.matrixBufferDst.buffer, offsetBytes, matBytes.buffer, matBytes.byteOffset + offsetBytes, len); + offsetBytes += len; + } + } +} diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/TexturesBindGroup.ts b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/TexturesBindGroup.ts new file mode 100644 index 00000000..8b860680 --- /dev/null +++ b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/TexturesBindGroup.ts @@ -0,0 +1,97 @@ +import { MaterialBase } from '../../../../../materials/MaterialBase'; +import { VirtualTexture } from '../../../../../textures/VirtualTexture'; +import { GPUTextureFormat } from '../../WebGPUConst'; +import { webGPUContext } from '../../Context3D'; +import { DepthCubeArrayTexture } from '../../../../../textures/DepthCubeArrayTexture'; +import { Texture } from '../texture/Texture'; +import { Depth2DTextureArray } from '../../../../../textures/Depth2DTextureArray'; +/** + * @internal + * @group GFX + */ +export class TexturesBindGroup { + public name: string; + public index: number = 2; + public gpuBindGroup: GPUBindGroup; + + constructor(index: number = 2) { + this.index = index; + } + + bindTextureToPipeline(pipeline: GPURenderPipeline | GPUComputePipeline, textures: Texture[]) { + if (!this.gpuBindGroup) { + let entries = []; + for (let i = 0; i < textures.length; i++) { + if (!textures[i]) continue; + const texture = textures[i]; + + if (texture instanceof DepthCubeArrayTexture) { + entries.push( + { + binding: i * 2 + 0, + resource: texture.gpuSampler, + }, + { + binding: i * 2 + 1, + resource: texture.getGPUView(), + }, + ); + } else if (texture instanceof Depth2DTextureArray) { + entries.push( + { + binding: i * 2 + 0, + resource: texture.gpuSampler_comparison, + }, + { + binding: i * 2 + 1, + resource: texture.getGPUView(), + }, + ); + } else if (texture instanceof VirtualTexture) { + let depth = texture.format.indexOf("depth") != -1; + entries.push( + { + binding: i * 2 + 0, + resource: depth ? texture.gpuSampler_comparison : texture.gpuSampler, + }, + { + binding: i * 2 + 1, + resource: texture.getGPUView(), + }, + ); + } + } + + let layout = pipeline.getBindGroupLayout(this.index); + this.gpuBindGroup = webGPUContext.device.createBindGroup({ + layout: layout, + entries: entries, + }); + } + } + + bindTextureToPipeline2(pipeline: GPURenderPipeline | GPUComputePipeline, textures: Texture[]) { + if (!this.gpuBindGroup) { + let entries = []; + for (let i = 0; i < textures.length; i++) { + if (!textures[i]) continue; + const texture = textures[i]; + + entries.push( + { + binding: i, + resource: texture.getGPUView(), + }, + ); + } + + let layout = pipeline.getBindGroupLayout(this.index); + this.gpuBindGroup = webGPUContext.device.createBindGroup({ + layout: layout, + entries: entries, + }); + } + } + + public static pool: Map = new Map(); +} diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/groups/LightEntries.ts b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/groups/LightEntries.ts new file mode 100644 index 00000000..2b349646 --- /dev/null +++ b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/groups/LightEntries.ts @@ -0,0 +1,68 @@ +import { LightData } from '../../../../../../components/lights/LightData'; +import { MemoryInfo } from '../../../../../../core/pool/memory/MemoryInfo'; +import { View3D } from '../../../../../../core/View3D'; +import { Engine3D } from '../../../../../../Engine3D'; +import { EntityCollect } from '../../../../../renderJob/collect/EntityCollect'; +import { DDGIIrradianceVolume } from '../../../../../renderJob/passRenderer/ddgi/DDGIIrradianceVolume'; +import { StorageGPUBuffer } from '../../buffer/StorageGPUBuffer'; + +//TODO dynamic lights need fixed +/** + * @internal + * @group GFX + */ +export class LightEntries { + public storageGPUBuffer: StorageGPUBuffer; + public irradianceVolume: DDGIIrradianceVolume; + private _lightList: MemoryInfo[] = []; + + constructor() { + this.storageGPUBuffer = new StorageGPUBuffer( + LightData.lightSize * Engine3D.setting.light.maxLight, + GPUBufferUsage.COPY_SRC + ); + + for (let i = 0; i < Engine3D.setting.light.maxLight; i++) { + let memory = this.storageGPUBuffer.memory.allocation_node(LightData.lightSize * 4); + this._lightList.push(memory); + } + + this.storageGPUBuffer.visibility = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; + this.irradianceVolume = new DDGIIrradianceVolume(); + this.irradianceVolume.init(Engine3D.setting.gi); + } + + public update(view: View3D) { + let lights = EntityCollect.instance.getLights(view.scene); + for (let i = 0; i < lights.length; i++) { + const light = lights[i].lightData; + this.writeLightBytes(light, this._lightList[i]); + } + this.storageGPUBuffer.apply(); + } + + private writeLightBytes(light: LightData, memory: MemoryInfo) { + memory.offset = 0; + memory.writeFloat(light.index); + memory.writeInt32(light.lightType); + memory.writeFloat(light.radius); + memory.writeFloat(light.linear); + + memory.writeVector3(light.lightPosition); + memory.writeFloat(light.lightMatrixIndex); + + memory.writeVector3(light.direction); + memory.writeFloat(light.quadratic); + + memory.writeRGBColor(light.lightColor); + memory.writeFloat(light.intensity); + + memory.writeFloat(light.innerAngle); + memory.writeFloat(light.outerAngle); + memory.writeFloat(light.range); + memory.writeInt32(light.castShadowIndex); + + memory.writeVector3(light.lightTangent); + memory.writeFloat(-1); + } +} diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/groups/ProbeEntries.ts b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/groups/ProbeEntries.ts new file mode 100644 index 00000000..6d3eb90a --- /dev/null +++ b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/groups/ProbeEntries.ts @@ -0,0 +1,53 @@ +import { MemoryDO } from '../../../../../../core/pool/memory/MemoryDO'; +import { MemoryInfo } from '../../../../../../core/pool/memory/MemoryInfo'; +import { Probe } from '../../../../../renderJob/passRenderer/ddgi/Probe'; +import { webGPUContext } from '../../../Context3D'; +/** + * @internal + * @group GFX + */ +export class ProbeEntries { + public gpuBuffer: GPUBuffer; + public probes: Probe[]; + public memoryDo: MemoryDO; + private _probeInfoList: MemoryInfo[]; + + public initDataUniform(probes: Probe[]) { + this.memoryDo = new MemoryDO(); + this.probes = probes; + this._probeInfoList = []; + + let len = 0; + this.memoryDo.destroy(); + this.memoryDo.allocation(probes.length * 17 * 4); + for (let i = 0; i < probes.length; i++) { + var size = 17; + len += size; + let memoryInfo = this.memoryDo.allocation_node(size * 4); + this._probeInfoList.push(memoryInfo); + + let probeWorldPos = probes[i].transform.worldPosition; + memoryInfo.setArray(0, [probeWorldPos.x, probeWorldPos.y, probeWorldPos.z]); + } + + len = Math.max(64, len); + + this.gpuBuffer = webGPUContext.device.createBuffer({ + size: this.memoryDo.shareDataBuffer.byteLength, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE, + label: 'ProbeBuffer', + mappedAtCreation: false, + }); + } + + private updateGPUBuffer() { + const bufferData = this.memoryDo.shareDataBuffer; + let totalBytes = this.memoryDo.shareDataBuffer.byteLength; + let offsetBytes = 0;//this.memoryDo.shareDataBuffer.byteOffset; + const space = 5000 * 64; + while (offsetBytes < totalBytes) { + webGPUContext.device.queue.writeBuffer(this.gpuBuffer, offsetBytes, bufferData, offsetBytes, Math.floor(Math.min(space, totalBytes - offsetBytes))); + offsetBytes += space; + } + } +} diff --git a/src/engine/gfx/generate/renderJob/GPUContext.ts b/src/engine/gfx/generate/renderJob/GPUContext.ts new file mode 100644 index 00000000..45193ae5 --- /dev/null +++ b/src/engine/gfx/generate/renderJob/GPUContext.ts @@ -0,0 +1,290 @@ +import { ProfilerUtil, RenderShader, View3D } from '../../..'; +import { Camera3D } from '../../core/Camera3D'; +import { GeometryBase } from '../../core/geometry/GeometryBase'; +import { ViewQuad } from '../../core/ViewQuad'; +import { GlobalBindGroup } from '../graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { Texture } from '../graphics/webGpu/core/texture/Texture'; +import { ComputeShader } from '../graphics/webGpu/shader/ComputeShader'; +import { webGPUContext } from '../graphics/webGpu/Context3D'; +import { RendererType } from './passRenderer/state/RendererType'; +import { RendererPassState } from './passRenderer/state/RendererPassState'; + +/** + * WebGPU api use context + */ +export class GPUContext { + public static lastGeometry: GeometryBase; + public static lastPipeline: GPURenderPipeline; + public static lastShader: RenderShader; + public static drawCount: number = 0; + public static renderPassCount: number = 0; + public static geometryCount: number = 0; + public static pipelineCount: number = 0; + public static matrixCount: number = 0; + public static lastRenderPassState: RendererPassState; + public static LastCommand: GPUCommandEncoder; + + /** + * renderPipeline before render need bind pipeline + * @param encoder current GPURenderPassEncoder {@link GPURenderPassEncoder } {@link GPURenderBundleEncoder } + * @param renderShader render pass shader {@link RenderShader } + * @returns + */ + public static bindPipeline(encoder: GPURenderPassEncoder | GPURenderBundleEncoder, renderShader: RenderShader) { + if (GPUContext.lastShader != renderShader) { + GPUContext.lastShader = renderShader; + } else { + return; + } + + if (GPUContext.lastPipeline != renderShader.pipeline) { + GPUContext.lastPipeline = renderShader.pipeline; + encoder.setPipeline(renderShader.pipeline); + } + + for (let i = 1; i < renderShader.bindGroups.length; i++) { + const bindGroup = renderShader.bindGroups[i]; + if (bindGroup) { + encoder.setBindGroup(i, bindGroup); + } + } + } + + /** + * render before need make sure use camera + * @param encoder current GPURenderPassEncoder {@link GPURenderPassEncoder } {@link GPURenderBundleEncoder } + * @param camera use camera {@link Camera3D} + */ + public static bindCamera(encoder: GPURenderPassEncoder | GPURenderBundleEncoder, camera: Camera3D) { + let cameraBindGroup = GlobalBindGroup.getCameraGroup(camera); + encoder.setBindGroup(0, cameraBindGroup.globalBindGroup); + } + + /** + * bind geometry vertex buffer to current render pipeline + * @param encoder current GPURenderPassEncoder {@link GPURenderPassEncoder } {@link GPURenderBundleEncoder } + * @param geometry engine geometry + * @param offset geometry buffer bytes offset + * @param size geometry buffer bytes length + */ + public static bindGeometryBuffer(encoder: GPURenderPassEncoder | GPURenderBundleEncoder, geometry: GeometryBase) { + if (this.lastGeometry != geometry) { + this.lastGeometry = geometry; + + if (geometry.indicesBuffer) + encoder.setIndexBuffer(geometry.indicesBuffer.indicesGPUBuffer.buffer, geometry.indicesBuffer.indicesFormat); + + let vertexBuffer = geometry.vertexBuffer.vertexGPUBuffer; + let vertexBufferLayouts = geometry.vertexBuffer.vertexBufferLayouts; + for (let i = 0; i < vertexBufferLayouts.length; i++) { + const vbLayout = vertexBufferLayouts[i]; + encoder.setVertexBuffer(i, vertexBuffer.buffer, vbLayout.offset, vbLayout.size); + } + } + } + + /** + * begin or end clean all use cache + */ + public static cleanCache() { + this.lastGeometry = null; + this.lastPipeline = null; + this.lastShader = null; + } + + /** + * create a render pipeline + * @param gpuRenderPipeline {@link GPURenderPipelineDescriptor} + * @returns + */ + public static createPipeline(gpuRenderPipeline: GPURenderPipelineDescriptor) { + ProfilerUtil.countStart("GPUContext", "pipeline"); + return webGPUContext.device.createRenderPipeline(gpuRenderPipeline); + } + + /** + * auto get webgpu commandEncoder and start a command encoder + * @returns commandEncoder {@link GPUCommandEncoder} + */ + public static beginCommandEncoder(): GPUCommandEncoder { + ProfilerUtil.countStart("GPUContext", "beginCommandEncoder"); + if (this.LastCommand) { + webGPUContext.device.queue.submit([this.LastCommand.finish()]); + } + this.LastCommand = webGPUContext.device.createCommandEncoder(); + return this.LastCommand; + } + + /** + * end CommandEncoder record and submit + * @param command {@link GPUCommandEncoder} + */ + public static endCommandEncoder(command: GPUCommandEncoder) { + if (this.LastCommand == command) { + webGPUContext.device.queue.submit([this.LastCommand.finish()]); + this.LastCommand = null; + ProfilerUtil.countStart("GPUContext", "endCommandEncoder"); + } + } + + /** + * create a renderBundle gpu object by GPURenderBundleEncoderDescriptor + * @param des {@link GPURenderBundleEncoderDescriptor} + * @returns renderBundleEncoder {@link GPURenderBundleEncoder} + */ + public static recordBundleEncoder(des: GPURenderBundleEncoderDescriptor): GPURenderBundleEncoder { + let bundleEncoder: GPURenderBundleEncoder = webGPUContext.device.createRenderBundleEncoder(des); + return bundleEncoder; + } + + /** + * render pass start return current use gpu renderPassEncoder + * @param command {@link GPUCommandEncoder} + * @param renderPassState {@link RendererPassState} + * @returns encoder {@link GPURenderPassEncoder} + */ + public static beginRenderPass(command: GPUCommandEncoder, renderPassState: RendererPassState): GPURenderPassEncoder { + this.cleanCache(); + this.renderPassCount++; + this.lastRenderPassState = renderPassState; + if (renderPassState.renderTargets && renderPassState.renderTargets.length > 0) { + for (let i = 0; i < renderPassState.renderTargets.length; ++i) { + const renderTarget = renderPassState.renderTargets[i]; + let att = renderPassState.renderPassDescriptor.colorAttachments[i]; + + if (renderPassState.multisample > 0 && renderPassState.renderTargets.length == 1) { + att.view = renderPassState.multiTexture.createView(); + att.resolveTarget = renderTarget.getGPUView(); + } else { + att.view = renderTarget.getGPUTexture().createView(); + } + } + return command.beginRenderPass(renderPassState.renderPassDescriptor); + } else { + let att0 = renderPassState.renderPassDescriptor.colorAttachments[0]; + if (att0) { + if (renderPassState.multisample > 0) { + att0.view = renderPassState.multiTexture.createView(); + att0.resolveTarget = webGPUContext.context.getCurrentTexture().createView(); + } else { + att0.view = webGPUContext.context.getCurrentTexture().createView(); + } + } + return command.beginRenderPass(renderPassState.renderPassDescriptor); + } + } + + /** + * Start the rendering process to draw any pipes + * @param encoder + * @param indexCount + * @param instanceCount + * @param firstIndex + * @param baseVertex + * @param firstInstance + */ + public static drawIndexed(encoder: GPURenderPassEncoder, indexCount: GPUSize32, + instanceCount?: GPUSize32, + firstIndex?: GPUSize32, + baseVertex?: GPUSignedOffset32, + firstInstance?: GPUSize32) { + encoder.drawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance); + this.drawCount++; + } + + public static draw(encoder: GPURenderPassEncoder, vertexCount: GPUSize32, + instanceCount?: GPUSize32, + firstVertex?: GPUSize32, + firstInstance?: GPUSize32) { + encoder.draw(vertexCount, instanceCount, firstVertex, firstInstance); + this.drawCount++; + } + + /** + * The GPU must be informed of the end of encoder recording + * @param encoder + */ + public static endPass(encoder: GPURenderPassEncoder) { + encoder.insertDebugMarker("end") + encoder.end(); + } + + + /** + * By inputting a map to viewQuad and setting corresponding + * processing shaders, the corresponding results are output for off-screen rendering + * Can also be directly used as the final display rendering result rendering canvas + * @param viewQuad + * @see ViewQuad + * @param scene3D + * @see Scene3D + * @param command + */ + public static renderTarget(view: View3D, viewQuad: ViewQuad, command: GPUCommandEncoder) { + let camera = view.camera; + let encoder = GPUContext.beginRenderPass(command, viewQuad.rendererPassState); + GPUContext.bindCamera(encoder, camera); + viewQuad.quadRenderer.nodeUpdate(view, RendererType.COLOR, viewQuad.rendererPassState, null); + viewQuad.quadRenderer.renderPass2(view, RendererType.COLOR, viewQuad.rendererPassState, null, encoder); + GPUContext.endPass(encoder); + } + + /** + * Output to screen through screen based shading + * @param viewQuad + * @see ViewQuad + * @param scene3D + * @see Scene3D + * @param command + * @param colorTexture + */ + public static renderToViewQuad(view: View3D, viewQuad: ViewQuad, command: GPUCommandEncoder, colorTexture: Texture) { + let camera = view.camera; + viewQuad.colorTexture = colorTexture; + let encoder = GPUContext.beginRenderPass(command, viewQuad.rendererPassState); + GPUContext.bindCamera(encoder, camera); + + // viewQuad.x = view.viewPort.x; + // viewQuad.y = view.viewPort.y; + // viewQuad.scaleX = view.viewPort.width; + // viewQuad.scaleY = view.viewPort.height; + // viewQuad.transform.updateWorldMatrix(true); + // encoder.setViewport( + // view.viewPort.x * webGPUContext.presentationSize[0], + // view.viewPort.y * webGPUContext.presentationSize[1], + // view.viewPort.width * webGPUContext.presentationSize[0], + // view.viewPort.height * webGPUContext.presentationSize[1], + // 0.0, 1.0); + // encoder.setScissorRect( + // view.viewPort.x * webGPUContext.presentationSize[0], + // view.viewPort.y * webGPUContext.presentationSize[0], + // view.viewPort.width * webGPUContext.presentationSize[0], + // view.viewPort.height * webGPUContext.presentationSize[1], + // ); + + // encoder.setScissorRect(view.viewPort.x, view.viewPort.y, 300, 150); + // encoder.setViewport(view.viewPort.x, view.viewPort.y, view.viewPort.width / (view.viewPort.width / view.viewPort.height), view.viewPort.height, 0.0, 1.0); + // encoder.setScissorRect(view.viewPort.x, view.viewPort.y, view.viewPort.width, view.viewPort.height); + + // encoder.setViewport(camera.viewPort.x, camera.viewPort.y, camera.viewPort.width, camera.viewPort.height, 0.0, 1.0); + // encoder.setScissorRect(camera.viewPort.x, camera.viewPort.y, camera.viewPort.width, camera.viewPort.height); + + viewQuad.quadRenderer.nodeUpdate(view, RendererType.COLOR, viewQuad.rendererPassState, null); + viewQuad.quadRenderer.renderPass2(view, RendererType.COLOR, viewQuad.rendererPassState, null, encoder); + GPUContext.endPass(encoder); + } + + /** + * Perform the final calculation and submit the Shader to the GPU + * @param command + * @param computes + */ + public static computeCommand(command: GPUCommandEncoder, computes: ComputeShader[]) { + let computePass = command.beginComputePass(); + for (let i = 0; i < computes.length; i++) { + const compute = computes[i]; + compute.compute(computePass); + } + computePass.end(); + } +} diff --git a/src/engine/math/Matrix4.ts b/src/engine/math/Matrix4.ts index 4db4eb0e..03918dce 100644 --- a/src/engine/math/Matrix4.ts +++ b/src/engine/math/Matrix4.ts @@ -1934,7 +1934,7 @@ export class Matrix4 { /** * Returns the value of the matrix as a string * - * @returns string 字符 + * @returns string * @version Orillusion3D 0.5.1 */ public toString(): string { From 680b2e858b8a549e71f6812b1efa100d9599aeb4 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Mon, 24 Apr 2023 10:48:29 +0800 Subject: [PATCH 022/100] feat(ecs): add base entity (#28) * feat(ecs): add base entity add ecs entity add res add engine main entry add object3D --- .gitignore | 2 + src/engine/Engine3D.ts | 355 ++++++++ src/engine/assets/Res.ts | 354 ++++++++ src/engine/core/entities/Entity.ts | 342 ++++++++ src/engine/core/entities/Object3D.ts | 504 +++++++++++ .../core/bindGroups/GlobalUniformGroup.ts | 2 +- src/engine/math/Color.ts | 698 ++++------------ src/engine/math/Line.ts | 8 +- src/engine/math/MathUtil.ts | 786 ++++++++++++++++++ src/engine/math/Matrix4.ts | 23 +- 10 files changed, 2500 insertions(+), 574 deletions(-) create mode 100644 src/engine/Engine3D.ts create mode 100644 src/engine/assets/Res.ts create mode 100644 src/engine/core/entities/Entity.ts create mode 100644 src/engine/core/entities/Object3D.ts create mode 100644 src/engine/math/MathUtil.ts diff --git a/.gitignore b/.gitignore index 8bf04c36..edeb56a2 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ package-lock.json /.env /.env.local /js + +/.vscode diff --git a/src/engine/Engine3D.ts b/src/engine/Engine3D.ts new file mode 100644 index 00000000..5fc4120b --- /dev/null +++ b/src/engine/Engine3D.ts @@ -0,0 +1,355 @@ +import { version } from '../../package.json'; +import { Res } from './assets/Res'; +import { ShaderLib } from './assets/shader/ShaderLib'; +import { View3D } from './core/View3D'; +import { webGPUContext } from './gfx/graphics/webGpu/Context3D'; +import { CanvasConfig } from './gfx/graphics/webGpu/CanvasConfig'; +import { GlobalBindGroup } from './gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { RTResourceMap } from './gfx/renderJob/frame/RTResourceMap'; +import { ForwardRenderJob } from './gfx/renderJob/jobs/ForwardRenderJob'; +import { RendererJob } from './gfx/renderJob/jobs/RendererJob'; +import { FXAAPost } from './gfx/renderJob/post/FXAAPost'; +import { InputSystem } from './io/InputSystem'; +import { Color } from './math/Color'; +import { Interpolator } from './math/TimeInterpolator'; +import { EngineSetting } from './setting/EngineSetting'; +import { defaultRes } from './textures/DefaultRes'; +import { Time } from './util/Time'; + +/** + * Orillusion 3D Engine + * @notExported + * @group engine3D + */ +class _Engine3D { + /** + * @internal + */ + // [x: string]: any; + /** + * resource manager + */ + public res: Res; + /** + * input system + */ + public inputSystem: InputSystem; + public views: View3D[]; + + private _frameRateValue: number = 0; + private _frameRate: number = 360; + private _isRun: boolean = false; + private _frameTimeCount: number = 0; + private _deltaTime: number = 0; + private _time: number = 0; + + public get frameRate(): number { + return this._frameRate; + } + + public set frameRate(value: number) { + this._frameRate = value; + this._frameRateValue = 1.0 / value; + if (value >= 360) { + this._frameRateValue = 0; + } + } + + public get size(): number[] { + return webGPUContext.presentationSize; + } + + public get aspect(): number { + return webGPUContext.aspect; + } + + /** + * engine setting + */ + public setting: EngineSetting = { + occlusionQuery: { + enable: true, + debug: false, + }, + pick: { + enable: true, + mode: `bound`, + detail: `mesh`, + }, + render: { + debug: false, + renderPassState: 4, + renderState_left: 5, + renderState_right: 5, + renderState_split: 0.5, + quadScale: 1, + hdrExposure: 1.5, + debugQuad: -1, + maxPointLight: 1000, + maxDirectLight: 4, + maxSportLight: 1000, + drawOpMin: 0, + drawOpMax: Number.MAX_SAFE_INTEGER, + drawTrMin: 0, + drawTrMax: Number.MAX_SAFE_INTEGER, + zPrePass: false, + gi: false, + postProcessing: { + globalFog: { + debug: false, + enable: false, + fogType: 0.0, + height: 100, + start: 400, + end: 0, + density: 0.02, + ins: 1, + fogColor: new Color(84 / 255, 90 / 255, 239 / 255, 1), + }, + ssao: { + enable: false, + radius: 0.15, + bias: -0.1, + aoPower: 2.0, + debug: true, + }, + outline: { + enable: false, + strength: 1, + groupCount: 4, + outlinePixel: 2, + fadeOutlinePixel: 4, + useAddMode: false, + debug: true, + }, + taa: { + enable: false, + jitterSeedCount: 8, + blendFactor: 0.1, + sharpFactor: 0.6, + sharpPreBlurFactor: 0.5, + temporalJitterScale: 0.13, + debug: true, + }, + gtao: { + enable: false, + darkFactor: 1.0, + maxDistance: 5.0, + maxPixel: 50.0, + rayMarchSegment: 6, + multiBounce: false, + usePosFloat32: true, + blendColor: true, + debug: true, + }, + ssr: { + enable: false, + pixelRatio: 1, + fadeEdgeRatio: 0.2, + rayMarchRatio: 0.5, + fadeDistanceMin: 600, + fadeDistanceMax: 2000, + roughnessThreshold: 0.5, + powDotRN: 0.2, + mixThreshold: 0.1, + debug: true, + }, + bloom: { + enable: false, + blurX: 4, + blurY: 4, + intensity: 0.25, + brightness: 1.3, + debug: false, + }, + fxaa: { + enable: false, + }, + depthOfView: { + enable: false, + iterationCount: 3, + pixelOffset: 1.0, + near: 150, + far: 300, + }, + }, + }, + shadow: { + enable: true, + type: 'HARD', + shadowBias: 0.00204, + pointShadowBias: 0.002, + shadowQuality: 2.5, + shadowBound: 50, + shadowSize: 2048, + pointShadowSize: 1024, + shadowSoft: 0.005, + shadowNear: 1, + shadowFar: 2000, + needUpdate: true, + autoUpdate: true, + updateFrameRate: 2, + debug: false, + }, + gi: { + enable: false, + offsetX: 0, + offsetY: 0, + offsetZ: 0, + probeSpace: 64, + probeXCount: 4, + probeYCount: 2, + probeZCount: 4, + probeSize: 32, + probeSourceTextureSize: 2048, + octRTMaxSize: 2048, + octRTSideSize: 16, + maxDistance: 64 * 1.73, + normalBias: 0.25, + depthSharpness: 1, + hysteresis: 0.98, + lerpHysteresis: 0.01, + irradianceChebyshevBias: 0.01, + rayNumber: 144, + irradianceDistanceBias: 32, + indirectIntensity: 1.0, + ddgiGamma: 2.2, + bounceIntensity: 0.025, + probeRoughness: 1, + realTimeGI: false, + debug: false, + autoRenderProbe: false, + }, + sky: { + type: 'HDRSKY', + sky: null, + skyExposure: 1.0, + defaultFar: 1000000, + defaultNear: 1, + }, + light: { + maxLight: 1024, + }, + material: { + materialChannelDebug: false, + materialDebug: false + }, + }; + + private _beforeRender: Function; + private _renderLoop: Function; + private _lateRender: Function; + /** + * @internal + */ + public renderJobs: Map; + + public get width(): number { + return webGPUContext.windowWidth; + } + + public get height(): number { + return webGPUContext.windowHeight; + } + + /** + * create webgpu 3d engine + * @param descriptor {@link CanvasConfig} + * @returns + */ + public async init(descriptor: { canvasConfig?: CanvasConfig; beforeRender?: Function; renderLoop?: Function; lateRender?: Function, engineSetting?: EngineSetting } = {}) { + console.log('engine version', version); + + this.setting = { ...this.setting, ...descriptor.engineSetting } + + await webGPUContext.init(descriptor.canvasConfig); + + ShaderLib.init(); + + GlobalBindGroup.initCommon(); + + this.res = new Res(); + + await defaultRes.initCommon(); + + RTResourceMap.init(); + + this._beforeRender = descriptor.beforeRender; + this._renderLoop = descriptor.renderLoop; + this._lateRender = descriptor.lateRender; + this.inputSystem = new InputSystem(); + this.inputSystem.initCanvas(webGPUContext.canvas); + return; + } + + public startRenderView(view: View3D) { + this.renderJobs ||= new Map(); + this.views = [view]; + let renderJob = new ForwardRenderJob(view); + this.renderJobs.set(view, renderJob); + renderJob.addPost(new FXAAPost()); + renderJob.start(); + this.render(0); + return renderJob; + } + + public startRenderViews(views: View3D[]) { + this.renderJobs ||= new Map(); + this.views = views; + for (let i = 0; i < views.length; i++) { + const view = views[i]; + let renderJob = new ForwardRenderJob(view); + this.renderJobs.set(view, renderJob); + renderJob.addPost(new FXAAPost()); + renderJob.start(); + } + this.render(0); + } + + public getRenderJob(view: View3D): RendererJob { + return this.renderJobs.get(view); + } + + + /** + * @internal + */ + public render(time) { + if (!this._isRun) { + this._deltaTime = time - this._time; + this._time = time; + + if (this._frameRateValue > 0) { + this._frameTimeCount += this._deltaTime * 0.001; + if (this._frameTimeCount >= this._frameRateValue * 0.95) { + this._frameTimeCount = 0; + this.updateFrame(time); + } + } else { + this.updateFrame(time); + } + } + requestAnimationFrame((t) => this.render(t)); + } + + public updateFrame(time: number) { + Time.delta = time - Time.time; + Time.time = time; + Time.frame += 1; + // let camera = Camera3D.mainCamera; + Interpolator.tick(Time.delta); + if (this._beforeRender) this._beforeRender(); + + this.renderJobs.forEach((v, k) => { + v.render(this._renderLoop); + }); + + if (this._lateRender) this._lateRender(); + } +} + +/** + * Orillusion 3D + * @group engine3D + */ +export let Engine3D = new _Engine3D(); diff --git a/src/engine/assets/Res.ts b/src/engine/assets/Res.ts new file mode 100644 index 00000000..4f00da16 --- /dev/null +++ b/src/engine/assets/Res.ts @@ -0,0 +1,354 @@ + +import { Object3D } from '../core/entities/Object3D'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { FileLoader } from '../loader/FileLoader'; +import { LoaderFunctions } from '../loader/LoaderFunctions'; +import { GLBParser } from '../loader/parser/gltf/GLBParser'; +import { GLTFParser } from '../loader/parser/gltf/GLTFParser'; +import { OBJParser } from '../loader/parser/OBJParser'; +import { MaterialBase } from '../materials/MaterialBase'; +import { BitmapTexture2D } from '../textures/BitmapTexture2D'; +import { BitmapTextureCube } from '../textures/BitmapTextureCube'; +import { HDRTextureCube } from '../textures/HDRTextureCube'; +import { B3DMParser } from '../loader/parser/B3DMParser'; +import { I3DMParser } from "../loader/parser/I3DMParser"; +import { FntParser, FontInfo } from "../loader/parser/FntParser"; +import { AtlasParser } from "../loader/parser/AtlasParser"; +import { GUIAtlasTexture } from '../components/gui/core/GUIAtlasTexture'; +import { GUISubTexture } from '../components/gui/core/GUISubTexture'; +import { GLTF_Info } from '../loader/parser/gltf/GLTFInfo'; +import { HDRTexture } from '../textures/HDRTexture'; +import { LDRTextureCube } from '../textures/LDRTextureCube'; +import { fonts } from './Fonts'; +// import { PrefabLoader } from '../plugins/serialize/unserialize/PrefabLoader'; + +/** + * Resource management classes for textures, materials, models, and preset bodies. + * @group Assets + */ +export class Res { + private _texturePool: Map; + private _materialPool: Map; + private _prefabPool: Map; + // private _prefabLoaderPool: Map; + private _atlasList: Map; + private _gltfPool: Map; + + /** + * @constructor + */ + constructor() { + this._texturePool = new Map(); + this._materialPool = new Map(); + this._prefabPool = new Map(); + // this._prefabLoaderPool = new Map; + this._atlasList = new Map(); + this._gltfPool = new Map; + } + + public getGltf(url: string): GLTF_Info { + return this._gltfPool.get(url); + } + + // public getPrefabLoader(url: string): PrefabLoader { + // return this._prefabLoaderPool.get(url); + // } + + public addAtlas(name: string, atlas: GUIAtlasTexture) { + atlas.name = name; + this._atlasList.set(name, atlas); + } + + public getAtlas(name: string) { + return this._atlasList.get(name); + } + + public getSubTexture(id: string): GUISubTexture { + for (let item of this._atlasList.values()) { + let tex = item.getTexture(id); + if (tex) return tex; + } + return null; + } + + /** + * add a texture with reference of url + * @param url file path + * @param texture source texture + */ + public addTexture(url: string, texture: Texture) { + this._texturePool.set(url, texture); + } + + /** + * get texture by url + * @param url file path + * @returns + */ + public getTexture(url: string): Texture { + return this._texturePool.get(url); + } + + /** + * add a material with reference of name + * @param name material name + * @param mat target material + */ + public addMat(name: string, mat: MaterialBase) { + return this._materialPool.set(name, mat); + } + + /** + * get material by name + * @param name mateiral name + * @returns + */ + public getMat(name: string) { + return this._materialPool.get(name); + } + + /** + * add prefab with reference name + * @param name prefab name + * @param rootScene root object of prefab + */ + public addPrefab(name: string, rootScene: Object3D) { + this._prefabPool.set(name, rootScene); + } + + /** + * get prefab by name + * @param name prefab name + * @returns + */ + public getPrefab(name: string) { + return this._prefabPool.get(name).instantiate(); + } + + /** + * load a gltf file + * @param url the url of file + * @param loaderFunctions callback + * @returns + */ + public async loadGltf(url: string, loaderFunctions?: LoaderFunctions): Promise { + if (this._prefabPool.has(url)) { + return this._prefabPool.get(url) as Object3D; + } + + let parser; + let ext = url.substring(url.lastIndexOf('.')).toLowerCase(); + let loader = new FileLoader(); + if (ext == '.gltf') { + parser = await loader.load(url, GLTFParser, loaderFunctions); + + } else { + parser = await loader.load(url, GLBParser, loaderFunctions); + } + let obj = parser.data as Object3D; + this._prefabPool.set(url, obj); + this._gltfPool.set(url, parser.gltf); + return obj; + // return null; + } + + /** + * load obj file + * @param url obj file path + * @param loaderFunctions callback + * @returns + */ + public async loadObj(url: string, loaderFunctions?: LoaderFunctions): Promise { + if (this._prefabPool.has(url)) { + return this._prefabPool.get(url) as Object3D; + } + + let parser; + let ext = url.substring(url.lastIndexOf('.')).toLowerCase(); + let loader = new FileLoader(); + if (ext == ".obj") { + parser = await loader.load(url, OBJParser, loaderFunctions); + } + let obj = parser.data as Object3D; + this._prefabPool.set(url, obj); + return obj; + // return null; + } + + /** + * load b3dm file by url + * @param url path of file + * @param loaderFunctions callback + * @returns + */ + public async loadB3DM(url: string, loaderFunctions?: LoaderFunctions, userData?: any): Promise { + if (this._prefabPool.has(url)) { + return this._prefabPool.get(url) as Object3D; + } + let loader = new FileLoader(); + let parser = await loader.load(url, B3DMParser, loaderFunctions, userData); + let obj = parser.data; + this._prefabPool.set(url, obj); + return obj; + } + + /** + * load i3dm file by url + * @param url path of i3dm file + * @param loaderFunctions callback + * @returns + */ + public async loadI3DM(url: string, loaderFunctions?: LoaderFunctions, userData?: any): Promise { + if (this._prefabPool.has(url)) { + return this._prefabPool.get(url) as Object3D; + } + let loader = new FileLoader(); + let parser = await loader.load(url, I3DMParser, loaderFunctions, userData); + let obj = parser.data; + this._prefabPool.set(url, obj); + return obj; + } + + /** + * load font file by url + * @param url font file url + * @param loaderFunctions callback + * @returns + */ + public async loadFont(url: string, loaderFunctions?: LoaderFunctions, userData?: any): Promise { + let loader = new FileLoader(); + let parser = await loader.load(url, FntParser, loaderFunctions, userData); + let data = parser.data as FontInfo; + fonts.addFontData(data.face, data.size, data) + return parser.data; + } + + /** + * load a atlas file by url + * @param url file path + * @param loaderFunctions callback + * @returns + */ + public async loadAtlas(url: string, loaderFunctions?: LoaderFunctions): Promise { + let loader = new FileLoader(); + let parser = await loader.load(url, AtlasParser, loaderFunctions, url); + return parser.data; + } + + /** + * load texture by url + * @param url texture path + * @param loaderFunctions callback + * @param flipY use filp y or not + * @returns + */ + public async loadTexture(url: string, loaderFunctions?: LoaderFunctions, flipY?: boolean) { + if (this._texturePool.has(url)) { + return this._texturePool.get(url); + } + let texture = new BitmapTexture2D(); + texture.textureSource.setNetImage(url); + texture.flipY = flipY; + await texture.load(url, loaderFunctions); + this._texturePool.set(url, texture); + return texture; + } + + /** + * load a hdr texture + * @param url texture url + * @param loaderFunctions callback + * @returns + */ + public async loadHDRTexture(url: string, loaderFunctions?: LoaderFunctions) { + if (this._texturePool.has(url)) { + return this._texturePool.get(url); + } + + let hdrTexture = new HDRTexture(); + hdrTexture.textureSource.setHDRNetImage(url); + hdrTexture = await hdrTexture.load(url, loaderFunctions); + this._texturePool.set(url, hdrTexture); + return hdrTexture; + } + + + /** + * load hdr cube texture + * @param url file url + * @param loaderFunctions callback + * @returns + */ + public async loadHDRTextureCube(url: string, loaderFunctions?: LoaderFunctions) { + if (this._texturePool.has(url)) { + return this._texturePool.get(url); + } + let hdrTexture = new HDRTextureCube(); + hdrTexture = await hdrTexture.load(url, loaderFunctions); + hdrTexture.textureSource.setCubeHDR(url); + this._texturePool.set(url, hdrTexture); + return hdrTexture; + } + + /** + * load ldr cube texture + * @param url file path + * @param loaderFunctions callback + * @returns + */ + public async loadLDRTextureCube(url: string, loaderFunctions?: LoaderFunctions) { + if (this._texturePool.has(url)) { + return this._texturePool.get(url); + } + let ldrTextureCube = new LDRTextureCube(); + ldrTextureCube = await ldrTextureCube.load(url, loaderFunctions); + ldrTextureCube.textureSource.setCubeLDR(url); + this._texturePool.set(url, ldrTextureCube); + return ldrTextureCube; + } + + /** + * load texture data from array of web url. + * make sure there are six images in a group, + * and the order is: nx, px, py, ny, nz, pz + * @param urls + */ + public async loadTextureCubeMaps(urls: string[]) { + let url = urls[0]; + if (this._texturePool.has(url)) { + return this._texturePool.get(url); + } + + let textureCube = new BitmapTextureCube(); + await textureCube.load(urls); + textureCube.textureSource.setCubeFace6(urls); + this._texturePool.set(urls[0], textureCube); + return textureCube; + } + + /** + * load texture data from url. + * the image is assembled from six images into cross shaped image. + * @param url the path of image + */ + public async loadTextureCubeStd(url: string, loaderFunctions?: LoaderFunctions) { + if (this._texturePool.has(url)) { + return this._texturePool.get(url); + } + + let cubeMap = new BitmapTextureCube(); + await cubeMap.loadStd(url); + cubeMap.textureSource.setCubeStd(url); + return cubeMap; + } + + public async loadJSON(url: string, loaderFunctions?: LoaderFunctions) { + return await new FileLoader() + .loadJson(url, loaderFunctions) + .then(async (ret) => { + return ret; + }) + .catch((e) => { + }); + } +} diff --git a/src/engine/core/entities/Entity.ts b/src/engine/core/entities/Entity.ts new file mode 100644 index 00000000..9863bff3 --- /dev/null +++ b/src/engine/core/entities/Entity.ts @@ -0,0 +1,342 @@ +import { ComponentBase } from '../../components/ComponentBase'; +import { RenderNode } from '../../components/renderer/RenderNode'; +import { Transform } from '../../components/Transform'; +import { CEventDispatcher } from '../../event/CEventDispatcher'; +import { RenderLayer } from '../../gfx/renderJob/config/RenderLayer'; +import { Vector3 } from '../../math/Vector3'; +import { UUID } from '../../util/Global'; +import { BoundingBox } from '../bound/BoundingBox'; +import { IBound } from '../bound/IBound'; +import { Object3D } from './Object3D'; + +/** + * The entity class provides an abstract base class for all scene objects that are considered to have "existence" in the scene, + * which can be considered as actual objects with positions and sizes. + * Entity class is an abstract class and cannot be instantiated. If you want to instantiate it, please use the Object 3D class. + * @group Entity + */ +export class Entity extends CEventDispatcher { + /** + * + * The name of the object. The default value is an empty string. + */ + public name: string = ''; + + protected readonly _uuid: string = ''; + + /** + * The unique identifier of the object. + */ + public get uuid(): string { + return this._uuid; + } + + /** + * + * The layer membership of the object. + * The object is only visible when it has at least one common layer with the camera in use. + * When using a ray projector, this attribute can also be used to filter out unwanted objects in ray intersection testing. + */ + private _renderLayer: RenderLayer = RenderLayer.None; + + public get renderLayer(): RenderLayer { + return this._renderLayer; + } + + public set renderLayer(value: RenderLayer) { + for (let i = 0; i < this.entityChildren.length; i++) { + const element = this.entityChildren[i]; + element.renderLayer = value; + } + this._renderLayer = value; + } + + /** + * + * The Transform attached to this object. + */ + public transform: Transform; + /** + * + * Renderer components + */ + public renderNode: RenderNode; + /** + * + * An array containing sub objects of an object + */ + public entityChildren: Entity[]; + /** + * + * List of components attached to an object + */ + public components: Map; + /** + * + * The bounding box of an object + */ + public bound: IBound; + + protected waitDisposeComponents: ComponentBase[]; + + private _dispose: boolean = false; + // private _visible: boolean = true; + + /** + * + * Starting from the object itself, search for the object and its children, and return the first child object with a matching name. + * For most objects, the name is an empty string by default. You must manually set it to use this method. + * @param name input name + * @returns result Entity + */ + public getObjectByName(name: string): Entity { + let isPath = name.indexOf('/') >= 0; + if (!isPath) { + return this.getChildByName(name, false); + } else { + let list = name.split('/'); + let currentEntity = this; + + while (list.length > 0 && currentEntity) { + let shortName = list.shift(); + currentEntity = currentEntity.getChildByName(shortName, false); + if (!currentEntity) { + return null; + } + } + return currentEntity; + } + } + + /** + * + * @constructor + */ + constructor() { + super(); + this.entityChildren = []; + this.components = new Map(); + this.waitDisposeComponents = []; + this._uuid = UUID(); + } + + /** + * + * Returns the number of child objects of an object + */ + public get numChildren(): number { + return this.entityChildren.length; + } + + /** + * + * Add an object as a child of this object. You can add any number of objects. + * Any current parent object on the object passed here will be deleted, as an object can only have at most one parent object. + * @param child target child entity + * @returns + */ + public addChild(child: Entity): Entity { + if (child == null) { + return new console.error('child is null!'); + } + if (child === this) { + return new console.error('child is self!'); + } + + let index = this.entityChildren.indexOf(child); + if (index == -1) { + if (child.transform.parent) { + child.transform.parent.object3D.removeChild(child); + } + child.transform.parent = this.transform; + this.entityChildren.push(child); + child.transform.notifyLocalChange(); + return child; + } + return null; + } + + /** + * + * Remove the child objects of the object. You can remove any number of objects. + * @param child Removed objects + */ + public removeChild(child: Entity) { + if (child === null) return new console.error('remove child is null!'); + if (child === this) return new console.error('add child is self!'); + let index = this.entityChildren.indexOf(child); + if (index != -1) { + this.entityChildren.splice(index, 1); + child.transform.parent = null; + } + } + + /** + * + * Remove all children of the current object + */ + public removeAllChild() { + while (this.numChildren > 0) { + this.removeChild(this.entityChildren[0]); + } + } + + /** + * + * Remove the current node from the parent + * @returns this + */ + public removeSelf(): this { + return this.removeFromParent(); + } + + /** + * + * Search for child nodes of objects and remove child objects with matching indexes. + * @param index assign index + * @returns + */ + public removeChildByIndex(index: number) { + if (index >= 0 && index < this.entityChildren.length) { + this.removeChild(this.entityChildren[index]); + } else { + console.error('remove child by index , index out of range'); + } + } + + /** + * + * Does the current object contain a certain object + * @param child certain object + * @returns boolean + */ + public hasChild(child: Entity) { + let index = this.entityChildren.indexOf(child); + return index != -1; + } + + /** + * + * Remove the current node from the parent + * @returns this + */ + public removeFromParent(): this { + let parent = this.transform.parent; + if (parent && parent.object3D) { + parent.object3D.removeChild(this); + } + return this; + } + + /** + * + * Search for object children and return the first child object with a matching index. + * @param index matching index + * @returns child entity + */ + public getChildByIndex(index: number): Entity { + let outObj = null; + if (index < this.entityChildren.length) { + outObj = this.entityChildren[index]; + } + return outObj; + } + + /** + * + * Search for object children and return a child object with a matching name。 + * @param name matching name + * @param loopChild Whether to traverse the children of the child object. The default value is true + * @returns result + */ + public getChildByName(name: string, loopChild: boolean = true) { + let out = null; + for (const iterator of this.entityChildren) { + if (iterator.name == name) { + out = iterator; + return out; + } else if (loopChild) { + out = iterator.getChildByName(name, loopChild); + if (out) { + return out; + } + } + } + return out; + } + + /** + * @internal + */ + public update() { + } + + /** + * @internal + */ + public dispose() { + this._dispose = true; + } + + /** + * + * @private + * @returns + */ + public instantiate(): Object3D { + return null; + } + + /** + * + * @private + * @returns + */ + public waitUpdate(): void { + if (this._dispose) { + if (this.transform.parent) { + this.transform.parent.object3D.removeChild(this); + } + this.components.forEach((v, k) => { + v.enable = false; + v.destroy(); + }); + this.components.clear(); + } else { + ComponentBase.waitStartComponent.forEach((v, k) => { + v.forEach((v) => { + v[`__start`](); + }) + ComponentBase.waitStartComponent.delete(k); + }); + } + } + + /** + * Returns a bounding box that defines the display area of the specified layer. + * @returns + */ + public genBounds() { + if (!this.bound) { + this.bound = new BoundingBox(Vector3.ZERO.clone(), Vector3.ONE.clone()); + } + for (const children of this.entityChildren) { + if (children.bound) { + this.bound.merge(children.bound); + } + } + return this.bound; + } + + + /** + * release current object + */ + public destroy() { + this.transform.parent = null; + this.components.forEach((c) => { + c.destroy(); + }); + this.components.clear(); + } +} diff --git a/src/engine/core/entities/Object3D.ts b/src/engine/core/entities/Object3D.ts new file mode 100644 index 00000000..941adf31 --- /dev/null +++ b/src/engine/core/entities/Object3D.ts @@ -0,0 +1,504 @@ +import { ComponentBase } from '../../components/ComponentBase'; +import { Transform } from '../../components/Transform'; +import { Quaternion } from '../../math/Quaternion'; +import { Vector3 } from '../../math/Vector3'; +import { Entity } from './Entity'; +import { Ctor } from "../../util/Global"; +import { SerializeTag } from '../../util/SerializeDefine'; +/** + * The base class of most objects provides a series of properties and methods for manipulating objects in three-dimensional space. + * @group Entity + */ +export class Object3D extends Entity { + protected _isScene3D: boolean; + public serializeTag?: SerializeTag; + public prefabRef?: string; + + /** + * Instantiate a 3D object + */ + constructor() { + super(); + this.transform = this.addComponent(Transform); + } + + public get isScene3D(): boolean { + return this._isScene3D; + } + + /** + * + * Traverse all sub objects starting from the object itself. + * If there are still sub objects in the sub object, recursively traverse. + * @param callFunction execution body. Will execute sub objects as parameters + * @returns + */ + public forChild(call: Function) { + this.entityChildren.forEach((element) => { + call(element); + (element as Object3D).forChild(call); + }); + } + + /** + * + * Create a new component and add it to the object, and return an instance of the component. + * If a component of this type already exists, it will not be added and will return null. + * @param c class of component + * @return result component + */ + public addComponent(c: Ctor, param?: any): T { + if (!this.components.has(c.prototype)) { + let instance: T = new c() as T; + instance.object3D = this; + instance[`__init`](param); + // instance[`__start`](); + this.components.set(c.prototype, instance); + this.appendLateStart(instance); + return instance; + } + return null; + } + + private appendLateStart(component: ComponentBase) { + let arr = ComponentBase.waitStartComponent.get(this); + if (!arr) { + ComponentBase.waitStartComponent.set(this, [component]); + } else { + let index = arr.indexOf(component); + if (index == -1) { + arr.push(component); + } + } + } + + /** + * + * Returns an instance of a component object of the specified type. + * If there are no components of that type, a new component is created and added to the object. + * @param c class of component + * @returns result component + */ + public getOrAddComponent(c: Ctor): T { + let component = this.components.get(c.prototype); + if (!component) { + component = this.addComponent(c); + } + return component as T; + } + + /** + * + * Remove components of the specified type + * @param c class of component + */ + public removeComponent(c: Ctor) { + if (this.components.has(c.prototype)) { + let component = this.components.get(c.prototype); + this.components.delete(c.prototype); + component[`__stop`](); + component.destroy(); + } + } + + /** + * + * Is there a component of the specified type + * @param c type of component + * @returns boolean + */ + public hasComponent(c: Ctor): boolean { + return this.components.has(c.prototype); + } + + /** + * + * Returns a component of the specified type. + * @param c class of component + * @returns result component + */ + public getComponent(c: Ctor): T { + return this.components.get(c.prototype) as T; + } + + /** + * + * Returns a component object of the specified type from the parent node. + * If there are no components of that type, + * calls the parent object lookup of the parent object + * @param c class of component + * @returns reulst component + */ + public getComponentFromParent(c: Ctor): T { + if (!this.parent) { + return null; + } + + let component = this.parent.object3D.getComponent(c); + if (component) { + return component; + } + + return this.parent.object3D.getComponentFromParent(c); + } + + /** + * + * Returns an array of component objects of the specified type. + * If there are no components of that type, search in the list of self body class objects + * @param c class of component + * @returns result components + */ + public getComponentsInChild(c: Ctor): T[] { + let list: T[] = []; + let component = this.components.get(c.prototype); + if (component) { + list.push(component as T); + } + for (let i = 0; i < this.entityChildren.length; i++) { + let child = this.entityChildren[i] as Object3D; + let coms = child.getComponentsInChild(c); + list.push(...coms); + } + return list; + } + + /** + * + * Returns all components of the specified type contained in the current object and its children. + * If there are children in the child object, recursively search. + * @param c class of component + * @param outList result component list + * @param includeInactive Whether to include invisible objects, default to false + * @returns {outList} + */ + public getComponents(c: Ctor, outList?: Array, includeInactive?: boolean): T[] { + outList ||= []; + let component = this.getComponent(c); + if (component && (component.enable || includeInactive)) { + outList.push(component) + }; + for (let i = 0, count = this.entityChildren.length; i < count; i++) { + let child = this.entityChildren[i]; + if (child && child instanceof Object3D) { + child.getComponents(c, outList, includeInactive); + } + } + return outList; + } + + /** + * + * Quickly obtain components and no longer access child nodes after obtaining them at a certain node + * @template T + * @param {{ new(): T; }} c class of component + * @param ret List of incoming T + * @param includeInactive Whether to include invisible objects, default to false + * @return {*} {T} + * @memberof ELPObject3D + */ + public getComponentsExt(c: Ctor, ret?: T[], includeInactive?: boolean): T[] { + if (!ret) ret = []; + let component = this.components.get(c.prototype); + if (component && (component.enable || includeInactive)) { + ret.push(component as T); + } else { + for (const node of this.entityChildren) { + if (node instanceof Object3D) { + node.getComponentsExt(c, ret, includeInactive); + } + } + } + return ret; + } + + /** + * + * clone a Object3D + * @returns + */ + public clone(): Object3D { + return this.instantiate(); + } + + /** + * + * @private + * @returns + */ + public instantiate(): Object3D { + let tmp = new Object3D(); + tmp.name = this.name + "_clone"; + this.entityChildren.forEach((v, k) => { + let tmpChild = v.instantiate(); + tmp.addChild(tmpChild); + }); + + let coms = this.components; + coms.forEach((v, k) => { + v.cloneTo(tmp); + }); + return tmp; + } + + //**************** + //**************** + //**************** + //**************** + + /** + * Get the position of an object relative to its parent + */ + public get localPosition(): Vector3 { + return this.transform.localPosition; + } + + /** + * Set the position of an object relative to its parent + */ + public set localPosition(value: Vector3) { + this.transform.localPosition = value; + } + + /** + * Get the rotation attribute of an object relative to its parent + */ + public get localRotation(): Vector3 { + return this.transform.localRotation; + } + + /** + * Set the rotation attribute of an object relative to its parent + */ + public set localRotation(value: Vector3) { + this.transform.localRotation = value; + } + + /** + * Get the scaling attribute of an object relative to its parent + */ + public get localScale(): Vector3 { + return this.transform.localScale; + } + + /** + * Set the scaling attribute of an object relative to its parent + */ + public set localScale(value: Vector3) { + this.transform.localScale = value; + } + + /** + * Get the rotation attribute of an object relative to its parent, which is a quaternion + */ + public get localQuaternion(): Quaternion { + return this.transform.localRotQuat; + } + + /** + * Set the rotation attribute of an object relative to its parent, which is a quaternion + */ + public set localQuaternion(value: Quaternion) { + this.transform.localRotQuat = value; + } + + /** + * Notify transformation attribute updates + */ + public notifyChange(): void { + this.transform.notifyChange(); + } + + /** + * + * Transform component of object parent + */ + public get parent(): Transform { + return this.transform.parent; + } + + /** + * + * parent object3D + */ + public get parentObject(): Object3D { + return this.transform.parent.object3D; + } + + /** + * + * Set the x coordinate relative to the local coordinates of the parent container. + */ + public set x(value: number) { + this.transform.x = value; + } + + /** + * + * Get the x coordinate relative to the local coordinates of the parent container. + */ + public get x(): number { + return this.transform.x; + } + + /** + * Set the y coordinate relative to the local coordinates of the parent container. + */ + public set y(value: number) { + this.transform.y = value; + } + + /** + * + * Get the y coordinate relative to the local coordinates of the parent container. + */ + public get y(): number { + return this.transform.y; + } + + /** + * Set the z coordinate relative to the local coordinates of the parent container. + */ + public set z(value: number) { + this.transform.z = value; + } + + /** + * Get the z coordinate relative to the local coordinates of the parent container. + */ + public get z(): number { + return this.transform.z; + } + + /** + * Set the x scale relative to the local coordinates of the parent container. + */ + public set scaleX(value: number) { + this.transform.scaleX = value; + } + + /** + * + * Get the x scale relative to the local coordinates of the parent container. + */ + public get scaleX(): number { + return this.transform.scaleX; + } + + /** + * + * Set the y scale relative to the local coordinates of the parent container. + */ + public set scaleY(value: number) { + this.transform.scaleY = value; + } + + /** + * + * Get the y scale relative to the local coordinates of the parent container. + */ + public get scaleY(): number { + return this.transform.scaleY; + } + + /** + * + * Set the z scale relative to the local coordinates of the parent container. + */ + public set scaleZ(value: number) { + this.transform.scaleZ = value; + } + + /** + * + * Get the z scale relative to the local coordinates of the parent container. + */ + public get scaleZ(): number { + return this.transform.scaleZ; + } + + /** + * + * Set the x rotation relative to the local coordinates of the parent container. + */ + public set rotationX(value: number) { + this.transform.rotationX = value; + } + + /** + * + * Get the x rotation relative to the local coordinates of the parent container. + */ + public get rotationX(): number { + return this.transform.rotationX; + } + + /** + * + * Set the y rotation relative to the local coordinates of the parent container. + */ + public set rotationY(value: number) { + this.transform.rotationY = value; + } + + /** + * + * Get the y rotation relative to the local coordinates of the parent container. + */ + public get rotationY(): number { + return this.transform.rotationY; + } + + /** + * + * Set the z rotation relative to the local coordinates of the parent container. + */ + public set rotationZ(value: number) { + this.transform.rotationZ = value; + } + + /** + * + * Set the z rotation relative to the local coordinates of the parent container. + */ + public get rotationZ(): number { + return this.transform.rotationZ; + } + + /** + * @internal + */ + protected fixedUpdate(): void { + } + + /** + * @internal + */ + protected lateUpdate(): void { + } + + /** + * + * Recursive child nodes and execute specified function + * @param callback specified function + */ + public traverse(callback: (child) => void) { + callback(this); + for (let i = 0, l = this.entityChildren.length; i < l; i++) { + let item = this.entityChildren[i]; + if (item instanceof Object3D) { + item.traverse(callback); + } + } + + } + + /** + * + * Release self + */ + public destroy(): void { + super.destroy(); + } + +} diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalUniformGroup.ts b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalUniformGroup.ts index eed1502a..16e3762a 100644 --- a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalUniformGroup.ts +++ b/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalUniformGroup.ts @@ -31,7 +31,7 @@ export class GlobalUniformGroup { /** * - * @param matrixBindGroup 全局矩阵绑定group,通用统一 + * @param matrixBindGroup global matrix bindgroup */ constructor(matrixBindGroup: MatrixBindGroup) { this.uuid = UUID(); diff --git a/src/engine/math/Color.ts b/src/engine/math/Color.ts index 09ac7493..361763de 100644 --- a/src/engine/math/Color.ts +++ b/src/engine/math/Color.ts @@ -296,561 +296,145 @@ export class Color { public static PRIMARY = 0x3f51b5; // public static PRIMARYDARK = 0x303f9f; // public static ACCENT = 0xff4081; // - /** - * 白色十六进制值 - */ - public static WHITE = 0xffffff; // - /** - * 象牙色十六进制值 - */ - public static IVORY = 0xfffff0; // - /** - * 亮黄色十六进制值 - */ - public static LIGHTYELLOW = 0xffffe0; // - /** - * 黄色十六进制值 - */ - public static YELLOW = 0xffff00; // - /** - * 雪白色十六进制值 - */ - public static SNOW = 0xfffafa; // - /** - * 花白色十六进制值 - */ - public static FLORALWHITE = 0xfffaf0; // - /** - * 柠檬绸十六进制值 - */ - public static LEMONCHIFFON = 0xfffacd; // - /** - * 米绸色十六进制值 - */ - public static CORNSILK = 0xfff8dc; // - /** - * 海贝色十六进制值 - */ - public static SEASHELL = 0xfff5ee; // - /** - * 淡紫红十六进制值 - */ - public static LAVENDERBLUSH = 0xfff0f5; // - /** - * 番木色十六进制值 - */ - public static PAPAYAWHIP = 0xffefd5; // - /** - * 白杏色十六进制值 - */ - public static BLANCHEDALMOND = 0xffebcd; // - /** - * 浅玫瑰色十六进制值 - */ - public static MISTYROSE = 0xffe4e1; // - /** - * 桔黄色十六进制值 - */ - public static BISQUE = 0xffe4c4; // - /** - * 鹿皮色十六进制值 - */ - public static MOCCASIN = 0xffe4b5; // - /** - * 纳瓦白十六进制值 - */ - public static NAVAJOWHITE = 0xffdead; // - /** - * 桃色十六进制值 - */ - public static PEACHPUFF = 0xffdab9; // - /** - * 金色十六进制值 - */ - public static GOLD = 0xffd700; // - /** - * 粉红色十六进制值 - */ - public static PINK = 0xffc0cb; // - /** - * 亮粉红色十六进制值 - */ - public static LIGHTPINK = 0xffb6c1; // - /** - * 橙色十六进制值 - */ - public static ORANGE = 0xffa500; // - /** - * 亮肉色十六进制值 - */ - public static LIGHTSALMON = 0xffa07a; // - /** - * 暗桔黄色十六进制值 - */ - public static DARKORANGE = 0xff8c00; // - /** - * 珊瑚色十六进制值 - */ - public static CORAL = 0xff7f50; // - /** - * 热粉红色十六进制值 - */ - public static HOTPINK = 0xff69b4; // - /** - * 西红柿色十六进制值 - */ - public static TOMATO = 0xff6347; // - /** - * 红橙色十六进制值 - */ - public static ORANGERED = 0xff4500; // - /** - * 深粉红色十六进制值 - */ - public static DEEPPINK = 0xff1493; // - /** - * 紫红色十六进制值 - */ - public static FUCHSIA = 0xff00ff; // - /** - * 红紫色十六进制值 - */ - public static MAGENTA = 0xff00ff; // - /** - * 红色十六进制值 - */ - public static RED = 0xff0000; // - /** - * 老花色十六进制值 - */ - public static OLDLACE = 0xfdf5e6; // - /** - * 亮金黄色十六进制值 - */ - public static LIGHTGOLDENRODYELLOW = 0xfafad2; // - /** - * 亚麻色十六进制值 - */ - public static LINEN = 0xfaf0e6; // - /** - * 古董白十六进制值 - */ - public static ANTIQUEWHITE = 0xfaebd7; // - /** - * 鲜肉色十六进制值 - */ - public static SALMON = 0xfa8072; // - /** - * 幽灵白十六进制值 - */ - public static GHOSTWHITE = 0xf8f8ff; // - /** - * 薄荷色十六进制值 - */ - public static MINTCREAM = 0xf5fffa; // - /** - * 烟白色十六进制值 - */ - public static WHITESMOKE = 0xf5f5f5; // - /** - * 米色十六进制值 - */ - public static BEIGE = 0xf5f5dc; // - /** - * 浅黄色十六进制值 - */ - public static WHEAT = 0xf5deb3; // - /** - * 沙褐色十六进制值 - */ - public static SANDYBROWN = 0xf4a460; // - /** - * 天蓝色十六进制值 - */ - public static AZURE = 0xf0ffff; // - /** - * 蜜色十六进制值 - */ - public static HONEYDEW = 0xf0fff0; // - /** - * 艾利斯兰色十六进制值 - */ - public static ALICEBLUE = 0xf0f8ff; // - /** - * 黄褐色十六进制值 - */ - public static KHAKI = 0xf0e68c; // - /** - * 亮珊瑚色十六进制值 - */ - public static LIGHTCORAL = 0xf08080; // - /** - * 苍麒麟色十六进制值 - */ - public static PALEGOLDENROD = 0xeee8aa; // - /** - * 紫罗兰色十六进制值 - */ - public static VIOLET = 0xee82ee; // - /** - * 暗肉色十六进制值 - */ - public static DARKSALMON = 0xe9967a; // - /** - * 淡紫色十六进制值 - */ - public static LAVENDER = 0xe6e6fa; // - /** - * 亮青色十六进制值 - */ - public static LIGHTCYAN = 0xe0ffff; // - /** - * 实木色十六进制值 - */ - public static BURLYWOOD = 0xdeb887; // - /** - * 洋李色十六进制值 - */ - public static PLUM = 0xdda0dd; // - /** - * 淡灰色十六进制值 - */ - public static GAINSBORO = 0xdcdcdc; // - /** - * 暗深红色十六进制值 - */ - public static CRIMSON = 0xdc143c; // - /** - * 苍紫罗兰色十六进制值 - */ - public static PALEVIOLETRED = 0xdb7093; // - /** - * 金麒麟色十六进制值 - */ - public static GOLDENROD = 0xdaa520; // - /** - * 淡紫色十六进制值 - */ - public static ORCHID = 0xda70d6; // - /** - * 蓟色十六进制值 - */ - public static THISTLE = 0xd8bfd8; // - /** - * 亮灰色十六进制值 - */ - public static LIGHTGREY = 0xd3d3d3; // - /** - * 茶色十六进制值 - */ - public static TAN = 0xd2b48c; // - /** - * 巧可力色十六进制值 - */ - public static CHOCOLATE = 0xd2691e; // - /** - * 秘鲁色十六进制值 - */ - public static PERU = 0xcd853f; // - /** - * 印第安红十六进制值 - */ - public static INDIANRED = 0xcd5c5c; // - /** - * 中紫罗兰色十六进制值 - */ - public static MEDIUMVIOLETRED = 0xc71585; // - /** - * 银色十六进制值 - */ - public static SILVER = 0xc0c0c0; // - /** - * 暗黄褐色十六进制值 - */ - public static DARKKHAKI = 0xbdb76b; // - /** - * 褐玫瑰红十六进制值 - */ - public static ROSYBROWN = 0xbc8f8f; // - /** - * 中粉紫色十六进制值 - */ - public static MEDIUMORCHID = 0xba55d3; // - /** - * 暗金黄色十六进制值 - */ - public static DARKGOLDENROD = 0xb8860b; // - /** - * 火砖色十六进制值 - */ - public static FIREBRICK = 0xb22222; // - /** - * 粉蓝色十六进制值 - */ - public static POWDERBLUE = 0xb0e0e6; // - /** - * 亮钢兰色十六进制值 - */ - public static LIGHTSTEELBLUE = 0xb0c4de; // - /** - * 苍宝石绿十六进制值 - */ - public static PALETURQUOISE = 0xafeeee; // - /** - * 黄绿色十六进制值 - */ - public static GREENYELLOW = 0xadff2f; // - /** - * 亮蓝色十六进制值 - */ - public static LIGHTBLUE = 0xadd8e6; // - /** - * 暗灰色十六进制值 - */ - public static DARKGRAY = 0xa9a9a9; // - /** - * 褐色十六进制值 - */ - public static BROWN = 0xa52a2a; // - /** - * 赭色十六进制值 - */ - public static SIENNA = 0xa0522d; // - /** - * 暗紫色十六进制值 - */ - public static DARKORCHID = 0x9932cc; // - /** - * 苍绿色十六进制值 - */ - public static PALEGREEN = 0x98fb98; // - /** - * 暗紫罗兰色十六进制值 - */ - public static DARKVIOLET = 0x9400d3; // - /** - * 中紫色十六进制值 - */ - public static MEDIUMPURPLE = 0x9370db; // - /** - * 亮绿色十六进制值 - */ - public static LIGHTGREEN = 0x90ee90; // - /** - * 暗海兰色十六进制值 - */ - public static DARKSEAGREEN = 0x8fbc8f; // - /** - * 重褐色十六进制值 - */ - public static SADDLEBROWN = 0x8b4513; // - /** - * 暗洋红十六进制值 - */ - public static DARKMAGENTA = 0x8b008b; // - /** - * 暗红色十六进制值 - */ - public static DARKRED = 0x8b0000; // - /** - * 紫罗兰蓝色十六进制值 - */ - public static BLUEVIOLET = 0x8a2be2; // - /** - * 亮天蓝色十六进制值 - */ - public static LIGHTSKYBLUE = 0x87cefa; // - /** - * 天蓝色十六进制值 - */ - public static SKYBLUE = 0x87ceeb; // - /** - * 灰色十六进制值 - */ - public static GRAY = 0x808080; // - /** - * 橄榄色十六进制值 - */ - public static OLIVE = 0x808000; // - /** - * 紫色十六进制值 - */ - public static PURPLE = 0x800080; // - /** - * 粟色十六进制值 - */ - public static MAROON = 0x800000; // - /** - * 碧绿色十六进制值 - */ - public static AQUAMARINE = 0x7fffd4; // - /** - * 黄绿色十六进制值 - */ - public static CHARTREUSE = 0x7fff00; // - /** - * 草绿色十六进制值 - */ - public static LAWNGREEN = 0x7cfc00; // - /** - * 中暗蓝色十六进制值 - */ - public static MEDIUMSLATEBLUE = 0x7b68ee; // - /** - * 亮蓝灰十六进制值 - */ - public static LIGHTSLATEGRAY = 0x778899; // - /** - * 灰石色十六进制值 - */ - public static SLATEGRAY = 0x708090; // - /** - * 深绿褐色十六进制值 - */ - public static OLIVEDRAB = 0x6b8e23; // - /** - * 石蓝色十六进制值 - */ - public static SLATEBLUE = 0x6a5acd; // - /** - * 暗灰色十六进制值 - */ - public static DIMGRAY = 0x696969; // - /** - * 中绿色十六进制值 - */ - public static MEDIUMAQUAMARINE = 0x66cdaa; // - /** - * 菊兰色十六进制值 - */ - public static CORNFLOWERBLUE = 0x6495ed; // - /** - * 军兰色十六进制值 - */ - public static CADETBLUE = 0x5f9ea0; // - /** - * 暗橄榄绿色十六进制值 - */ - public static DARKOLIVEGREEN = 0x556b2f; // - /** - * 靛青色十六进制值 - */ - public static INDIGO = 0x4b0082; // - /** - * 中绿宝石色十六进制值 - */ - public static MEDIUMTURQUOISE = 0x48d1cc; // - /** - * 暗灰蓝色十六进制值 - */ - public static DARKSLATEBLUE = 0x483d8b; // - /** - * 钢兰色十六进制值 - */ - public static STEELBLUE = 0x4682b4; // - /** - * 皇家蓝色十六进制值 - */ - public static ROYALBLUE = 0x4169e1; // - /** - * 青绿色十六进制值 - */ - public static TURQUOISE = 0x40e0d0; // - /** - * 中海蓝色十六进制值 - */ - public static MEDIUMSEAGREEN = 0x3cb371; // - /** - * 橙绿色十六进制值 - */ - public static LIMEGREEN = 0x32cd32; // - /** - * 暗瓦灰色十六进制值 - */ - public static DARKSLATEGRAY = 0x2f4f4f; // - /** - * 海绿色十六进制值 - */ - public static SEAGREEN = 0x2e8b57; // - /** - * 森林绿十六进制值 - */ - public static FORESTGREEN = 0x228b22; // - /** - * 亮海蓝色十六进制值 - */ - public static LIGHTSEAGREEN = 0x20b2aa; // - /** - * 闪兰色十六进制值 - */ - public static DODGERBLUE = 0x1e90ff; // - /** - * 中灰兰色十六进制值 - */ - public static MIDNIGHTBLUE = 0x191970; // - /** - * 浅绿色十六进制值 - */ - public static AQUA = 0x00ffff; // - /** - * 青色十六进制值 - */ - public static CYAN = 0x00ffff; // - /** - * 春绿色十六进制值 - */ - public static SPRINGGREEN = 0x00ff7f; // - /** - * 酸橙色十六进制值 - */ - public static LIME = 0x00ff00; // - /** - * 中春绿色十六进制值 - */ - public static MEDIUMSPRINGGREEN = 0x00fa9a; // - /** - * 暗宝石绿色十六进制值 - */ - public static DARKTURQUOISE = 0x00ced1; // - /** - * 深天蓝色十六进制值 - */ - public static DEEPSKYBLUE = 0x00bfff; // - /** - * 暗青色十六进制值 - */ - public static DARKCYAN = 0x008b8b; // - /** - * 水鸭色十六进制值 - */ - public static TEAL = 0x008080; // - /** - * 绿色十六进制值 - */ - public static GREEN = 0x008000; // - /** - * 暗绿色十六进制值 - */ - public static DARKGREEN = 0x006400; // - /** - * 蓝色十六进制值 - */ - public static BLUE = 0x0000ff; // - /** - * 中兰色十六进制值 - */ - public static MEDIUMBLUE = 0x0000cd; // - /** - * 暗蓝色十六进制值 - */ - public static DARKBLUE = 0x00008b; // - /** - * 海军色十六进制值 - */ - public static NAVY = 0x000080; // - /** - * 黑色十六进制值 - */ - public static BLACK = 0x000000; // -} + public static WHITE = 0xffffff; + public static IVORY = 0xfffff0; + public static LIGHTYELLOW = 0xffffe0; + public static YELLOW = 0xffff00; + public static SNOW = 0xfffafa; + public static FLORALWHITE = 0xfffaf0; + public static LEMONCHIFFON = 0xfffacd; + public static CORNSILK = 0xfff8dc; + public static SEASHELL = 0xfff5ee; + public static LAVENDERBLUSH = 0xfff0f5; + public static PAPAYAWHIP = 0xffefd5; + public static BLANCHEDALMOND = 0xffebcd; + public static MISTYROSE = 0xffe4e1; + public static BISQUE = 0xffe4c4; + public static MOCCASIN = 0xffe4b5; + public static NAVAJOWHITE = 0xffdead; + public static PEACHPUFF = 0xffdab9; + public static GOLD = 0xffd700; + public static PINK = 0xffc0cb; + public static LIGHTPINK = 0xffb6c1; + public static ORANGE = 0xffa500; + public static LIGHTSALMON = 0xffa07a; + public static DARKORANGE = 0xff8c00; + public static CORAL = 0xff7f50; + public static HOTPINK = 0xff69b4; + public static TOMATO = 0xff6347; + public static ORANGERED = 0xff4500; + public static DEEPPINK = 0xff1493; + public static FUCHSIA = 0xff00ff; + public static MAGENTA = 0xff00ff; + public static RED = 0xff0000; + public static OLDLACE = 0xfdf5e6; + public static LIGHTGOLDENRODYELLOW = 0xfafad2; + public static LINEN = 0xfaf0e6; + public static ANTIQUEWHITE = 0xfaebd7; + public static SALMON = 0xfa8072; + public static GHOSTWHITE = 0xf8f8ff; + public static MINTCREAM = 0xf5fffa; + public static WHITESMOKE = 0xf5f5f5; + public static BEIGE = 0xf5f5dc; + public static WHEAT = 0xf5deb3; + public static SANDYBROWN = 0xf4a460; + public static AZURE = 0xf0ffff; + public static HONEYDEW = 0xf0fff0; + public static ALICEBLUE = 0xf0f8ff; + public static KHAKI = 0xf0e68c; + public static LIGHTCORAL = 0xf08080; + public static PALEGOLDENROD = 0xeee8aa; + public static VIOLET = 0xee82ee; + public static DARKSALMON = 0xe9967a; + public static LAVENDER = 0xe6e6fa; + public static LIGHTCYAN = 0xe0ffff; + public static BURLYWOOD = 0xdeb887; + public static PLUM = 0xdda0dd; + public static GAINSBORO = 0xdcdcdc; + public static CRIMSON = 0xdc143c; + public static PALEVIOLETRED = 0xdb7093; + + public static GOLDENROD = 0xdaa520; + public static ORCHID = 0xda70d6; + public static THISTLE = 0xd8bfd8; + public static LIGHTGREY = 0xd3d3d3; + public static TAN = 0xd2b48c; + public static CHOCOLATE = 0xd2691e; + public static PERU = 0xcd853f; + public static INDIANRED = 0xcd5c5c; + public static MEDIUMVIOLETRED = 0xc71585; + public static SILVER = 0xc0c0c0; + public static DARKKHAKI = 0xbdb76b; + public static ROSYBROWN = 0xbc8f8f; + public static MEDIUMORCHID = 0xba55d3; + public static DARKGOLDENROD = 0xb8860b; + public static FIREBRICK = 0xb22222; + public static POWDERBLUE = 0xb0e0e6; + public static LIGHTSTEELBLUE = 0xb0c4de; + public static PALETURQUOISE = 0xafeeee; + public static GREENYELLOW = 0xadff2f; + public static LIGHTBLUE = 0xadd8e6; + public static DARKGRAY = 0xa9a9a9; + public static BROWN = 0xa52a2a; + public static SIENNA = 0xa0522d; + public static DARKORCHID = 0x9932cc; + public static PALEGREEN = 0x98fb98; + public static DARKVIOLET = 0x9400d3; + public static MEDIUMPURPLE = 0x9370db; + public static LIGHTGREEN = 0x90ee90; + public static DARKSEAGREEN = 0x8fbc8f; + public static SADDLEBROWN = 0x8b4513; + public static DARKMAGENTA = 0x8b008b; + public static DARKRED = 0x8b0000; + public static BLUEVIOLET = 0x8a2be2; + public static LIGHTSKYBLUE = 0x87cefa; + public static SKYBLUE = 0x87ceeb; + public static GRAY = 0x808080; + public static OLIVE = 0x808000; + public static PURPLE = 0x800080; + public static MAROON = 0x800000; + public static AQUAMARINE = 0x7fffd4; + public static CHARTREUSE = 0x7fff00; + public static LAWNGREEN = 0x7cfc00; + public static MEDIUMSLATEBLUE = 0x7b68ee; + public static LIGHTSLATEGRAY = 0x778899; + public static SLATEGRAY = 0x708090; + public static OLIVEDRAB = 0x6b8e23; + public static SLATEBLUE = 0x6a5acd; + public static DIMGRAY = 0x696969; + public static MEDIUMAQUAMARINE = 0x66cdaa; + public static CORNFLOWERBLUE = 0x6495ed; + public static CADETBLUE = 0x5f9ea0; + public static DARKOLIVEGREEN = 0x556b2f; + public static INDIGO = 0x4b0082; + public static MEDIUMTURQUOISE = 0x48d1cc; + public static DARKSLATEBLUE = 0x483d8b; + public static STEELBLUE = 0x4682b4; + public static ROYALBLUE = 0x4169e1; + public static TURQUOISE = 0x40e0d0; + public static MEDIUMSEAGREEN = 0x3cb371; + public static LIMEGREEN = 0x32cd32; + public static DARKSLATEGRAY = 0x2f4f4f; + public static SEAGREEN = 0x2e8b57; + public static FORESTGREEN = 0x228b22; + public static LIGHTSEAGREEN = 0x20b2aa; + public static DODGERBLUE = 0x1e90ff; + public static MIDNIGHTBLUE = 0x191970; + public static AQUA = 0x00ffff; + public static CYAN = 0x00ffff; + public static SPRINGGREEN = 0x00ff7f; + public static LIME = 0x00ff00; + public static MEDIUMSPRINGGREEN = 0x00fa9a; + public static DARKTURQUOISE = 0x00ced1; + public static DEEPSKYBLUE = 0x00bfff; + public static DARKCYAN = 0x008b8b; + public static TEAL = 0x008080; + public static GREEN = 0x008000; + public static DARKGREEN = 0x006400; + public static BLUE = 0x0000ff; + public static MEDIUMBLUE = 0x0000cd; + public static DARKBLUE = 0x00008b; + public static NAVY = 0x000080; + public static BLACK = 0x000000; +} \ No newline at end of file diff --git a/src/engine/math/Line.ts b/src/engine/math/Line.ts index 80c504ca..6edbff13 100644 --- a/src/engine/math/Line.ts +++ b/src/engine/math/Line.ts @@ -87,11 +87,11 @@ export class Line { } /** - * 判断两个直线关系 + * Determine the relationship between two straight lines * this line A = x0, y0 and B = x1, y1 * other is A = x2, y2 and B = x3, y3 - * @param other 另一条直线 - * @param pIntersectPoint (out)返回两线段的交点 + * @param other compare other line + * @param pIntersectPoint (out)Returns the intersection point of two line segments * @return */ public intersection(other: Line, pIntersectPoint: Vector3 = null): LineClassification { @@ -131,7 +131,7 @@ export class Line { } /** - * 直线方向 + * Straight direction * @return */ public getDirection(): Vector3 { diff --git a/src/engine/math/MathUtil.ts b/src/engine/math/MathUtil.ts new file mode 100644 index 00000000..457b3f05 --- /dev/null +++ b/src/engine/math/MathUtil.ts @@ -0,0 +1,786 @@ +import { Matrix4 } from './Matrix4'; +import { Quaternion } from './Quaternion'; +import { Rand } from './Rand'; +import { Vector2 } from './Vector2'; +import { Vector3 } from './Vector3'; + +/** + * This is a constant value used to convert radians to angles + */ +export let RADIANS_TO_DEGREES: number = 180 / Math.PI; + +/** + * This is a constant value used to convert angles to radians + */ +export let DEGREES_TO_RADIANS: number = Math.PI / 180; + +/** + * @internal + */ +export let MAX_VALUE: number = 0x7fffffff; + +/** + * @internal + */ +export let MIN_VALUE: number = -0x7fffffff; + +export let PI: number = 3.1415926; + + +/** + * value min max bound + * @internal + * @param value + * @param min + * @param max + * @returns + */ +export function clamp(value, min, max) { + return Math.max(min, Math.min(max, value)); +} + +/** + * Built-in mathematical basic calculation factory function + * @group Math + */ +export class MathUtil { + /** + * @private + * The gaussian function to calculate the color value + * @param {number} value the value (the x-value) + * @param {number} amplitude the curve peak + * @param {number} center the curve center + * @param {number} rmsWidth the curve width + * @returns {number} the color value (the y-value) + */ + private static gaussFunction(value, amplitude, center, rmsWidth) { + let numerator = Math.pow(value - center, 2); + let denominator = 2 * Math.pow(rmsWidth, 2); + let exp = -1 * (numerator / denominator); + let curve = Math.pow(Math.E, exp); + return Math.round(curve * amplitude); + } + + /** + * Calculate the Gaussian distribution function + * @param n Function variable value + * @param theta The degree of dispersion of the data distribution + * @returns The result of the calculated Gaussian distribution value + */ + private static computeGaussian(n, theta) { + return (1.0 / Math.sqrt(2 * Math.PI * theta)) * Math.exp(-(n * n) / (2 * theta * theta)); + } + + /** + * Calculate Gaussian coefficient + * @param sigma sigma value + * @returns Return the calculation result + */ + private static gaussCoef(sigma) { + if (sigma < 0.5) { + sigma = 0.5; + } + + let a = Math.exp(0.726 * 0.726) / sigma; + let g1 = Math.exp(-a); + let g2 = Math.exp(-2 * a); + let k = ((1 - g1) * (1 - g1)) / (1 + 2 * a * g1 - g2); + + let a0 = k; + let a1 = k * (a - 1) * g1; + let a2 = k * (a + 1) * g1; + let a3 = -k * g2; + let b1 = 2 * g1; + let b2 = -g2; + let left_corner = (a0 + a1) / (1 - b1 - b2); + let right_corner = (a2 + a3) / (1 - b1 - b2); + + // Attempt to force type to FP32. + return new Float32Array([a0, a1, a2, a3, b1, b2, left_corner, right_corner]); + } + + /** + * Limit the value to a certain range + * @param value Original value + * @param min_inclusive minimum value + * @param max_inclusive maximum value + * @returns Return the calculation result + */ + public static clampf(value: number, min_inclusive: number, max_inclusive: number): number { + if (min_inclusive > max_inclusive) { + let temp: number = min_inclusive; + min_inclusive = max_inclusive; + max_inclusive = temp; + } + return value < min_inclusive ? min_inclusive : value < max_inclusive ? value : max_inclusive; + } + + /** + * Normalize the Angle so that it is limited to the range [-180, 180] + * @param a Angle of input + * @returns Return the processing result + */ + public static normalizeAngle(a: number): number { + while (a > 180) { + a -= 360; + } + while (a < -180) { + a += 360; + } + return a; + } + + /** + * Returns the fractional part of a number + * @param v input value + * @returns Return the result + */ + public static fract(v: number): number { + return v - Math.floor(v); + } + + /** + * Generate a random pair of x and z coordinates that fall within the radius of the circle + * @param r radius + * @returns The generated x, z results + */ + public static getRandDirXZ(r: number) { + let rr = r * Math.random(); + let ra = 360 * Math.random() * DEGREES_TO_RADIANS; + let x = Math.cos(ra) * rr; + let z = Math.sin(ra) * rr; + return { x: x, z: z }; + } + + /** + * Generate a random pair of x, y, and z coordinates that fall within the radius of the sphere + * @param r radius + * @returns The Vector3 vector formed by the generated x, y, and z coordinate values + */ + public static getRandDirXYZ(r: number) { + let rr = r * Math.random(); + let ra = 360 * Math.random() * DEGREES_TO_RADIANS; + let x = Math.cos(ra) * rr; + let y = Math.tan(ra) * rr; + let z = Math.sin(ra) * rr; + return new Vector3(x, y, z); + } + + /** + * According to the radius, generate a random pair of x, y, z coordinates that fall within the sphere and the y value is between [-r/2, r/2] + * @param r radius + * @returns The Vector3 vector formed by the generated x, y, and z coordinate values + */ + public static getCycleXYZ(r: number) { + let rr = r * Math.random(); + let ra = 360 * Math.random() * DEGREES_TO_RADIANS; + let x = Math.cos(ra) * rr; + let y = r * Math.random() - r * 0.5; + let z = Math.sin(ra) * rr; + return new Vector3(x, y, z); + } + + /** + * Calculate the Angle between two vectors + * @param p1 Vector 1 + * @param p2 Vector 2 + * @returns Return the calculation result + */ + public static angle(p1: Vector3, p2: Vector3): number { + let v1 = Vector2.HELP_0; + let v2 = Vector2.HELP_1; + + v1.set(p1.x, p1.z); + v2.set(p2.x, p2.z); + + return Math.acos((v1.x * v2.x + v1.y * v2.y) / (v1.abs() * v2.abs())); + } + + /** + * Calculate the Angle between two vectors + * @param from Vector 1 + * @param to Vector 2 + * @returns The Angle between two vectors + */ + public static angle_360(from, to) { + let v3 = Vector3.HELP_0; + from.cross(to, v3); + if (v3.z > 0) { + return MathUtil.angle(from, to); + } + else { + return 360 - MathUtil.angle(from, to); + } + } + + /** + * The rotation Angle around the Y-axis is obtained from the input vector + * @param v input vector + * @returns Return the calculation result + */ + public getRotationY(v: Vector3): number { + let rot = MathUtil.normalizeAngle(Math.atan2(v.z, v.x) * RADIANS_TO_DEGREES); //- 90; + return rot; + } + + /** + * Calculate the quaternion from one direction to the other + * @param fromDirection Initial direction + * @param toDirection The transformed direction + * @param target The calculated quaternion is null by default and the result is returned + * @returns Quaternion The calculated quaternion returns a new instance created if target is null + * @version Orillusion3D 0.5.1 + */ + public static fromToRotation(fromDirection: Vector3, toDirection: Vector3, target: Quaternion = null): Quaternion { + target ||= new Quaternion(); + let mat: Matrix4 = new Matrix4(); + Matrix4.fromToRotation(fromDirection, toDirection, mat); + target.fromMatrix(mat); + return target; + } + + /** + * Get the Eular direction + * @param v input value + * @returns Return the calculation result + */ + public static getEularDir_yUp(v: number): Vector3 { + let q = Quaternion.HELP_0; + q.fromEulerAngles(0, v, 0); + q.transformVector(Vector3.Z_AXIS, Vector3.HELP_5); + return Vector3.HELP_5; + } + + /** + * Compute the vector transformation and assign the results to the input variables + * @param matrix transformation matrix + * @param vector Original vector + * @param result output vector + * @returns Returns the output vector + */ + public static transformVector(matrix: Matrix4, vector: Vector3, result: Vector3 = null): Vector3 { + result ||= new Vector3(); + let raw: Float32Array = matrix.rawData; + let a: number = raw[0]; + let e: number = raw[1]; + let i: number = raw[2]; + let m: number = raw[3]; + let b: number = raw[4]; + let f: number = raw[5]; + let j: number = raw[6]; + let n: number = raw[7]; + let c: number = raw[8]; + let g: number = raw[9]; + let k: number = raw[10]; + let o: number = raw[11]; + let d: number = raw[12]; + let h: number = raw[13]; + let l: number = raw[14]; + let p: number = raw[15]; + + let x: number = vector.x; + let y: number = vector.y; + let z: number = vector.z; + result.x = a * x + b * y + c * z + d; + result.y = e * x + f * y + g * z + h; + result.z = i * x + j * y + k * z + l; + result.w = m * x + n * y + o * z + p; + return result; + } +} + +/** + * @internal + */ +export let PingPong = function (t: number, start: number, end: number): number { + let len = end - start; + let tt = Math.floor(t / len); + let sd = tt % 2; + if (sd == 0) { + return (t % len) + start; + } else { + return end - (t % len) + start; + } +}; + +/** + * @internal + */ +export let RepeatSE = function (t: number, start: number, end: number): number { + let len = end - start; + return (t % len) + start; +}; + +/** + * @internal + */ +export let GetRepeat = function (datas: any[], element: any): number { + let count = 0; + for (let i in datas) { + if (i == element) { + count++; + } + } + return count; +}; + +/** + * @internal + * @group Math + */ +export class RandomSeed { + public x: number = 0; + public y: number = 0; + public z: number = 0; + public w: number = 0; + + public randSeedList: number[]; + constructor() { + this.randSeedList = []; + } + + public reset() { + this.x = Math.random() * 1; + this.y = Math.random() * 1; + this.z = Math.random() * 1; + this.w = Math.random() * 1; + + this.randSeedList.length = 0; + for (let i = 0; i < 20; i++) { + this.randSeedList.push(Math.random() * 1); + } + } +} + +/** + * @internal + */ +export function dot(lhs: Vector2 | Quaternion | Vector3, rhs: Vector2 | Quaternion | Vector3) { + if (lhs instanceof Vector3 && rhs instanceof Vector3) { + return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z; + } + else if (lhs instanceof Quaternion && rhs instanceof Quaternion) { + return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z; + + } else { + return lhs.x * rhs.x + lhs.y * rhs.y; + } +} + +/** + * @internal + */ +export function scale(lhs: Vector3, rhs: Vector3) { + return new Vector3(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z); +} + +/** + * @internal + */ +export function sqrtImpl(f: number) { + return Math.sqrt(f); +} + +/** + * @internal + */ +export function magnitude(inV: Vector2 | Vector3 | Quaternion) { + return sqrtImpl(dot(inV, inV)); +} + +/** + * @internal + */ +export function normalizeSafe(inV: Vector2 | Vector3 | Quaternion, defaultV?: Vector2 | Vector3 | Quaternion) { + let mag = magnitude(inV); + if (mag > Vector3.EPSILON) { + return inV.divide(magnitude(inV)); + } + else { + if (inV instanceof Vector2) { + return new Vector2(); + } + if (inV instanceof Vector3) { + return new Vector3(); + } + if (inV instanceof Quaternion) { + return new Quaternion(); + } + } +} + +/** + * @internal + */ +export function getFloatFromInt(value) { + // take 23 bits of integer, and divide by 2^23-1 + let v = value & 0x007fffff; + return v * (1.0 / 8388607.0); +} + +/** + * @internal + */ +export function random01(value) { + // take 23 bits of integer, and divide by 2^23-1 + return value.getFloat(); +} + +/** + * @internal + */ +export function rangedRandomFloat(r: Rand, min: number, max: number) { + let t = r.getFloat(); + t = min * t + (1.0 - t) * max; + return t; +} + +/** + * @internal + * @param r Rand + * @param min int + * @param max int + */ +export function rangedRandomInt(r: Rand, min: number, max: number) { + let dif; + if (min < max) { + dif = max - min; + // let t = r.Get () % dif; + let t = r.get() % dif; + t += min; + return t; + } else if (min > max) { + dif = min - max; + // let t = r.Get () % dif; + let t = r.get() % dif; + t = min - t; + return t; + } else { + return min; + } +} + +/** + * @internal + */ +export function randomUnitVector(rand: Rand) { + let z = rangedRandomFloat(rand, -1.0, 1.0); + let a = rangedRandomFloat(rand, 0.0, 2.0 * PI); + + let r = Math.sqrt(1.0 - z * z); + + let x = r * Math.cos(a); + let y = r * Math.sin(a); + + return new Vector3(x, y, z); +} + +/** + * @internal + */ +export function randomUnitVector2(rand: Rand) { + let a = rangedRandomFloat(rand, 0.0, 2.0 * PI); + + let x = Math.cos(a); + let y = Math.sin(a); + + return new Vector2(x, y); +} + +/** + * @internal + */ +export function randomQuaternion(rand: Rand) { + let q: Quaternion = new Quaternion(); + q.x = rangedRandomFloat(rand, -1.0, 1.0); + q.y = rangedRandomFloat(rand, -1.0, 1.0); + q.z = rangedRandomFloat(rand, -1.0, 1.0); + q.w = rangedRandomFloat(rand, -1.0, 1.0); + q = normalizeSafe(q) as Quaternion; + if (dot(q, Quaternion.identity()) < 0.0) { + return -q; + } + else { + return q; + } +} + +/** + * @internal + */ +export function randomQuaternionUniformDistribution(rand: Rand) { + const two_pi = 2.0 * PI; + + // Employs Hopf fibration to uniformly distribute quaternions + let u1 = rangedRandomFloat(rand, 0.0, 1.0); + let theta = rangedRandomFloat(rand, 0.0, two_pi); + let rho = rangedRandomFloat(rand, 0.0, two_pi); + + let i = Math.sqrt(1.0 - u1); + let j = Math.sqrt(u1); + + // We do not need to normalize the generated quaternion, because the probability density corresponds to the Haar measure. + // This means that a random rotation is obtained by picking a point at random on S^3, and forming the unit quaternion. + let q = new Quaternion(i * Math.sin(theta), i * Math.cos(theta), j * Math.sin(rho), j * Math.cos(rho)); + + if (dot(q, Quaternion.identity()) < 0.0) { + return -q; + } + else { + return q; + } +} + +/** + * @internal + */ +export function randomPointInsideCube(r: Rand, extents: Vector3) { + return new Vector3(rangedRandomFloat(r, -extents.x, extents.x), rangedRandomFloat(r, -extents.y, extents.y), rangedRandomFloat(r, -extents.z, extents.z)); +} + +// /** +// * @internal +// */ +// export function randomPointBetweenCubes(r: Rand, min: Vector3, max: Vector3) { +// let v: Vector3; +// for (let i = 0; i < 3; i++) { +// let x = r.getFloat() * 2.0 - 1.0; +// if (x > 0.0) { +// v[i] = min[i] + x * (max[i] - min[i]); +// } +// else { +// v[i] = -min[i] + x * (max[i] - min[i]); +// } +// } +// return v; +// } +/** + * @internal + */ +export function randomPointInsideUnitSphere(r: Rand) { + let v = randomUnitVector(r); + v.scaleBy(Math.pow(random01(r), 1.0 / 3.0)); // *= Math.pow (Random01 (r), 1.0 / 3.0); + return v; +} + +/** + * @internal + */ +export function randomPointInsideEllipsoid(r: Rand, extents: Vector3) { + return scale(randomPointInsideUnitSphere(r), extents); +} + +/** + * @internal + */ +export function randomPointBetweenSphere(r: Rand, minRadius: number, maxRadius: number) { + let v = randomUnitVector(r); + // As the volume of the sphere increases (x^3) over an interval we have to increase range as well with x^(1/3) + let range = Math.pow(rangedRandomFloat(r, 0.0, 1.0), 1.0 / 3.0); + v.scaleBy(minRadius + (maxRadius - minRadius) * range); + return v; +} + +/** + * @internal + */ +export function randomPointInsideUnitCircle(r: Rand) { + let v = randomUnitVector2(r); + // As the volume of the sphere increases (x^3) over an interval we have to increase range as well with x^(1/3) + v.multiply(Math.pow(rangedRandomFloat(r, 0.0, 1.0), 1.0 / 2.0), v); + return v; +} + +/** + * @internal + */ +export function randomPointBetweenEllipsoid(r: Rand, maxExtents: Vector3, minRange: number) { + let v = scale(randomUnitVector(r), maxExtents); + // As the volume of the sphere increases (x^3) over an interval we have to increase range as well with x^(1/3) + let range = Math.pow(rangedRandomFloat(r, minRange, 1.0), 1.0 / 3.0); + v.scaleBy(range); + return v; +} + +/// Builds a random Barycentric coordinate which can be used to generate random points on a triangle: +/// Vector3f point = v0 * barycentric.x + v1 * barycentric.y + v2 * barycentric.z; +/** + * @internal + */ +export function randomBarycentricCoord(rand: Rand) { + let u = rand.getFloat(); + let v = rand.getFloat(); + if (u + v > 1.0) { + u = 1.0 - u; + v = 1.0 - v; + } + let w = 1.0 - u - v; + return new Vector3(u, v, w); +} + +/** + * @internal + */ +export function deg2Rad(deg) { + // TODO : should be deg * kDeg2Rad, but can't be changed, + // because it changes the order of operations and that affects a replay in some RegressionTests + return (deg / 360.0) * 2.0 * PI; +} + +/** + * @internal + */ +export function rad2Deg(deg) { + // TODO : should be deg * kDeg2Rad, but can't be changed, + // because it changes the order of operations and that affects a replay in some RegressionTests + return (180 * deg) / PI; +} + +/** + * @internal + */ +export function sin(v: number) { + return Math.sin(v); +} + +/** + * @internal + */ +export function cos(v: number) { + return Math.cos(v); +} + +/** + * @internal + */ +export let randomSeed = 0x1337; + +/** + * @internal + */ +export function getGlobalRandomSeed() { + return ++randomSeed; +} + +/** + * @internal + */ +export function swap(values: any[], i1: number, i2: number) { + let v1 = values[i1]; + let v2 = values[i2]; + values[i1] = v2; + values[i2] = v1; +} + +/** + * @internal + */ +export function floorfToIntPos(f) { + return Math.floor(f); +} + +/** + * @internal + */ +export function roundfToIntPos(f) { + return floorfToIntPos(f + 0.5); +} + +/// Fast conversion of float [0...1] to 0 ... 65535 +/** + * @internal + */ +export function normalizedToWord(f) { + f = Math.max(f, 0.0); + f = Math.min(f, 1.0); + return roundfToIntPos(f * 65535.0); +} + +/** + * @internal + */ +export function normalizedToByte(f) { + f = Math.max(f, 0.0); + f = Math.min(f, 1.0); + return roundfToIntPos(f * 255.0); +} + +/** + * @internal + */ +export function fastInvSqrt(f) { + // The Newton iteration trick used in FastestInvSqrt is a bit faster on + // Pentium4 / Windows, but lower precision. Doing two iterations is precise enough, + // but actually a bit slower. + if (Math.abs(f) == 0.0) { + return f; + } + return 1.0 / Math.sqrt(f); +} + +/** + * @internal + */ +export function normalizeFast(inV: Vector3) { + let m = sqrMagnitude(inV); + return inV.scaleBy(fastInvSqrt(m)); +} + +/** + * @internal + */ +export function cross(lhs: Vector3, rhs: Vector3) { + return new Vector3(lhs.y * rhs.z - lhs.z * rhs.y, lhs.z * rhs.x - lhs.x * rhs.z, lhs.x * rhs.y - lhs.y * rhs.x); +} + +/** + * @internal + */ +export function sqrMagnitude(inV: Vector3) { + return dot(inV, inV); +} + +/** + * @internal + */ +export function generateRandom(randomIn) { + let rand = new Rand(randomIn); + return random01(rand); +} + +/** + * @internal + */ +export function generateRandom3(randomOut: Vector3, randomIn: number) { + let rand = new Rand(randomIn); + randomOut.x = random01(rand); + randomOut.y = random01(rand); + randomOut.z = random01(rand); +} + +// export function clamp(t, t0, t1) { +// if (t < t0) return t0; +// else if (t > t1) return t1; +// else return t; +// } +/** + * @internal + */ +export function clampRepeat(t, t0, t1) { + if (t < t0) { + return t1; + } + else if (t > t1) { + return t0; + } + else { + return t; + } +} + +/** + * @internal + */ +export function repeat(t, length) { + return t - Math.floor(t / length) * length; +} diff --git a/src/engine/math/Matrix4.ts b/src/engine/math/Matrix4.ts index 03918dce..4116fad5 100644 --- a/src/engine/math/Matrix4.ts +++ b/src/engine/math/Matrix4.ts @@ -1,6 +1,5 @@ -import { clamp, DEGREES_TO_RADIANS, RADIANS_TO_DEGREES } from './MathUtil'; +import { PI, clamp, DEGREES_TO_RADIANS, RADIANS_TO_DEGREES } from './MathUtil'; import { Orientation3D } from './Orientation3D'; -import { kPI } from './ParticleMath'; import { Quaternion } from './Quaternion'; import { Vector3 } from './Vector3'; @@ -212,27 +211,27 @@ export class Matrix4 { */ public static makePositive(euler: Vector3): void { let negativeFlip = -0.0001; - let positiveFlip = kPI * 2.0 - 0.0001; + let positiveFlip = PI * 2.0 - 0.0001; if (euler.x < negativeFlip) { - euler.x += 2.0 * kPI; + euler.x += 2.0 * PI; } else if (euler.x > positiveFlip) { - euler.x -= 2.0 * kPI; + euler.x -= 2.0 * PI; } if (euler.y < negativeFlip) { - euler.y += 2.0 * kPI; + euler.y += 2.0 * PI; } else if (euler.y > positiveFlip) { - euler.y -= 2.0 * kPI; + euler.y -= 2.0 * PI; } if (euler.z < negativeFlip) { - euler.z += 2.0 * kPI; + euler.z += 2.0 * PI; } else if (euler.z > positiveFlip) { - euler.z -= 2.0 * kPI; + euler.z -= 2.0 * PI; } } @@ -256,7 +255,7 @@ export class Matrix4 { return true; } else { // WARNING. Not unique. YA - ZA = atan2(r01,r00) - v.x = kPI * 0.5; + v.x = PI * 0.5; v.y = Math.atan2(matrix.get(0, 1), matrix.get(0, 0)); v.z = 0.0; Matrix4.sanitizeEuler(v); @@ -264,7 +263,7 @@ export class Matrix4 { } } else { // WARNING. Not unique. YA + ZA = atan2(-r01,r00) - v.x = -kPI * 0.5; + v.x = -PI * 0.5; v.y = Math.atan2(-matrix.get(0, 1), matrix.get(0, 0)); v.z = 0.0; Matrix4.sanitizeEuler(v); @@ -1909,7 +1908,7 @@ export class Matrix4 { /** * get Component of scale * - * @returns Vector3 缩放 + * @returns Vector3 scale * @version Orillusion3D 0.5.1 */ public get scale(): Vector3 { From 2f71e0ceebdd2740cf68d57874a51850f735d9b0 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Mon, 24 Apr 2023 11:19:14 +0800 Subject: [PATCH 023/100] chore(bindgroup): change folder (#36) * fix(bindgroup): change bindgroup change bindgroup folder --- .../webgpu => graphics/webGpu}/Context3D.ts | 0 .../webgpu => graphics/webGpu}/WebGPUConst.ts | 0 .../webGpu}/core/bindGroups/GlobalBindGroup.ts | 9 ++++----- .../core/bindGroups/GlobalBindGroupLayout.ts | 0 .../core/bindGroups/GlobalUniformGroup.ts | 17 +---------------- .../webGpu}/core/bindGroups/MatrixBindGroup.ts | 0 .../core/bindGroups/TexturesBindGroup.ts | 0 .../core/bindGroups/groups/LightEntries.ts | 8 +------- .../core/bindGroups/groups/ProbeEntries.ts | 0 .../gfx/{generate => }/renderJob/GPUContext.ts | 0 10 files changed, 6 insertions(+), 28 deletions(-) rename src/engine/gfx/{generate/graphic/webgpu => graphics/webGpu}/Context3D.ts (100%) rename src/engine/gfx/{generate/graphic/webgpu => graphics/webGpu}/WebGPUConst.ts (100%) rename src/engine/gfx/{generate/graphic/webgpu => graphics/webGpu}/core/bindGroups/GlobalBindGroup.ts (86%) rename src/engine/gfx/{generate/graphic/webgpu => graphics/webGpu}/core/bindGroups/GlobalBindGroupLayout.ts (100%) rename src/engine/gfx/{generate/graphic/webgpu => graphics/webGpu}/core/bindGroups/GlobalUniformGroup.ts (87%) rename src/engine/gfx/{generate/graphic/webgpu => graphics/webGpu}/core/bindGroups/MatrixBindGroup.ts (100%) rename src/engine/gfx/{generate/graphic/webgpu => graphics/webGpu}/core/bindGroups/TexturesBindGroup.ts (100%) rename src/engine/gfx/{generate/graphic/webgpu => graphics/webGpu}/core/bindGroups/groups/LightEntries.ts (79%) rename src/engine/gfx/{generate/graphic/webgpu => graphics/webGpu}/core/bindGroups/groups/ProbeEntries.ts (100%) rename src/engine/gfx/{generate => }/renderJob/GPUContext.ts (100%) diff --git a/src/engine/gfx/generate/graphic/webgpu/Context3D.ts b/src/engine/gfx/graphics/webGpu/Context3D.ts similarity index 100% rename from src/engine/gfx/generate/graphic/webgpu/Context3D.ts rename to src/engine/gfx/graphics/webGpu/Context3D.ts diff --git a/src/engine/gfx/generate/graphic/webgpu/WebGPUConst.ts b/src/engine/gfx/graphics/webGpu/WebGPUConst.ts similarity index 100% rename from src/engine/gfx/generate/graphic/webgpu/WebGPUConst.ts rename to src/engine/gfx/graphics/webGpu/WebGPUConst.ts diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalBindGroup.ts b/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts similarity index 86% rename from src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalBindGroup.ts rename to src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts index e267840a..1a177369 100644 --- a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalBindGroup.ts +++ b/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts @@ -1,8 +1,7 @@ -import { Camera3D } from '../../../../../core/Camera3D'; -import { LightEntries } from './groups/LightEntries'; -import { MatrixBindGroup } from './MatrixBindGroup'; -import { GlobalUniformGroup } from './GlobalUniformGroup'; -import { Scene3D } from '../../../../../core/Scene3D'; +import { GlobalUniformGroup } from "./GlobalUniformGroup"; +import { LightEntries } from "./groups/LightEntries"; +import { MatrixBindGroup } from "./MatrixBindGroup"; + /** * @internal * Use Global DO Matrix ArrayBuffer Descriptor diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalBindGroupLayout.ts b/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout.ts similarity index 100% rename from src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalBindGroupLayout.ts rename to src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout.ts diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalUniformGroup.ts b/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts similarity index 87% rename from src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalUniformGroup.ts rename to src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts index 16e3762a..8558a48c 100644 --- a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/GlobalUniformGroup.ts +++ b/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts @@ -1,19 +1,4 @@ -import { ShadowLightsCollect } from '../../../../renderJob/collect/ShadowLightsCollect'; -import { Camera3D } from '../../../../../core/Camera3D'; -import { CubeCamera } from '../../../../../core/CubeCamera'; -import { PointShadowCubeCamera } from '../../../../../core/PointShadowCubeCamera'; -import { Engine3D } from '../../../../../Engine3D'; -import { Matrix4 } from '../../../../../math/Matrix4'; - -import { UUID } from '../../../../../util/Global'; -import { Time } from '../../../../../util/Time'; -import { WebGPUDescriptorCreator } from '../../descriptor/WebGPUDescriptorCreator'; -import { webGPUContext } from '../../Context3D'; -import { StorageGPUBuffer } from '../buffer/StorageGPUBuffer'; -import { UniformGPUBuffer } from '../buffer/UniformGPUBuffer'; -import { GlobalBindGroup } from './GlobalBindGroup'; -import { GlobalBindGroupLayout } from './GlobalBindGroupLayout'; -import { MatrixBindGroup } from './MatrixBindGroup'; + /** * @internal diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/MatrixBindGroup.ts b/src/engine/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts similarity index 100% rename from src/engine/gfx/generate/graphic/webgpu/core/bindGroups/MatrixBindGroup.ts rename to src/engine/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/TexturesBindGroup.ts b/src/engine/gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup.ts similarity index 100% rename from src/engine/gfx/generate/graphic/webgpu/core/bindGroups/TexturesBindGroup.ts rename to src/engine/gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup.ts diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/groups/LightEntries.ts b/src/engine/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts similarity index 79% rename from src/engine/gfx/generate/graphic/webgpu/core/bindGroups/groups/LightEntries.ts rename to src/engine/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts index 2b349646..1f146ba5 100644 --- a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/groups/LightEntries.ts +++ b/src/engine/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts @@ -1,10 +1,4 @@ -import { LightData } from '../../../../../../components/lights/LightData'; -import { MemoryInfo } from '../../../../../../core/pool/memory/MemoryInfo'; -import { View3D } from '../../../../../../core/View3D'; -import { Engine3D } from '../../../../../../Engine3D'; -import { EntityCollect } from '../../../../../renderJob/collect/EntityCollect'; -import { DDGIIrradianceVolume } from '../../../../../renderJob/passRenderer/ddgi/DDGIIrradianceVolume'; -import { StorageGPUBuffer } from '../../buffer/StorageGPUBuffer'; + //TODO dynamic lights need fixed /** diff --git a/src/engine/gfx/generate/graphic/webgpu/core/bindGroups/groups/ProbeEntries.ts b/src/engine/gfx/graphics/webGpu/core/bindGroups/groups/ProbeEntries.ts similarity index 100% rename from src/engine/gfx/generate/graphic/webgpu/core/bindGroups/groups/ProbeEntries.ts rename to src/engine/gfx/graphics/webGpu/core/bindGroups/groups/ProbeEntries.ts diff --git a/src/engine/gfx/generate/renderJob/GPUContext.ts b/src/engine/gfx/renderJob/GPUContext.ts similarity index 100% rename from src/engine/gfx/generate/renderJob/GPUContext.ts rename to src/engine/gfx/renderJob/GPUContext.ts From 5e49245c622d447d640b137452d38d9d23b16b9d Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Mon, 24 Apr 2023 11:31:42 +0800 Subject: [PATCH 024/100] feat(texture): add base texture (#37) add interface itexture add texture base --- .../graphics/webGpu/core/texture/ITexture.ts | 21 + .../graphics/webGpu/core/texture/Texture.ts | 482 ++++++++++++++++++ 2 files changed, 503 insertions(+) create mode 100644 src/engine/gfx/graphics/webGpu/core/texture/ITexture.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/texture/Texture.ts diff --git a/src/engine/gfx/graphics/webGpu/core/texture/ITexture.ts b/src/engine/gfx/graphics/webGpu/core/texture/ITexture.ts new file mode 100644 index 00000000..dabbd99b --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/texture/ITexture.ts @@ -0,0 +1,21 @@ +export interface ITexture { + /** + * create binding layout description + */ + internalCreateBindingLayoutDesc(); + + /** + * create texture instance + */ + internalCreateTexture(); + + /** + * create GPU View + */ + internalCreateView(); + + /** + * create CPU Sample + */ + internalCreateSampler(); +} \ No newline at end of file diff --git a/src/engine/gfx/graphics/webGpu/core/texture/Texture.ts b/src/engine/gfx/graphics/webGpu/core/texture/Texture.ts new file mode 100644 index 00000000..46f45163 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/texture/Texture.ts @@ -0,0 +1,482 @@ +import { webGPUContext } from "../../Context3D"; +import { GPUAddressMode } from "../../WebGPUConst"; +import { SerializeTextureSource } from "./SerializeTextureSource"; +import { TextureMipmapGenerator } from "./TextureMipmapGenerator"; + +/** + * Texture + * @group Texture + */ +export class Texture implements GPUSamplerDescriptor { + + public readonly textureSource: SerializeTextureSource = new SerializeTextureSource(); + /** + * name of texture + */ + public name: string; + /** + * source url + */ + public url: string; + /** + * gpu texture + */ + protected gpuTexture: GPUTexture; + + /** + * Return index in texture array + */ + public pid: number; + + /** + * GPUTextureView + */ + public view: GPUTextureView; // Assigned later + + /** + * GPUSampler + */ + public gpuSampler: GPUSampler; + + /** + * GPUSampler for comparison + */ + public gpuSampler_comparison: GPUSampler; + + /** + * GPUTextureFormat + */ + public format: GPUTextureFormat; + /** + * GPUTextureUsage + */ + public usage: number; + /** + * texture width + */ + public width: number = 4; + /** + * texture height + */ + public height: number = 4; + /** + * depth or layers, default value is 1 + */ + public depthOrArrayLayers: number = 1; + /** + * depth or layers, default value is 1 + */ + public numberLayer: number = 1; + /** + * GPUTextureViewDescriptor + */ + public viewDescriptor: GPUTextureViewDescriptor; + /** + * GPUTextureDescriptor + */ + public textureDescriptor: GPUTextureDescriptor; + /** + * GPUShaderStage + */ + public visibility: number = GPUShaderStage.COMPUTE | GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT; + + /** + * GPUTextureBindingLayout, contains viewDimension and multisampled + */ + public textureBindingLayout: GPUTextureBindingLayout = { + viewDimension: `2d`, + multisampled: false, + }; + /** + * GPUSamplerBindingLayout + */ + public samplerBindingLayout: GPUSamplerBindingLayout = { + type: `filtering`, + }; + /** + * GPUSamplerBindingLayout + */ + public sampler_comparisonBindingLayout: GPUSamplerBindingLayout = { + type: `comparison`, + }; + /** + * whether to flip the image on the y-axis + */ + + public flipY: boolean; + /** + * whether is video texture + */ + public isVideoTexture?: boolean; + + private _useMipmap: boolean = false; + protected _textureChange: boolean = false; + private _sourceImageData: HTMLCanvasElement | ImageBitmap | OffscreenCanvas; + /** + * mipmap Count, default value is 1 + */ + public mipmapCount: number = 1; + + /** + * Create a texture2D + * @param width size of texture width + * @param height height of texture width + * @param numberLayer number layer of texture + * @returns + */ + constructor(width: number = 32, height: number = 32, numberLayer: number = 1) { + this.width = width; + this.height = height; + this.numberLayer = numberLayer; + + this.minFilter = 'linear'; + this.magFilter = 'linear'; + this.mipmapFilter = `linear`; + this.addressModeU = GPUAddressMode.repeat; + this.addressModeV = GPUAddressMode.repeat; + this.visibility = GPUShaderStage.FRAGMENT; + } + + public init(): this { + let self = this; + if (self[`internalCreateBindingLayoutDesc`]) { + self[`internalCreateBindingLayoutDesc`](); + } + if (self[`internalCreateTexture`]) { + self[`internalCreateTexture`](); + } + if (self[`internalCreateView`]) { + self[`internalCreateView`](); + } + if (self[`internalCreateSampler`]) { + self[`internalCreateSampler`](); + } + return this; + } + + /** + * creatTextureDescriptor + */ + protected createTextureDescriptor( + width: number, + height: number, + mipLevelCount: number, + format: GPUTextureFormat, + usage: number = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.STORAGE_BINDING, + sizeCount: number = 1, + sampleCount: number = 0, + ) { + this.width = width; + this.height = height; + this.format = format; + this.usage = usage; + this.textureDescriptor = { + size: [width, height, sizeCount], + mipLevelCount: mipLevelCount, + format: format, + usage: usage, + label: `${this.name + this.width + this.height + this.format}` + }; + + if (sampleCount > 0) { + this.textureDescriptor.sampleCount = sampleCount; + } + + if (sizeCount > 1) { + this.viewDescriptor = { + dimension: `2d-array`, + }; + } else { + this.viewDescriptor = { + dimension: this.textureBindingLayout.viewDimension, + }; + } + } + + protected generate(imageBitmap: HTMLCanvasElement | ImageBitmap | OffscreenCanvas) { + let width = 32; + let height = 32; + + if ('width' in imageBitmap) { + width = imageBitmap.width; + height = imageBitmap.height; + } + + if (width < 32 || height < 32) { + console.log(imageBitmap['name'] + 'Size must be greater than 32!'); + } + + this.width = width; + this.height = height; + + this.visibility = GPUShaderStage.FRAGMENT; + + this.createTexture(imageBitmap); + } + + private createTexture(imageBitmap: HTMLCanvasElement | ImageBitmap | OffscreenCanvas) { + this._sourceImageData = imageBitmap; + this.updateTextureDescription(); + + this.updateGPUTexture(); + + let device = webGPUContext.device; + if (this.gpuTexture instanceof GPUTexture) + device.queue.copyExternalImageToTexture({ source: this._sourceImageData }, { texture: this.gpuTexture }, [this.width, this.height]); + + if (this.useMipmap) { + TextureMipmapGenerator.webGPUGenerateMipmap(this); + } + } + + /** + * enable/disable mipmap + */ + public get useMipmap(): boolean { + return this._useMipmap; + } + + /** + * get mipmap + */ + public set useMipmap(value: boolean) { + if (value) { + this.samplerBindingLayout.type = 'filtering'; + if (this._useMipmap == false && this._sourceImageData) { + this._useMipmap = true; + this.updateTextureDescription(); + this.updateGPUTexture(); + + let device = webGPUContext.device; + if (this.gpuTexture instanceof GPUTexture) + device.queue.copyExternalImageToTexture({ source: this._sourceImageData }, { texture: this.gpuTexture }, [this.width, this.height]); + TextureMipmapGenerator.webGPUGenerateMipmap(this); + } + } else { + this.samplerBindingLayout.type = 'non-filtering'; + if (this._useMipmap == true && this._sourceImageData) { + this._useMipmap = false; + this.updateTextureDescription(); + this.updateGPUTexture(); + + let device = webGPUContext.device; + if (this.gpuTexture instanceof GPUTexture) + device.queue.copyExternalImageToTexture({ source: this._sourceImageData }, { texture: this.gpuTexture }, [this.width, this.height]); + } + } + + this._textureChange = true; + this._useMipmap = value; + this.noticeChange(); + } + + protected updateTextureDescription() { + // let mipmapCount = this.useMipmap ? Math.floor(Math.log2(this.width)) : 1; + this.mipmapCount = Math.floor(this.useMipmap ? Math.log2(Math.min(this.width, this.height)) : 1); + this.createTextureDescriptor(this.width, this.height, this.mipmapCount, this.format); + } + + protected updateGPUTexture() { + if (this.gpuTexture) { + if (this.gpuTexture instanceof GPUTexture) + this.gpuTexture.destroy(); + } + this.gpuTexture = null; + this.view = null; + this.gpuTexture = this.getGPUTexture(); + } + + /** + * create or get GPUTexture + * @returns GPUTexture + */ + public getGPUTexture() { + if (!this.gpuTexture) { + this.gpuTexture = webGPUContext.device.createTexture(this.textureDescriptor); + } + return this.gpuTexture; + } + + /** + * create or get GPUTextureView + * @returns GPUTextureView | GPUExternalTexture + */ + public getGPUView(index: number = 0): GPUTextureView | GPUExternalTexture { + if (!this.view) { + this.gpuTexture = this.getGPUTexture(); + if (this.gpuTexture instanceof GPUTexture) + this.view = this.gpuTexture.createView(this.viewDescriptor); + } + return this.view; + } + + protected _stateChangeRef: Map = new Map(); + + public bindStateChange(fun: Function, ref: any) { + this._stateChangeRef.set(ref, fun); + } + + public unBindStateChange(ref: any) { + this._stateChangeRef.delete(ref); + } + + protected noticeChange() { + this.gpuSampler = webGPUContext.device.createSampler(this); + this._stateChangeRef.forEach((v, k) => { + v(); + }); + } + + public destoryView(): this { + this.view = null; + return this; + } + + /** + * release the texture + */ + public destroy() { + if (this.gpuTexture instanceof GPUTexture) + this.gpuTexture.destroy(); + this._stateChangeRef.clear(); + } + + //****************************************/ + /** + */ + private _addressModeU?: GPUAddressMode; + public get addressModeU(): GPUAddressMode { + return this._addressModeU; + } + public set addressModeU(value: GPUAddressMode) { + if (this._addressModeU != value) { + this._addressModeU = value; + this.noticeChange(); + } + } + /** + */ + private _addressModeV?: GPUAddressMode; + public get addressModeV(): GPUAddressMode { + return this._addressModeV; + } + public set addressModeV(value: GPUAddressMode) { + if (this._addressModeV != value) { + this._addressModeV = value; + this.noticeChange(); + } + } + /** + * Specifies the {{GPUAddressMode|address modes}} for the texture width, height, and depth + * coordinates, respectively. + */ + private _addressModeW?: GPUAddressMode; + public get addressModeW(): GPUAddressMode { + return this._addressModeW; + } + public set addressModeW(value: GPUAddressMode) { + if (this._addressModeW != value) { + this._addressModeW = value; + this.noticeChange(); + } + } + /** + * Specifies the sampling behavior when the sample footprint is smaller than or equal to one + * texel. + */ + private _magFilter?: GPUFilterMode; + public get magFilter(): GPUFilterMode { + return this._magFilter; + } + public set magFilter(value: GPUFilterMode) { + if (this._magFilter != value) { + this._magFilter = value; + this.noticeChange(); + } + } + /** + * Specifies the sampling behavior when the sample footprint is larger than one texel. + */ + private _minFilter?: GPUFilterMode; + public get minFilter(): GPUFilterMode { + return this._minFilter; + } + public set minFilter(value: GPUFilterMode) { + if (this._minFilter != value) { + this._minFilter = value; + this.noticeChange(); + } + } + /** + * Specifies behavior for sampling between mipmap levels. + */ + private _mipmapFilter?: GPUMipmapFilterMode; + public get mipmapFilter(): GPUMipmapFilterMode { + return this._mipmapFilter; + } + public set mipmapFilter(value: GPUMipmapFilterMode) { + if (this._mipmapFilter != value) { + this._mipmapFilter = value; + this.noticeChange(); + } + } + /** + */ + private _lodMinClamp?: number; + public get lodMinClamp(): number { + return this._lodMinClamp; + } + public set lodMinClamp(value: number) { + if (this._lodMinClamp != value) { + this._lodMinClamp = value; + this.noticeChange(); + } + } + /** + * Specifies the minimum and maximum levels of detail, respectively, used internally when + * sampling a texture. + */ + private _lodMaxClamp?: number; + public get lodMaxClamp(): number { + return this._lodMaxClamp; + } + public set lodMaxClamp(value: number) { + if (this._lodMaxClamp != value) { + this._lodMaxClamp = value; + this.noticeChange(); + } + } + /** + * When provided the sampler will be a comparison sampler with the specified + * {@link GPUCompareFunction}. + * Note: Comparison samplers may use filtering, but the sampling results will be + * implementation-dependent and may differ from the normal filtering rules. + */ + private _compare?: GPUCompareFunction; + public get compare(): GPUCompareFunction { + return this._compare; + } + public set compare(value: GPUCompareFunction) { + if (this._compare != value) { + this._compare = value; + this.noticeChange(); + } + } + /** + * Specifies the maximum anisotropy value clamp used by the sampler. + * Note: Most implementations support {@link GPUSamplerDescriptor#maxAnisotropy} values in range + * between 1 and 16, inclusive. The used value of {@link GPUSamplerDescriptor#maxAnisotropy} will + * be clamped to the maximum value that the platform supports. + */ + private _maxAnisotropy?: number; + public get maxAnisotropy(): number { + return this._maxAnisotropy; + } + public set maxAnisotropy(value: number) { + if (this._maxAnisotropy != value) { + this._maxAnisotropy = value; + this.noticeChange(); + } + } + +} From 3433ace8b726e263f77eb3f30132d1c5d7d90a20 Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Mon, 24 Apr 2023 13:44:25 +0800 Subject: [PATCH 025/100] feat(GPUBuffer): add GPUBuffer wrapper (#40) add GPUBufferBase add ComputeGPUBuffer add IndicesGPUBuffer add VertexGPUBuffer --- .../webGpu/core/buffer/ComputeGPUBuffer.ts | 13 + .../webGpu/core/buffer/GPUBufferBase.ts | 364 ++++++++++++++++++ .../webGpu/core/buffer/IndicesGPUBuffer.ts | 39 ++ .../webGpu/core/buffer/VertexGPUBuffer.ts | 35 ++ 4 files changed, 451 insertions(+) create mode 100644 src/engine/gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/buffer/VertexGPUBuffer.ts diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer.ts b/src/engine/gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer.ts new file mode 100644 index 00000000..cf93521b --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer.ts @@ -0,0 +1,13 @@ +import { GPUBufferBase } from './GPUBufferBase'; + +/** + * Storage class buffer for calculating shaders + * Usage GPUBufferUsage.STORAGE & GPUBufferUsage.COPY_SRC & GPUBufferUsage.COPY_DST + * @group GFX + */ +export class ComputeGPUBuffer extends GPUBufferBase { + constructor(size: number, data?: Float32Array) { + super(); + this.createBuffer(GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, size, data); + } +} diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts b/src/engine/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts new file mode 100644 index 00000000..718ade80 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts @@ -0,0 +1,364 @@ +import { Color, GPUContext, Matrix4, MemoryDO, MemoryInfo, Quaternion, Struct, Vector2, Vector3, Vector4 } from "../../../../../.."; +import { webGPUContext } from "../../Context3D"; + +export type ArrayBufferData = Uint8Array | Uint16Array | Uint32Array | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array + +/** + * @internal + * @group GFX + */ +export class GPUBufferBase { + public buffer: GPUBuffer; + public memory: MemoryDO; + public memoryNodes: Map; + public seek: number; + public outFloat32Array: Float32Array; + public byteSize: number; + public usage: GPUBufferUsageFlags; + public visibility: number = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; + + private _readBuffer: GPUBuffer; + + constructor() { + this.memory = new MemoryDO(); + this.memoryNodes = new Map(); + } + + public debug() { + } + + public reset(clean: boolean = false, size: number = 0, data?: Float32Array) { + this.seek = 0; + this.memory.reset(); + if (clean) { + this.createBuffer(this.usage, size, data); + } + } + + public setBoolean(name: string, v: boolean) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(1 * 4); + this.memoryNodes.set(name, node); + } + node.setX(v ? 1 : 0); + } + + public setFloat(name: string, v: number) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(1 * 4); + this.memoryNodes.set(name, node); + } + node.setX(v); + } + + public setInt8(name: string, v: number) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(1 * 1); + this.memoryNodes.set(name, node); + } + node.setInt8(v); + } + + public setInt16(name: string, v: number) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(1 * 2); + this.memoryNodes.set(name, node); + } + node.setInt16(v); + } + + public setInt32(name: string, v: number) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(1 * 4); + this.memoryNodes.set(name, node); + } + node.setInt32(v); + } + + public setUint8(name: string, v: number) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(1 * 1); + this.memoryNodes.set(name, node); + } + node.setUint8(v); + } + + public setUint16(name: string, v: number) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(1 * 2); + this.memoryNodes.set(name, node); + } + node.setUint16(v); + } + + public setUint32(name: string, v: number) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(1 * 4); + this.memoryNodes.set(name, node); + } + node.setUint32(v); + } + + public setVector2(name: string, v2: Vector2) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(2 * 4); + this.memoryNodes.set(name, node); + } + node.setXY(v2.x, v2.y); + } + + public setVector3(name: string, v3: Vector3) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(3 * 4); + this.memoryNodes.set(name, node); + } + node.setXYZ(v3.x, v3.y, v3.z); + } + + public setVector4(name: string, v4: Vector4 | Quaternion) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(4 * 4); + this.memoryNodes.set(name, node); + } + node.setXYZW(v4.x, v4.y, v4.z, v4.w); + } + + public setVector4Array(name: string, v4Array: Vector4[] | Quaternion[]) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(4 * 4 * v4Array.length); + this.memoryNodes.set(name, node); + } + node.setVector4Array(v4Array); + } + + public setColor(name: string, color: Color) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(4 * 4); + this.memoryNodes.set(name, node); + } + node.setXYZW(color.r, color.g, color.b, color.a); + } + + public setColorArray(name: string, colorArray: Color[]) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(4 * 4 * colorArray.length); + this.memoryNodes.set(name, node); + } + node.setColorArray(colorArray); + } + + public setMatrix(name: string, mat: Matrix4) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(16 * 4); + this.memoryNodes.set(name, node); + } + node.setFloat32Array(0, mat.rawData); + } + + public setMatrixArray(name: string, mats: Matrix4[]) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(16 * 4 * mats.length); + this.memoryNodes.set(name, node); + } + for (let i = 0; i < mats.length; i++) { + const mat = mats[i]; + node.setFloat32Array(i * 16, mat.rawData); + } + } + + public setArray(name: string, data: number[]) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(data.length * 4); + this.memoryNodes.set(name, node); + } + node.setArray(0, data); + } + + public setFloat32Array(name: string, data: Float32Array) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(data.length * 4); + this.memoryNodes.set(name, node); + } + node.setFloat32Array(0, data); + } + + public setInt32Array(name: string, data: Int32Array) { + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(data.length * 4); + this.memoryNodes.set(name, node); + } + node.setInt32Array(0, data); + } + + public setStruct(c: { new(): T }, index: number, data: any, property?: string) { + let ref = Struct.Ref(c); + let size = Struct.GetSize(c); + + let name = index; + let node = this.memoryNodes.get(name); + node.reset(); + + let obj = data; + if (property) { + obj = obj[property]; + } + + for (let i = 0; i < ref.length; i++) { + const att = ref[i]; + let value = obj[att.name]; + + switch (att.type) { + case `Boolean`: + node.writeFloat(value); + break; + + case `Number`: + node.writeFloat(value); + break; + + case `Float32Array`: + node.writeFloat32Array(value); + break; + + case `Vector2`: + node.writeVector2(value); + break; + + case `Vector3`: + node.writeVector3(value); + break; + + case `Vector4`: + node.writeVector4(value); + break; + + case `Color`: + node.writeRGBColor(value); + break; + + case `Array`: + node.writeArray(value); + break; + } + } + } + + public setStructArray(c: { new(): T }, dataList: any[], property?: string) { + let len = dataList.length; + for (let i = 0; i < len; i++) { + const data = dataList[i]; + this.setStruct(c, i, data, property); + } + } + + // public writeFloat(v: number) { + // this.memory.shareFloat32Array[this.seek] = v; + // this.seek += 1; + // } + + public apply() { + webGPUContext.device.queue.writeBuffer(this.buffer, 0, this.memory.shareDataBuffer);//, this.memory.shareFloat32Array.byteOffset, this.memory.shareFloat32Array.byteLength); + } + + public destroy() { + this.outFloat32Array = null; + this.buffer.destroy(); + this.memory.destroy(); + } + + protected createBuffer(usage: GPUBufferUsageFlags, size: number, data?: ArrayBufferData) { + let device = webGPUContext.device; + this.byteSize = size * 4; + this.usage = usage; + if (this.buffer) { + this.destroy(); + } + this.buffer = device.createBuffer({ + size: this.byteSize, + usage: usage, + mappedAtCreation: false, + }); + + this.memory.allocation(this.byteSize); + if (data) { + let m = this.memory.allocation_node(data.length * 4); + m.setArrayBuffer(0, data); + this.apply(); + } + + this.outFloat32Array = new Float32Array(size); + } + + protected createBufferByStruct(usage: GPUBufferUsageFlags, struct: { new(): T }, count: number) { + let structSize = Struct.GetSize(struct); + let totalLength = structSize * count; + + let device = webGPUContext.device; + this.buffer = device.createBuffer({ + size: totalLength, + // size: totalLength * 4, + usage: usage, + mappedAtCreation: false, + }); + + this.memory.allocation(totalLength); + for (let i = 0; i < count; i++) { + let name = i; + + let node = this.memoryNodes.get(name); + if (!node) { + node = this.memory.allocation_node(structSize); + this.memoryNodes.set(name, node); + } + } + } + + private _readFlag: boolean = false; + private readBuffer() { + if (!this._readBuffer) { + this._readBuffer = webGPUContext.device.createBuffer({ + size: this.memory.shareDataBuffer.byteLength, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, + mappedAtCreation: false, + }); + } + + if (!this._readFlag) { + this.read(); + } + return this.outFloat32Array; + } + + private async read() { + this._readFlag = true; + let command = GPUContext.beginCommandEncoder(); + command.copyBufferToBuffer(this.buffer, 0, this._readBuffer, 0, this.memory.shareDataBuffer.byteLength); + GPUContext.endCommandEncoder(command); + + await this._readBuffer.mapAsync(GPUMapMode.READ); + const copyArrayBuffer = this._readBuffer.getMappedRange(); + this.outFloat32Array.set(new Float32Array(copyArrayBuffer), 0); + // this.memory.shareDataBuffer.set(new Float32Array(copyArrayBuffer), 0); + this._readBuffer.unmap(); + this._readFlag = false; + } +} diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer.ts b/src/engine/gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer.ts new file mode 100644 index 00000000..5cab421f --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer.ts @@ -0,0 +1,39 @@ +import { MemoryInfo } from '../../../../../core/pool/memory/MemoryInfo'; +import { webGPUContext } from '../../Context3D'; +import { ArrayBufferData, GPUBufferBase } from './GPUBufferBase'; + +/** + * The buffer use at geometry indices + * written in the computer shader or CPU Coder + * usage GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.INDEX | GPUBufferUsage.INDIRECT + * @group GFX + */ +export class IndicesGPUBuffer extends GPUBufferBase { + public indicesNode: MemoryInfo; + constructor(data?: ArrayBufferData) { + super(); + this.createIndicesBuffer(GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.INDEX | GPUBufferUsage.INDIRECT, data); + } + + protected createIndicesBuffer(usage: GPUBufferUsageFlags, data?: ArrayBufferData) { + let device = webGPUContext.device; + this.byteSize = data.length * 4; + this.usage = usage; + if (this.buffer) { + this.destroy(); + } + this.buffer = device.createBuffer({ + size: this.byteSize, + usage: usage, + mappedAtCreation: false, + }); + + + this.memory.allocation(this.byteSize); + if (data) { + this.indicesNode = this.memory.allocation_node(data.length * 4); + this.indicesNode.setArrayBuffer(0, data); + this.apply(); + } + } +} diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/VertexGPUBuffer.ts b/src/engine/gfx/graphics/webGpu/core/buffer/VertexGPUBuffer.ts new file mode 100644 index 00000000..e1984534 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/buffer/VertexGPUBuffer.ts @@ -0,0 +1,35 @@ +import { MemoryInfo } from '../../../../../core/pool/memory/MemoryInfo'; +import { webGPUContext } from '../../Context3D'; +import { ArrayBufferData, GPUBufferBase } from './GPUBufferBase'; + +/** + * The buffer use at geometry indices + * written in the computer shader or CPU Coder + * usage GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.VERTEX + * @group GFX + */ +export class VertexGPUBuffer extends GPUBufferBase { + public node: MemoryInfo; + constructor(size: number) { + super(); + this.createVertexBuffer(GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.VERTEX, size); + } + + protected createVertexBuffer(usage: GPUBufferUsageFlags, size: number) { + let device = webGPUContext.device; + this.byteSize = size * Float32Array.BYTES_PER_ELEMENT; + this.usage = usage; + if (this.buffer) { + this.destroy(); + } + this.buffer = device.createBuffer({ + size: this.byteSize, + usage: usage, + mappedAtCreation: false, + }); + + this.memory.allocation(this.byteSize); + this.node = this.memory.allocation_node(this.byteSize); + // this.outFloat32Array = new Float32Array(size); + } +} From 4b4140688d568950d77987a5e2100c044b84a180 Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Mon, 24 Apr 2023 13:47:26 +0800 Subject: [PATCH 026/100] feat(memory): add UniformNode (#39) add UniformNode --- .../webGpu/core/uniforms/UniformNode.ts | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 src/engine/gfx/graphics/webGpu/core/uniforms/UniformNode.ts diff --git a/src/engine/gfx/graphics/webGpu/core/uniforms/UniformNode.ts b/src/engine/gfx/graphics/webGpu/core/uniforms/UniformNode.ts new file mode 100644 index 00000000..d7705efb --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/uniforms/UniformNode.ts @@ -0,0 +1,156 @@ +import { MemoryInfo } from '../../../../../core/pool/memory/MemoryInfo'; +import { Color } from '../../../../../math/Color'; +import { Vector2 } from '../../../../../math/Vector2'; +import { Vector3 } from '../../../../../math/Vector3'; +import { Vector4 } from '../../../../../math/Vector4'; +import { UniformType, UniformValue } from '../../shader/value/UniformValue'; + +/** + * @internal + */ +export class UniformNode { + + public size: number; + public memoryInfo: MemoryInfo; + public bindOnChange: () => void; + + private _data: UniformValue; + private _type: UniformType = UniformType.Number; + + constructor(value: UniformValue) { + this.data = value; + } + + public get data(): UniformValue { + return this._data; + } + + public set data(value: UniformValue) { + this._data = value; + this._type = UniformType.Number; + if (value instanceof Vector2) { + this.size = 2; + this._type = UniformType.Vector2; + } else if (value instanceof Vector3) { + this.size = 3; + this._type = UniformType.Vector3; + } else if (value instanceof Vector4) { + this.size = 4; + this._type = UniformType.Vector4; + } else if (value instanceof Color) { + this.size = 4; + this._type = UniformType.Color; + } else if (value instanceof Float32Array) { + this.size = value.length; + this._type = UniformType.Float32Array; + } else { + this.size = 1; + this._type = UniformType.Number; + } + } + + public get color(): Color { + let c = new Color(this._data.r, this._data.g, this._data.b, this._data.a); + return c; + } + + public set color(value: Color) { + if ( + this._data.r != value.r || + this._data.g != value.g || + this._data.b != value.b || + this._data.a != value.a + ) { + this._data.r = value.r; + this._data.g = value.g; + this._data.b = value.b; + this._data.a = value.a; + this.onChange(); + } + } + + public get value(): number { + return this._data; + } + + public set value(value: number) { + if (this._data != value) { + this._data = value; + this.onChange(); + } + } + + public get vector2(): Vector2 { + return new Vector2(this._data.x, this._data.y); + } + + public set vector2(value: Vector2) { + if (this._data.x != value.x || this._data.y != value.y) { + this._data.x = value.x; + this._data.y = value.y; + this.onChange(); + } + } + + public get vector3(): Vector3 { + return new Vector3(this._data.x, this._data.y, this._data.z); + } + + public set vector3(value: Vector3) { + if (this._data.x != value.x || this._data.y != value.y || this._data.z != value.z) { + this._data.x = value.x; + this._data.y = value.y; + this._data.z = value.z; + this.onChange(); + } + } + + public get vector4(): Vector4 { + // this.onChange(); + return new Vector4(this._data.x, this._data.y, this._data.z, this._data.w); + } + + public set vector4(value: Vector4) { + if (this._data.x != value.x || this._data.y != value.y || this._data.z != value.z || this._data.w != value.w) { + this._data.x = value.x; + this._data.y = value.y; + this._data.z = value.z; + this._data.w = value.w; + this.onChange(); + } + } + + public onChange() { + if (this.bindOnChange) { + this.bindOnChange(); + } + } + + public float32Array(value: Float32Array) { + this._data.set(value); + this.onChange(); + } + + public update() { + switch (this._type) { + case UniformType.Number: + this.memoryInfo.dataBytes.setFloat32(0 * Float32Array.BYTES_PER_ELEMENT, this._data, true); + break; + case UniformType.Vector2: + this.memoryInfo.setVector2(0, this._data); + break; + case UniformType.Vector3: + this.memoryInfo.setVector3(0, this._data); + break; + case UniformType.Vector4: + this.memoryInfo.setVector4(0, this._data); + break; + case UniformType.Color: + this.memoryInfo.setColor(0, this._data); + break; + case UniformType.Float32Array: + this.memoryInfo.setFloat32Array(0, this._data); + break; + } + } +} From 956b8db966421b75abaf05a3bad6eca0cc4a7fd1 Mon Sep 17 00:00:00 2001 From: hellmor Date: Mon, 24 Apr 2023 13:48:09 +0800 Subject: [PATCH 027/100] feat(webGPU): add create WebGPU texture cube code. (#45) Add convert compute shaders Change code comments to English --- .../gfx/generate/convert/BlurEffectCreator.ts | 87 +++++++++ .../gfx/generate/convert/ErpImage2CubeMap.ts | 178 ++++++++++++++++++ .../generate/convert/TextureCubeStdCreator.ts | 138 ++++++++++++++ .../gfx/generate/convert/TextureCubeUtils.ts | 54 ++++++ 4 files changed, 457 insertions(+) create mode 100644 src/engine/gfx/generate/convert/BlurEffectCreator.ts create mode 100644 src/engine/gfx/generate/convert/ErpImage2CubeMap.ts create mode 100644 src/engine/gfx/generate/convert/TextureCubeStdCreator.ts create mode 100644 src/engine/gfx/generate/convert/TextureCubeUtils.ts diff --git a/src/engine/gfx/generate/convert/BlurEffectCreator.ts b/src/engine/gfx/generate/convert/BlurEffectCreator.ts new file mode 100644 index 00000000..2135dad6 --- /dev/null +++ b/src/engine/gfx/generate/convert/BlurEffectCreator.ts @@ -0,0 +1,87 @@ +import { BlurEffectCreator_compute } from '../../../assets/shader/compute/BlurEffectCreator_compute'; +import { webGPUContext } from '../../graphics/webGpu/Context3D'; +import { GPUContext } from '../../renderJob/GPUContext'; +/** + * @internal + * @group GFX + */ +export class BlurTexture2DBufferCreator { + //Image is the texture of converting from rgba8unorm to rgba8unorm + public static blurImageFromTexture(image: { width: number; height: number; gpuTexture: GPUTexture }, dstWidth: number, dstHeight: number, blur: boolean): GPUTexture { + const device = webGPUContext.device; + let code: string = blur ? BlurEffectCreator_compute.blur_rgba8unorm : BlurEffectCreator_compute.sample_rgba8unorm; + const computePipeline = device.createComputePipeline({ + layout: `auto`, + compute: { + module: device.createShaderModule({ + code: code, + }), + entryPoint: 'main', + }, + }); + + //config + const configStride = 4 * 4; //4 float + const configBuffer = device.createBuffer({ + size: configStride, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + device.queue.writeBuffer(configBuffer, 0, new Uint32Array([image.width, image.height, dstWidth, dstHeight])); + + //output + const outputTexture = device.createTexture({ + size: [dstWidth, dstHeight, 1], + mipLevelCount: 1, + format: 'rgba8unorm', + usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT, + label: `blurImageFromTexture`, + }); + + let entries0 = [ + { + binding: 0, + resource: { + buffer: configBuffer, + size: 4 * 4, + }, + }, + { + binding: 1, + resource: image.gpuTexture.createView({ + format: 'rgba8unorm', + dimension: '2d', + baseMipLevel: 0, + mipLevelCount: 1, + }), + }, + { + binding: 2, + resource: outputTexture.createView({ + format: 'rgba8unorm', + dimension: '2d', + baseMipLevel: 0, + mipLevelCount: 1, + }), + }, + ]; + + const computeBindGroup0 = device.createBindGroup({ + layout: computePipeline.getBindGroupLayout(0), + entries: entries0, + }); + + const commandEncoder = GPUContext.beginCommandEncoder(); + const computePass = commandEncoder.beginComputePass(); + computePass.setPipeline(computePipeline); + computePass.setBindGroup(0, computeBindGroup0); + computePass.dispatchWorkgroups(Math.floor(dstWidth / 8), Math.floor(dstHeight / 8)); + + computePass.end(); + + GPUContext.endCommandEncoder(commandEncoder); + + configBuffer.destroy(); + + return outputTexture; + } +} diff --git a/src/engine/gfx/generate/convert/ErpImage2CubeMap.ts b/src/engine/gfx/generate/convert/ErpImage2CubeMap.ts new file mode 100644 index 00000000..8db7ded8 --- /dev/null +++ b/src/engine/gfx/generate/convert/ErpImage2CubeMap.ts @@ -0,0 +1,178 @@ +import { GPUContext } from '../../../..'; +import ErpImage2CubeMapCreateCube_compute from '../../../assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl?raw'; +import ErpImage2CubeMapRgbe2rgba_compute from '../../../assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl?raw'; +import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { Texture } from '../../graphics/webGpu/core/texture/Texture'; +import { webGPUContext } from '../../graphics/webGpu/Context3D'; +import { TextureCubeUtils } from './TextureCubeUtils'; +/** + * @internal + * @group GFX + */ +export class ErpImage2CubeMap { + public static convertRGBE2RGBA(image: VirtualTexture, data: Float32Array): void { + const device = webGPUContext.device; + const computePipeline = device.createComputePipeline({ + layout: `auto`, + compute: { + module: device.createShaderModule({ + code: ErpImage2CubeMapRgbe2rgba_compute, + }), + entryPoint: 'main', + }, + }); + + //config + const configBuffer = device.createBuffer({ + size: 4 * 4, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + device.queue.writeBuffer(configBuffer, 0, new Uint32Array([image.width, image.height, image.width, image.height])); + + //input + const input: GPUBuffer = device.createBuffer({ + size: data.byteLength, + usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, + }); + device.queue.writeBuffer(input, 0, data); + + //entries0 + let entries0 = [ + { + binding: 0, + resource: { + buffer: configBuffer, + size: 4 * 4, + }, + }, + { + binding: 1, + resource: { + buffer: input, + size: data.byteLength, + }, + }, + { + binding: 2, + resource: image.getGPUView(), + }, + ]; + + const computeBindGroup0 = device.createBindGroup({ + layout: computePipeline.getBindGroupLayout(0), + entries: entries0, + }); + + const commandEncoder = GPUContext.beginCommandEncoder(); + const computePass = commandEncoder.beginComputePass(); + computePass.setPipeline(computePipeline); + computePass.setBindGroup(0, computeBindGroup0); + computePass.dispatchWorkgroups(Math.floor(image.width / 8), Math.floor(image.height / 8)); + + computePass.end(); + + GPUContext.endCommandEncoder(commandEncoder); + + configBuffer.destroy(); + } + + private static makeFaceTexturePipeline: GPUComputePipeline; + private static configBuffer: GPUBuffer; + private static quaternionBuffer: GPUBuffer; + + //Image is the float32 color value converted from rgbe to rgba + public static makeTextureCube(image: Texture, dstSize: number, dstView: GPUTextureView): void { + const device = webGPUContext.device; + ErpImage2CubeMap.makeFaceTexturePipeline ||= device.createComputePipeline({ + layout: `auto`, + compute: { + module: device.createShaderModule({ + code: ErpImage2CubeMapCreateCube_compute, + }), + entryPoint: 'main', + }, + }); + const computePipeline = ErpImage2CubeMap.makeFaceTexturePipeline; + + //config + const configStride = 4 * 4; //4 float + ErpImage2CubeMap.configBuffer ||= device.createBuffer({ + size: configStride, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + device.queue.writeBuffer(ErpImage2CubeMap.configBuffer, 0, new Uint32Array([image.width, image.height, dstSize, dstSize])); + + //quaternion + const quaternionSize = 4 * 6; ////xyzw * float + if (!ErpImage2CubeMap.quaternionBuffer) { + ErpImage2CubeMap.quaternionBuffer = device.createBuffer({ + size: quaternionSize * 4 * 6, + usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, + }); + + let qArray = new Float32Array(4 * 6); + for (let i = 0; i < 6; i++) { + let q = TextureCubeUtils.getRotationToFace(i); + qArray[i * 4 + 0] = q.x; + qArray[i * 4 + 1] = q.y; + qArray[i * 4 + 2] = q.z; + qArray[i * 4 + 3] = q.w; + } + device.queue.writeBuffer(ErpImage2CubeMap.quaternionBuffer, 0, qArray); + } + + //output + let entries0 = [ + { + binding: 0, + resource: { + buffer: ErpImage2CubeMap.configBuffer, + size: 4 * 4, + }, + }, + { + binding: 1, + resource: { + buffer: ErpImage2CubeMap.quaternionBuffer, + size: quaternionSize * 4, + }, + }, + { + binding: 2, + resource: image.gpuSampler, + }, + { + binding: 3, + resource: image.getGPUView(), + }, + ]; + + let entries1 = [ + { + binding: 0, + resource: dstView, + }, + ]; + + const computeBindGroup0 = device.createBindGroup({ + layout: computePipeline.getBindGroupLayout(0), + entries: entries0, + }); + + const computeBindGroup1 = device.createBindGroup({ + layout: computePipeline.getBindGroupLayout(1), + entries: entries1, + }); + + const commandEncoder = GPUContext.beginCommandEncoder(); + const computePass = commandEncoder.beginComputePass(); + computePass.setPipeline(computePipeline); + computePass.setBindGroup(0, computeBindGroup0); + computePass.setBindGroup(1, computeBindGroup1); + computePass.dispatchWorkgroups(dstSize / 8, dstSize / 8, 6); + + computePass.end(); + + GPUContext.endCommandEncoder(commandEncoder); + } +} diff --git a/src/engine/gfx/generate/convert/TextureCubeStdCreator.ts b/src/engine/gfx/generate/convert/TextureCubeStdCreator.ts new file mode 100644 index 00000000..8ff70551 --- /dev/null +++ b/src/engine/gfx/generate/convert/TextureCubeStdCreator.ts @@ -0,0 +1,138 @@ +import { Texture } from '../../graphics/webGpu/core/texture/Texture'; +import { webGPUContext } from '../../graphics/webGpu/Context3D'; +import { GPUContext, VirtualTexture } from '../../../..'; + +/** + * @internal + * @group GFX + */ +export class TextureCubeStdCreator { + + private static createCube = /*wgsl*/ ` + +struct SettingUniform { + faceIndex : i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32 +}; + +@group(0) @binding(0) var settingUniform : SettingUniform; +@group(0) @binding(1) var inputTex : texture_2d; +@group(0) @binding(2) var outTex : texture_storage_2d; + +@compute @workgroup_size(8, 8, 1) +fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let coord = vec2(GlobalInvocationID.xy); + + let outTexSize = textureDimensions(outTex).xy; + let outTexel = 1.0 / vec2(outTexSize - 1); + + let uv_0 = vec2(coord) * outTexel; + var oc = samplePixel(settingUniform.faceIndex, uv_0); + textureStore(outTex, coord, oc); +} + +fn samplePixel(face:i32, uv01:vec2) -> vec4 { + let rectangle_v2_f32 = round(vec2(0.25, 0.33333) * vec2(textureDimensions(inputTex).xy)); + let rectangle = vec2(rectangle_v2_f32); + + var offsetIndex = vec2(0); + if(face == 0){ + offsetIndex.x = 2; + offsetIndex.y = 1; + }else if(face == 1){ + offsetIndex.x = 0; + offsetIndex.y = 1; + }else if(face == 2){ + offsetIndex.x = 1; + offsetIndex.y = 0; + }else if(face == 3){ + offsetIndex.x = 1; + offsetIndex.y = 2; + }else if(face == 4){ + offsetIndex.x = 1; + offsetIndex.y = 1; + }else if(face == 5){ + offsetIndex.x = 3; + offsetIndex.y = 1; + } + + let coordOffset = rectangle * offsetIndex; + let coordIndex = vec2(vec2(rectangle - 1) * uv01); + var oc = textureLoad(inputTex, coordOffset + coordIndex, 0); + return oc; +} +`; + + private static configBuffer: GPUBuffer = null; + private static blurSettingBuffer: GPUBuffer = null; + private static pipeline: GPUComputePipeline; + + static createFace(index: number, size: number, inTex: Texture, outTex: VirtualTexture): void { + const device = webGPUContext.device; + if (this.pipeline == null) { + this.pipeline = device.createComputePipeline({ + layout: `auto`, + compute: { + module: device.createShaderModule({ + code: TextureCubeStdCreator.createCube, + }), + entryPoint: 'main', + }, + }); + } + const computePipeline = this.pipeline; + + //config + const configStride = 4 * 4; //4 float + this.configBuffer ||= device.createBuffer({ + size: configStride, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + device.queue.writeBuffer(this.configBuffer, 0, new Uint32Array([index, 0, 0, 0])); + + const quaternionSize = 4 * 6; ////xyzw * float + + //roughness + this.blurSettingBuffer ||= device.createBuffer({ + size: configStride, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + device.queue.writeBuffer(this.blurSettingBuffer, 0, new Float32Array([0, 0, 0, 0])); + + //image + let entries0 = [ + { + binding: 0, + resource: { + buffer: this.configBuffer, + size: 4 * 4, + }, + }, + { + binding: 1, + resource: inTex.getGPUView(), + }, + { + binding: 2, + resource: outTex.getGPUView(), + } + ]; + + + const computeBindGroup0 = device.createBindGroup({ + layout: computePipeline.getBindGroupLayout(0), + entries: entries0, + }); + + const commandEncoder = GPUContext.beginCommandEncoder(); + const computePass = commandEncoder.beginComputePass(); + computePass.setPipeline(computePipeline); + computePass.setBindGroup(0, computeBindGroup0); + computePass.dispatchWorkgroups(size / 8, size / 8); + + computePass.end(); + GPUContext.endCommandEncoder(commandEncoder); + } +} diff --git a/src/engine/gfx/generate/convert/TextureCubeUtils.ts b/src/engine/gfx/generate/convert/TextureCubeUtils.ts new file mode 100644 index 00000000..510e3e58 --- /dev/null +++ b/src/engine/gfx/generate/convert/TextureCubeUtils.ts @@ -0,0 +1,54 @@ +import { Matrix4 } from '../../../math/Matrix4'; +import { Quaternion } from '../../../math/Quaternion'; +import { Vector3 } from '../../../math/Vector3'; +/** + * @internal + */ +export enum CubeMapFaceEnum { + Left = 0, + Right = 1, + Bottom = 2, + Top = 3, + Back = 4, + Front = 5, +} +/** + * @internal + * @group GFX + */ +export class TextureCubeUtils { + public static getRotationToFace(face: number): Quaternion { + let quaternion: Quaternion = Quaternion.identity().clone(); + let target: Vector3 = new Vector3(); + let matrix = new Matrix4().identity(); + let up: Vector3 = new Vector3(); + switch (face) { + case CubeMapFaceEnum.Top: + target.set(0, -1, 0); + up.set(0, 0, -1); + break; + case CubeMapFaceEnum.Bottom: + target.set(0, 1, 0); + up.set(0, 0, 1); + break; + case CubeMapFaceEnum.Right: + target.set(1, 0, 0); + up.set(0, 1, 0); + break; + case CubeMapFaceEnum.Left: + target.set(-1, 0, 0); + up.set(0, 1, 0); + break; + case CubeMapFaceEnum.Back: + target.set(0, 0, -1); + up.set(0, 1, 0); + break; + case CubeMapFaceEnum.Front: + return Quaternion.identity(); + } + matrix.lookAt(new Vector3(), target, up); + quaternion.setFromRotationMatrix(matrix); + return quaternion; + } + +} From 56615e00999f09887b2ddbf446dd46d4809fea32 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Mon, 24 Apr 2023 14:00:18 +0800 Subject: [PATCH 028/100] feat(shader): add shader module and resource (#24) add inline shader add uniform shader add matrix shader add cluster shader add shadow shader add normalMap shader add brdf shader add lighting function shader add light uniform shader add lit material shader add unlit material shader add material color shader add gbuffer shader add skyGbuffer shader add castShader add shader state ConstValue add shader state ShaderState add shader state ShaderValue add shader state ShaderReflectionInfo add shader state UniformValue --- src/engine/assets/shader/ShaderLib.ts | 125 +++++ .../shader/core/pass/CastShadowPass_wgsl.ts | 196 +++++++ .../core/pass/FrustumCullingShader_cs.wgsl | 123 ++++ .../shader/core/pass/GBuffer_shader.wgsl | 71 +++ .../shader/core/pass/SkyGBuffer_fs.wgsl | 40 ++ .../shader/core/pass/ZPassShader_cs.wgsl | 13 + .../shader/core/pass/ZPassShader_fs.wgsl | 9 + .../assets/shader/core/pass/ZPassShader_vs.ts | 99 ++++ .../core/struct/ColorPassFragmentOutput.wgsl | 11 + .../core/struct/EmptyFrag_CommonFragment.wgsl | 30 + .../core/struct/EmptyFrag_FragmentOutput.wgsl | 10 + .../shader/core/struct/FragmentVarying.wgsl | 20 + .../shader/core/struct/LightStruct.wgsl | 106 ++++ .../shader/core/struct/LightStructFrag.ts | 114 ++++ .../shader/core/struct/ShadingInput.wgsl | 18 + .../shader/core/struct/VertexAttributes.ts | 114 ++++ src/engine/assets/shader/glsl/Quad_glsl.ts | 76 +++ src/engine/assets/shader/glsl/Sky_glsl.ts | 92 +++ .../assets/shader/glsl/post/LUT_glsl.ts | 72 +++ .../assets/shader/lighting/BRDF_frag.wgsl | 314 +++++++++++ .../assets/shader/lighting/BxDF_frag.wgsl | 161 ++++++ .../shader/lighting/IESProfiles_frag.wgsl | 32 ++ .../shader/lighting/Irradiance_frag.wgsl | 277 +++++++++ .../shader/lighting/LightingFunction_frag.ts | 136 +++++ .../assets/shader/lighting/UnLit_frag.ts | 25 + .../assets/shader/materials/ColorLitShader.ts | 30 + .../assets/shader/materials/PavementShader.ts | 68 +++ .../shader/materials/PointShadowDebug.ts | 33 ++ .../materials/program/BxdfDebug_frag.wgsl | 175 ++++++ .../materials/program/Clearcoat_frag.wgsl | 16 + .../materials/program/ClusterDebug_frag.ts | 50 ++ .../materials/program/NormalMap_frag.wgsl | 57 ++ .../materials/program/ShadowMapping_frag.wgsl | 142 +++++ .../materials/uniforms/MaterialUniform.ts | 16 + .../uniforms/PhysicMaterialUniform_frag.ts | 30 + .../uniforms/UnLitMaterialUniform_frag.ts | 11 + .../materials/uniforms/VideoUniform_frag.ts | 12 + .../webGpu/shader/value/ConstValue.ts | 4 + .../webGpu/shader/value/DefineValue.ts | 4 + .../shader/value/ShaderReflectionInfo.ts | 531 ++++++++++++++++++ .../webGpu/shader/value/ShaderState.ts | 114 ++++ .../webGpu/shader/value/ShaderValue.ts | 51 ++ .../webGpu/shader/value/UniformValue.ts | 18 + 43 files changed, 3646 insertions(+) create mode 100644 src/engine/assets/shader/ShaderLib.ts create mode 100644 src/engine/assets/shader/core/pass/CastShadowPass_wgsl.ts create mode 100644 src/engine/assets/shader/core/pass/FrustumCullingShader_cs.wgsl create mode 100644 src/engine/assets/shader/core/pass/GBuffer_shader.wgsl create mode 100644 src/engine/assets/shader/core/pass/SkyGBuffer_fs.wgsl create mode 100644 src/engine/assets/shader/core/pass/ZPassShader_cs.wgsl create mode 100644 src/engine/assets/shader/core/pass/ZPassShader_fs.wgsl create mode 100644 src/engine/assets/shader/core/pass/ZPassShader_vs.ts create mode 100644 src/engine/assets/shader/core/struct/ColorPassFragmentOutput.wgsl create mode 100644 src/engine/assets/shader/core/struct/EmptyFrag_CommonFragment.wgsl create mode 100644 src/engine/assets/shader/core/struct/EmptyFrag_FragmentOutput.wgsl create mode 100644 src/engine/assets/shader/core/struct/FragmentVarying.wgsl create mode 100644 src/engine/assets/shader/core/struct/LightStruct.wgsl create mode 100644 src/engine/assets/shader/core/struct/LightStructFrag.ts create mode 100644 src/engine/assets/shader/core/struct/ShadingInput.wgsl create mode 100644 src/engine/assets/shader/core/struct/VertexAttributes.ts create mode 100644 src/engine/assets/shader/glsl/Quad_glsl.ts create mode 100644 src/engine/assets/shader/glsl/Sky_glsl.ts create mode 100644 src/engine/assets/shader/glsl/post/LUT_glsl.ts create mode 100644 src/engine/assets/shader/lighting/BRDF_frag.wgsl create mode 100644 src/engine/assets/shader/lighting/BxDF_frag.wgsl create mode 100644 src/engine/assets/shader/lighting/IESProfiles_frag.wgsl create mode 100644 src/engine/assets/shader/lighting/Irradiance_frag.wgsl create mode 100644 src/engine/assets/shader/lighting/LightingFunction_frag.ts create mode 100644 src/engine/assets/shader/lighting/UnLit_frag.ts create mode 100644 src/engine/assets/shader/materials/ColorLitShader.ts create mode 100644 src/engine/assets/shader/materials/PavementShader.ts create mode 100644 src/engine/assets/shader/materials/PointShadowDebug.ts create mode 100644 src/engine/assets/shader/materials/program/BxdfDebug_frag.wgsl create mode 100644 src/engine/assets/shader/materials/program/Clearcoat_frag.wgsl create mode 100644 src/engine/assets/shader/materials/program/ClusterDebug_frag.ts create mode 100644 src/engine/assets/shader/materials/program/NormalMap_frag.wgsl create mode 100644 src/engine/assets/shader/materials/program/ShadowMapping_frag.wgsl create mode 100644 src/engine/assets/shader/materials/uniforms/MaterialUniform.ts create mode 100644 src/engine/assets/shader/materials/uniforms/PhysicMaterialUniform_frag.ts create mode 100644 src/engine/assets/shader/materials/uniforms/UnLitMaterialUniform_frag.ts create mode 100644 src/engine/assets/shader/materials/uniforms/VideoUniform_frag.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/value/ConstValue.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/value/DefineValue.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/value/ShaderReflectionInfo.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/value/ShaderState.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/value/ShaderValue.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/value/UniformValue.ts diff --git a/src/engine/assets/shader/ShaderLib.ts b/src/engine/assets/shader/ShaderLib.ts new file mode 100644 index 00000000..dadd690e --- /dev/null +++ b/src/engine/assets/shader/ShaderLib.ts @@ -0,0 +1,125 @@ +import { Bloom_shader, CubeSky_Shader, IrradianceVolumeData_frag, ParticleDataStructShader, Quad_shader, UnLitMaterialUniform_frag, UnLit_frag, VideoUniform_frag } from "../../.."; +import { VertexAttributes } from "./core/struct/VertexAttributes" +import ColorPassFragmentOutput from "./core/struct/ColorPassFragmentOutput.wgsl?raw"; +import Common_frag from "./core/base/Common_frag.wgsl?raw"; +import Common_vert from "./core/base/Common_vert.wgsl?raw"; +import FragmentVarying from "./core/struct/FragmentVarying.wgsl?raw"; +import BxdfDebug_frag from "./materials/program/BxdfDebug_frag.wgsl?raw"; +import Clearcoat_frag from "./materials/program/Clearcoat_frag.wgsl?raw"; +import NormalMap_frag from "./materials/program/NormalMap_frag.wgsl?raw"; +import ShadowMapping_frag from "./materials/program/ShadowMapping_frag.wgsl?raw"; +import BrdfLut_frag from "./core/common/BrdfLut_frag.wgsl?raw"; +import EnvMap_frag from "./core/common/EnvMap_frag.wgsl?raw"; +import GlobalUniform from "./core/common/GlobalUniform.wgsl?raw"; +import Inline_vert from "./core/inline/Inline_vert.wgsl?raw"; +import WorldMatrixUniform from "./core/common/WorldMatrixUniform.wgsl?raw"; +import InstanceUniform from "./core/common/InstanceUniform.wgsl?raw"; +import { LightStructFrag } from "./core/struct/LightStructFrag"; +import { LightingFunction_frag } from "./lighting/LightingFunction_frag"; +import { PhysicMaterialUniform_frag } from "./materials/uniforms/PhysicMaterialUniform_frag"; +import { MathShader } from "./math/MathShader"; +import ShadingInput from "./core/struct/ShadingInput.wgsl?raw"; +import { ClusterDebug_frag } from "./materials/program/ClusterDebug_frag"; + +import FastMathShader from "./math/FastMathShader.wgsl?raw"; +import BRDF_frag from "./lighting/BRDF_frag.wgsl?raw"; +import BxDF_frag from "./lighting/BxDF_frag.wgsl?raw"; +import Irradiance_frag from "./lighting/Irradiance_frag.wgsl?raw"; +import LitShader from '../shader/materials/LitShader.wgsl?raw' +import PBRLItShader from '../shader/materials/PBRLItShader.wgsl?raw' + +import ColorUtil from './utils/ColorUtil.wgsl?raw' +import GenerayRandomDir from './utils/GenerayRandomDir.wgsl?raw' +import IESProfiles_frag from './lighting/IESProfiles_frag.wgsl?raw' +import { ShaderLibs } from "./ShaderLibs"; + +/** + * @internal + */ +export class ShaderLib { + + public static init() { + ShaderLibs.init(); + ShaderLib.register('MathShader', MathShader); + ShaderLib.register('FastMathShader', FastMathShader); + + ShaderLib.register('GlobalUniform', GlobalUniform); + ShaderLib.register('WorldMatrixUniform', WorldMatrixUniform); + ShaderLib.register('NormalMap_frag', NormalMap_frag); + ShaderLib.register('LightingFunction_frag', LightingFunction_frag); + + ShaderLib.register('PhysicMaterialUniform_frag', PhysicMaterialUniform_frag); + ShaderLib.register('UnLitMaterialUniform_frag', UnLitMaterialUniform_frag); + ShaderLib.register('VideoUniform_frag', VideoUniform_frag); + + ShaderLib.register('InstanceUniform', InstanceUniform); + ShaderLib.register('Inline_vert', Inline_vert); + ShaderLib.register('VertexAttributes_vert', VertexAttributes); + ShaderLib.register('Common_vert', Common_vert); + + ShaderLib.register('Common_frag', Common_frag); + ShaderLib.register('FragmentVarying', FragmentVarying); + ShaderLib.register('ColorPassFragmentOutput', ColorPassFragmentOutput); + + ShaderLib.register('LightStruct', LightStructFrag); + ShaderLib.register('ShadingInput', ShadingInput); + ShaderLib.register('IESProfiles_frag', IESProfiles_frag); + + ShaderLib.register('ShadowMapping_frag', ShadowMapping_frag); + + ShaderLib.register('Irradiance_frag', Irradiance_frag); + ShaderLib.register('IrradianceVolumeData_frag', IrradianceVolumeData_frag); + ShaderLib.register('BrdfLut_frag', BrdfLut_frag); + ShaderLib.register('EnvMap_frag', EnvMap_frag); + + ShaderLib.register('ColorUtil_frag', ColorUtil); + ShaderLib.register('ColorUtil', ColorUtil); + ShaderLib.register('BRDF_frag', BRDF_frag); + ShaderLib.register('BxDF_frag', BxDF_frag); + ShaderLib.register('UnLit_frag', UnLit_frag); + ShaderLib.register('Clearcoat_frag', Clearcoat_frag); + ShaderLib.register('LitShader', LitShader); + ShaderLib.register('PBRLItShader', PBRLItShader); + + + + // ShaderLib.register('Surface', Surface_Shader.Surface_Common); + + ShaderLib.register('ClusterDebug_frag', ClusterDebug_frag); + ShaderLib.register('BxdfDebug_frag', BxdfDebug_frag); + + ShaderLib.register('GenerayRandomDir', GenerayRandomDir); + + ShaderLib.register('Quad_vert_wgsl', Quad_shader.Quad_vert_wgsl); + ShaderLib.register('Quad_frag_wgsl', Quad_shader.Quad_frag_wgsl); + ShaderLib.register('Quad_depth2d_frag_wgsl', Quad_shader.Quad_depth2d_frag_wgsl); + ShaderLib.register('Quad_depthCube_frag_wgsl', Quad_shader.Quad_depthCube_frag_wgsl); + ShaderLib.register('sky_vs_frag_wgsl', CubeSky_Shader.sky_vs_frag_wgsl); + ShaderLib.register('sky_fs_frag_wgsl', CubeSky_Shader.sky_fs_frag_wgsl); + ShaderLib.register('Bloom_Brightness_frag_wgsl', Bloom_shader.Bloom_Brightness_frag_wgsl); + ShaderLib.register('Bloom_blur_frag_wgsl', Bloom_shader.Bloom_blur_frag_wgsl); + ShaderLib.register('Bloom_composite_frag_wgsl', Bloom_shader.Bloom_composite_frag_wgsl); + + + ShaderLib.register('ParticleDataStruct', ParticleDataStructShader); + } + + public static register(keyName: string, code: string) { + if (!ShaderLib[keyName.toLowerCase()]) { + // console.warn(`The registered shader already exists: ${keyName}`); + ShaderLib[keyName.toLowerCase()] = code; + } + } + + public static getShader(keyName: string): string { + // let shaderName = keyName.toLowerCase() ; + // let shaderSource = "" + if (ShaderLib[keyName.toLowerCase()]) { + return ShaderLib[keyName.toLowerCase()]; + } + return ShaderLib[keyName.toLowerCase()]; + } + + + +} diff --git a/src/engine/assets/shader/core/pass/CastShadowPass_wgsl.ts b/src/engine/assets/shader/core/pass/CastShadowPass_wgsl.ts new file mode 100644 index 00000000..e35f12a9 --- /dev/null +++ b/src/engine/assets/shader/core/pass/CastShadowPass_wgsl.ts @@ -0,0 +1,196 @@ +import { SkeletonAnimation_shader } from "../../anim/SkeletonAnimation_shader"; +import { MorphTarget_shader } from "../../../../components/anim/morphAnim/MorphTarget_shader"; + +export class CastShadow { + public static shadowCastMap_vert_wgsl: string = /* wgsl */ ` + #include "WorldMatrixUniform" + #include "GlobalUniform" + + struct VertexOutput { + @location(0) fragUV: vec2, + @builtin(position) member: vec4 + }; + + #if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetShaderBinding(2, 1)} + #endif + + #if USE_SKELETON + ${SkeletonAnimation_shader.groupBindingAndFunctions(2, 1)} + #endif + + var worldMatrix: mat4x4; + + struct VertexAttributes{ + @builtin(instance_index) index : u32, + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) uv: vec2, + @location(3) TEXCOORD_1: vec2, + + #if USE_TANGENT + @location(4) TANGENT: vec4, + #if USE_SKELETON + @location(5) joints0: vec4, + @location(6) weights0: vec4, + #if USE_JOINT_VEC8 + @location(7) joints1: vec4, + @location(8) weights1: vec4, + #endif + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(5)} + #endif + #elseif USE_SKELETON + @location(4) joints0: vec4, + @location(5) weights0: vec4, + #if USE_JOINT_VEC8 + @location(6) joints1: vec4, + @location(7) weights1: vec4, + #endif + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(4)} + #endif + } + + @vertex + fn main(vertex:VertexAttributes) -> VertexOutput { + worldMatrix = models.matrix[vertex.index]; + let shadowMatrix: mat4x4 = globalUniform.projMat * globalUniform.viewMat ; + var vertexPosition = vertex.position.xyz; + var vertexNormal = vertex.normal.xyz; + + #if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetCalcVertex()} + #endif + + #if USE_SKELETON + #if USE_JOINT_VEC8 + worldMatrix *= getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); + #else + worldMatrix *= getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); + #endif + #endif + + var worldPos = worldMatrix * vec4(vertexPosition, 1.0) ; + var vPos = shadowMatrix * worldPos; + return VertexOutput(vertex.uv, vPos ); + } + `; + public static castPointShadowMap_vert_wgsl: string = /* wgsl */ ` + #include "WorldMatrixUniform" + #include "GlobalUniform" + + struct VertexOutput { + @location(0) fragUV: vec2, + @location(1) worldPos: vec3, + @builtin(position) member: vec4 + }; + + #if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetShaderBinding(2, 1)} + ##endif + + #if USE_SKELETON + ${SkeletonAnimation_shader.groupBindingAndFunctions(2, 1)} + #endif + + var worldMatrix: mat4x4; + + struct VertexAttributes{ + @builtin(instance_index) index : u32, + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) uv: vec2, + @location(3) TEXCOORD_1: vec2, + + #if USE_TANGENT + @location(4) TANGENT: vec4, + #if USE_SKELETON + @location(5) joints0: vec4, + @location(6) weights0: vec4, + #if USE_JOINT_VEC8 + @location(7) joints1: vec4, + @location(8) weights1: vec4, + #endif + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(5)} + #endif + #elseif USE_SKELETON + @location(4) joints0: vec4, + @location(5) weights0: vec4, + #if USE_JOINT_VEC8 + @location(6) joints1: vec4, + @location(7) weights1: vec4, + #endif + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(4)} + #endif + } + + @vertex + fn main(vertex:VertexAttributes) -> VertexOutput { + worldMatrix = models.matrix[vertex.index]; + let shadowMatrix: mat4x4 = globalUniform.projMat * globalUniform.viewMat ; + var vertexPosition = vertex.position.xyz; + + #if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetCalcVertex()} + #endif + + #if USE_SKELETON + #if USE_JOINT_VEC8 + worldMatrix *= getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); + #else + worldMatrix *= getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); + #endif + #endif + + var worldPos = worldMatrix * vec4(vertexPosition, 1.0) ; + var vPos = shadowMatrix * worldPos; + return VertexOutput(vertex.uv, worldPos.xyz , vPos ); + } + `; + public static shadowCastMap_frag_wgsl: string = /* wgsl */ ` + #if USE_ALPHACUT + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d; + #endif + + struct FragmentOutput { + @location(0) o_Target: vec4, + @builtin(frag_depth) out_depth: f32 + }; + + struct MaterialUniform { + lightWorldPos: vec3, + cameraFar: f32, + }; + + @group(2) @binding(0) + var materialUniform: MaterialUniform; + + @fragment + fn main(@location(0) fragUV: vec2 , @location(1) worldPos:vec3 ) -> FragmentOutput { + var distance = length(worldPos.xyz - materialUniform.lightWorldPos ) ; + distance = distance / materialUniform.cameraFar ; + + #if USE_ALPHACUT + let Albedo = textureSample(baseMap,baseMapSampler,fragUV); + var fragOut:FragmentOutput; + if(Albedo.w > 0.5){ + fragOut = FragmentOutput(vec4(0.0),distance); + } + // if(Albedo.w > 0.5){ + // fragOut = FragmentOutput(vec4(0.0),distance); + // }else{ + // discard; + // } + return fragOut ; + #else + fragOut = FragmentOutput(vec4(0.0),distance); + #endif + } + `; +} diff --git a/src/engine/assets/shader/core/pass/FrustumCullingShader_cs.wgsl b/src/engine/assets/shader/core/pass/FrustumCullingShader_cs.wgsl new file mode 100644 index 00000000..2ae4cfb2 --- /dev/null +++ b/src/engine/assets/shader/core/pass/FrustumCullingShader_cs.wgsl @@ -0,0 +1,123 @@ +struct ConstUniform { + projMat: mat4x4, + viewMat: mat4x4, + cameraWorldMatrix: mat4x4, + pvMatrixInv : mat4x4, + shadowMatrix: array,8>, + CameraPos: vec3, + + frame: f32, + time: f32, + delta: f32, + shadowBias: f32, + skyExposure: f32, + renderPassState:f32, + quadScale: f32, + hdrExposure: f32, + + renderState_left: i32, + renderState_right: i32, + renderState_split: f32, + + mouseX: f32, + mouseY: f32, + windowWidth: f32, + windowHeight: f32, + + near: f32, + far: f32, + + pointShadowBias: f32, + shadowMapSize: f32, + shadowSoft: f32, +} + +struct RenderBound{ + index:f32, +} + +struct Uniforms { + matrix : array> +}; + +@group(0) @binding(0) var models : Uniforms; +@group(0) @binding(1) var standUniform: ConstUniform; +@group(0) @binding(2) var planes: array,7>; +@group(0) @binding(3) var cullingList: array; +@group(0) @binding(4) var outBuffer: array; + + +var boundPoints : array,8> ; + +fn IsInClipSpace( coord : vec4 ) -> bool { + return -coord.w <= coord.x && coord.x <= coord.w + && -coord.w <= coord.y && coord.y <= coord.w + && -coord.w <= coord.z && coord.z <= coord.w; +} + +fn IsOutsideThePlane( plane: vec4, pointPosition : vec3 ) -> bool{ + if(dot(plane.xyz, pointPosition) + plane.w > 0.0){ + return true; + } + return false; +} + +fn containsBox( size:vec3 , center:vec3 ) -> f32 { + var c = 0.0 ; + var d = 0.0 ; + + var r = max(size.x, size.y); + var sr = max(r , size.z); + var scx = center.x; + var scy = center.y; + var scz = center.z; + + for(var p:i32 = 0; p < 6 ; p = p + 1 ){ + var plane = planes[p]; + d = plane.x * scx + plane.y * scy + plane.z * scz + plane.w; + if (d <= -sr) { + return 0.0; + } + if (d > sr) { + c+=1.0; + } + } + + if( c >= 6.0 ){ + return 2.0 ; + }else{ + return 1.0 ; + } +} + +@compute @workgroup_size( 128 ) +fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) +{ + let id = globalInvocation_id.x ; + if(id + 1u > u32(planes[6].x) ){ + outBuffer[id] = f32(0.0); + return ; + } + + let renderBound = cullingList[id]; + let boundID = i32(renderBound.index) ; + var plane = planes[0]; + + let worldMatrix = models.matrix[boundID]; + let projMat = standUniform.projMat ; + + let const_boundMin : vec3 = vec3(-0.5,-0.5,-0.5) ; + let const_boundMax : vec3 = vec3(0.5,0.5,0.5) ; + + let boundMin = worldMatrix * vec4(const_boundMin, 1.0); + let boundMax = worldMatrix * vec4(const_boundMax, 1.0); + + let size = abs( boundMax.xyz - boundMin.xyz ) * 0.65 ; + let center = worldMatrix[3].xyz ; + + var isIn :f32 = 0.0 ; + + isIn = containsBox(size,center); + + outBuffer[id] = f32(isIn); +} diff --git a/src/engine/assets/shader/core/pass/GBuffer_shader.wgsl b/src/engine/assets/shader/core/pass/GBuffer_shader.wgsl new file mode 100644 index 00000000..7b1968a2 --- /dev/null +++ b/src/engine/assets/shader/core/pass/GBuffer_shader.wgsl @@ -0,0 +1,71 @@ +#include "Common_vert" +#include "FragmentVarying" +#include "GlobalUniform" + +struct FragmentOutput { + @location(0) o_Position: vec4, + @location(1) o_Normal: vec4, + @location(2) o_Color: vec4 +}; + +struct MaterialUniform { + baseColor: vec4, + emissiveColor: vec4, + emissiveIntensity: f32, + normalScale: f32, + alphaCutoff: f32 +}; + +@group(2) @binding(0) +var materialUniform: MaterialUniform; + +@group(1) @binding(auto) +var baseMapSampler: sampler; +@group(1) @binding(auto) +var baseMap: texture_2d; + +@group(1) @binding(auto) +var normalMapSampler: sampler; +@group(1) @binding(auto) +var normalMap: texture_2d; + +@group(1) @binding(auto) +var emissiveMapSampler: sampler; +@group(1) @binding(auto) +var emissiveMap: texture_2d; + +fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; +} + +var ORI_FragmentOutput: FragmentOutput; +var ORI_VertexVarying: FragmentVarying; + +@fragment +fn FragMain(vertex_varying:FragmentVarying) -> FragmentOutput { + ORI_VertexVarying = vertex_varying; + var texColor = textureSample(baseMap, baseMapSampler, ORI_VertexVarying.fragUV0.xy ); + + var emissive = textureSample(emissiveMap, emissiveMapSampler, ORI_VertexVarying.fragUV0.xy ).rgb ; + let intensity = materialUniform.emissiveIntensity * materialUniform.emissiveColor.a ; + emissive = emissive.rgb * materialUniform.emissiveColor.rgb ; + emissive = convertToHDRRGB(emissive,intensity); + + if (materialUniform.alphaCutoff-texColor.w > 0.0) { + discard ; + } + + var o_Position = vec4(ORI_VertexVarying.vWorldPos.xyz,emissive.r) ; + var o_Normal = vec4((ORI_VertexVarying.vWorldNormal.xyz * 0.5 + 0.5 ),emissive.g) ; + var o_Color = vec4((texColor * materialUniform.baseColor).rgb , emissive.b ) ; + return FragmentOutput(o_Position,o_Normal,vec4(o_Color)); +} + +fn convertToHDRRGB( color : vec3 , ins:f32 ) -> vec3 { + var hdrColor = vec3(0.0,0.0,0.0); + hdrColor.r = color.r * pow(2.4, ins); + hdrColor.g = color.g * pow(2.4, ins); + hdrColor.b = color.b * pow(2.4, ins); + return hdrColor; +} diff --git a/src/engine/assets/shader/core/pass/SkyGBuffer_fs.wgsl b/src/engine/assets/shader/core/pass/SkyGBuffer_fs.wgsl new file mode 100644 index 00000000..d18ac870 --- /dev/null +++ b/src/engine/assets/shader/core/pass/SkyGBuffer_fs.wgsl @@ -0,0 +1,40 @@ +#include "GlobalUniform" + +struct uniformData { + exposure: f32, + roughness: f32 +}; + +struct FragmentOutput { + @location(0) o_Position: vec4, + @location(1) o_Normal: vec4, + @location(2) o_Color: vec4 +}; + +@group(1) @binding(4) +var baseMapSampler: sampler; +@group(1) @binding(5) +var baseMap: texture_cube; + +@group(2) @binding(0) +var global: uniformData; + +fn LinearToGammaSpace(linRGB: vec3) -> vec3 { + var linRGB1: vec3; + linRGB1 = linRGB; + linRGB1 = max(linRGB1, vec3(0.0, 0.0, 0.0)); + linRGB1.x = pow(linRGB1.x, 0.4166666567325592); + linRGB1.y = pow(linRGB1.y, 0.4166666567325592); + linRGB1.z = pow(linRGB1.z, 0.4166666567325592); + return max(((1.0549999475479126 * linRGB1) - vec3(0.054999999701976776)), vec3(0.0)); +} + +@fragment +fn main(@location(0) fragUV: vec2, @location(1) vWorldPos: vec4, @location(2) vWorldNormal: vec3) -> FragmentOutput { + let maxLevel: u32 = textureNumLevels(baseMap); + let textureColor:vec3 = textureSampleLevel(baseMap, baseMapSampler, normalize(vWorldPos.xyz), global.roughness * f32(maxLevel) ).xyz; + let o_Color = 0.618 * vec4(LinearToGammaSpace(textureColor) * globalUniform.skyExposure , 1.0); + let o_Normal = vec4(vWorldNormal,1.0) ; + let o_Position = vec4(vWorldPos.xyz,100000.0) ; + return FragmentOutput(o_Position,o_Normal,o_Color); +} diff --git a/src/engine/assets/shader/core/pass/ZPassShader_cs.wgsl b/src/engine/assets/shader/core/pass/ZPassShader_cs.wgsl new file mode 100644 index 00000000..f43accc9 --- /dev/null +++ b/src/engine/assets/shader/core/pass/ZPassShader_cs.wgsl @@ -0,0 +1,13 @@ +@group(0) @binding(0) var visibleBuffer: array; +@group(0) @binding(1) var zBufferTexture : texture_2d; + +@compute @workgroup_size(8, 8, 1) +fn CsMain( @builtin(global_invocation_id) globalInvocation_id : vec3 ) { + var fragCoord = vec2( globalInvocation_id.xy ); + let md = textureLoad(zBufferTexture,fragCoord,0); + + let meshID = i32(floor( md.w + 0.1 )); + if (meshID >= 0) { + visibleBuffer[meshID] = 1.0 ; + } +} diff --git a/src/engine/assets/shader/core/pass/ZPassShader_fs.wgsl b/src/engine/assets/shader/core/pass/ZPassShader_fs.wgsl new file mode 100644 index 00000000..4d1d8ea9 --- /dev/null +++ b/src/engine/assets/shader/core/pass/ZPassShader_fs.wgsl @@ -0,0 +1,9 @@ +struct FragmentOutput { + @location(0) o_Target: vec4 +}; + +@fragment +fn main(@location(0) vID: f32, @location(1) vPos:vec3) -> FragmentOutput { + var op = vec4( vPos, vID); + return FragmentOutput(op); +} diff --git a/src/engine/assets/shader/core/pass/ZPassShader_vs.ts b/src/engine/assets/shader/core/pass/ZPassShader_vs.ts new file mode 100644 index 00000000..54995fd2 --- /dev/null +++ b/src/engine/assets/shader/core/pass/ZPassShader_vs.ts @@ -0,0 +1,99 @@ +import { MorphTarget_shader } from "../../../../components/anim/morphAnim/MorphTarget_shader"; +import { SkeletonAnimation_shader } from "../../anim/SkeletonAnimation_shader"; + +export let ZPassShader_vs: string = /* wgsl */ ` + #include "GlobalUniform" + + struct VertexOutput { + @location(0) vID: f32 , + @location(1) vPos: vec3 , + @builtin(position) member: vec4 + }; + + struct Uniforms { + matrix : array> + }; + + @group(0) @binding(1) + var models : Uniforms; + + var worldMatrix: mat4x4; + + #if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetShaderBinding(1, 0)} + #endif + + #if USE_SKELETON + ${SkeletonAnimation_shader.groupBindingAndFunctions(1, 0)} + #endif + + @vertex + fn main( + @builtin(instance_index) index : u32, + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) uv: vec2, + @location(3) TEXCOORD_1: vec2, + + #if USE_TANGENT + @location(4) TANGENT: vec4, + #if USE_SKELETON + @location(5) joints0: vec4, + @location(6) weights0: vec4, + #if USE_JOINT_VEC8 + @location(7) joints1: vec4, + @location(8) weights1: vec4, + #endif + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(5)} + #endif + #elseif USE_SKELETON + @location(4) joints0: vec4, + @location(5) weights0: vec4, + #if USE_JOINT_VEC8 + @location(6) joints1: vec4, + @location(7) weights1: vec4, + #endif + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(4)} + #endif + ) -> VertexOutput { + worldMatrix = models.matrix[index]; + + var vertexPosition = position; + var vertexNormal = normal; + #if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetCalcVertex()} + #endif + + #if USE_SKELETON + #if USE_JOINT_VEC8 + worldMatrix *= getSkeletonWorldMatrix_8(joints0, weights0, joints1, weights1); + #else + worldMatrix *= getSkeletonWorldMatrix_4(joints0, weights0); + #endif + #endif + + + let wPos = worldMatrix * vec4(vertexPosition.xyz, 1.0); + var fixProjMat = globalUniform.projMat ; + // fixProjMat[2].z = -1.0 ;//99999.0 / (99999.0 - 1.0) ; + // fixProjMat[3].z = 0.0 ;//(-1.0 * 99999.0) / (99999.0 - 1.0) ; + var rzMatrix : mat4x4 ; + rzMatrix[0] = vec4(1.0,0.0,0.0,0.0) ; + rzMatrix[1] = vec4(0.0,1.0,0.0,0.0) ; + rzMatrix[2] = vec4(0.0,0.0,1.0,0.0) ; + rzMatrix[3] = vec4(0.0,0.0,0.0,1.0) ; + // rzMatrix[2].z = (-globalUniform.near * globalUniform.far) / (globalUniform.far - globalUniform.near) ; + // rzMatrix[3].z = globalUniform.far / (globalUniform.far - globalUniform.near) ; + var clipPos:vec4 = fixProjMat * globalUniform.viewMat * rzMatrix * wPos ; + // clipPos.z = clipPos.z + (clipPos.z / clipPos.w + globalUniform.near / clipPos.w + 0.002 / clipPos.w) * (globalUniform.near / globalUniform.far) ; + // clipPos.z = depthToLinear01(clipPos.z / clipPos.w) ; + return VertexOutput(f32(index) , wPos.xyz, clipPos); + } + + fn depthToLinear01(depth:f32) -> f32 { + let a = 1.0 / (globalUniform.near - globalUniform.far); + return (globalUniform.near*globalUniform.far*a) / (depth + globalUniform.far * a) ; + } +`; diff --git a/src/engine/assets/shader/core/struct/ColorPassFragmentOutput.wgsl b/src/engine/assets/shader/core/struct/ColorPassFragmentOutput.wgsl new file mode 100644 index 00000000..b05fee10 --- /dev/null +++ b/src/engine/assets/shader/core/struct/ColorPassFragmentOutput.wgsl @@ -0,0 +1,11 @@ +struct FragmentOutput { + @location(0) color: vec4, + #if USE_WORLDPOS + @location(1) worldPos: vec4, + #endif + #if USEGBUFFER + @location(2) worldNormal: vec4, + @location(3) material: vec4, + #endif + // @builtin(frag_depth) out_depth: f32 +}; diff --git a/src/engine/assets/shader/core/struct/EmptyFrag_CommonFragment.wgsl b/src/engine/assets/shader/core/struct/EmptyFrag_CommonFragment.wgsl new file mode 100644 index 00000000..e2b621e1 --- /dev/null +++ b/src/engine/assets/shader/core/struct/EmptyFrag_CommonFragment.wgsl @@ -0,0 +1,30 @@ +#include "FragmentVarying" +#include "FragmentOutput.wgsl" +#include "GlobalUniform" +#include "Lit_Parmers.wgsl" +#include "PBRLit.wgsl" + +var ORI_FragmentOutput: FragmentOutput; +var ORI_VertexVarying: FragmentVarying; +var ORI_ShadingInput: ShadingStruct; + +@fragment +fn FragMain( vertex_varying:FragmentVarying ) -> FragmentOutput { + ORI_VertexVarying = vertex_varying; + ORI_FragmentOutput.color = vec4(1.0, 0.0, 0.0, 1.0); + + #if USE_WORLDPOS + ORI_FragmentOutput.worldPos = ORI_VertexVarying.vWorldPos; + #endif + #if USEGBUFFER + ORI_FragmentOutput.worldNormal = vec4(ORI_VertexVarying.vWorldNormal,1.0); + ORI_FragmentOutput.material = vec4(0.0,1.0,0.0,0.0); + #endif + + frag(); + + #if USE_DEBUG + debugFragmentOut(); + #endif + return ORI_FragmentOutput ; +} diff --git a/src/engine/assets/shader/core/struct/EmptyFrag_FragmentOutput.wgsl b/src/engine/assets/shader/core/struct/EmptyFrag_FragmentOutput.wgsl new file mode 100644 index 00000000..3c306828 --- /dev/null +++ b/src/engine/assets/shader/core/struct/EmptyFrag_FragmentOutput.wgsl @@ -0,0 +1,10 @@ +struct FragmentOutput { + @location(0) color: vec4, + #if USE_WORLDPOS + @location(1) worldPos: vec4, + #endif + #if USEGBUFFER + @location(2) worldNormal: vec4, + @location(3) material: vec4 + #endif +}; diff --git a/src/engine/assets/shader/core/struct/FragmentVarying.wgsl b/src/engine/assets/shader/core/struct/FragmentVarying.wgsl new file mode 100644 index 00000000..0d790ea4 --- /dev/null +++ b/src/engine/assets/shader/core/struct/FragmentVarying.wgsl @@ -0,0 +1,20 @@ +struct FragmentVarying { + @location(0) fragUV0: vec2, + @location(1) fragUV1: vec2, + @location(2) viewPosition: vec4, + @location(3) fragPosition: vec4, + @location(4) vWorldPos: vec4, + @location(5) vWorldNormal: vec3, + @location(6) vColor: vec4, + + #if USE_SHADOWMAPING + @location(7) vShadowPos: vec4, + #endif + + #if USE_TANGENT + @location(8) TANGENT: vec4, + #endif + + @builtin(front_facing) face: bool, + @builtin(position) fragCoord : vec4 +}; diff --git a/src/engine/assets/shader/core/struct/LightStruct.wgsl b/src/engine/assets/shader/core/struct/LightStruct.wgsl new file mode 100644 index 00000000..9a53b8f4 --- /dev/null +++ b/src/engine/assets/shader/core/struct/LightStruct.wgsl @@ -0,0 +1,106 @@ +struct LightData { + index:f32, + lightType:i32, + radius:f32, + linear:f32, + + position:vec3, + lightMatrixIndex:f32, + + direction:vec3, + quadratic:f32, + + lightColor:vec3, + intensity:f32, + + innerCutOff :f32, + outerCutOff:f32, + range :f32, + castShadow:i32, + + lightTangent:vec3, + ies:f32, +}; + +const PointLightType = 1; +const DirectLightType = 2; +const SpotLightType = 3; + +struct ClusterBox { + minPoint:vec4, + maxPoint:vec4 +}; + +struct LightIndex { + count:f32, + start:f32, + empty0:f32, + empty1:f32, +}; + +struct ClustersUniform { + clusterTileX:f32, + clusterTileY:f32, + clusterTileZ:f32, + numLights:f32, + maxNumLightsPerCluster:f32, + near:f32, + far:f32, + screenWidth:f32, + screenHeight:f32, + clusterPix:f32, +}; + +@group(2) @binding(1) +var lightBuffer: array; +@group(2) @binding(2) +var clustersUniform : ClustersUniform; +@group(2) @binding(3) +var lightAssignBuffer : array; +@group(2) @binding(4) +var assignTable : array; +#if DEBUG_CLUSTER + @group(2) @binding(5) + var clusterBuffer : array; +#endif + +fn getLight( index:i32 ) -> LightData { + let lightId = i32(lightAssignBuffer[index]); + var lightData = lightBuffer[lightId]; + return lightData ; +} + +fn linear01Depth(depth : f32) -> f32 { + return globalUniform.far * globalUniform.near / fma(depth, globalUniform.near-globalUniform.far, globalUniform.far); +} + +fn getTile(fragCoord : vec4) -> vec3 { + var coord = fragCoord ; + coord.z = linear01Depth(coord.z) ; + + let sliceScale = f32(clustersUniform.clusterTileZ) / log2(globalUniform.far / globalUniform.near); + let sliceBias = -(f32(clustersUniform.clusterTileZ) * log2(globalUniform.near) / log2(globalUniform.far / globalUniform.near)); + let zTile = u32(max(log2(coord.z) * sliceScale + sliceBias, 0.0)); + return vec3(u32(coord.x / (clustersUniform.screenWidth / f32(clustersUniform.clusterTileX))), + u32(coord.y / (clustersUniform.screenHeight / f32(clustersUniform.clusterTileY))), + zTile); +} + +fn getCluster(fragCoord : vec4) -> LightIndex { + let tile = getTile(fragCoord); + let id = tile.x + + tile.y * u32(clustersUniform.clusterTileX) + + tile.z * u32(clustersUniform.clusterTileX) * u32(clustersUniform.clusterTileY); + return assignTable[id]; +} + +#if DEBUG_CLUSTER + fn getClusterIndex(fragCoord : vec4) -> u32 { + let tile = getTile(fragCoord); + let id = tile.x + + tile.y * u32(clustersUniform.clusterTileX) + + tile.z * u32(clustersUniform.clusterTileX) * u32(clustersUniform.clusterTileY); + return id; + // return 0u ; + } +#endif diff --git a/src/engine/assets/shader/core/struct/LightStructFrag.ts b/src/engine/assets/shader/core/struct/LightStructFrag.ts new file mode 100644 index 00000000..2abf2f23 --- /dev/null +++ b/src/engine/assets/shader/core/struct/LightStructFrag.ts @@ -0,0 +1,114 @@ + +/** + * @internal + */ + +export let LightStructFrag: string = /* wgsl */ ` + struct LightData { + index:f32, + lightType:i32, + radius:f32, + linear:f32, + + position:vec3, + lightMatrixIndex:f32, + + direction:vec3, + quadratic:f32, + + lightColor:vec3, + intensity:f32, + + innerCutOff :f32, + outerCutOff:f32, + range :f32, + castShadow:i32, + + lightTangent:vec3, + ies:f32, + }; + + const PointLightType = 1; + const DirectLightType = 2; + const SpotLightType = 3; + + struct ClusterBox{ + minPoint:vec4, + maxPoint:vec4 + }; + + struct LightIndex + { + count:f32, + start:f32, + empty0:f32, + empty1:f32, + }; + + struct ClustersUniform{ + clusterTileX:f32, + clusterTileY:f32, + clusterTileZ:f32, + numLights:f32, + maxNumLightsPerCluster:f32, + near:f32, + far:f32, + screenWidth:f32, + screenHeight:f32, + clusterPix:f32, + }; + + @group(2) @binding(1) + var lightBuffer: array; + @group(2) @binding(2) + var clustersUniform : ClustersUniform; + @group(2) @binding(3) + var lightAssignBuffer : array; + @group(2) @binding(4) + var assignTable : array; + #if DEBUG_CLUSTER + @group(2) @binding(5) + var clusterBuffer : array; + #endif + + fn getLight( index:i32 ) -> LightData{ + let lightId = i32(lightAssignBuffer[index]); + var lightData = lightBuffer[lightId]; + return lightData ; + } + + fn linear01Depth(depth : f32) -> f32 { + return globalUniform.far * globalUniform.near / fma(depth, globalUniform.near-globalUniform.far, globalUniform.far); + } + + fn getTile(fragCoord : vec4) -> vec3 { + var coord = fragCoord ; + coord.z = linear01Depth(coord.z) ; + + let sliceScale = f32(clustersUniform.clusterTileZ) / log2(globalUniform.far / globalUniform.near); + let sliceBias = -(f32(clustersUniform.clusterTileZ) * log2(globalUniform.near) / log2(globalUniform.far / globalUniform.near)); + let zTile = u32(max(log2(coord.z) * sliceScale + sliceBias, 0.0)); + return vec3(u32(coord.x / (clustersUniform.screenWidth / f32(clustersUniform.clusterTileX))), + u32(coord.y / (clustersUniform.screenHeight / f32(clustersUniform.clusterTileY))), + zTile); + } + + fn getCluster(fragCoord : vec4) -> LightIndex { + let tile = getTile(fragCoord); + let id = tile.x + + tile.y * u32(clustersUniform.clusterTileX) + + tile.z * u32(clustersUniform.clusterTileX) * u32(clustersUniform.clusterTileY); + return assignTable[id]; + } + + #if DEBUG_CLUSTER + fn getClusterIndex(fragCoord : vec4) -> u32 { + let tile = getTile(fragCoord); + let id = tile.x + + tile.y * u32(clustersUniform.clusterTileX) + + tile.z * u32(clustersUniform.clusterTileX) * u32(clustersUniform.clusterTileY); + return id; + // return 0u ; + } + #endif + `; diff --git a/src/engine/assets/shader/core/struct/ShadingInput.wgsl b/src/engine/assets/shader/core/struct/ShadingInput.wgsl new file mode 100644 index 00000000..725b8078 --- /dev/null +++ b/src/engine/assets/shader/core/struct/ShadingInput.wgsl @@ -0,0 +1,18 @@ +struct ShadingInput{ + BaseColor:vec4, + Roughness:f32, + Metallic:f32, + Specular:f32, + EmissiveColor:vec4, + SurfaceColor:vec4, + Normal:vec3, + Tangent:vec4, + WorldPositionOffset:vec3, + AmbientOcclusion:f32, + PixelDepthOffset:f32, + + Opacity:f32, + OpacityMask:f32, + + Refraction:f32, +} diff --git a/src/engine/assets/shader/core/struct/VertexAttributes.ts b/src/engine/assets/shader/core/struct/VertexAttributes.ts new file mode 100644 index 00000000..91d66388 --- /dev/null +++ b/src/engine/assets/shader/core/struct/VertexAttributes.ts @@ -0,0 +1,114 @@ +import { SkeletonAnimation_shader } from "../../anim/SkeletonAnimation_shader"; +import { MorphTarget_shader } from "../../../../components/anim/morphAnim/MorphTarget_shader"; + + +export let VertexAttributes: string = /* wgsl */ ` + + #if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetShaderBinding(3, 0)} + #endif + + #if USE_SKELETON + ${SkeletonAnimation_shader.groupBindingAndFunctions(3, 0)} + #endif + + struct VertexAttributes{ + @builtin(instance_index) index : u32, + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) uv: vec2, + @location(3) TEXCOORD_1: vec2, + + #if USE_TANGENT + @location(4) TANGENT: vec4, + #if USE_SKELETON + @location(5) joints0: vec4, + @location(6) weights0: vec4, + #if USE_JOINT_VEC8 + @location(7) joints1: vec4, + @location(8) weights1: vec4, + #endif + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(5)} + #endif + #elseif USE_SKELETON + @location(4) joints0: vec4, + @location(5) weights0: vec4, + #if USE_JOINT_VEC8 + @location(6) joints1: vec4, + @location(7) weights1: vec4, + #endif + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(4)} + #endif + } + + struct VertexOutput { + @location(0) varying_UV0: vec2, + @location(1) varying_UV1: vec2, + @location(2) varying_ViewPos: vec4, + @location(3) varying_Clip: vec4, + @location(4) varying_WPos: vec4, + @location(5) varying_WNormal: vec3, + @location(6) varying_Color: vec4, + + #if USE_SHADOWMAPING + @location(7) varying_ShadowPos: vec4, + #endif + + #if USE_TANGENT + @location(8) varying_Tangent: vec4, + #endif + + @builtin(position) member: vec4 + }; + + var ORI_VertexOut: VertexOutput ; + + fn ORI_Vert(vertex:VertexAttributes){ + var vertexPosition = vertex.position; + var vertexNormal = vertex.normal; + + #if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetCalcVertex()} + #endif + + #if USE_SKELETON + #if USE_JOINT_VEC8 + let skeletonNormal = getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); + ORI_MATRIX_M *= skeletonNormal ; + // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; + #else + let skeletonNormal = getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); + ORI_MATRIX_M *= skeletonNormal ; + // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; + #endif + #endif + + // #if USE_SHADOWMAPING + // var shadowPos = globalUniform.shadowMatrix * ORI_MATRIX_M * vec4(vertex.position.xyz, 1.0) ; + // ORI_VertexOut.varying_ShadowPos = shadowPos ; + // #endif + + #if USE_TANGENT + ORI_VertexOut.varying_Tangent = vertex.TANGENT ; + #endif + + ORI_NORMALMATRIX = transpose(inverse( mat3x3(ORI_MATRIX_M[0].xyz,ORI_MATRIX_M[1].xyz,ORI_MATRIX_M[2].xyz) )); + + var worldPos = (ORI_MATRIX_M * vec4(vertexPosition.xyz, 1.0)); + var viewPosition = ORI_MATRIX_V * worldPos; + var clipPosition = ORI_MATRIX_P * viewPosition ; + + ORI_CameraWorldDir = normalize(ORI_CAMERAMATRIX[3].xyz - worldPos.xyz) ; + + ORI_VertexOut.varying_UV0 = vertex.uv.xy ; + ORI_VertexOut.varying_UV1 = vertex.TEXCOORD_1.xy; + ORI_VertexOut.varying_ViewPos = viewPosition / viewPosition.w; + ORI_VertexOut.varying_Clip = clipPosition ; + ORI_VertexOut.varying_WPos = worldPos ; + ORI_VertexOut.varying_WPos.w = f32(vertex.index); + ORI_VertexOut.varying_WNormal = normalize(ORI_NORMALMATRIX * vertexNormal.xyz) ; + ORI_VertexOut.member = clipPosition ; + } + `; \ No newline at end of file diff --git a/src/engine/assets/shader/glsl/Quad_glsl.ts b/src/engine/assets/shader/glsl/Quad_glsl.ts new file mode 100644 index 00000000..fac3b8af --- /dev/null +++ b/src/engine/assets/shader/glsl/Quad_glsl.ts @@ -0,0 +1,76 @@ + + +export let QuadGlsl_vs = /* wgsl */ ` + #include "WorldMatrixUniform" + #include "GlobalUniform" + + struct VertexOutput { + @location(0) fragUV: vec2, + @builtin(position) member: vec4 + }; + + @vertex + fn main(@builtin(instance_index) index : u32, @location(0) position: vec3, @location(1) TEXCOORD_1: vec2) -> VertexOutput { + let id = u32(index); + let worldMatrix = models.matrix[id]; + + let screenPos = vec2(((TEXCOORD_1 * 2.0) - vec2(1.0))) * 0.5 ; + return VertexOutput(TEXCOORD_1, vec4(screenPos, 0.0, 1.0)); + } +`; + +/** + * @internal + */ +export let QuadGlsl_fs = /* wgsl */` +#version 450 + +layout(location = 0) in vec2 fragUV; + +layout(location = 0) out vec4 o_Target; + +layout(set = 0, binding = 0) uniform ConstUniform { + mat4 projMat; + mat4 viewMat; + mat4 shadowMatrix; + mat4 cameraWorldMatrix; + mat4 pvMatrixInv; + float frame; + float time; + float detail; + float shadowBias; + float skyExposure; + float renderPassState; + float quadScale; + +}; + +layout(set = 2, binding = 0) uniform sampler baseMapSampler; +layout(set = 2, binding = 1) uniform texture2D baseMap; +layout(set = 3, binding = 0) uniform MaterialDataUniform { + vec4 color; +}; + +void main() { + vec2 uv = fragUV.xy; + uv.y = 1.0 - uv.y; + vec4 colorTexture = texture(sampler2D(baseMap, baseMapSampler), uv * quadScale) * color; + o_Target = vec4(colorTexture.rgb, colorTexture.a); + + if (o_Target.r <= 0.5 && o_Target.g <= 0.5 && o_Target.b <= 0.5) { + discard; + } + // float gamma = 2.2; + // float exposure = 1.0; + // float pureWhite = 1.0; + + // float luminance = dot(colorTexture.rgb, vec3(0.2126, 0.7152, 0.0722)); + // float mappedLuminance = (luminance * (1.0 + luminance/(pureWhite*pureWhite))) / (1.0 + luminance); + + // // Scale color by ratio of average luminances. + // vec3 mappedColor = (mappedLuminance / luminance) * colorTexture.rgb; + + // // Gamma correction. + // o_Target = vec4(pow(o_Target.rgb, vec3(1.0/gamma)), 1.0); +}; +`; diff --git a/src/engine/assets/shader/glsl/Sky_glsl.ts b/src/engine/assets/shader/glsl/Sky_glsl.ts new file mode 100644 index 00000000..e5780d85 --- /dev/null +++ b/src/engine/assets/shader/glsl/Sky_glsl.ts @@ -0,0 +1,92 @@ +/** + * @internal + */ +export let Sky_glsl_vs = ` +#version 450 +layout(location = 0) in vec3 position; +layout(location = 1) in vec3 normal; +layout(location = 2) in vec2 uv; + +layout(location = 0) out vec2 fragUV; +layout(location = 1) out vec4 vWorldPos; +layout(location = 2) out vec3 vWorldNormal; + +layout(set = 0, binding = 0) +uniform ConstUniform { + mat4 projMat; + mat4 viewMat; + mat4 shadowMatrix; +}; + +layout(set = 1, binding = 0) +buffer Uniforms { + mat4[] modeMat; +}; + + mat4 inverse( in mat4 m ){ + return mat4( + m[0][0], m[1][0], m[2][0], 0.0, + m[0][1], m[1][1], m[2][1], 0.0, + m[0][2], m[1][2], m[2][2], 0.0, + -dot(m[0].xyz,m[3].xyz), + -dot(m[1].xyz,m[3].xyz), + -dot(m[2].xyz,m[3].xyz), + 1.0 ); +} + +void main(){ + fragUV = uv; + mat4 modelMat = modeMat[gl_InstanceID]; + mat4 vm = viewMat * modelMat; + mat3 normalMatrix = mat3(vm[0].xyz,vm[1].xyz,vm[2].xyz); + vec3 eNormal = normalize( normalMatrix * normal ); + + vWorldPos = modelMat * vec4(position.xyz,1.0) ; + + mat4 fixedViewMat = viewMat ; + fixedViewMat[3] = vec4(0.0,0.0,-8.0,1.0); + vec4 mvPosition = modelMat * vec4( position.xyz, 1.0 ); + gl_Position = projMat * fixedViewMat * mvPosition; +} + +`; +/** + * @internal + */ +export let Sky_glsl_fs = ` +#version 450 + +layout(location = 0) in vec2 fragUV; +layout(location = 1) in vec4 vWorldPos; +layout(location = 2) in vec3 vWorldNormal; + +layout(location = 0) out vec4 o_Target; + +layout(set = 2, binding = 0) +uniform sampler baseMapSampler; +layout(set = 2, binding = 1) +uniform texture2D baseMap; + +layout(set = 3, binding = 0) uniform uniformData { + vec3 eyesPos; + float exposure; + float roughness; +}; + +vec3 LinearToGammaSpace(in vec3 linRGB) +{ + vec3 _linRGB = vec3(linRGB) ; + _linRGB = max(linRGB, vec3(0.0, 0.0, 0.0)); + _linRGB.r = pow(linRGB.r,0.416666667); + _linRGB.g = pow(linRGB.g,0.416666667); + _linRGB.b = pow(linRGB.b,0.416666667); + return max(1.055 * _linRGB - 0.055, vec3(0.0)); +} + +void main(){ + int maxMipLevel = textureQueryLevels(baseMap, fragUV).x ; + vec4 textureColor = textureCubeLod( sampler2D(baseMap, baseMapSampler), normalize(vWorldPos.xyz), roughness * float(maxMipLevel) ) ; + o_Target = vec4(LinearToGammaSpace(textureColor.rgb),1.0) * exposure ; +} + +`; diff --git a/src/engine/assets/shader/glsl/post/LUT_glsl.ts b/src/engine/assets/shader/glsl/post/LUT_glsl.ts new file mode 100644 index 00000000..32787a98 --- /dev/null +++ b/src/engine/assets/shader/glsl/post/LUT_glsl.ts @@ -0,0 +1,72 @@ +/** + * @internal + */ +export let LUT_glsl = ` +#version 450 + +layout(location = 0) in vec2 fragUV; + +layout(location = 0) out vec4 o_Target; + +layout(set = 0, binding = 0) uniform ConstUniform { + mat4 projMat; + mat4 viewMat; + mat4 shadowMatrix; + mat4 cameraWorldMatrix ; + mat4 pvMatrixInv ; + float frame; + float time; + float detail; + float shadowBias; + float skyExposure; + float renderPassState; + float quadScale; + float intensity; +}; + +layout(set = 2, binding = 0) uniform sampler baseMapSampler; +layout(set = 2, binding = 1) uniform texture2D baseMap; + +layout(set = 2, binding = 2) uniform sampler lutMapSample; +layout(set = 2, binding = 3) uniform texture2D lutMap; + +layout(set = 3, binding = 0) uniform UniformData{ + float intensity ; +}; + +void main() { + vec2 uv = fragUV.xy; + uv.y = 1.0 - uv.y; + vec4 col = texture(sampler2D(baseMap, baseMapSampler), uv * quadScale); + // vec3 col = vec3(pow(base.xyz,vec3(1.0/2.2))); + + float Bcolor = col.b * 63.0; + vec2 quad1; + quad1.y = floor(floor(Bcolor) / 8.0); + quad1.x = floor(Bcolor) - (quad1.y * 8.0); + + vec2 quad2; + quad2.y = floor(ceil(Bcolor) / 8.0); + quad2.x = ceil(Bcolor) - (quad2.y * 8.0); + + const float tmp = (0.125-(0.5/512.0)) ; + const float tmp2 = 0.5/512.0 ; + + vec2 uv1; + vec2 uv2; + uv1.x = ((quad1.x)*0.125)+ tmp2 + (tmp* col.r); + uv1.y = (((quad1.y)*0.125) + tmp2 + (tmp* col.g)); + + uv2.x = ((quad2.x)*0.125)+ tmp2 + (tmp* col.r); + uv2.y = (((quad2.y)*0.125)+ tmp2 + (tmp* col.g)); + + vec4 color1 = texture(sampler2D(lutMap, lutMapSample), uv1); + vec4 color2 = texture(sampler2D(lutMap, lutMapSample), uv2); + + vec4 newColor = mix(color1, color2, fract(Bcolor)); + // vec3 outC = pow(newColor.xyz,vec3(2.2)); + + o_Target = vec4(newColor.rgb, col.a ); + // o_Target = vec4(1.0); +} +`; diff --git a/src/engine/assets/shader/lighting/BRDF_frag.wgsl b/src/engine/assets/shader/lighting/BRDF_frag.wgsl new file mode 100644 index 00000000..365208d0 --- /dev/null +++ b/src/engine/assets/shader/lighting/BRDF_frag.wgsl @@ -0,0 +1,314 @@ + + #include "Clearcoat_frag" + #include "EnvMap_frag" + #include "BrdfLut_frag" + + struct FragData { + Ao: f32, + Metallic: f32, + Roughness: f32, + + Albedo: vec4, + Emissive: vec3, + + N: vec3, + V: vec3, + R: vec3, + + F0: vec3, + F: vec3, + KS: vec3, + KD: vec3, + Shadow: f32, + Indirect: f32, + Reflectance: f32, + + NoV: f32, + FaceDirection:f32, + + DiffuseColor: vec3, + SpecularColor: vec3, + ClearcoatRoughness:f32, + EnvColor: vec3, + Irradiance: vec3, + }; + + var fragData: FragData; + + struct BxDFContext + { + NoV : f32 , + NoL : f32 , + VoL : f32 , + NoH : f32 , + VoH : f32 + }; + + fn getContext( N:vec3, V:vec3, H:vec3, L:vec3 ) -> BxDFContext + { + var Context:BxDFContext ; + Context.NoL = saturate(dot(N, L)) ; + Context.NoV = saturate(dot(N, V)) ; + Context.VoL = saturate(dot(V, L)) ; + Context.NoH = saturate(dot(N, H)); + Context.VoH = saturate(dot(V, H)); + + // Context.NoL = max(dot(N, L),0.0); + // Context.NoV = max(dot(N, V),0.0); + // Context.VoL = max(dot(V, L),0.0) ; + // Context.NoH = saturate(dot(N, H)); + // Context.VoH = max(dot(V, H),0.0); + return Context ; + } + + // convert roughness to mipmapLevel + fn roughnessToMipmapLevel( roughness: f32 , mipmapCount:i32 ) -> f32{ + let level = roughness * (1.7 - 0.7 * roughness ); + return level * f32(mipmapCount); + } + + fn Fd90( NoL:f32, roughness:f32) -> f32 + { + return (2.0 * NoL * roughness) + 0.4; + } + + fn KDisneyTerm( NoL:f32, NoV:f32 , roughness:f32) -> f32 + { + return (1.0 + Fd90(NoL, roughness) * pow(1.0 - NoL, 5.0)) * (1.0 + Fd90(NoV, roughness) * pow(1.0 - NoV, 5.0)); + } + + fn FresnelSchlick( NoV:f32, F0:vec3) -> vec3 + { + return F0 + (1.0 - F0) * pow(1.0 - NoV, 5.0); + } + + fn FresnelSchlickRoughness( NoV:f32, F0:vec3, roughness:f32) -> vec3 + { + return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - NoV, 5.0); + } + + fn DistributionGGX( NdotH:f32 , roughness:f32 ) -> f32 + { + let alpha = roughness * roughness; + let alpha2 = roughness * roughness; + + let NdotH2 = NdotH * NdotH; + + let nom = alpha2; + var denom = (NdotH2 * (alpha2 - 1.0) + 1.0); + denom = PI * denom * denom; + + return nom / denom; + } + + // [Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs"] + fn Vis_SmithJoint( NoV : f32 , NoL : f32 , a2 : f32) -> f32 + { + var Vis_SmithV = NoL * sqrt(NoV * (NoV - NoV * a2) + a2); + var Vis_SmithL = NoV * sqrt(NoL * (NoL - NoL * a2) + a2); + return 0.5 * rcp(Vis_SmithV + Vis_SmithL); + } + + fn GeometrySchlickGGX( NdotV : f32 , roughness : f32 ) -> f32 + { + //roughness compute ks + let r = (roughness + 1.0); + let k = (r*r) / 8.0; + + let nom = NdotV; + let denom = NdotV * (1.0 - k) + k; + + return nom / denom; + } + + fn GeometrySmith( NdotV:f32 , NdotL:f32 , roughness : f32) -> f32 + { + // let NdotV = max(dot(N, V), 0.0); + // let NdotL = max(dot(N, L), 0.0); + let ggx1 = GeometrySchlickGGX(NdotV, roughness); + let ggx2 = GeometrySchlickGGX(NdotL, roughness); + return ggx1 * ggx2; + } + + fn GeometryAttenuationGGXSmith( NdotL:f32, NdotV:f32, roughness:f32) -> f32 + { + var NdotL2 = NdotL * NdotL; + var NdotV2 = NdotV * NdotV; + var kRough2 = roughness * roughness + 0.0001; + + var ggxL = (2.0 * NdotL) / (NdotL + sqrt(NdotL2 + kRough2 * (1.0 - NdotL2))); + var ggxV = (2.0 * NdotV) / (NdotV + sqrt(NdotV2 + kRough2 * (1.0 - NdotV2))); + + return ggxL * ggxV; + } + + fn colorLinear( colorVector:vec3 ) -> vec3 + { + var linearColor = pow(colorVector.rgb, vec3(2.2)); + return linearColor; + } + + fn computeFresnelSchlick( NoV:f32 , F0:vec3) -> vec3 + { + return F0 + (1.0 - F0) * pow(clamp(1.0 - NoV,0.0,1.0), 5.0); + } + + fn computeFresnelSchlickRoughness(NoV:f32 , F0:vec3, roughness:f32) -> vec3 + { + return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(clamp(1.0 - fragData.NoV,0.0,1.0), 5.0); + } + + fn computeDistributionGGX( N:vec3, H:vec3, roughness:f32) -> f32 + { + var alpha = roughness * roughness; + var alpha2 = alpha * alpha; + + var NdotH = saturate(dot(N, H)); + var NdotH2 = NdotH * NdotH; + + return (alpha2) / (PI * (NdotH2 * (alpha2 - 1.0) + 1.0) * (NdotH2 * (alpha2 - 1.0) + 1.0)); + } + + fn D_GGX( N:vec3, H:vec3, roughness:f32 ) -> f32 + { + var NoH = saturate(dot(N, H)); + var d = ( NoH * roughness - NoH ) * NoH + 1.0; // 2 mad + return roughness / ( PI*d*d ); // 4 mul, 1 rcp + } + + fn computeGeometryAttenuationGGXSmith( NdotL:f32 , NdotV:f32, roughness:f32) -> f32 + { + var NdotL2 = NdotL * NdotL; + var NdotV2 = NdotV * NdotV; + var kRough2 = roughness * roughness + 0.0001; + + var ggxL = (2.0 * NdotL) / (NdotL + sqrt(NdotL2 + kRough2 * (1.0 - NdotL2))); + var ggxV = (2.0 * NdotV) / (NdotV + sqrt(NdotV2 + kRough2 * (1.0 - NdotV2))); + + return ggxL * ggxV; + } + + fn Vis_Smith( NoL:f32 , NoV:f32, a2:f32 )-> f32 + { + var Vis_SmithV = NoV + sqrt( NoV * (NoV - NoV * a2) + a2 ); + var Vis_SmithL = NoL + sqrt( NoL * (NoL - NoL * a2) + a2 ); + return rcp( Vis_SmithV * Vis_SmithL ); + } + + fn simpleBRDF( albedo:vec3, N:vec3, V:vec3,L:vec3,att:f32,lightColor:vec3,roughness:f32 )-> vec3{ + let H = normalize(V + L); + let Context:BxDFContext = getContext(N,V,H,L); + + let D = DistributionGGX( Context.NoH , roughness); + let G = GeometrySmith(Context.NoV,Context.NoL, roughness ); + let F = FresnelSchlick(Context.VoH, vec3(fragData.F0)); + let specular = ( D * G * F ) / (4.0 * Context.NoV * Context.NoL + 0.001); + let kS = F; + var kd = 1.0 - kS ; + kd *= 1.0 - fragData.Metallic ; + var diffuse = kd * (albedo.rgb / PI ) ; + let ambient = specular.rgb ; + + fragData.KD += kd; + fragData.KS += F; + + var col = (diffuse + ambient) * Context.NoL * lightColor * att ; + // var col = (diffuse + ambient) * Context.NoL * lightColor ; + return (col.rgb ) ; + } + + fn getSpecularDominantDir ( N : vec3 , R : vec3 , roughness : f32 ) -> vec3 + { + var smoothness = saturate (1.0 - roughness ); + var lerpFactor = smoothness * ( sqrt ( smoothness ) + roughness ); + // The result is not normalized as we fetch in a cubemap + return mix (N, R, lerpFactor ); + } + + fn approximateSpecularIBL( specularColor:vec3 , roughness:f32 , R:vec3) -> vec3 { + let NoV = fragData.NoV ; + let MAX_REFLECTION_LOD = i32(textureNumLevels(prefilterMap)) ; + let mip = roughnessToMipmapLevel(roughness,MAX_REFLECTION_LOD); + var prefilteredColor: vec3 = (textureSampleLevel(prefilterMap, prefilterMapSampler, getSpecularDominantDir(fragData.N,R,roughness) , mip ).rgb); + prefilteredColor = globalUniform.skyExposure * LinearToGammaSpace(prefilteredColor); + var envBRDF = textureSampleLevel(brdflutMap, brdflutMapSampler, vec2(NoV, roughness) , 0.0 ) ; + return prefilteredColor * (specularColor.rgb * envBRDF.x + saturate( 50.0 * specularColor.g ) * envBRDF.y) ; + } + + fn fresnel_coat(n:vec3,v:vec3,ior:f32) -> f32 { + var f0 = (1.0-ior)/(1.0+ior); + f0 = f0 * f0 ; + let fr = pow((f0 + (1.0 - f0)*(1.0 - abs( max(dot(n,v),0.0) ))) , 5.0 ) ; + return fr ; + } + + fn reflectEnvMap(n:vec3 , v:vec3 , roughness:f32) -> vec3 { + let MAX_REFLECTION_LOD = i32(textureNumLevels(envMap)) ; + let mip = roughnessToMipmapLevel(roughness,MAX_REFLECTION_LOD); + let R = 2.0 * dot( v , n ) * n - v ; + var prefilteredColor: vec3 = globalUniform.skyExposure * (textureSampleLevel(envMap, envMapSampler, R , mip ).rgb); + prefilteredColor = LinearToGammaSpace(prefilteredColor); + return prefilteredColor ; + } + + fn Specular_D_GGX( NoH:f32, roughness:f32 ) -> f32 + { + let a2 = roughness * roughness ; + let f = (NoH * a2 - NoH) * NoH + 1.0; + return a2 / (PI * f * f) ; + } + + fn V_Kelemen( LoH : f32 ) -> f32 { + return 0.25 / (LoH * LoH); + } + + fn F_Schlick( f0:vec3 , f90 : f32 , VoH : f32 ) -> vec3 { + return f0 + (f90 - f0) * pow(1.0 - VoH,5.0); + } + + //https://google.github.io/filament/Filament.html materialsystem/clearcoatmodel/clearcoatparameterization + fn CoatSpecular_brdf( f:vec3, s:vec3, n:vec3 , v:vec3 , l:vec3 , att:f32 , layer :vec3) -> vec3 { + let H = normalize(v + l); + let VdotNc = max(dot(v,n),0.0); + let LdotNc = max(dot(l,n),0.0); + let NoH = max(dot(n,H),0.0); + let LoH = clamp(dot(l,H),0.0,1.0); + let NoL = max(dot(n,l),0.0); + + let Fd = f ; + let Fr = s ; + + let clearcoatRoughnessFactor = clamp(materialUniform.clearcoatRoughnessFactor,0.089,1.0); + let clearCoatRoughness = clearcoatRoughnessFactor * clearcoatRoughnessFactor ; + + let Dc = Specular_D_GGX( NoH , clearCoatRoughness ) ; + let Vc = V_Kelemen( LoH ) ; + let Fc = F_Schlick(vec3(0.04), clearCoatRoughness , pow(LoH,2.0)); + let Frc = (Dc * Vc) * Fc ; + // return layer * vec3((Fd + Fr * (1.0 - Fc)) * (1.0 - Fc) + Frc) ;//* NoL; + return layer * vec3((Fd + Fr * (1.0 - Fc)) * (1.0 - Fc) + Frc) * ( 0.5 + NoL * 0.5 ) ; + } + + + fn approximate_coating(base:vec3 , clearColor: vec3, n:vec3 , v:vec3 , light:LightData ) -> vec3 { + let clearcoatRoughnessFactor = clamp(materialUniform.clearcoatRoughnessFactor,0.084,1.0); + var clearcoatAlpha = clearcoatRoughnessFactor * clearcoatRoughnessFactor + fragData.ClearcoatRoughness; + + // var lightColor = getHDRColor( lightCC.rgb , light.linear ) ; + var att = light.intensity ; + let l = light.direction ; + + let NdotV = max(dot(n,v),0.0); + let MAX_REFLECTION_LOD = i32(textureNumLevels(prefilterMap)) ; + let mip = roughnessToMipmapLevel(clearcoatAlpha,MAX_REFLECTION_LOD); + let R = 2.0 * dot( v , n ) * n - v ; + var envIBL: vec3 = globalUniform.skyExposure * (textureSampleLevel(prefilterMap, prefilterMapSampler, R ,mip ).rgb) ; + envIBL = LinearToGammaSpace(envIBL); + + let clearCoat = materialUniform.clearcoatFactor ; + let f = FresnelSchlickRoughness( max(dot(n,v),0.0) , vec3(0.0) , clearcoatAlpha ) ; + let clearcoat_brdf = (f * envIBL) + CoatSpecular_brdf( clearColor , vec3( clearCoat ) , n , v , -l , att , envIBL ) ; + + // return clearcoat_brdf;+ fragData.ClearcoatRoughness + return mix(base,clearcoat_brdf,materialUniform.clearcoatWeight ) ; + } diff --git a/src/engine/assets/shader/lighting/BxDF_frag.wgsl b/src/engine/assets/shader/lighting/BxDF_frag.wgsl new file mode 100644 index 00000000..684fcc20 --- /dev/null +++ b/src/engine/assets/shader/lighting/BxDF_frag.wgsl @@ -0,0 +1,161 @@ + + #include "Clearcoat_frag" + #include "BRDF_frag" + #include "MathShader" + #include "FastMathShader" + #include "Common_frag" + #include "GlobalUniform" + + #include "PhysicMaterialUniform_frag" + #include "NormalMap_frag" + #include "LightingFunction_frag" + #include "Irradiance_frag" + #include "ColorUtil_frag" + #include "BxdfDebug_frag" + + + + //ORI_ShadingInput + fn initFragData() { + fragData.Albedo = ORI_ShadingInput.BaseColor ; + fragData.Ao = ORI_ShadingInput.AmbientOcclusion ; + fragData.Roughness = max(ORI_ShadingInput.Roughness,0.003) ; + fragData.Metallic = ORI_ShadingInput.Metallic ; + fragData.Emissive = ORI_ShadingInput.EmissiveColor.rgb ; + fragData.N = ORI_ShadingInput.Normal; + fragData.V = normalize(globalUniform.cameraWorldMatrix[3].xyz - ORI_VertexVarying.vWorldPos.xyz) ; + + let R = 2.0 * dot( fragData.V , fragData.N ) * fragData.N - fragData.V ; + fragData.R = R;//reflect( fragData.V , -fragData.N ) ; + + fragData.NoV = saturate(dot(fragData.N, fragData.V)) ; + + fragData.F0 = mix(vec3(0.04), fragData.Albedo.rgb, fragData.Metallic); + + fragData.F = computeFresnelSchlick(fragData.NoV, fragData.F0); + fragData.KD = vec3(fragData.F) ; + fragData.KS = vec3(0.0) ; + + fragData.Indirect = 0.0 ; + fragData.Reflectance = 1.0 ; + + fragData.DiffuseColor = fragData.Albedo.rgb * (1.0 - fragData.Metallic); + fragData.SpecularColor = mix(vec3(1.0), fragData.Albedo.rgb, fragData.Metallic); + + fragData.ClearcoatRoughness = 0.0 ; + #if USE_CLEARCOAT_ROUGHNESS + fragData.ClearcoatRoughness = getClearcoatRoughnees() ; + #endif + } + + fn BxDFShading(){ + initFragData(); + + var color = vec3(0.0); + + let lightIndex = getCluster(ORI_VertexVarying.fragCoord); + let start = max(lightIndex.start, 0.0); + let count = max(lightIndex.count, 0.0); + let end = max(start + count , 0.0); + for(var i:i32 = i32(start) ; i < i32(end); i += 1 ) + { + let light = getLight(i32(i)); + + switch (light.lightType) { + case PointLightType: { + color += pointLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; + } + case DirectLightType: { + color += directLighting( fragData.Albedo.rgb ,fragData.N,fragData.V,fragData.Roughness , light , globalUniform.shadowBias) ; + } + case SpotLightType: { + color += spotLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; + } + default: { + } + } + } + + var kS = FresnelSchlickRoughness(fragData.NoV, fragData.F0, fragData.Roughness ); + var kD = vec3(1.0) - kS; + kD = kD * (1.0 - fragData.Metallic); + kD = max(vec3(0.04),kD) ; + + let MAX_REFLECTION_LOD = f32(textureNumLevels(prefilterMap)) ; + var diffuseIrradiance: vec3 = vec3(0.0);// + + #if USE_SKYLIGHT + var prefilterTex: vec3 = globalUniform.skyExposure * (textureSampleLevel(prefilterMap, prefilterMapSampler, fragData.N.xyz, 8.0 ).rgb); + prefilterTex = LinearToGammaSpace(prefilterTex); + var skyLight = kD * fragData.Albedo.xyz * prefilterTex; + // color += skyLight ; + #endif + + var envRef = kS * approximateSpecularIBL( fragData.SpecularColor , fragData.Roughness , fragData.R ) ;//* (materialUniform.ior - 1.0) ; + + var irradiance = diffuseIrradiance ; + #if USEGI + irradiance += getIrradiance().rgb ; + #else + irradiance += globalUniform.skyExposure * LinearToGammaSpace(textureSampleLevel(prefilterMap, prefilterMapSampler, fragData.N.xyz, 0.8 * (MAX_REFLECTION_LOD) ).rgb); + #endif + + fragData.Irradiance = irradiance; + + + var diffuseIBL = fragData.Albedo.rgb * irradiance.rgb ; + // var ambientIBL = kD * fragData.Albedo.rgb * fragData.Ao; + fragData.EnvColor = materialUniform.envIntensity * envRef ; + + ORI_FragmentOutput.color = vec4(0.0); + + #if USE_CLEARCOAT + for(var i:i32 = i32(start) ; i < i32(end); i = i + 1 ) + { + let light = getLight(i); + switch (light.lightType) { + case PointLightType: { + color += pointLighting(fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; + } + case DirectLightType: { + color += directLighting( fragData.Albedo.rgb ,fragData.N,fragData.V,fragData.Roughness , light , globalUniform.shadowBias) ; + } + case SpotLightType: { + color += spotLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; + } + default: { + } + } + } + #endif + + // // Using stripped down, 'pure log', formula. Parameterized by grey points and dynamic range covered. + #if USEGBUFFER + var normal_rgba8unorm = (ORI_VertexVarying.vWorldNormal + 1.0) * 0.5; + normal_rgba8unorm = clamp(normal_rgba8unorm, vec3(0.0), vec3(1.0)); + #endif + + // ORI_FragmentOutput.color = vec4(ORI_FragmentOutput.color.xyz,fragData.Albedo.a) ; + #if USE_WORLDPOS + ORI_FragmentOutput.worldPos = vec4(ORI_VertexVarying.vWorldPos.xyzw); + #endif + + #if USEGBUFFER + ORI_FragmentOutput.worldNormal = vec4(normal_rgba8unorm,1.0); + ORI_FragmentOutput.material = vec4(1.0,fragData.Roughness,fragData.Metallic,1.0); + #endif + + // color = pow(color.rgb,vec3(2.0)); + + color += diffuseIBL ; + // color += ambientIBL ; + color += fragData.EnvColor * fragData.Ao ; + color += fragData.Emissive.xyz ; + + //-1 1 + // color = diffuseIBL ; + ORI_FragmentOutput.color = vec4(color.rgb,fragData.Albedo.a) ; + + // let gamma = 2.0 ; + // ORI_FragmentOutput.color = pow(ORI_FragmentOutput.color,vec4(gamma,gamma,gamma,1.0)); + } diff --git a/src/engine/assets/shader/lighting/IESProfiles_frag.wgsl b/src/engine/assets/shader/lighting/IESProfiles_frag.wgsl new file mode 100644 index 00000000..b44d48fa --- /dev/null +++ b/src/engine/assets/shader/lighting/IESProfiles_frag.wgsl @@ -0,0 +1,32 @@ +#if USE_IES_PROFILE + @group(1) @binding(auto) + var iesTextureArrayMapSampler : sampler; + @group(1) @binding(auto) + var iesTextureArrayMap: texture_2d_array ; +#endif + +fn getLightIESProfileAtt( wPos : vec3 , light:LightData ) -> f32 +{ + #if USE_IES_PROFILE + let tangent = vec3(1.0,0.0,0.0); + let lightBitangent = normalize( cross( tangent, light.direction ) ); + let lightMatrix = mat4x4( vec4(light.direction.xyz, 0.0), vec4(lightBitangent.xyz, 0.0), vec4(tangent.xyz, 0.0), vec4(0.0, 0.0, 0.0, 1.0) ); + let lightMatrixInv = transpose(lightMatrix); + let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; + let l = lightPos - wPos; + let toLight = normalize(l); + let localToLight = (vec4(toLight.xyz, 0.0) * lightMatrixInv).xyz; + let dotProd = dot(toLight, light.direction); + let angle = asin(dotProd); + let normAngle = (angle / PI) + 0.5 ; + let tangentAngle = atan2( -localToLight.z, -localToLight.x ); + let normTangentAngle = tangentAngle / (PI * 2.0) + 0.5 ; + if(light.ies >= 0.0){ + return textureSampleLevel(iesTextureArrayMap, iesTextureArrayMapSampler, vec2(normAngle , normTangentAngle) , i32(light.ies) , 0.0).r ; + }else{ + return 1.0; + } + #else + return 1.0; + #endif +} diff --git a/src/engine/assets/shader/lighting/Irradiance_frag.wgsl b/src/engine/assets/shader/lighting/Irradiance_frag.wgsl new file mode 100644 index 00000000..672ccd6e --- /dev/null +++ b/src/engine/assets/shader/lighting/Irradiance_frag.wgsl @@ -0,0 +1,277 @@ + + #include "IrradianceVolumeData_frag" + fn pow3( x : f32 ) -> f32 + { + var xx = x*x; + return x * xx; + } + + struct IrradianceField { + probeStartPosition: vec4, + probeCounts:vec4, + probeStep:f32, + irradianceTextureWidth:f32, + irradianceTextureHeight:f32, + irradianceProbeSideLength:f32, + }; + + @group(1) @binding(auto) + var irradianceMapSampler: sampler; + @group(1) @binding(auto) + var irradianceMap: texture_2d; + @group(1) @binding(auto) + var irradianceDepthMapSampler: sampler; + @group(1) @binding(auto) + var irradianceDepthMap: texture_2d; + + @group(2) @binding(6) + var irradianceData : IrradianceVolumeData ; + + var irradianceFieldSurface: IrradianceField; + var energyPreservation: f32 = 0.85; + var quaternion:vec4 = vec4(0.0, -0.7071067811865475, 0.7071067811865475, 0.0); + + fn getIrradianceFieldSurface() -> IrradianceField{ + let data = irradianceData ; + irradianceFieldSurface.probeStartPosition = vec4(data.startX, data.startY, data.startZ, 0.0); + irradianceFieldSurface.probeCounts = vec4(data.gridXCount, data.gridYCount, data.gridZCount, 0.0); + irradianceFieldSurface.probeStep = data.ProbeSpace; + irradianceFieldSurface.irradianceTextureWidth = data.OctRTMaxSize; + irradianceFieldSurface.irradianceTextureHeight = data.OctRTMaxSize; + irradianceFieldSurface.irradianceProbeSideLength = data.OctRTSideSize; + return irradianceFieldSurface; + } + + fn rotateDir(n:vec3) -> vec3{ + return normalize(applyQuaternion(-n, quaternion)); + } + + fn square1f(v:f32) -> f32 { + return v * v ; + } + + fn square(v:vec3) -> vec3{ + return v*v; + } + + fn getIrradiance() -> vec4{ + var irradiance = sampleIrradianceField(); + var outerVolumeFactor:f32 = getOuterVolume(irradianceFieldSurface, ORI_VertexVarying.vWorldPos.xyz); + irradiance *= outerVolumeFactor; + return irradiance ; + } + + fn debugProbe(id:i32) -> vec4{ + getIrradianceFieldSurface(); + var direction = normalize(ORI_VertexVarying.vWorldNormal); + direction = applyQuaternion(-direction, quaternion); + var probeTextureUV : vec2 = textureCoordFromDirection(normalize(direction), + id, + irradianceFieldSurface.irradianceTextureWidth, + irradianceFieldSurface.irradianceTextureHeight, + irradianceFieldSurface.irradianceProbeSideLength); + + var probeIrradiance: vec4 = textureSampleLevel(irradianceMap, irradianceMapSampler, probeTextureUV ,0.0); + return probeIrradiance; + } + + fn debugProbeDepth(id:i32) -> vec4{ + getIrradianceFieldSurface(); + var direction = normalize(ORI_VertexVarying.vWorldNormal); + direction = applyQuaternion(-direction, quaternion); + var probeTextureUV : vec2 = textureCoordFromDirection(normalize(direction), + id, + irradianceFieldSurface.irradianceTextureWidth, + irradianceFieldSurface.irradianceTextureHeight, + irradianceFieldSurface.irradianceProbeSideLength); + + var probeIrradiance: vec4 = textureSampleLevel(irradianceDepthMap, irradianceDepthMapSampler, probeTextureUV ,0.0); + probeIrradiance.x = probeIrradiance.x / irradianceData.maxDistance; + probeIrradiance.y = 0.0; + probeIrradiance.z = 0.0; + probeIrradiance.w = 1.0; + return probeIrradiance; + } + + fn getOuterVolume(L:IrradianceField, position:vec3) -> f32{ + let halfWidth:vec3 = 0.5 * (L.probeCounts.xyz - 1.0) * L.probeStep; + let edgeWidth:vec3 = halfWidth + L.probeStep; + let centerPosition:vec3 = halfWidth + L.probeStartPosition.xyz; + let clampPos = min(edgeWidth, abs(position - centerPosition)); + + let factorX = getOuterAxis(clampPos.x, edgeWidth.x, L.probeStep); + let factorY = getOuterAxis(clampPos.y, edgeWidth.y, L.probeStep); + let factorZ = getOuterAxis(clampPos.z, edgeWidth.z, L.probeStep); + return factorX * factorY * factorZ; + } + + fn getOuterAxis(current:f32, edge:f32, space:f32) -> f32{ + return clamp((edge - current) / space, 0.0, 1.0); + } + + fn getBaseGridCoord(L:IrradianceField, X:vec3) -> vec3 { + var offsetIndex = (X - L.probeStartPosition.xyz) / irradianceFieldSurface.probeStep; + return clamp(vec3(offsetIndex.xyz), vec3(0), vec3(L.probeCounts.xyz) - 1); + } + + fn gridCoordToProbeIndex(L:IrradianceField, grid:vec3) -> i32 + { + return grid.x + i32(L.probeCounts.x) * grid.z + grid.y * i32(L.probeCounts.z * L.probeCounts.x); + } + + fn gridCoordToPosition(L:IrradianceField, grid:vec3) -> vec3 + { + var pos:vec3 = vec3(grid.xyz) * L.probeStep + L.probeStartPosition.xyz; + return pos; + } + + fn textureCoordFromDirection(dir:vec3, probeIndex:i32, width:f32, height:f32, sideLength:f32) -> vec2 + { + var uv = getWriteOctUVByID(dir, u32(probeIndex), sideLength) ; + uv.x = uv.x / irradianceFieldSurface.irradianceTextureWidth; + uv.y = uv.y / irradianceFieldSurface.irradianceTextureHeight; + return uv ; + } + + fn getWriteOctUVByID(dir:vec3 , probeID:u32, size: f32) -> vec2 + { + var blockCount = u32(irradianceFieldSurface.probeCounts.x * irradianceFieldSurface.probeCounts.z) ; + var offsetX = (probeID % blockCount) % u32(irradianceFieldSurface.probeCounts.x) ; + var offsetY = u32(irradianceFieldSurface.probeCounts.z - 1.0) - (probeID % blockCount) / u32(irradianceFieldSurface.probeCounts.x) ; + var offsetZ = probeID / blockCount ; + + var pixelCoord = (( octEncode(dir) + 1.0 ) * 0.5) * vec2(size,size) ; + + var blockOffset = vec2(0.0); + blockOffset.x = f32(offsetX) * size; + blockOffset.y = f32(offsetY) * size + f32(offsetZ) * irradianceFieldSurface.probeCounts.z * size; + + let mapHeight = u32(irradianceFieldSurface.irradianceTextureHeight); + var probeCounts:vec3 = irradianceFieldSurface.probeCounts.xyz; + + var gridOffsetFrom = vec2(blockOffset) + 1; + var gridOffsetTo = offsetByCol(gridOffsetFrom, size, mapHeight, probeCounts); + + pixelCoord = pixelCoord + vec2(gridOffsetTo - 1) + vec2(vec2(vec2(gridOffsetTo) / size) * 2); + + return pixelCoord + 1.0 ; + } + + fn offsetByCol(pixelCoord0:vec2, octSideSize:f32, mapHeight:u32, counts:vec3) -> vec2 + { + var pixelCoord = pixelCoord0; + let blockSize:vec2 = vec2(i32(octSideSize * counts.x), i32(octSideSize * counts.z)); + let blockSizeYBorder:i32 = i32((octSideSize + 2.0) * counts.z); + let blockMaxRowBorder:i32 = i32(mapHeight) / blockSizeYBorder; + let pixelCountYMax:i32 = blockMaxRowBorder * i32(octSideSize * counts.z); + let col:i32 = pixelCoord.y / pixelCountYMax; + pixelCoord.x = col * i32(octSideSize * counts.x) + pixelCoord.x; + pixelCoord.y = pixelCoord.y % pixelCountYMax; + return pixelCoord; + } + + var wpNormal:vec3 ; + fn sampleIrradianceField() -> vec4{ + wpNormal = ORI_ShadingInput.Normal.xyz ; + var wo:vec3 = ORI_CameraWorldDir ; + var wsN:vec3 = normalize(wpNormal); + var direction:vec3 = wpNormal; + var worldPosition: vec3 = ORI_VertexVarying.vWorldPos.xyz; + + getIrradianceFieldSurface(); + + let surfaceBias = (wsN + 3.0 * wo) * irradianceData.normalBias ; + + var irradiance = vec3(0.0, 0.0, 0.0); + var accumulatedWeights = 0.0; + var biasedWorldPosition = (worldPosition + surfaceBias); + + var baseProbeCoords: vec3 = getBaseGridCoord(irradianceFieldSurface, worldPosition); + + var baseProbeWorldPosition: vec3 = gridCoordToPosition(irradianceFieldSurface, baseProbeCoords) ; + + var gridSpaceDistance = (biasedWorldPosition - baseProbeWorldPosition); + + // alpha is how far from the floor(currentVertex) position. on [0, 1] for each axis. + var alpha: vec3 = clamp(gridSpaceDistance / (irradianceFieldSurface.probeStep), vec3(0.0), vec3(1.0)); + // let irradianceDir = rotateDir(wsN.xyz); + // Iterate over adjacent probe cage + for (var i:i32 = 0; i < 8; i = i + 1) { + var adjacentProbeOffset : vec3 = vec3(i, i32(f32(i) * 0.5), i32(f32(i) * 0.25)) & vec3(1); + var adjacentProbeCoords: vec3 = clamp(baseProbeCoords + adjacentProbeOffset, vec3(0), vec3(irradianceFieldSurface.probeCounts.xyz) - 1) ; + + var adjacentProbeIndex :i32 = gridCoordToProbeIndex(irradianceFieldSurface, adjacentProbeCoords); + var adjacentProbeWorldPosition :vec3 = gridCoordToPosition(irradianceFieldSurface, adjacentProbeCoords) ;//+ (wsN + 3.0 * w_o) * globalUniform.normalBias; + + var worldPosToAdjProbe = normalize(adjacentProbeWorldPosition - worldPosition); + var biasedPosToAdjProbe = normalize(adjacentProbeWorldPosition - biasedWorldPosition); + var biasedPosToAdjProbeDist = length(adjacentProbeWorldPosition - biasedWorldPosition); + + let trilinear = max(vec3(0.001), mix(1.0 - alpha, alpha, vec3(adjacentProbeOffset))); + let trilinearWeight = (trilinear.x * trilinear.y * trilinear.z); + var weight = 1.0; + + var wrapShading = (dot(worldPosToAdjProbe, direction) + 1.0) * 0.5; + weight *= (wrapShading * wrapShading) + 0.2; + + var depthDir = -biasedPosToAdjProbe;//probe - world + depthDir = applyQuaternion(depthDir, quaternion); + var probeTextureUV : vec2 = textureCoordFromDirection(depthDir.xyz, + adjacentProbeIndex, + irradianceFieldSurface.irradianceTextureWidth, + irradianceFieldSurface.irradianceTextureHeight, + irradianceFieldSurface.irradianceProbeSideLength); + + var filteredDistance : vec2 = 2.0 * textureSampleLevel(irradianceDepthMap, irradianceDepthMapSampler, probeTextureUV,0.0).rg ; + + var variance = abs((filteredDistance.x * filteredDistance.x) - filteredDistance.y); + + var chebyshevWeight = 1.0; + if(biasedPosToAdjProbeDist > filteredDistance.x ) // occluded + { + var v = biasedPosToAdjProbeDist - filteredDistance.x ; + chebyshevWeight = variance / (variance + (v * v)); + // Increase the contrast in the weight + chebyshevWeight = max((chebyshevWeight * chebyshevWeight * chebyshevWeight), 0.0); + } + + weight *= max(0.05, chebyshevWeight); + weight = max(0.000001, weight); + + let crushThreshold = 0.2; + if (weight < crushThreshold) + { + weight *= (weight * weight) * (1.0 / (crushThreshold * crushThreshold)); + } + + weight *= trilinearWeight; + + //worldPosToAdjProbe + let rotateDir = applyQuaternion(-direction, quaternion); + probeTextureUV = textureCoordFromDirection((rotateDir), + adjacentProbeIndex, + irradianceFieldSurface.irradianceTextureWidth, + irradianceFieldSurface.irradianceTextureHeight, + irradianceFieldSurface.irradianceProbeSideLength); + + var probeIrradiance: vec3 = textureSampleLevel(irradianceMap, irradianceMapSampler, probeTextureUV ,0.0).xyz; + + var exponent = irradianceData.ddgiGamma * 0.5; + probeIrradiance = pow(probeIrradiance, vec3(exponent)); + + irradiance += (weight * probeIrradiance); + accumulatedWeights += weight; + } + + if(accumulatedWeights == 0.0){ + return vec4(0.0, 0.0, 0.0,1.0); + } + + irradiance *= (1.0 / accumulatedWeights); + irradiance *= irradiance; + + irradiance *= 6.2831853071795864; + irradiance *= irradianceData.indirectIntensity; + return vec4(irradiance,1.0) ; + } + diff --git a/src/engine/assets/shader/lighting/LightingFunction_frag.ts b/src/engine/assets/shader/lighting/LightingFunction_frag.ts new file mode 100644 index 00000000..c0887bd3 --- /dev/null +++ b/src/engine/assets/shader/lighting/LightingFunction_frag.ts @@ -0,0 +1,136 @@ + +export let LightingFunction_frag: string = /* wgsl */ ` + #include "BRDF_frag" + #include "LightStruct" + #include "ShadowMapping_frag" + + #if USE_IES_PROFILE + #include "IESProfiles_frag" + #endif + + + + const LUMEN = 10.764; + + + + fn calcAttenuation( d : f32 , falloffStart : f32 , falloffEnd : f32)-> f32 + { + // Linear falloff. + return saturate((falloffEnd-d) / (falloffEnd - falloffStart)); + } + + fn directLighting( albedo:vec3, N:vec3, V:vec3, roughness:f32 , light:LightData , shadowBias:f32 ) -> vec3 { + var color = vec3(0.0) ; + #if USE_LIGHT + var L = -normalize(light.direction.xyz) ; + let lightCC = pow( light.lightColor.rgb,vec3(2.2)); + var lightColor = getHDRColor( lightCC.rgb , light.linear ) ; + var att = light.intensity / LUMEN ; + if(light.castShadow>=0){ + #if USE_SHADOWMAPING + att *= shadowStrut.directShadowVisibility[light.castShadow] ; + #endif + } + + #if USE_LAMBERT + color = vec3(1.0,0.5,1.0) ; + #endif + + #if USE_BRDF + color = simpleBRDF(albedo,N,V,L,att,lightColor,fragData.Roughness) ; + #endif + #endif + return color ; + } + + fn pointLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, roughness:f32 , light:LightData ) -> vec3 { + var color = vec3(0.0) ; + let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; + var dir = lightPos.xyz - WP ; + let dist = length(dir); + if(dist != 0.0){ + dir *= 1.0 / dist ; + } + if( abs(dist) < light.range ){ + var L = dir ; + var atten = 1.0 ; + atten = 1.0 - smoothstep(0.0,light.range,dist) ; + atten *= 1.0 / max(light.radius,0.001) * light.intensity / LUMEN; + if( light.castShadow >= 0 ) + { + atten *= shadowStrut.pointShadows[light.castShadow] ; + } + + #if USE_IES_PROFILE + atten *= getLightIESProfileAtt(WP,light); + #endif + + var lightColor = light.lightColor.rgb ; + lightColor = getHDRColor(lightColor , light.linear ) ; + // lightColor = LinearToSrgbBranchless(lightColor.rgb) ; + + #if USE_LAMBERT + color = vec3(1.0,0.5,1.0) ; + #endif + + #if USE_BRDF + color = (simpleBRDF(albedo,N,V,L,atten,lightColor,fragData.Roughness)) ; + #endif + } + return color ; + } + + fn getDistanceAtten( light:LightData , dist : f32 ) -> f32 { + return 1.0 - smoothstep(0.0,light.range,dist) ; + } + + fn spotLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, roughness:f32 , light:LightData ) -> vec3 { + let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; + var dir = lightPos.xyz - WP ; + let dist = length(dir) ; + if(dist != 0.0){ + dir *= 1.0 / dist ; + } + var color = vec3(0.0) ; + if( abs(dist) < light.range * 2.0 ){ + var L = dir ; + let theta = dot(-L, normalize(light.direction)); + let angle = acos(theta) ; + var atten = 1.0 ; + var lightColor = light.lightColor.rgb ; + + atten = 1.0 - smoothstep(0.0,light.range,dist) ; + atten *= 1.0 / max(light.radius,0.1) * light.intensity / LUMEN; + if(angle < light.outerCutOff){ + if(angle > light.innerCutOff){ + atten *= 1.0 - smoothstep(light.innerCutOff, light.outerCutOff, angle) ; + + + } + }else{ + atten = 0.0 ; + } + + if( light.castShadow >= 0 ) + { + atten *= shadowStrut.pointShadows[light.castShadow] ; + } + + #if USE_IES_PROFILE + atten *= getLightIESProfileAtt(WP,light); + #endif + + lightColor = getHDRColor(lightColor , light.linear ) ; + + #if USE_LAMBERT + color = vec3(1.0,0.5,1.0) ; + #endif + + #if USE_BRDF + color = (simpleBRDF(albedo,N,V,L,atten,lightColor,fragData.Roughness)) ; + #endif + } + return color ; + } +` diff --git a/src/engine/assets/shader/lighting/UnLit_frag.ts b/src/engine/assets/shader/lighting/UnLit_frag.ts new file mode 100644 index 00000000..23550c9f --- /dev/null +++ b/src/engine/assets/shader/lighting/UnLit_frag.ts @@ -0,0 +1,25 @@ +export let UnLit_frag: string = /*wgsl*/ ` + #include "Common_frag" + #include "GlobalUniform" + + fn UnLit(){ + + let alpha = ORI_ShadingInput.BaseColor.a ; + ORI_FragmentOutput.color = vec4(ORI_ShadingInput.BaseColor.rgb * alpha , alpha) ; + + #if USE_WORLDPOS + ORI_FragmentOutput.worldPos = vec4(ORI_VertexVarying.vWorldPos.xyzw); + #endif + + #if USEGBUFFER + var normal_rgba8unorm = (ORI_VertexVarying.vWorldNormal + 1.0) * 0.5; + normal_rgba8unorm = clamp(normal_rgba8unorm, vec3(0.0), vec3(1.0)); + ORI_FragmentOutput.worldNormal = vec4(normal_rgba8unorm,1.0); + ORI_FragmentOutput.material = vec4(1.0,1.0,0.0,1.0); + #endif + } + + fn debugFragmentOut(){ + + } +` diff --git a/src/engine/assets/shader/materials/ColorLitShader.ts b/src/engine/assets/shader/materials/ColorLitShader.ts new file mode 100644 index 00000000..7e6b9337 --- /dev/null +++ b/src/engine/assets/shader/materials/ColorLitShader.ts @@ -0,0 +1,30 @@ +export class ColorLitShader { + public static Ori_AllShader:string = /*wgsl*/` + #include "Common_vert" + #include "Common_frag" + #include "BxDF_frag" + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + ORI_ShadingInput.BaseColor = materialUniform.baseColor ; + ORI_ShadingInput.Roughness = materialUniform.roughness ; + ORI_ShadingInput.Metallic = materialUniform.metallic ; + ORI_ShadingInput.Specular = 0.5 ; + ORI_ShadingInput.AmbientOcclusion = materialUniform.ao ; + ORI_ShadingInput.EmissiveColor = vec4(0.0); + + ORI_ShadingInput.Normal = ORI_VertexVarying.vWorldNormal.rgb ; + + #if USE_SHADOWMAPING + directShadowMaping(globalUniform.shadowBias); + pointShadowMapCompare(globalUniform.pointShadowBias); + #endif + + BxDFShading(); + } + ` +} diff --git a/src/engine/assets/shader/materials/PavementShader.ts b/src/engine/assets/shader/materials/PavementShader.ts new file mode 100644 index 00000000..6a1f306b --- /dev/null +++ b/src/engine/assets/shader/materials/PavementShader.ts @@ -0,0 +1,68 @@ +export let PavementShader:string = /*wgsl*/` + #include "Common_vert" + #include "Common_frag" + #include "BxDF_frag" + + @group(1) @binding(auto) + var rtColorTex: texture_2d; + + @group(1) @binding(auto) + var baseMapSampler: sampler; + @group(1) @binding(auto) + var baseMap: texture_2d; + + @group(1) @binding(auto) + var normalMapSampler: sampler; + @group(1) @binding(auto) + var normalMap: texture_2d; + + @group(1) @binding(auto) + var displaceMapSampler: sampler; + @group(1) @binding(auto) + var displaceMap: texture_2d; + + @group(1) @binding(auto) + var aoMapSampler: sampler; + @group(1) @binding(auto) + var aoMap: texture_2d; + + @group(1) @binding(auto) + var reflectMapSampler: sampler; + @group(1) @binding(auto) + var reflectMap: texture_2d; + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + // let displaceDimensions = textureDimensions(displaceMap) ; + // let displace = textureGather(0,displaceMap,displaceMapSampler,inputData.uv) ; + // ORI_VertexOut.member.y += displace.r * 10.0; + return ORI_VertexOut ; + } + + fn frag(){ + var screenUV = ORI_VertexVarying.fragPosition.xy / ORI_VertexVarying.fragPosition.w; + screenUV = (screenUV.xy + 1.0) * 0.5; + screenUV.y = 1.0 - screenUV.y; + + let FrameMap = textureSample(rtColorTex,baseMapSampler,screenUV); + + let Albedo = textureSample(baseMap,baseMapSampler,ORI_VertexVarying.fragUV0); + var Normal = textureSample(normalMap,normalMapSampler,ORI_VertexVarying.fragUV0).rgb ; + Normal.y = 1.0 - Normal.y ; + let Displace = textureSample(displaceMap,displaceMapSampler,ORI_VertexVarying.fragUV0).rgb ; + let Ao = textureSample(aoMap,aoMapSampler,ORI_VertexVarying.fragUV0).r ; + let ReflectMap = 1.0 - textureSample(reflectMap,reflectMapSampler,ORI_VertexVarying.fragUV0).r ; + + ORI_ShadingInput.BaseColor = FrameMap * materialUniform.baseColor * vec4(LinearToGammaSpace(Albedo.rgb),1.0); + ORI_ShadingInput.Roughness = ReflectMap * materialUniform.roughness ; + ORI_ShadingInput.Metallic = materialUniform.metallic ; + ORI_ShadingInput.Specular = 0.5 ; + ORI_ShadingInput.AmbientOcclusion = Ao * materialUniform.ao ; + ORI_ShadingInput.EmissiveColor = vec4(0.0); + + let normal = unPackRGNormal(Normal,Displace.r*materialUniform.normalScale,1.0) ; + ORI_ShadingInput.Normal = normal ; + + BxDFShading(); + } + ` diff --git a/src/engine/assets/shader/materials/PointShadowDebug.ts b/src/engine/assets/shader/materials/PointShadowDebug.ts new file mode 100644 index 00000000..e5788317 --- /dev/null +++ b/src/engine/assets/shader/materials/PointShadowDebug.ts @@ -0,0 +1,33 @@ + +export let PointShadowDebug:string = /*wgsl*/` + #include "Common_vert" + #include "Common_frag" + #include "UnLit_frag" + + @group(1) @binding(auto) var pointShadowMapSampler: sampler; + @group(1) @binding(auto) var pointShadowMap: texture_depth_cube ; + + struct MaterialUniform { + center: vec3, + }; + + @group(2) @binding(0) + var materialUniform: MaterialUniform; + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + + var center = materialUniform.center ; + + var dir = normalize(ORI_VertexVarying.vWorldPos.xyz - center) ; + var depth = textureSample(pointShadowMap,pointShadowMapSampler,dir.xyz) ; + depth = depth * globalUniform.far ; + + ORI_ShadingInput.BaseColor = vec4(depth*255.0,0.0,0.0,1.0) ; + UnLit(); + } + ` diff --git a/src/engine/assets/shader/materials/program/BxdfDebug_frag.wgsl b/src/engine/assets/shader/materials/program/BxdfDebug_frag.wgsl new file mode 100644 index 00000000..ee337854 --- /dev/null +++ b/src/engine/assets/shader/materials/program/BxdfDebug_frag.wgsl @@ -0,0 +1,175 @@ + + #include "ClusterDebug_frag" + + fn debugPosition(){ + ORI_FragmentOutput.color = vec4(ORI_VertexVarying.vWorldPos.xyz,1.0); + } + + fn debugNormal(){ + ORI_FragmentOutput.color = vec4(ORI_ShadingInput.Normal.xyz,1.0); + } + + fn debugUV(){ + ORI_FragmentOutput.color = vec4(ORI_VertexVarying.fragUV0.xy,0.0,1.0); + } + + fn debugColor(){ + ORI_FragmentOutput.color = vec4(fragData.Albedo.rgb,1.0); + } + + fn debugDiffuse(){ + ORI_FragmentOutput.color = vec4(1.0/3.1415926 * fragData.Albedo.rgb,1.0); + // ORI_FragmentOutput.color = vec4(0.2,0.2,0.2,1.0); + } + + fn debugAmbient(){ + ORI_FragmentOutput.color = vec4(fragData.Irradiance * fragData.Albedo.rgb,1.0); + } + + fn debugEmissive(){ + ORI_FragmentOutput.color = vec4(fragData.Emissive.rgb,1.0); + } + + fn debugEnvment(){ + ORI_FragmentOutput.color = vec4(fragData.EnvColor.rgb,1.0); + } + + fn debugAo(){ + ORI_FragmentOutput.color = vec4(vec3(fragData.Ao),1.0); + } + + fn debugRoughness(){ + ORI_FragmentOutput.color = vec4(vec3(fragData.Roughness),1.0); + } + + fn debugMetallic(){ + ORI_FragmentOutput.color = vec4(vec3(fragData.Metallic),1.0); + } + + fn debugIrradiance(){ + ORI_FragmentOutput.color = vec4(vec3(fragData.Irradiance),1.0); + } + + fn debugFragmentOut(){ + if(ORI_VertexVarying.fragCoord.x > globalUniform.renderState_split) { + switch (globalUniform.renderState_right) + { + case 0: { + debugPosition(); + } + case 1: { + debugColor(); + } + case 2: { + debugNormal(); + } + case 3: { + debugIrradiance(); + } + case 4: { + debugDiffuse(); + } + case 5: { + // debugAmbient(); + } + case 6: { + debugEmissive(); + } + case 7: { + debugEnvment(); + } + case 8: { + debugAo(); + } + case 9: { + debugRoughness(); + } + case 10: { + debugMetallic(); + } + case 11: { + debugDiffuse(); + } + case 12: { + debugAmbient(); + } + case 13: { + debugPosition(); + } + case 14: { + #if DEBUG_CLUSTER + debugCluster( ORI_VertexVarying.fragCoord ); + #endif + } + case 15: { + #if DEBUG_CLUSTER + debugClusterBox( ORI_VertexVarying.fragCoord ); + #endif + } + case 16: { + #if DEBUG_CLUSTER + debugClusterLightCount( vec4(ORI_VertexVarying.fragCoord.xyz,0.0)); + #endif + } + default: { + } + } + } else { + switch (globalUniform.renderState_left) + { + case 0: { + debugPosition(); + } + case 1: { + debugColor(); + } + case 2: { + debugNormal(); + } + case 3: { + debugIrradiance(); + } + case 4: { + debugDiffuse(); + } + case 5: { + // debugAmbient(); + } + case 6: { + debugEmissive(); + } + case 7: { + debugEnvment(); + } + case 8: { + debugAo(); + } + case 9: { + debugRoughness(); + } + case 10: { + debugMetallic(); + } + case 11: { + debugDiffuse(); + } + case 12: { + debugAmbient(); + } + case 13: { + debugPosition(); + } + case 14: { + // debugCluster( vec4(ORI_VertexVarying.fragCoord.xyz,0.0)); + } + case 15: { + // debugClusterBox( vec4(ORI_VertexVarying.fragCoord.xyz,0.0)); + } + case 16: { + // debugClusterLightCount( vec4(ORI_VertexVarying.fragCoord.xyz,0.0)); + } + default: { + } + } + } + } \ No newline at end of file diff --git a/src/engine/assets/shader/materials/program/Clearcoat_frag.wgsl b/src/engine/assets/shader/materials/program/Clearcoat_frag.wgsl new file mode 100644 index 00000000..3081ebb8 --- /dev/null +++ b/src/engine/assets/shader/materials/program/Clearcoat_frag.wgsl @@ -0,0 +1,16 @@ + + #if USE_CLEARCOAT_ROUGHNESS + @group(1) @binding(auto) + var clearCoatRoughnessMapSampler: sampler; + @group(1) @binding(auto) + var clearCoatRoughnessMap: texture_2d; + + fn getClearcoatRoughnees() -> f32{ + let clearcoatRoughness = textureSample(clearCoatRoughnessMap, clearCoatRoughnessMapSampler , ORI_VertexVarying.fragUV0.xy).r ; + return clearcoatRoughness ; + } + #else + fn getClearcoatRoughnees() -> f32{ + return 0.0 ; + } + #endif \ No newline at end of file diff --git a/src/engine/assets/shader/materials/program/ClusterDebug_frag.ts b/src/engine/assets/shader/materials/program/ClusterDebug_frag.ts new file mode 100644 index 00000000..f0bc12bd --- /dev/null +++ b/src/engine/assets/shader/materials/program/ClusterDebug_frag.ts @@ -0,0 +1,50 @@ + +export let ClusterDebug_frag:string = /*wgsl*/` + var colorSet : array, 9> = array, 9>( + vec3(1.0, 0.0, 0.0), + vec3(1.0, 0.5, 0.0), + vec3(0.5, 1.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 1.0, 0.5), + vec3(0.0, 0.5, 1.0), + vec3(0.0, 0.0, 1.0), + vec3(0.5, 0.0, 1.0), + vec3(1.0, 0.0, 0.5) + ); + + #if DEBUG_CLUSTER + fn debugCluster(fragCoord:vec4) { + #if USE_LIGHT + var tile : vec3 = getTile(fragCoord); + let clusterDebug = vec4(colorSet[u32(tile.z) % 9u], 1.0); + ORI_FragmentOutput.color = clusterDebug ; + // ORI_FragmentOutput.color = vec4(0.5,0.5,0.0,1.0); + #endif + } + + fn debugClusterBox(fragCoord:vec4) { + #if USE_LIGHT + let clusterIndex : u32 = getClusterIndex(fragCoord); + let cluster = clusterBuffer[clusterIndex]; + + let midPoint : vec3 = (cluster.maxPoint.xyz - cluster.minPoint.xyz) / vec3(2.0, 2.0, 2.0); + let center : vec3 = cluster.minPoint.xyz + midPoint; + let radius : f32 = length(midPoint) ; + + let fragToBoundsCenter : vec3 = ORI_VertexVarying.viewPosition.xyz - center; + let distToBoundsCenter : f32 = length(fragToBoundsCenter); + let normDist : f32 = distToBoundsCenter / radius; + ORI_FragmentOutput.color = vec4(vec3(normDist,normDist,normDist) , 1.0); + #endif + } + + fn debugClusterLightCount(fragCoord:vec4){ + #if USE_LIGHT + let clusterIndex : u32 = getClusterIndex(fragCoord); + let lightCount : u32 = u32(assignTable[clusterIndex].count); + let lightFactor : f32 = f32(lightCount) / f32(32.0); + ORI_FragmentOutput.color = mix(vec4(0.0, 0.0, 1.0, 1.0), vec4(1.0, 0.0, 0.0, 1.0), vec4(lightFactor, lightFactor, lightFactor, lightFactor)); + #endif + } + #endif + ` \ No newline at end of file diff --git a/src/engine/assets/shader/materials/program/NormalMap_frag.wgsl b/src/engine/assets/shader/materials/program/NormalMap_frag.wgsl new file mode 100644 index 00000000..d3f023dd --- /dev/null +++ b/src/engine/assets/shader/materials/program/NormalMap_frag.wgsl @@ -0,0 +1,57 @@ + + fn perturbNormal( worldPos:vec3, surf_norm:vec3, mapN:vec3 , normalScale:f32 , face:f32 ) -> vec3 { + var q0 = vec3( dpdx( worldPos.x ), dpdx( worldPos.y ), dpdx( worldPos.z ) ); + var q1 = vec3( dpdy( worldPos.x ), dpdy( worldPos.y ), dpdy( worldPos.z ) ); + var st0 = dpdx( ORI_VertexVarying.fragUV0.xy ); + var st1 = dpdy( ORI_VertexVarying.fragUV0.xy ); + var N = surf_norm; + var q1perp = cross( q1, N ); + var q0perp = cross( N, q0 ); + var T = q1perp * st0.x + q0perp * st1.x; + var B = q1perp * st0.y + q0perp * st1.y; + + var det = max( dot( T, T ), dot( B, B ) ); + var scale = 1.0 ; + if( det != 0.0 ){ + scale = inverseSqrt( det ) ; + } + scale *= normalScale; + return normalize( (T * ( -mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z ) * face ) ; + } + + fn unpackNormalMap( normal : vec3 ) -> vec3 + { + var normalTex = vec3( normal.xyz * 2.0 - 1.0 ) ; + return normalize(normalTex); + } + + fn unPackNormal(normal : vec3 , height:f32 ) -> vec3{ + var face = 1.0 ; + if(ORI_VertexVarying.face){ + face = 1.0 ; + }else{ + face = -1.0 ; + } + + #if USE_RGNORMAL + return unPackRGNormal(normal,height,face); + #else + var n = normal ; + #if USE_NORMALFILPY + n.y = 1.0 - n.y ; + #endif + + var mapNormal: vec3 = unpackNormalMap(n) ; + return perturbNormal(ORI_VertexVarying.vWorldPos.xyz , ORI_VertexVarying.vWorldNormal.xyz , mapNormal , height , face ) ; + #endif + } + + fn unPackRGNormal(normal : vec3 , height:f32 , face:f32) -> vec3 { + var d = normal.rg * 2.0 - 1.0 ; + var l = 1.0 - saturate(dot(d,d)); + var s = sqrt(l); + var rg = d * height ; + var mapNormal = vec3(rg,s); + var outN = perturbNormal(ORI_VertexVarying.vWorldPos.xyz,ORI_VertexVarying.vWorldNormal,mapNormal,1.0,face) ; + return outN ; + } diff --git a/src/engine/assets/shader/materials/program/ShadowMapping_frag.wgsl b/src/engine/assets/shader/materials/program/ShadowMapping_frag.wgsl new file mode 100644 index 00000000..e67a6717 --- /dev/null +++ b/src/engine/assets/shader/materials/program/ShadowMapping_frag.wgsl @@ -0,0 +1,142 @@ + + + #if USE_SHADOWMAPING + @group(1) @binding(auto) var shadowMapSampler: sampler_comparison; + @group(1) @binding(auto) var shadowMap: texture_depth_2d_array ; + #endif + + @group(1) @binding(auto) var pointShadowMapSampler: sampler; + @group(1) @binding(auto) var pointShadowMap: texture_depth_cube_array ; + + struct ShadowStruct{ + directShadowVisibility:array, + pointShadows:array , + } + + var shadowStrut: ShadowStruct ; + + fn directShadowMaping(shadowBias:f32) { + for(var i:i32 = i32(0) ; i < i32(clustersUniform.numLights) ; i = i + 1 ) + { + var light = lightBuffer[i] ; + var shadowIndex = i32(light.castShadow) ; + shadowStrut.directShadowVisibility[shadowIndex] = 1.0 ; + #if USE_SHADOWMAPING + + + if(shadowIndex < 0 && light.lightType != DirectLightType){ + continue ; + } + + var shadowPosTmp = globalUniform.shadowMatrix[shadowIndex] * vec4(ORI_VertexVarying.vWorldPos.xyz,1.0) ; + var shadowPos = shadowPosTmp.xyz / shadowPosTmp.w ; + var varying_shadowUV = shadowPos.xy * vec2(0.5, -0.5) + vec2(0.5, 0.5) ; + var bias = max(shadowBias * (1.0 - dot(ORI_ShadingInput.Normal, light.direction)) , 0.000005); + + // if(varying_shadowUV.y>=1.0) { + // shadowStrut.directShadowVisibility[shadowIndex] = 2.0 ; + // continue; + // } + if(varying_shadowUV.x <= 1.0 && varying_shadowUV.x >= 0.0 && varying_shadowUV.y <= 1.0 && varying_shadowUV.y >= 0.0 && shadowPosTmp.z <= 1.0 ){ + var texelSize = 1.0 / vec2(globalUniform.shadowMapSize); + var oneOverShadowDepthTextureSize = texelSize ; + var size = 1 ; + var sizeBlock = size * 2 + 1; + var sizeBlockA = sizeBlock * sizeBlock ; + var visibility = 0.0 ; + for (var y = -size; y <= size; y++) { + for (var x = -size; x <= size; x++) { + var offset = vec2(f32(x),f32(y)) * oneOverShadowDepthTextureSize / f32(sizeBlock) ; + visibility += textureSampleCompare( + shadowMap, + shadowMapSampler, + varying_shadowUV + offset, + shadowIndex, + shadowPos.z - bias + ); + } + } + visibility /= f32(sizeBlockA) ; + shadowStrut.directShadowVisibility[shadowIndex] = visibility + 0.001 ; + } + #endif + } + } + + fn pointShadowMapCompare(shadowBias:f32){ + let worldPos = ORI_VertexVarying.vWorldPos.xyz ; + let offset = 0.1 ; + let lightIndex = getCluster(ORI_VertexVarying.fragCoord); + let start = max(lightIndex.start, 0.0); + let count = max(lightIndex.count, 0.0); + let end = max(start + count , 0.0); + for(var i:i32 = i32(start) ; i < i32(end) ; i = i + 1 ) + { + let light = getLight(i); + shadowStrut.pointShadows[light.castShadow] = 1.0 ; + + #if USE_SHADOWMAPING + if(light.castShadow < 0 || light.lightType == DirectLightType){ + continue ; + } + let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; + var shadow = 0.0 ; + let frgToLight = worldPos - lightPos.xyz; + var dir:vec3 = normalize(frgToLight) ; + var len = length(frgToLight) ; + var bias = max(shadowBias * globalUniform.far * (1.0 - dot(ORI_ShadingInput.Normal, dir)) , 0.005); + + #if USE_PCF_SHADOW + let samples = 4.0 ; + for (var x : f32 = -offset ; x < offset ; x += offset / (samples * 0.5) ) { + for (var y : f32 = -offset ; y < offset ; y += offset / (samples * 0.5) ) { + for (var z : f32 = -offset ; z < offset ; z += offset / (samples * 0.5) ) { + let offsetDir = normalize(dir.xyz + vec3(x,y,z)) ; + var depth = textureSampleLevel(pointShadowMap,pointShadowMapSampler,offsetDir,light.castShadow,0); + depth *= globalUniform.far ; + if((len - bias ) > depth){ + shadow += 1.0 * dot(offsetDir,dir.xyz); + } + } + } + } + shadow = min(max(shadow / (samples*samples*samples),0.0),1.0) ; + #endif + + #if USE_SOFT_SHADOW + let vDis = length( globalUniform.CameraPos.xyz - worldPos.xyz ); + let sampleRadies = globalUniform.shadowSoft ; + let samples = 20 ; + for (var j : i32 = 0 ; j < samples ; j += 1 ) { + let offsetDir = normalize(dir.xyz + sampleOffetDir[j] * sampleRadies) ; + var depth = textureSampleLevel(pointShadowMap,pointShadowMapSampler,offsetDir,light.castShadow,0); + depth *= globalUniform.far ; + if((len - bias) > depth){ + shadow += 1.0 * dot(offsetDir,dir.xyz); + } + } + shadow = min(max(shadow / f32(samples) ,0.0),1.0) ; + #endif + + #if USE_HARD_SHADOW + var depth = textureSampleLevel(pointShadowMap,pointShadowMapSampler,dir.xyz,light.castShadow,0); + depth *= globalUniform.far ; + if((len - bias) > depth){ + shadow = 1.0 ; + } + #endif + + shadowStrut.pointShadows[light.castShadow] = 1.0 - shadow ; + #endif + } + } + + #if USE_SOFT_SHADOW + var sampleOffetDir : array,20> = array,20>( + vec3(1.0,1.0,1.0),vec3(1.0,-1.0,1.0),vec3(-1.0,-1.0,1.0),vec3(-1.0,1.0,1.0), + vec3(1.0,1.0,-1.0),vec3(1.0,-1.0,-1.0),vec3(-1.0,-1.0,-1.0),vec3(-1.0,1.0,-1.0), + vec3(1.0,1.0,0.0),vec3(1.0,-1.0,0.0),vec3(-1.0,-1.0,0.0),vec3(-1.0,1.0,0.0), + vec3(1.0,0.0,1.0),vec3(-1.0,0.0,1.0),vec3(1.0,0.0,-1.0),vec3(-1.0,0.0,-1.0), + vec3(0.0,1.0,1.0),vec3(0.0,-1.0,1.0),vec3(0.0,-1.0,-1.0),vec3(0.0,1.0,-1.0), + ); + #endif diff --git a/src/engine/assets/shader/materials/uniforms/MaterialUniform.ts b/src/engine/assets/shader/materials/uniforms/MaterialUniform.ts new file mode 100644 index 00000000..03baf7a3 --- /dev/null +++ b/src/engine/assets/shader/materials/uniforms/MaterialUniform.ts @@ -0,0 +1,16 @@ +export let MaterialUniform : string = /*wgsl*/ ` + struct MaterialUniform{ + #if USE_BRDF + #include "PhysicMaterialUniform_frag" + #endif + + #if USE_ColorLit + #endif + + #if USE_UnLit + #endif + } + + @group(2) @binding(0) + var materialUniform: MaterialUniform; +` diff --git a/src/engine/assets/shader/materials/uniforms/PhysicMaterialUniform_frag.ts b/src/engine/assets/shader/materials/uniforms/PhysicMaterialUniform_frag.ts new file mode 100644 index 00000000..a92cddcb --- /dev/null +++ b/src/engine/assets/shader/materials/uniforms/PhysicMaterialUniform_frag.ts @@ -0,0 +1,30 @@ +export let PhysicMaterialUniform_frag = /* wgsl */` + struct MaterialUniform { + transformUV1:vec4, + transformUV2:vec4, + + baseColor: vec4, + emissiveColor: vec4, + materialF0: vec4, + envIntensity: f32, + normalScale: f32, + roughness: f32, + metallic: f32, + ao: f32, + + roughness_min: f32, + roughness_max: f32, + metallic_min: f32, + metallic_max: f32, + emissiveIntensity: f32, + alphaCutoff: f32, + ior: f32, + clearcoatColor: vec4, + clearcoatWeight: f32, + clearcoatFactor: f32, + clearcoatRoughnessFactor: f32, + }; + + @group(2) @binding(0) + var materialUniform: MaterialUniform; + ` \ No newline at end of file diff --git a/src/engine/assets/shader/materials/uniforms/UnLitMaterialUniform_frag.ts b/src/engine/assets/shader/materials/uniforms/UnLitMaterialUniform_frag.ts new file mode 100644 index 00000000..07f05673 --- /dev/null +++ b/src/engine/assets/shader/materials/uniforms/UnLitMaterialUniform_frag.ts @@ -0,0 +1,11 @@ +export let UnLitMaterialUniform_frag = /* wgsl */` +struct MaterialUniform { + transformUV1:vec4, + transformUV2:vec4, + baseColor: vec4, + alphaCutoff: f32, +}; + +@group(2) @binding(0) +var materialUniform: MaterialUniform; +` \ No newline at end of file diff --git a/src/engine/assets/shader/materials/uniforms/VideoUniform_frag.ts b/src/engine/assets/shader/materials/uniforms/VideoUniform_frag.ts new file mode 100644 index 00000000..445e4877 --- /dev/null +++ b/src/engine/assets/shader/materials/uniforms/VideoUniform_frag.ts @@ -0,0 +1,12 @@ +export let VideoUniform_frag = /* wgsl */` +struct MaterialUniform { + transformUV1:vec4, + transformUV2:vec4, + baseColor: vec4, + rectClip: vec4, + alphaCutoff: f32, +}; + +@group(2) @binding(0) +var materialUniform: MaterialUniform; +` \ No newline at end of file diff --git a/src/engine/gfx/graphics/webGpu/shader/value/ConstValue.ts b/src/engine/gfx/graphics/webGpu/shader/value/ConstValue.ts new file mode 100644 index 00000000..16e3c464 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/value/ConstValue.ts @@ -0,0 +1,4 @@ +/** + * @internal + */ +export type ConstValue = number | boolean; diff --git a/src/engine/gfx/graphics/webGpu/shader/value/DefineValue.ts b/src/engine/gfx/graphics/webGpu/shader/value/DefineValue.ts new file mode 100644 index 00000000..89979f18 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/value/DefineValue.ts @@ -0,0 +1,4 @@ +/** + * @internal + */ +export type DefineValue = { name: string; value: number | boolean }; diff --git a/src/engine/gfx/graphics/webGpu/shader/value/ShaderReflectionInfo.ts b/src/engine/gfx/graphics/webGpu/shader/value/ShaderReflectionInfo.ts new file mode 100644 index 00000000..f9cefe31 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/value/ShaderReflectionInfo.ts @@ -0,0 +1,531 @@ +import { VertexFormat } from '../../../../../..'; +import { VertexAttributeSize } from '../../../../../core/geometry/VertexAttributeSize'; +import { ComputeShader } from '../ComputeShader'; +import { RenderShader } from '../RenderShader'; +import { ShaderBase } from '../ShaderBase'; +import { Preprocessor } from '../util/Preprocessor'; +import { ShaderValue } from './ShaderValue'; + +/** + * @internal + */ +export type ShaderReflectionAttribute = { + name: string; + group: number; + location: number; + type: string; + valueType: string; + value: number; + size: number; + format: GPUVertexFormat; +}; + +/** + * @internal + */ +export type ShaderReflectionVarInfo = { + group: number; + binding: number; + varType: string; + varName: string; + dataType: string; + dataIsBuiltinType: boolean; + dataFields: ShaderReflectionStructInfo[]; +}; + +/** + * @internal + */ +export type ShaderReflectionStructInfo = { + name: string; + type: string; +}; + +/** + * @internal + */ +export class ShaderReflection { + private static _shaderReflectionMap: Map = new Map(); + + public attributes: ShaderReflectionAttribute[] = []; + + public vs_variables: ShaderReflectionVarInfo[] = []; + + public fs_variables: ShaderReflectionVarInfo[] = []; + + public cs_variables: ShaderReflectionVarInfo[] = []; + + public groups: ShaderReflectionVarInfo[][] = []; + + public variables: { [name: string]: ShaderReflectionVarInfo } = {}; + + public useSplit: boolean = false; + + /** + * + * @param wgsl + * @param shaderReflection + */ + public static parser(wgsl: string, shaderValue: ShaderValue) { + if (!shaderValue.shaderReflection) shaderValue.shaderReflection = new ShaderReflection(); + if (wgsl.indexOf(`@vertex`) != -1) { + shaderValue.shaderReflection.attributes = this.parserVertexOld(wgsl); + shaderValue.shaderReflection.vs_variables = this.parserVariables(wgsl); + } else if (wgsl.indexOf(`@fragment`) != -1) { + shaderValue.shaderReflection.fs_variables = this.parserVariables(wgsl); + } else if (wgsl.indexOf(`@compute`) != -1) { + shaderValue.shaderReflection.cs_variables = this.parserVariables(wgsl); + } + } + + public static parser2(wgsl: string, shaderBase: ShaderBase) { + if (!shaderBase.shaderReflection) shaderBase.shaderReflection = new ShaderReflection(); + let shaderReflection = shaderBase.shaderReflection; + if (wgsl.indexOf(`@vertex`) != -1) { + shaderReflection.attributes = this.parserVertex(shaderBase.vsEntryPoint, wgsl); + shaderReflection.vs_variables = this.parserVariables(wgsl); + } else if (wgsl.indexOf(`@fragment`) != -1) { + shaderReflection.fs_variables = this.parserVariables(wgsl); + } else if (wgsl.indexOf(`@compute`) != -1) { + shaderReflection.cs_variables = this.parserVariables(wgsl); + } + + if (wgsl.indexOf("splitTexture") != -1) { + shaderReflection.useSplit = true; + } + } + + public static combineShaderReflectionVarInfo(shaderReflection: ShaderReflection, shader_variables: ShaderReflectionVarInfo[]) { + for (const iterator of shader_variables) { + if (!shaderReflection.groups[iterator.group]) { + shaderReflection.groups[iterator.group] = []; + } + + let combineInfo = iterator; + if (shaderReflection.groups[iterator.group][iterator.binding]) { + let aInfo = shaderReflection.groups[iterator.group][iterator.binding]; + let bInfo = iterator; + if (aInfo.varName != bInfo.varName) + console.warn(`shader reflection var not match! var name vs : ${aInfo.varName} , fs : ${bInfo.varName}`); + if (aInfo.varType != bInfo.varType) + console.error(`shader reflection varType not match! var varType vs : ${aInfo.varType} , fs : ${bInfo.varType}`); + if (aInfo.dataType != bInfo.dataType) + console.warn(`shader reflection dataType not match! var dataType vs : ${aInfo.dataType} , fs : ${bInfo.dataType}`); + if (aInfo.dataIsBuiltinType != bInfo.dataIsBuiltinType) + console.error(`shader reflection dataIsBuiltinType not match! var dataIsBuiltinType vs : ${aInfo.dataIsBuiltinType} , fs : ${bInfo.dataType}`); + if (!aInfo.dataFields || !bInfo.dataFields) { + console.warn(`shader reflection dataFields is empty! var dataFields vs : ${aInfo.dataFields} , fs : ${bInfo.dataFields}`); + } + // if (aInfo.dataFields.length != bInfo.dataFields.length) + // console.warn(`shader reflection dataFields lenth not match! var dataFields vs : ${aInfo.dataFields} , fs : ${bInfo.dataFields}`); + + let fileds = []; + if (aInfo.dataFields) { + for (let i = 0; i < aInfo.dataFields.length; i++) { + const element = aInfo.dataFields[i]; + fileds[i] = element; + } + } + if (bInfo.dataFields) { + for (let i = 0; i < bInfo.dataFields.length; i++) { + const element = bInfo.dataFields[i]; + fileds[i] = element; + } + } + } + shaderReflection.groups[iterator.group][iterator.binding] = combineInfo; + shaderReflection.variables[iterator.varName] = combineInfo; + } + } + + public static final(shaderBase: ShaderBase) { + let shaderReflection = shaderBase.shaderReflection; + this._shaderReflectionMap.set(shaderBase.shaderVariant, shaderReflection); + this.combineShaderReflectionVarInfo(shaderReflection, shaderReflection.vs_variables); + this.combineShaderReflectionVarInfo(shaderReflection, shaderReflection.fs_variables); + } + + public static getShaderReflection2(code: string, shaderBase: ShaderBase) { + if (shaderBase.shaderVariant != undefined) { + let preShader = Preprocessor.parse(code, shaderBase.defineValue); + ShaderReflection.parser2(preShader, shaderBase); + } + } + + /** + * + * @param shaderVariant shader variant name + * @returns + */ + public static poolGetReflection(shaderVariant: string): ShaderReflection { + let ref = this._shaderReflectionMap.get(shaderVariant); + return ref; + } + + public static genShaderVar(shaderValue: ShaderValue) { + let shaderVariant = `${shaderValue.vs}${shaderValue.fs}${shaderValue.compute}`; + shaderVariant += '|'; + for (const key in shaderValue.uniforms) { + shaderVariant += key + ':'; + } + shaderVariant += '|'; + for (const key in shaderValue.constValues) { + shaderVariant += key + ':'; + shaderVariant += shaderValue.constValues[key]; + } + shaderVariant += '|'; + for (const key in shaderValue.defines) { + shaderVariant += key + ':'; + shaderVariant += shaderValue.defines[key]; + } + shaderVariant += '|'; + for (const key in shaderValue.shaderState) { + shaderVariant += key + ':'; + shaderVariant += shaderValue.shaderState[key] + ';'; + } + return shaderVariant; + } + + public static genShaderVariant(shader: ShaderBase) { + let shaderVariant = ''; + for (const key in shader.uniforms) { + shaderVariant += key + ':'; + } + + shaderVariant += '|'; + for (const key in shader.constValues) { + shaderVariant += key + ':'; + shaderVariant += shader.constValues[key]; + } + + shaderVariant += '|'; + for (const key in shader.defineValue) { + shaderVariant += key + ':'; + shaderVariant += shader.defineValue[key]; + } + + return shaderVariant; + } + + public static genRenderShaderVariant(renderShader: RenderShader) { + let shaderVariant = `RenderShader(${renderShader.vsName},${renderShader.fsName})`; + + shaderVariant += '|'; + shaderVariant += this.genShaderVariant(renderShader); + + shaderVariant += '|'; + for (const key in renderShader.shaderState) { + shaderVariant += key + ':'; + shaderVariant += renderShader.shaderState[key] + ';'; + } + return shaderVariant; + } + + public static genComputeShaderVariant(computeShader: ComputeShader) { + let shaderVariant = `ComputeShader(${computeShader.instanceID})`; + + shaderVariant += '|'; + shaderVariant += this.genShaderVariant(computeShader); + + return shaderVariant; + } + + public combine(shaderValue: ShaderValue) { + let shaderReflection = shaderValue.shaderReflection; + let defines = shaderValue.defines; + + let tmp: { [name: string]: ShaderReflectionAttribute } = {}; + for (let i = 0; i < this.attributes.length; i++) { + let att = this.attributes[i]; + if (defines[att.name]) tmp[att.name] = att; + } + + let len = shaderReflection.attributes.length; + for (let j = 0; j < len; j++) { + const newAtt = shaderReflection.attributes[j]; + if (!tmp[newAtt.name]) { + this.attributes.push(newAtt); + } else { + let oldAtt = tmp[newAtt.name]; + if (oldAtt.location == newAtt.location && oldAtt.name != newAtt.name) { + console.log('location must same!'); + } + } + } + + // if(!defines["USE_TANGENT"]){ + // for (let i = 0; i < this.attributes.length; i++) { + // const element = this.attributes[i]; + // if(element.name == VertexAttributeName.TANGENT) + // this.attributes.splice(i,); + // } + // } + } + + private static parserVariables(wgsl: string) { + let position = 0; + let variables: any[] = []; + + while (position < wgsl.length) { + let nLeftIndex = wgsl.indexOf('@group(', position); + if (nLeftIndex < 0) break; + let nRightIndex = wgsl.indexOf(';', nLeftIndex); + position = nRightIndex; + + let item = wgsl.substring(nLeftIndex, nRightIndex); + let group = this.extract(item, '@group(', ')'); + let binding = this.extract(item, '@binding(', ')'); + + let varName = ''; + let varType = 'var'; + if (item.indexOf('var<') != -1) { + varName = this.extract(item, '>', ':'); + varType = this.extract(item, 'var<', '>').replace(',', '-').replaceAll(' ', ''); + } else { + varName = this.extract(item, 'var', ':'); + } + + let dataType = item.substring(item.lastIndexOf(':') + 1).trim(); + + let info: ShaderReflectionVarInfo = { + group: 0, + binding: 0, + varType: '', + varName: '', + dataType: '', + dataIsBuiltinType: true, + dataFields: null, + }; + + info.group = Number.parseInt(group); + info.binding = Number.parseInt(binding); + info.varType = varType; + info.varName = varName; + info.dataType = dataType; + info.dataIsBuiltinType = this.isBuiltinTypes(info.dataType); + + if (!info.dataIsBuiltinType) { + info.dataFields = this.parserStructFields(wgsl, info.dataType); + } + + variables.push(info); + } + + return variables; + } + + private static extract(str: string, leftStr: string, rightStr: string): string { + let indexL = str.indexOf(leftStr) + leftStr.length; + let indexR = str.indexOf(rightStr, indexL); + return str.substring(indexL, indexR).trim(); + } + + private static isBuiltinTypes(dataType: string): boolean { + switch (dataType) { + case 'i32': + return true; + case 'u32': + return true; + case 'f32': + return true; + default: + let index = dataType.indexOf('<'); + if (index != -1) { + let type = dataType.substring(0, index); + switch (type) { + case 'vec2': + return true; + case 'vec3': + return true; + case 'vec4': + return true; + case 'mat3': + return true; + case 'mat4': + return true; + case 'array': + return this.isBuiltinTypes(dataType.substring(index + 1, dataType.lastIndexOf('>'))); + } + } + break; + } + return false; + } + + private static parserStructFields(wgsl: string, structName: string) { + let result: any[] = []; + + let position = 0; + let variables: any[] = []; + + while (position < wgsl.length) { + let nLeftIndex = wgsl.indexOf('struct ', position); + if (nLeftIndex < 0) break; + let nRightIndex = wgsl.indexOf('{', nLeftIndex); + position = nRightIndex; + + let name = wgsl.substring(nLeftIndex + 6, nRightIndex).trim(); + if (name === structName) { + nLeftIndex = wgsl.indexOf('{', nLeftIndex); + nRightIndex = wgsl.indexOf('}', nLeftIndex); + let items = wgsl.substring(nLeftIndex + 1, nRightIndex); + let fields = items.split(','); + for (let field of fields) { + let index = field.indexOf(':'); + if (index != -1) { + let obj: ShaderReflectionStructInfo = { + name: field.substring(0, index).trim(), + type: field.substring(index + 1).trim(), + }; + result.push(obj); + } + } + break; + } + } + return result; + } + + private static parserVertexOld(wgsl: string) { + let attributes: any[] = []; + let list = wgsl.split(`fn main(`); + let block = list[1].split('->')[0]; + let blockList = block.split('@'); + if (blockList && blockList.length > 1) { + for (let i = 1; i < blockList.length; i++) { + const element = blockList[i]; + let code = element.replace(/\s*$/g, ''); + code = code.replaceAll(',', ''); + code = code.replaceAll('\n', ''); + code = code.replaceAll(' ', ' '); + this.parserAttribute(code, attributes); + } + } else { + let code1 = block.split(':'); + var code = code1[1]; + code = code.replaceAll(' ', ''); + code = code.replaceAll(' ', ''); + code = code.replaceAll(')', ''); + + code = wgsl.split(`struct ${code}`)[1]; + let start = code.indexOf('{'); + let end = code.indexOf('}'); + code = code.slice(start, end); + + blockList = code.split('@'); + for (let i = 1; i < blockList.length; i++) { + const element = blockList[i]; + let code = element.replace(/\s*$/g, ''); + code = code.replaceAll('\n', ''); + code = code.split(',')[0]; + code = code.replaceAll(' ', ' '); + this.parserAttribute(code, attributes); + } + } + return attributes; + } + + private static parserVertex(entryPoint: string, wgsl: string) { + let attributes: any[] = []; + let list = wgsl.split(`fn ${entryPoint}(`); + let block = list[1].split('->')[0]; + let blockList = block.split('@'); + if (blockList && blockList.length > 1) { + for (let i = 1; i < blockList.length; i++) { + const element = blockList[i]; + let code = element.replace(/\s*$/g, ''); + code = code.replaceAll(',', ''); + code = code.replaceAll('\n', ''); + code = code.replaceAll(' ', ' '); + this.parserAttribute(code, attributes); + } + } else { + let code1 = block.split(':'); + var code = code1[1]; + code = code.replaceAll(' ', ''); + code = code.replaceAll(' ', ''); + code = code.replaceAll(')', ''); + + code = wgsl.split(`struct ${code}`)[1]; + let start = code.indexOf('{'); + let end = code.indexOf('}'); + code = code.slice(start, end); + + blockList = code.split('@'); + for (let i = 1; i < blockList.length; i++) { + const element = blockList[i]; + let code = element.replace(/\s*$/g, ''); + code = code.replaceAll('\n', ''); + code = code.split(',')[0]; + code = code.replaceAll(' ', ' '); + this.parserAttribute(code, attributes); + } + } + return attributes; + } + + /** + * builtin(instance_index) index : u32 + * location(0) Vertex_Position : vec3 + * @param line + * @param attributes + */ + private static parserAttribute(line: string, attributes: any[]) { + let obj: ShaderReflectionAttribute = { + name: '', + group: 0, + location: 0, + type: '', + valueType: '', + value: 0, + size: 0, + format: `float32` + }; + + if (line.indexOf('builtin') != -1) { + obj.type = 'builtin'; + var tmp = line.match(/\((.+?)\)/g)[0]; + tmp = line.match(/\((.+?)\)/g)[0]; + tmp = tmp.replace('(', ''); + tmp = tmp.replaceAll(')', ''); + obj.location = parseInt(tmp); + + let cc = line.split(':'); + obj.name = cc[0].split(' ')[1]; + obj.name = obj.name.replaceAll(' ', ' '); + obj.name = obj.name.replaceAll(' ', ''); + // obj.valueType = cc[1].split(' ')[1]; + obj.valueType = cc[1]; + obj.valueType = obj.valueType.replaceAll(' ', ' '); + obj.valueType = obj.valueType.replaceAll(' ', ''); + obj.valueType = obj.valueType.replaceAll('\r', ''); + obj.valueType = obj.valueType.replaceAll(')', ''); + obj.valueType = obj.valueType.replaceAll(')', ''); + obj.size = VertexAttributeSize[obj.valueType]; + attributes.push(obj); + } else if (line.indexOf('location') != -1) { + obj.type = 'location'; + var tmp = line.match(/\((.+?)\)/g)[0]; + tmp = line.match(/\((.+?)\)/g)[0]; + tmp = tmp.replace('(', ''); + tmp = tmp.replaceAll(')', ''); + obj.location = parseInt(tmp); + + let cc = line.split(':'); + obj.name = cc[0].split(' ')[1]; + obj.name = obj.name.replaceAll(' ', ' '); + obj.name = obj.name.replaceAll(' ', ''); + // obj.valueType = cc[1].split(' ')[1]; + obj.valueType = cc[1]; + obj.valueType = obj.valueType.replaceAll(' ', ' '); + obj.valueType = obj.valueType.replaceAll(' ', ''); + obj.valueType = obj.valueType.replaceAll('\r', ''); + obj.valueType = obj.valueType.replaceAll(')', ''); + obj.valueType = obj.valueType.replaceAll(')', ''); + obj.size = VertexAttributeSize[obj.valueType]; + attributes.push(obj); + } + obj.format = VertexFormat[VertexAttributeSize[obj.valueType]] + } + +} diff --git a/src/engine/gfx/graphics/webGpu/shader/value/ShaderState.ts b/src/engine/gfx/graphics/webGpu/shader/value/ShaderState.ts new file mode 100644 index 00000000..f9b47460 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/value/ShaderState.ts @@ -0,0 +1,114 @@ +import { BlendMode } from '../../../../../materials/BlendMode'; +import { GPUCompareFunction, GPUCullMode, GPUPrimitiveTopology } from '../../WebGPUConst'; + +/** + * @internal + * ShaderState + * @group GFX + */ +export class ShaderState { + public blendMode?: BlendMode = BlendMode.NONE; + public depthCompare?: GPUCompareFunction = GPUCompareFunction.less; + public depthWriteEnabled?: boolean = true; + public frontFace?: GPUFrontFace = `ccw`; + public cullMode?: GPUCullMode = GPUCullMode.back; + public topology?: GPUPrimitiveTopology = GPUPrimitiveTopology.triangle_list; + public depthBias?: number = 10; + + public useLight: boolean = false; + public useProbe: boolean = false; + public acceptGI: boolean = false; + public acceptShadow: boolean = false; + public castShadow: boolean = false; + public castReflection: boolean = false; + public receiveEnv: boolean = false; + public renderLayer: number = 1000; + public renderOrder: number = 0; + public unclippedDepth: boolean = false; + + public multisample: number = 0; + + public label: string; + public useZ: boolean = true; + + public splitTexture: boolean = false; + + public setFromMapValues(values: Map) { + if (values.has('blendMode')) { + this.blendMode = this.convertBlendMode(values.get('blendMode')); + } + if (values.has('depthCompare')) { + this.depthCompare = values.get('depthCompare'); + } + if (values.has('depthWriteEnabled')) { + this.depthWriteEnabled = values.get('depthWriteEnabled'); + } + if (values.has('frontFace')) { + this.frontFace = values.get('frontFace'); + } + if (values.has('cullMode')) { + this.cullMode = values.get('cullMode'); + } + if (values.has('topology')) { + this.topology = values.get('topology'); + } + if (values.has('depthBias')) { + this.depthBias = values.get('depthBias'); + } + + if (values.has('useLight')) { + this.useLight = values.get('useLight'); + } + if (values.has('useProbe')) { + this.useProbe = values.get('useProbe'); + } + if (values.has('acceptGI')) { + this.acceptGI = values.get('acceptGI'); + } + if (values.has('acceptShadow')) { + this.acceptShadow = values.get('acceptShadow'); + } + if (values.has('castShadow')) { + this.castShadow = values.get('castShadow'); + } + if (values.has('receiveEnv')) { + this.receiveEnv = values.get('receiveEnv'); + } + if (values.has('renderLayer')) { + this.renderLayer = values.get('renderLayer'); + } + if (values.has('renderOrder')) { + this.renderOrder = values.get('renderOrder'); + } + if (values.has('unclippedDepth')) { + this.unclippedDepth = values.get('unclippedDepth'); + } + + if (values.has('multisample')) { + this.multisample = values.get('multisample'); + } + + if (values.has('label')) { + this.label = values.get('label'); + } + if (values.has('useZ')) { + this.useZ = values.get('useZ'); + } + } + + protected convertBlendMode(value: string): BlendMode { + switch (value) { + case 'ABOVE': return BlendMode.ABOVE; + case 'ALPHA': return BlendMode.ALPHA; + case 'NORMAL': return BlendMode.NORMAL; + case 'ADD': return BlendMode.ADD; + case 'BELOW': return BlendMode.BELOW; + case 'ERASE': return BlendMode.ERASE; + case 'MUL': return BlendMode.MUL; + case 'SCREEN': return BlendMode.SCREEN; + case 'DIVD': return BlendMode.DIVD; + case 'SOFT_ADD': return BlendMode.SOFT_ADD; + } + return BlendMode.NONE; + } +} diff --git a/src/engine/gfx/graphics/webGpu/shader/value/ShaderValue.ts b/src/engine/gfx/graphics/webGpu/shader/value/ShaderValue.ts new file mode 100644 index 00000000..4ef0c42c --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/value/ShaderValue.ts @@ -0,0 +1,51 @@ +import { Texture } from '../../core/texture/Texture'; +import { UniformNode } from '../../core/uniforms/UniformNode'; +import { ConstValue } from './ConstValue'; +import { DefineValue } from './DefineValue'; +import { ShaderReflection } from './ShaderReflectionInfo'; +import { ShaderState } from './ShaderState'; +/** + * @internal + */ +export type ShaderUniform = { [uniName: string]: UniformNode }; + +/** + * @internal + */ +export type ShaderConst = { [uniName: string]: ConstValue }; + +/** + * @internal + */ +export type ShaderDefines = { [uniName: string]: boolean | number | string }; + +/** + * @internal + */ +export type ShaderValue = { + vs?: string; + fs?: string; + compute?: string; + + vs_Source?: string; + fs_Source?: string; + compute_Source?: string; + + vs_shader?: string; + fs_shader?: string; + + vsModule?: GPUShaderModule; + fsModule?: GPUShaderModule; + csModule?: GPUShaderModule; + + shaderVariant?: string; + + uniforms?: ShaderUniform; + constValues?: ShaderConst; + defines?: ShaderDefines; + shaderState?: ShaderState; + shaderReflection?: ShaderReflection; + + // input_textures?:Texture[], + // output_textures?: Iterable; +}; diff --git a/src/engine/gfx/graphics/webGpu/shader/value/UniformValue.ts b/src/engine/gfx/graphics/webGpu/shader/value/UniformValue.ts new file mode 100644 index 00000000..3f62b4f5 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/value/UniformValue.ts @@ -0,0 +1,18 @@ +import { LightBase } from '../../../../../components/lights/LightBase'; +import { Color } from '../../../../../math/Color'; +import { Vector2 } from '../../../../../math/Vector2'; +import { Vector3 } from '../../../../../math/Vector3'; +import { Vector4 } from '../../../../../math/Vector4'; +/** + * @internal + */ +export type UniformValue = number | Vector2 | Vector3 | Vector4 | Color | Float32Array | any; + +export enum UniformType { + Number, + Vector2, + Vector3, + Vector4, + Color, + Float32Array +} From 646a2c2b862471925ef5e0e283c402acf6fbb21f Mon Sep 17 00:00:00 2001 From: hellmor Date: Mon, 24 Apr 2023 14:04:12 +0800 Subject: [PATCH 029/100] feat(textures): Add texture files (#44) Added: TextureCube.ts Added: TextureMipmapCompute.ts Added: TextureMipmapGenerator.ts Added: AtmosphericScatteringSky.ts Added: BitmapTexture2D.ts Added: BitmapTextureCube.ts Added: DefaultRes.ts Added: Float16ArrayTexture.ts Added: Float32ArrayTexture.ts Added: HDRTexture.ts Added: HDRTextureCube.ts Added: LDRTextureCube.ts Added: SolidColorSky.ts Added: Uint16Texture.ts Added: Uint8ArrayTexture.ts --- .../webGpu/core/texture/TextureCube.ts | 88 +++++++ .../core/texture/TextureMipmapCompute.ts | 163 +++++++++++++ .../core/texture/TextureMipmapGenerator.ts | 209 ++++++++++++++++ .../textures/AtmosphericScatteringSky.ts | 111 +++++++++ src/engine/textures/BitmapTexture2D.ts | 115 +++++++++ src/engine/textures/BitmapTextureCube.ts | 227 ++++++++++++++++++ src/engine/textures/DefaultRes.ts | 119 +++++++++ src/engine/textures/Float16ArrayTexture.ts | 99 ++++++++ src/engine/textures/Float32ArrayTexture.ts | 113 +++++++++ src/engine/textures/HDRTexture.ts | 85 +++++++ src/engine/textures/HDRTextureCube.ts | 158 ++++++++++++ src/engine/textures/LDRTextureCube.ts | 147 ++++++++++++ src/engine/textures/SolidColorSky.ts | 53 ++++ src/engine/textures/Uint16Texture.ts | 72 ++++++ src/engine/textures/Uint8ArrayTexture.ts | 99 ++++++++ 15 files changed, 1858 insertions(+) create mode 100644 src/engine/gfx/graphics/webGpu/core/texture/TextureCube.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapCompute.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapGenerator.ts create mode 100644 src/engine/textures/AtmosphericScatteringSky.ts create mode 100644 src/engine/textures/BitmapTexture2D.ts create mode 100644 src/engine/textures/BitmapTextureCube.ts create mode 100644 src/engine/textures/DefaultRes.ts create mode 100644 src/engine/textures/Float16ArrayTexture.ts create mode 100644 src/engine/textures/Float32ArrayTexture.ts create mode 100644 src/engine/textures/HDRTexture.ts create mode 100644 src/engine/textures/HDRTextureCube.ts create mode 100644 src/engine/textures/LDRTextureCube.ts create mode 100644 src/engine/textures/SolidColorSky.ts create mode 100644 src/engine/textures/Uint16Texture.ts create mode 100644 src/engine/textures/Uint8ArrayTexture.ts diff --git a/src/engine/gfx/graphics/webGpu/core/texture/TextureCube.ts b/src/engine/gfx/graphics/webGpu/core/texture/TextureCube.ts new file mode 100644 index 00000000..a164bf26 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/texture/TextureCube.ts @@ -0,0 +1,88 @@ +import { GPUAddressMode } from '../../WebGPUConst'; +import { Texture } from './Texture'; +/** + * Texture Cube + * @internal + * @group Texture + */ +export class TextureCube extends Texture { + /** + * texture width, default value is 4 + */ + public width: number = 4; + /** + * texture height, default value is 4 + */ + public height: number = 4; + /** + * depth or array layers, default value is 6 + */ + public depthOrArrayLayers: number = 6; + + /** + * GPUShaderStage + */ + public visibility: number = GPUShaderStage.FRAGMENT; + + /** + * GPUTextureBindingLayout + */ + public textureBindingLayout: GPUTextureBindingLayout = { + viewDimension: 'cube', + multisampled: false, + }; + + /** + * GPUSamplerBindingLayout + */ + public samplerBindingLayout: GPUSamplerBindingLayout = { + type: 'filtering', + }; + + /** + * @constructor + */ + constructor() { + super(4, 4); + this.addressModeU = GPUAddressMode.clamp_to_edge; + this.addressModeV = GPUAddressMode.clamp_to_edge; + this.addressModeW = GPUAddressMode.clamp_to_edge; + this.magFilter = this.minFilter = 'linear'; + this.mipmapFilter = 'linear'; + this.visibility = GPUShaderStage.FRAGMENT; + } + + /** + * createTextureDescriptor + */ + protected createTextureDescriptor( + width: number, + height: number, + mipLevelCount: number, + format: GPUTextureFormat, + usage: number = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT, + sizeCount: number = 1, + ) { + this.width = width; + this.height = height; + this.format = format; + this.usage = usage; + this.textureDescriptor = { + size: { width: width, height: height, depthOrArrayLayers: 6 }, + mipLevelCount: mipLevelCount, + format: format, + usage: usage, + dimension: '2d', + }; + + if (sizeCount > 1) { + this.viewDescriptor = { + dimension: `cube-array`, + }; + } else { + this.viewDescriptor = { + dimension: this.textureBindingLayout.viewDimension, + }; + } + } +} diff --git a/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapCompute.ts b/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapCompute.ts new file mode 100644 index 00000000..1ad92bc1 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapCompute.ts @@ -0,0 +1,163 @@ +import { GPUContext } from '../../../../../..'; +import { webGPUContext } from '../../Context3D'; +import { Texture } from './Texture'; + +class MipMapData { + public mipLevel: number; + public mipmapCount: number; + public texture: Texture; + public srcView: GPUTextureView; + public dstWidth: number; + public dstHeight: number; +} +/** + * @internal + * @group GFX + */ +export class TextureMipmapCompute { + private static codeMax = ` + @group(0) @binding(0) var inputTexture : texture_2d; + @group(0) @binding(1) var inputTextureSampler : sampler; + @group(0) @binding(2) var outputTexture : texture_storage_2d; + + @compute @workgroup_size(8, 8) + fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let dstSize = textureDimensions(outputTexture).xy; + let uv01 = vec2(f32(GlobalInvocationID.x) / f32(dstSize.x - 1), f32(GlobalInvocationID.y) / f32(dstSize.y - 1)); + var fromColor = textureSampleLevel(inputTexture, inputTextureSampler, uv01, 0.0); + let dstCoord = vec2(i32(GlobalInvocationID.x), i32(GlobalInvocationID.y)); + + //fromColor = vec4(0.0, 0.0, 0.0, 1.0); + //if(dstSize.x == 512){ + // fromColor.x = 1.0; + //}else if(dstSize.x == 256){ + // fromColor.y = 1.0; + //}else if(dstSize.x == 128){ + // fromColor.z = 1.0; + //} + + textureStore(outputTexture, dstCoord, fromColor); + } + `; + private static codeMin = ` + @group(0) @binding(0) var inputTexture : texture_2d; + @group(0) @binding(1) var inputTextureSampler : sampler; + @group(0) @binding(2) var outputTexture : texture_storage_2d; + + @compute @workgroup_size(1, 1) + fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let dstSize = textureDimensions(outputTexture).xy; + let uv01 = vec2(f32(GlobalInvocationID.x) / f32(dstSize.x - 1), f32(GlobalInvocationID.y) / f32(dstSize.y - 1)); + var fromColor = textureSampleLevel(inputTexture, inputTextureSampler, uv01, 0.0); + let dstCoord = vec2(i32(GlobalInvocationID.x), i32(GlobalInvocationID.y)); + + textureStore(outputTexture, dstCoord, fromColor); + } + `; + + private static _pipelineMax: GPUComputePipeline; + private static _pipelineMin: GPUComputePipeline; + + public static createMipmap(texture: Texture, mipmapCount: number): void { + const device = webGPUContext.device; + this._pipelineMax ||= device.createComputePipeline({ + layout: `auto`, + compute: { + module: device.createShaderModule({ + code: this.codeMax, + }), + entryPoint: 'main', + }, + }); + + this._pipelineMin ||= device.createComputePipeline({ + layout: `auto`, + compute: { + module: device.createShaderModule({ + code: this.codeMin, + }), + entryPoint: 'main', + }, + }); + + let dstWidth = Math.ceil(texture.width * 0.5); + let dstHeight = Math.ceil(texture.height * 0.5); + let mipmapData: MipMapData = { mipmapCount: mipmapCount, texture: texture, srcView: null, mipLevel: 1, dstHeight: dstHeight, dstWidth: dstWidth }; + mipmapData.srcView = texture.getGPUTexture().createView({ + format: texture.format, + dimension: '2d', + baseMipLevel: 0, // Make sure we're getting the right mip level... + mipLevelCount: 1, // And only selecting one mip level + }); + + let isMax = texture.width > 1024 && texture.height > 1024; + if (isMax) { + this.mipmap(this._pipelineMax, mipmapData); + } else { + this.mipmap(this._pipelineMin, mipmapData); + } + } + + private static mipmap(computePipeline: GPUComputePipeline, data: MipMapData): void { + const device = webGPUContext.device; + const commandEncoder = GPUContext.beginCommandEncoder(); + let isCurrentMax = computePipeline == this._pipelineMax; + let dstView: GPUTextureView; + let isBreakToMin: boolean; + for (let i = data.mipLevel; i < data.mipmapCount; i++) { + let entries = []; + let binding: number = 0; + entries.push({ + binding: binding++, + resource: data.srcView, + }); + + entries.push({ + binding: binding++, + resource: data.texture.gpuSampler, + }); + + dstView = data.texture.getGPUTexture().createView({ + format: data.texture.format, + dimension: '2d', + baseMipLevel: i, + mipLevelCount: 1, + }); + + entries.push({ + binding: binding++, + resource: dstView, + }); + + const computeBindGroup = device.createBindGroup({ + layout: computePipeline.getBindGroupLayout(0), + entries: entries, + }); + + const computePass = commandEncoder.beginComputePass(); + computePass.setPipeline(computePipeline); + computePass.setBindGroup(0, computeBindGroup); + let groupX = data.dstWidth; + let groupY = data.dstHeight; + if (isCurrentMax) { + groupX = Math.max(1, Math.floor(data.dstWidth / 8)); + groupY = Math.max(1, Math.floor(data.dstHeight / 8)); + } + computePass.dispatchWorkgroups(groupX, groupY); + data.dstHeight *= 0.5; + data.dstWidth *= 0.5; + data.srcView = dstView; + data.mipLevel = i + 1; + isBreakToMin = isCurrentMax && (data.dstWidth < 8 || data.dstHeight < 8); + computePass.end(); + if (isBreakToMin) { + break; + } + } + GPUContext.endCommandEncoder(commandEncoder); + + if (isBreakToMin) { + this.mipmap(this._pipelineMin, data); + } + } +} diff --git a/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapGenerator.ts b/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapGenerator.ts new file mode 100644 index 00000000..a8b3e384 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapGenerator.ts @@ -0,0 +1,209 @@ +import { GPUContext } from '../../../../../..'; +import { webGPUContext } from '../../Context3D'; +import { Texture } from './Texture'; +/** + * @internal + * @group GFX + */ +export class TextureMipmapGenerator { + private static mipmapShader = ` + var pos : array, 3> = array, 3>( + vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0)); + struct VertexOutput { + @builtin(position) position : vec4; + @location(0) texCoord : vec2; + }; + @vertex + fn vertexMain(@builtin(vertex_index) vertexIndex : u32) -> VertexOutput { + var output : VertexOutput; + output.texCoord = pos[vertexIndex] * vec2(0.5, -0.5) + vec2(0.5); + output.position = vec4(pos[vertexIndex], 0.0, 1.0); + return output; + } + @binding(0) @group(0) var imgSampler : sampler; + @binding(1) @group(0) var img : texture_2d; + @fragment + fn fragmentMain(@location(0) texCoord : vec2) -> @location(0) vec4 { + var outColor: vec4 = textureSample(img, imgSampler, texCoord); + return outColor ; + }`; + private static pipelineCache: { [key: string]: GPURenderPipeline } = {}; + private static pipeline: any; + + public static getMipmapPipeline(texture: Texture) { + let format = texture.format; + let device = webGPUContext.device; + let pipeline: GPURenderPipeline = TextureMipmapGenerator.pipelineCache[texture.format]; + let mipmapShaderModule: GPUShaderModule; + if (!pipeline) { + mipmapShaderModule = device.createShaderModule({ + code: TextureMipmapGenerator.mipmapShader, + }); + + let textureLayout = device.createBindGroupLayout({ + entries: [ + { + binding: 0, + //TODO : After adding a shadow reflection, it is necessary to know that the vertex is used | the segment is used + visibility: texture.visibility, + // use GPUSamplerBindingLayout = { type:`filtering`} error + sampler: texture.samplerBindingLayout, + }, + { + binding: 1, + //TODO : After adding a shadow reflection, it is necessary to know that the vertex is used | the segment is used + visibility: texture.visibility, + // use GPUTextureBindingLayout = { sampleType:`float`} error + texture: texture.textureBindingLayout, + }, + ], + }); + + let layouts = webGPUContext.device.createPipelineLayout({ + bindGroupLayouts: [textureLayout], + }); + + pipeline = GPUContext.createPipeline({ + layout: layouts, + vertex: { + module: mipmapShaderModule, + entryPoint: 'vertexMain', + }, + fragment: { + module: mipmapShaderModule, + entryPoint: 'fragmentMain', + targets: [{ format }], + }, + }); + TextureMipmapGenerator.pipelineCache[format] = pipeline; + } + return pipeline; + } + + // TextureDescriptor should be the descriptor that the texture was created with. + // This version only works for basic 2D textures. + public static webGPUGenerateMipmap(texture: Texture) { + let gpuDevice = webGPUContext.device; + let textureDescriptor = texture.textureDescriptor; + + if (!TextureMipmapGenerator.pipeline) { + // Create a simple shader that renders a fullscreen textured quad. + const mipmapShaderModule = gpuDevice.createShaderModule({ + code: ` + var pos : array, 4> = array, 4>( + vec2(-1.0, 1.0), vec2(1.0, 1.0), + vec2(-1.0, -1.0), vec2(1.0, -1.0)); + + struct VertexOutput { + @builtin(position) position : vec4, + @location(0) texCoord : vec2 + }; + + @vertex + fn vertexMain(@builtin(vertex_index) vertexIndex : u32) -> VertexOutput { + var output : VertexOutput; + output.texCoord = pos[vertexIndex] * vec2(0.5, -0.5) + vec2(0.5); + output.position = vec4(pos[vertexIndex], 0.0, 1.0); + return output; + } + + @binding(0) @group(0) var imgSampler : sampler; + @binding(1) @group(0) var img : texture_2d; + + @fragment + fn fragmentMain(@location(0) texCoord : vec2) -> @location(0) vec4 { + var outColor: vec4 = textureSample(img, imgSampler, texCoord); + return outColor; + } + `, + }); + + TextureMipmapGenerator.pipeline = gpuDevice.createRenderPipeline({ + layout: `auto`, + vertex: { + module: mipmapShaderModule, + entryPoint: 'vertexMain', + }, + fragment: { + module: mipmapShaderModule, + entryPoint: 'fragmentMain', + targets: [ + { + format: textureDescriptor.format, // Make sure to use the same format as the texture + }, + ], + }, + primitive: { + topology: 'triangle-strip', + stripIndexFormat: 'uint32', + }, + }); + } + + // We'll ALWAYS be rendering minified here, so that's the only filter mode we need to set. + let sampler: GPUSampler; + if (texture.format == `rgba16float`) { + sampler = gpuDevice.createSampler({ + minFilter: `nearest`, + magFilter: `linear`, + }); + } else { + sampler = gpuDevice.createSampler({ + minFilter: `linear`, + magFilter: `linear`, + }); + } + + let srcView = texture.getGPUTexture().createView({ + baseMipLevel: 0, + mipLevelCount: 1, + }); + + // Loop through each mip level and renders the previous level's contents into it. + const commandEncoder = GPUContext.beginCommandEncoder(); + for (let i = 1; i < textureDescriptor.mipLevelCount; ++i) { + const dstView = texture.getGPUTexture().createView({ + baseMipLevel: i, // Make sure we're getting the right mip level... + mipLevelCount: 1, // And only selecting one mip level + }); + + const passEncoder = commandEncoder.beginRenderPass({ + colorAttachments: [ + { + view: dstView, // Render pass uses the next mip level as it's render attachment. + clearValue: [0, 0, 0, 0], + loadOp: `clear`, + storeOp: 'store', + }, + ], + }); + + // Need a separate bind group for each level to ensurev + // we're only sampling from the previous level. + const bindGroup = gpuDevice.createBindGroup({ + layout: TextureMipmapGenerator.pipeline.getBindGroupLayout(0), + entries: [ + { + binding: 0, + resource: sampler, + }, + { + binding: 1, + resource: srcView, + }, + ], + }); + + // Render + passEncoder.setPipeline(TextureMipmapGenerator.pipeline); + passEncoder.setBindGroup(0, bindGroup); + passEncoder.draw(4); + passEncoder.end(); + + // The source texture view for the next iteration of the loop is the + // destination view for this one. + srcView = dstView; + } + GPUContext.endCommandEncoder(commandEncoder); + } +} diff --git a/src/engine/textures/AtmosphericScatteringSky.ts b/src/engine/textures/AtmosphericScatteringSky.ts new file mode 100644 index 00000000..e9294c11 --- /dev/null +++ b/src/engine/textures/AtmosphericScatteringSky.ts @@ -0,0 +1,111 @@ +import { AtmosphericScatteringSky_shader } from '../assets/shader/materials/sky/AtmosphericScatteringSky_shader'; +import { UniformGPUBuffer } from '../gfx/graphics/webGpu/core/buffer/UniformGPUBuffer'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { ComputeShader } from '../gfx/graphics/webGpu/shader/ComputeShader'; +import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; +import { GPUContext } from '../gfx/renderJob/GPUContext'; +import { HDRTextureCube } from './HDRTextureCube'; +import { VirtualTexture } from './VirtualTexture'; +/** + * AtmosphericScattering Sky Setting + * @group Texture + */ +export class AtmosphericScatteringSkySetting { + public sunRadius: number = 500.0; + public sunRadiance: number = 10.0; + public mieG: number = 0.76; + public mieHeight: number = 1200; + public eyePos: number = 1500; + public sunX: number = 0.55; + public sunY: number = 0.54; + public sunBrightness: number = 1.0; + public displaySun: boolean = true; + public defaultTextureCubeSize: number = 512; + public defaultTexture2DSize: number = 1024; +} + +/** + * Atmospheric Scattering Sky Texture + * @group Texture + */ +export class AtmosphericScatteringSky extends HDRTextureCube { + private _internalTexture: AtmosphericTexture2D; + private _cubeSize: number; + public readonly setting: AtmosphericScatteringSkySetting; + + /** + * @constructor + * @param setting AtmosphericScatteringSkySetting + * @returns + */ + constructor(setting: AtmosphericScatteringSkySetting) { + super(); + this.setting = setting; + this._cubeSize = setting.defaultTextureCubeSize; + this._internalTexture = new AtmosphericTexture2D(setting.defaultTexture2DSize, setting.defaultTexture2DSize * 0.5); + this._internalTexture.update(this.setting); + this.createFromTexture(this._cubeSize, this._internalTexture); + this.textureSource.setCubeAtmosphericScattering(); + + return this; + } + + public get texture2D(): Texture { + return this._internalTexture; + } + + /** + * @internal + * @returns + */ + public apply(): this { + this._internalTexture.update(this.setting); + this.uploadErpTexture(this._internalTexture); + return this; + } + +} + +/** + * @internal + */ +class AtmosphericTexture2D extends VirtualTexture { + private _computeShader: ComputeShader; + private _uniformBuffer: UniformGPUBuffer; + + constructor(width: number, height: number) { + super(width, height, GPUTextureFormat.rgba16float, false, GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING); + this.initCompute(width, height); + } + + private initCompute(w: number, h: number): void { + this._uniformBuffer = new UniformGPUBuffer(16 * 4); + this._uniformBuffer.apply(); + + this._computeShader = new ComputeShader(AtmosphericScatteringSky_shader.cs); + this._computeShader.setUniformBuffer('uniformBuffer', this._uniformBuffer); + this._computeShader.setStorageTexture(`outTexture`, this); + this._computeShader.workerSizeX = w / 8; + this._computeShader.workerSizeY = h / 8; + } + + public update(setting: AtmosphericScatteringSkySetting): this { + this._uniformBuffer.setFloat('width', this.width); + this._uniformBuffer.setFloat('height', this.height); + this._uniformBuffer.setFloat('sunU', setting.sunX); + this._uniformBuffer.setFloat('sunV', setting.sunY); + this._uniformBuffer.setFloat('eyePos', setting.eyePos); + this._uniformBuffer.setFloat('sunRadius', setting.sunRadius); + this._uniformBuffer.setFloat('sunRadiance', setting.sunRadiance); + this._uniformBuffer.setFloat('mieG', setting.mieG); + this._uniformBuffer.setFloat('mieHeight', setting.mieHeight); + this._uniformBuffer.setFloat('sunBrightness', setting.sunBrightness); + this._uniformBuffer.setFloat('displaySun', setting.displaySun ? 1 : 0); + this._uniformBuffer.apply(); + + let command = GPUContext.beginCommandEncoder(); + GPUContext.computeCommand(command, [this._computeShader]); + GPUContext.endCommandEncoder(command); + return this; + } +} diff --git a/src/engine/textures/BitmapTexture2D.ts b/src/engine/textures/BitmapTexture2D.ts new file mode 100644 index 00000000..6f80acbf --- /dev/null +++ b/src/engine/textures/BitmapTexture2D.ts @@ -0,0 +1,115 @@ +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; +import { LoaderBase } from '../loader/LoaderBase'; +import { LoaderFunctions } from '../loader/LoaderFunctions'; +import { StringUtil } from '../util/StringUtil'; + +/** + * bitmap texture + * @group Texture + */ +export class BitmapTexture2D extends Texture { + private _source: HTMLCanvasElement | ImageBitmap | OffscreenCanvas; + + /** + * @constructor + * @param useMipmap Set whether to use mipmap + */ + constructor(useMipmap: boolean = true) { + super(); + this.useMipmap = useMipmap; + } + + /** + * get raw data of this texture + */ + public get source(): HTMLCanvasElement | ImageBitmap | OffscreenCanvas { + return this._source; + } + + /** + * set raw data of this texture + */ + public set source(value: HTMLCanvasElement | ImageBitmap | OffscreenCanvas) { + this._source = value; + + if (this._source instanceof HTMLImageElement) { + this._source.decode().then(async () => { + if (this._source instanceof HTMLImageElement) { + const imageBitmap = await createImageBitmap(this._source, { imageOrientation: this.flipY ? "flipY" : "from-image" }); + this.generate(imageBitmap); + } + }); + } else { + //@bug not generate OffscreenCanvas + if (this._source instanceof HTMLCanvasElement || this._source instanceof ImageBitmap) { + this.generate(this._source); + } + } + } + + /** + * load texture data from web url + * @param url web url + * @param loaderFunctions callback function when load complete + */ + public async load(url: string, loaderFunctions?: LoaderFunctions) { + if (url.indexOf(';base64') != -1) { + this.textureSource.setNetImageBase64(url); + const img = document.createElement('img'); + let start = url.indexOf('data:image'); + let uri = url.substring(start, url.length); + img.src = uri; + await img.decode(); + img.width = Math.max(img.width, 32); + img.height = Math.max(img.height, 32); + const imageBitmap = await createImageBitmap(img, { + resizeWidth: img.width, + resizeHeight: img.height, + imageOrientation: this.flipY ? "flipY" : "from-image" + }); + this.format = GPUTextureFormat.rgba8unorm; + this.generate(imageBitmap); + } else { + this.textureSource.setNetImage(url); + const r = await fetch(url, { + headers: Object.assign({ + 'Accept': 'image/avif,image/webp,*/*' + }, loaderFunctions?.headers) + }); + // const img = await r.blob(); + // await this.loadFromBlob(img); + let chunks = await LoaderBase.read(url, r, loaderFunctions); + let img = new Blob([chunks], { type: 'image/jpeg' }); + chunks = null; + + await this.loadFromBlob(img); + } + this.name = StringUtil.getURLName(url); + return true; + } + + + private imageData: Blob; + /** + * load data from Blob + * @param imgData blob data which contains image + */ + public async loadFromBlob(imgData: Blob) { + this.imageData = imgData; + let imageBitmap = await createImageBitmap(imgData, { imageOrientation: this.flipY ? 'flipY' : 'from-image' }); + if (imageBitmap.width < 32 || imageBitmap.height < 32) { + let width = Math.max(imageBitmap.width, 32); + let height = Math.max(imageBitmap.height, 32); + imageBitmap = await createImageBitmap(imageBitmap, { + resizeWidth: width, + resizeHeight: height, + imageOrientation: this.flipY ? "flipY" : "from-image" + }); + } + this.format = GPUTextureFormat.rgba8unorm; + this.generate(imageBitmap); + return true; + } + +} diff --git a/src/engine/textures/BitmapTextureCube.ts b/src/engine/textures/BitmapTextureCube.ts new file mode 100644 index 00000000..cf30476f --- /dev/null +++ b/src/engine/textures/BitmapTextureCube.ts @@ -0,0 +1,227 @@ +import { BitmapTexture2D, GPUContext, StringUtil, Texture, VirtualTexture } from '../..'; +import { BlurTexture2DBufferCreator } from '../gfx/generate/convert/BlurEffectCreator'; +import { TextureCube } from '../gfx/graphics/webGpu/core/texture/TextureCube'; +import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +import { TextureCubeStdCreator } from "../gfx/generate/convert/TextureCubeStdCreator"; + +/** + * @group Texture + */ +export class BitmapTextureCube extends TextureCube { + private _images: HTMLCanvasElement[] | ImageBitmap[] | OffscreenCanvas[]; + + private _url: string | string[]; + + constructor() { + super(); + this.useMipmap = true; + } + + protected generateImages(images: HTMLCanvasElement[] | ImageBitmap[] | OffscreenCanvas[] | Texture[]) { + let device = webGPUContext.device; + this.width = this.height = 32; + if ('width' in images[0]) { + this.width = this.height = images[0].width; + } + let mipmapSize = Math.min(this.width, this.height); + this.mipmapCount = 1; + while (mipmapSize > 16) { + mipmapSize /= 2; + this.mipmapCount++; + } + + this.textureBindingLayout.viewDimension = 'cube'; + this.samplerBindingLayout.type = 'filtering'; + this.createTextureDescriptor(this.width, this.height, this.mipmapCount, this.format); + + this.textureDescriptor.size = { width: this.width, height: this.height, depthOrArrayLayers: 6 }; + this.textureDescriptor.dimension = '2d'; + this.gpuTexture = device.createTexture(this.textureDescriptor); + + let faceTextures: GPUTexture[] = []; + let lastFaceTextures: GPUTexture[] = faceTextures; + let mipWidth = this.width; + let mipHeight = this.height; + + if (images[0] instanceof Texture) { + for (let i = 0; i < 6; i++) { + let t = images[i] as Texture; + faceTextures[i] = t.getGPUTexture(); + } + this.uploadMipmapGPUTexture(0, this.width, this.width, faceTextures); + } else { + this.uploadBaseImages(this.width, images as any); + for (let i = 0; i < 6; i++) { + let t = new BitmapTexture2D(false); + t.format = this.format; + t.source = images[i] as any; + faceTextures[i] = t.getGPUTexture(); + } + } + + for (let i = 1; i < this.mipmapCount; i++) { + lastFaceTextures = faceTextures; + faceTextures = []; + let dstBuffer = { width: mipWidth, height: mipHeight, gpuTexture: null }; + mipWidth = mipWidth / 2; + mipHeight = mipHeight / 2; + for (let faceId = 0; faceId < 6; faceId++) { + dstBuffer.gpuTexture = lastFaceTextures[faceId]; + faceTextures[faceId] = BlurTexture2DBufferCreator.blurImageFromTexture(dstBuffer, mipWidth, mipHeight, false); + } + this.uploadMipmapGPUTexture(i, mipWidth, mipHeight, faceTextures); + } + this.gpuSampler = device.createSampler(this); + } + + private uploadBaseImages(size: number, textures: HTMLCanvasElement[] | ImageBitmap[] | OffscreenCanvas[]) { + let device = webGPUContext.device; + const commandEncoder = GPUContext.beginCommandEncoder(); + + for (let i = 0; i < 6; i++) { + device.queue.copyExternalImageToTexture( + { source: textures[i] }, + { + texture: this.gpuTexture, + mipLevel: 0, + origin: { x: 0, y: 0, z: i }, + }, + { width: size, height: size, depthOrArrayLayers: 1 }, + ); + } + + GPUContext.endCommandEncoder(commandEncoder); + } + + private uploadMipmapGPUTexture(mip: number, width: number, height: number, textures: GPUTexture[]) { + const commandEncoder = GPUContext.beginCommandEncoder(); + + for (let i = 0; i < 6; i++) { + commandEncoder.copyTextureToTexture( + { + texture: textures[i], + mipLevel: 0, + origin: { x: 0, y: 0, z: 0 }, + }, + { + texture: this.gpuTexture, + mipLevel: mip, + origin: { x: 0, y: 0, z: i }, + }, + { + width: width, + height: height, + depthOrArrayLayers: 1, + }, + ); + } + + GPUContext.endCommandEncoder(commandEncoder); + } + + /** + * get images of this texture + */ + public get images(): HTMLCanvasElement[] | ImageBitmap[] | OffscreenCanvas[] { + return this._images; + } + + /** + * set images of this texture + */ + public set images(value: HTMLCanvasElement[] | ImageBitmap[] | OffscreenCanvas[]) { + this._images = value; + + if (this._images[0] instanceof HTMLImageElement) { + let bitmaps: ImageBitmap[] = []; + let remain: number = 6; + let that = this; + + function loadImage(index: number, image: HTMLImageElement) { + image.decode().then(async () => { + bitmaps[index] = await createImageBitmap(image); + remain--; + if (remain == 0) { + that.generateImages(bitmaps); + } + }); + } + + for (let i = 0; i < 6; i++) { + loadImage(i, this._images[i] as any); + } + } else { + //@bug not generate OffscreenCanvas + if (this._images instanceof HTMLCanvasElement || this._images instanceof ImageBitmap) { + this.generateImages(this._images); + } + } + } + + /** + * load texture data from array of web url. + * make sure there are six images in a group, + * and the order is: nx, px, py, ny, nz, pz + * @param urls array of image url + */ + public async load(urls: string[]) { + this._url = urls; + let remain: number = 6; + let bitmaps: ImageBitmap[] = []; + this.format = GPUTextureFormat.rgba8unorm; + let that = this; + + async function loadImage(index: number, url: string) { + const img = document.createElement('img'); + img.src = url; + img.setAttribute('crossOrigin', ''); + await img.decode(); + bitmaps[index] = await createImageBitmap(img); + remain--; + if (remain == 0) { + that.generateImages(bitmaps); + return true; + } + } + + for (let i = 0; i < 6; i++) { + await loadImage(i, urls[i]); + } + return true; + } + + /** + * load texture data from url. + * the image is assembled from six images into cross shaped image. + * @param url the path of image + */ + public async loadStd(url: string) { + this._url = url; + this.format = GPUTextureFormat.rgba8unorm; + + const img = document.createElement('img'); + img.src = url; + img.setAttribute('crossOrigin', ''); + await img.decode(); + let srcTexture = new BitmapTexture2D(false); + srcTexture.name = StringUtil.getURLName(url); + srcTexture.format = 'rgba8unorm'; + srcTexture.source = await createImageBitmap(img); + + let cubeSize = Math.round(Math.log2(srcTexture.width / 4)); + cubeSize = Math.pow(2, cubeSize); + this.width = this.height = cubeSize; + + let textureList: VirtualTexture[] = []; + for (let i = 0; i < 6; i++) { + let item = new VirtualTexture(cubeSize, cubeSize, this.format, false, + GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.TEXTURE_BINDING); + item.name = 'face ' + i; + textureList.push(item); + TextureCubeStdCreator.createFace(i, this.width, srcTexture, item); + } + this.generateImages(textureList); + return true; + } +} diff --git a/src/engine/textures/DefaultRes.ts b/src/engine/textures/DefaultRes.ts new file mode 100644 index 00000000..4bd938df --- /dev/null +++ b/src/engine/textures/DefaultRes.ts @@ -0,0 +1,119 @@ +import { Engine3D } from '../Engine3D'; +import { BRDFLUTGenerate } from '../gfx/generate/BrdfLUTGenerate'; +import { Uint8ArrayTexture } from './Uint8ArrayTexture'; +import { GUISubTexture, GUITextureSource } from "../components/gui/core/GUISubTexture"; +import { Texture } from "../gfx/graphics/webGpu/core/texture/Texture"; +import { HDRTextureCube } from './HDRTextureCube'; + +/** + * default internal texture + * @internal + * @group Texture + */ +class _DefaultRes { + /** + * normal texture + */ + public normalTexture: Uint8ArrayTexture; + public maskTexture: Uint8ArrayTexture; + public whiteTexture: Uint8ArrayTexture; + public blackTexture: Uint8ArrayTexture; + public redTexture: Uint8ArrayTexture; + public blueTexture: Uint8ArrayTexture; + public greenTexture: Uint8ArrayTexture; + public yellowTexture: Uint8ArrayTexture; + public grayTexture: Uint8ArrayTexture; + + public defaultTextureKVMap: { [name: string]: Texture } = {}; + public defaultTextureVKMap: Map = new Map(); + + public defaultTextureSource: GUITextureSource;// = new GUITextureSource(defaultTexture.whiteTexture); + public defaultSubTexture: GUISubTexture;// = new GUISubTexture(); + public defaultSky: HDRTextureCube; + /** + * create a texture + * @param width width of texture + * @param height height of texture + * @param r component-red + * @param g component-green + * @param b component-blue + * @param a component-alpha(0 for transparent,1 for opaque) + * @param name name string + * @returns + */ + public createTexture(width: number, height: number, r: number, g: number, b: number, a: number, name?: string) { + let w = 32; + let h = 32; + let textureData = new Uint8Array(w * h * 4); + this.fillColor(textureData, width, height, r, g, b, a); + let texture = new Uint8ArrayTexture(); + texture.name = name; + texture.create(16, 16, textureData, true); + if (name) { + this.recordTexture(name, texture); + } + return texture; + } + + public recordTexture(name: string, texture: Texture) { + this.defaultTextureKVMap[name] = texture; + this.defaultTextureVKMap.set(texture, name); + } + + /** + * fill slod color to this texture + * @param array data of texture + * @param w width of texture + * @param h height of texture + * @param r component-red + * @param g component-green + * @param b component-blue + * @param a component-alpha(0 for transparent,1 for opaque) + */ + public fillColor(array: any, w: number, h: number, r: number, g: number, b: number, a: number) { + for (let i = 0; i < w; i++) { + for (let j = 0; j < h; j++) { + let pixelIndex = j * w + i; + array[pixelIndex * 4 + 0] = r; + array[pixelIndex * 4 + 1] = g; + array[pixelIndex * 4 + 2] = b; + array[pixelIndex * 4 + 3] = a; + } + } + } + + /** + * Initialize a common texture object. Provide a universal solid color texture object. + */ + public async initCommon() { + defaultRes.normalTexture = defaultRes.createTexture(32, 32, 255 * 0.5, 255 * 0.5, 255.0, 255.0, 'default-normalTexture'); + defaultRes.maskTexture = defaultRes.createTexture(32, 32, 255, 255 * 0.5, 0.0, 255.0, 'default-maskTexture'); + defaultRes.whiteTexture = defaultRes.createTexture(32, 32, 255, 255, 255, 255, 'default-whiteTexture'); + defaultRes.blackTexture = defaultRes.createTexture(32, 32, 0, 0, 0, 255.0, 'default-blackTexture'); + defaultRes.redTexture = defaultRes.createTexture(32, 32, 255, 0, 0, 255.0, 'default-redTexture'); + defaultRes.blueTexture = defaultRes.createTexture(32, 32, 0, 0, 255, 255.0, 'default-blueTexture'); + defaultRes.greenTexture = defaultRes.createTexture(32, 32, 0, 255, 0, 255, 'default-greenTexture'); + defaultRes.yellowTexture = defaultRes.createTexture(32, 32, 0, 255, 255, 255.0, 'default-yellowTexture'); + defaultRes.grayTexture = defaultRes.createTexture(32, 32, 128, 128, 128, 255.0, 'default-grayTexture'); + + defaultRes.defaultTextureSource = new GUITextureSource(defaultRes.whiteTexture); + defaultRes.defaultSubTexture = new GUISubTexture(); + defaultRes.defaultSubTexture.trimSize.set(4, 4) + + let brdf = new BRDFLUTGenerate(); + let texture = brdf.generateBRDFLUTTexture(); + let BRDFLUT = texture.name = 'BRDFLUT'; + Engine3D.res.addTexture(BRDFLUT, texture); + this.recordTexture(BRDFLUT, texture); + + defaultRes.defaultSky = new HDRTextureCube(); + defaultRes.defaultSky.createFromTexture(128, defaultRes.blackTexture); + } +} + +/** + * @internal + * default internal texture + * @group Texture + */ +export let defaultRes = new _DefaultRes(); diff --git a/src/engine/textures/Float16ArrayTexture.ts b/src/engine/textures/Float16ArrayTexture.ts new file mode 100644 index 00000000..7844bc8e --- /dev/null +++ b/src/engine/textures/Float16ArrayTexture.ts @@ -0,0 +1,99 @@ +import { GPUContext } from '../..'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { TextureMipmapGenerator } from '../gfx/graphics/webGpu/core/texture/TextureMipmapGenerator'; +import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +import { toHalfFloat } from '../util/Convert'; +/** + * @internal + * Float16Array texture + * @group Texture + */ +export class Float16ArrayTexture extends Texture { + public uint16Array: Uint16Array; + public floatArray: number[]; + private _dataBuffer: GPUBuffer; + /** + * fill this texture by array of numbers;the format as [red0, green0, blue0, alpha0, red1, green1, blue1, alpha1...] + * @param width assign the texture width + * @param height assign the texture height + * @param numbers color of each pixel + * @param useMipmap whether or not gen mipmap + * @returns + */ + public create(width: number, height: number, numbers: number[] = null, mipmap: boolean = true): this { + if (numbers == null) { + numbers = []; + for (let i = 0, c = width * height * 4; i < c; i++) { + numbers[i] = 0; + } + } + this.updateTexture(width, height, numbers, mipmap); + return this; + } + + /** + * validate the change of this texture + */ + public updateTexture(width: number, height: number, numbers: number[], mipmap: boolean = true) { + if (width != this.width || height != this.height) { + this._dataBuffer && this._dataBuffer.destroy(); + this._dataBuffer = null; + this.gpuTexture && this.gpuTexture.destroy(); + this.gpuTexture = null; + } + + this.floatArray = numbers; + let device = webGPUContext.device; + const bytesPerRow = width * 4 * 2; + this.format = GPUTextureFormat.rgba16float; + + this.mipmapCount = Math.floor(mipmap ? Math.log2(width) : 1); + this.createTextureDescriptor(width, height, this.mipmapCount, this.format); + if (!this.uint16Array || this.uint16Array.length != numbers.length) { + this.uint16Array = new Uint16Array(numbers.length); + } + let uint16Array = this.uint16Array; + for (let i = 0, c = uint16Array.length; i < c; i++) { + uint16Array[i] = toHalfFloat(numbers[i]); + } + const textureDataBuffer = (this._dataBuffer = device.createBuffer({ + size: uint16Array.byteLength, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, + })); + + device.queue.writeBuffer(textureDataBuffer, 0, uint16Array); + const commandEncoder = GPUContext.beginCommandEncoder(); + commandEncoder.copyBufferToTexture( + { + buffer: textureDataBuffer, + bytesPerRow: bytesPerRow, + }, + { + texture: this.getGPUTexture(), + }, + { + width: width, + height: height, + depthOrArrayLayers: 1, + }, + ); + if (!this.useMipmap) { + this.samplerBindingLayout.type = `filtering`; + this.textureBindingLayout.sampleType = `float`; + } + GPUContext.endCommandEncoder(commandEncoder); + + // this.sampler.minFilter = `nearest`; + // this.sampler.magFilter = `nearest`; + // this.sampler.mipmapFilter = `nearest`; + // this.sampler.maxAnisotropy = 0.5 ; + // this.bindingSampler.type = `non-filtering`; + // this.bindingTexture.sampleType = `unfilterable-float`; + + this.gpuSampler = device.createSampler(this); + this.gpuTexture = this.getGPUTexture(); + + if (this.mipmapCount > 1) TextureMipmapGenerator.webGPUGenerateMipmap(this); + } +} diff --git a/src/engine/textures/Float32ArrayTexture.ts b/src/engine/textures/Float32ArrayTexture.ts new file mode 100644 index 00000000..30cf5609 --- /dev/null +++ b/src/engine/textures/Float32ArrayTexture.ts @@ -0,0 +1,113 @@ +import { GPUContext } from '../..'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { TextureMipmapGenerator } from '../gfx/graphics/webGpu/core/texture/TextureMipmapGenerator'; +import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +/** + * @internal + * Float32Array texture + * @group Texture + */ +export class Float32ArrayTexture extends Texture { + /** + * fill this texture by array of numbers;the format as [red0, green0, blue0, alpha0, red1, green1, blue1, alpha1...] + * @param width assign the texture width + * @param height assign the texture height + * @param data color of each pixel + * @param filtering set the sampler type to filtering, else it's non-filtering + * @returns + */ + public create(width: number, height: number, data: Float32Array, filtering: boolean = true) { + let device = webGPUContext.device; + const bytesPerRow = width * 4 * 4; + this.format = GPUTextureFormat.rgba32float; + + let mipmapCount = 1; + this.createTextureDescriptor(width, height, mipmapCount, this.format); + + const textureDataBuffer = device.createBuffer({ + size: data.byteLength, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, + }); + + device.queue.writeBuffer(textureDataBuffer, 0, data); + const commandEncoder = GPUContext.beginCommandEncoder(); + commandEncoder.copyBufferToTexture( + { + buffer: textureDataBuffer, + bytesPerRow: bytesPerRow, + }, + { + texture: this.getGPUTexture(), + }, + { + width: width, + height: height, + depthOrArrayLayers: 1, + }, + ); + + GPUContext.endCommandEncoder(commandEncoder); + + // this.sampler.minFilter = `nearest`; + // this.sampler.magFilter = `nearest`; + // this.sampler.mipmapFilter = `nearest`; + // this.sampler.maxAnisotropy = 0.5 ; + // this.bindingSampler.type = `non-filtering`; + // this.bindingTexture.sampleType = `unfilterable-float`; + if (filtering) { + this.samplerBindingLayout.type = `non-filtering`; + this.textureBindingLayout.sampleType = `unfilterable-float`; + } + + this.gpuSampler = device.createSampler({}); + + if (mipmapCount > 1) TextureMipmapGenerator.webGPUGenerateMipmap(this); + } + + /** + * fill this texture GPUBuffer + * @param width assign the texture width + * @param height assign the texture height + * @param textureDataBuffer GPUBuffer + * @returns + */ + public fromBuffer(width: number, height: number, textureDataBuffer: GPUBuffer): this { + let device = webGPUContext.device; + const bytesPerRow = width * 4 * 4; + this.format = GPUTextureFormat.rgba32float; + + this.mipmapCount = 1; + this.createTextureDescriptor(width, height, this.mipmapCount, this.format); + + const commandEncoder = GPUContext.beginCommandEncoder(); + commandEncoder.copyBufferToTexture( + { + buffer: textureDataBuffer, + bytesPerRow: bytesPerRow, + }, + { + texture: this.getGPUTexture(), + }, + { + width: width, + height: height, + depthOrArrayLayers: 1, + }, + ); + + GPUContext.endCommandEncoder(commandEncoder); + + // this.sampler.minFilter = `nearest`; + // this.sampler.magFilter = `nearest`; + // this.sampler.mipmapFilter = `nearest`; + // this.sampler.maxAnisotropy = 0.5 ; + // this.bindingSampler.type = `non-filtering`; + // this.bindingTexture.sampleType = `unfilterable-float`; + this.samplerBindingLayout.type = `non-filtering`; + this.textureBindingLayout.sampleType = `unfilterable-float`; + this.gpuSampler = device.createSampler({}); + return this; + // if (mipmapCount > 1) textureMipmapGenerator.webGPUGenerateMipmap(this); + } +} diff --git a/src/engine/textures/HDRTexture.ts b/src/engine/textures/HDRTexture.ts new file mode 100644 index 00000000..fd82bae3 --- /dev/null +++ b/src/engine/textures/HDRTexture.ts @@ -0,0 +1,85 @@ +import { FileLoader, GPUContext, LoaderFunctions, RGBEParser } from '../..'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +/** + * HDR Texture + * @group Texture + */ +export class HDRTexture extends Texture { + + constructor() { + super(32, 32, null); + } + + /** + * fill this texture by array of numbers;the format as [red0, green0, blue0, e0, red1, green1, blue1, e1...] + * @param width assign the texture width + * @param height assign the texture height + * @param data color of each pixel + * @param useMipmap gen mipmap or not + * @returns + */ + public create(width: number = 32, height: number = 32, data: ArrayBuffer = null, useMipmap: boolean = true): this { + this.width = width; + this.height = height; + let device = webGPUContext.device; + const bit = 2; //half float + const bytesPerRow = width * 4 * bit; + let fixedData: ArrayBuffer = data; + + this.format = GPUTextureFormat.rgba16float; + this.useMipmap = useMipmap; + + this.updateTextureDescription(); + + this.updateGPUTexture(); + + const textureDataBuffer = device.createBuffer({ + size: fixedData.byteLength, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, + }); + + device.queue.writeBuffer(textureDataBuffer, 0, fixedData); + const commandEncoder = GPUContext.beginCommandEncoder(); + commandEncoder.copyBufferToTexture( + { + buffer: textureDataBuffer, + bytesPerRow: bytesPerRow, + }, + { + texture: this.getGPUTexture(), + }, + { + width: width, + height: height, + depthOrArrayLayers: 1, + }, + ); + GPUContext.endCommandEncoder(commandEncoder); + + if (!this.useMipmap) { + this.samplerBindingLayout.type = `filtering`; + this.textureBindingLayout.sampleType = `float`; + } + + this.gpuSampler = device.createSampler(this); + + // if (this.useMipmap && this.mipmapCount > 1) TextureMipmapGenerator.webGPUGenerateMipmap(this); + + return this; + } + + + /** + * load one hdr image + * @param url the url of hdr image + * @param loaderFunctions callback when load complete + * @returns + */ + public async load(url: string, loaderFunctions?: LoaderFunctions): Promise { + let loader = new FileLoader(); + let parser = await loader.load(url, RGBEParser, loaderFunctions); + return parser.getHDRTexture(); + } +} diff --git a/src/engine/textures/HDRTextureCube.ts b/src/engine/textures/HDRTextureCube.ts new file mode 100644 index 00000000..57f7859c --- /dev/null +++ b/src/engine/textures/HDRTextureCube.ts @@ -0,0 +1,158 @@ +import { FileLoader, LoaderFunctions, RGBEParser } from '../..'; +import { ErpImage2CubeMap } from '../gfx/generate/convert/ErpImage2CubeMap'; +import { IBLEnvMapCreator } from '../gfx/generate/convert/IBLEnvMapCreator'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { TextureCube } from '../gfx/graphics/webGpu/core/texture/TextureCube'; +import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +import { VirtualTexture } from './VirtualTexture'; + +/** + * HDR TextureCube + * @group Texture + */ +export class HDRTextureCube extends TextureCube { + private faceTextureRef: { [key: string]: { t: GPUTexture; v: GPUTextureView } }; + + private _url: string; + /** + * create a cube texture, it's high dynamic range texture + */ + constructor() { + super(); + this.faceTextureRef = {}; + this.useMipmap = true; + this.format = GPUTextureFormat.rgba16float; + } + + /** + * fill this texture by array of numbers;the format as [red0, green0, blue0, alpha0, red1, green1, blue1, alpha1...] + * @param size assign the cube texture size + * @param data raw data of cubeTexture; the format is { width: number; height: number; array: Uint8Array } + * @returns + */ + public createFromHDRData(size: number, data: { width: number; height: number; array: Uint8Array }): this { + let texture = new VirtualTexture(data.width, data.height, GPUTextureFormat.rgba16float, false, GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING); + + let float32Array: Float32Array = new Float32Array(data.array); + ErpImage2CubeMap.convertRGBE2RGBA(texture, float32Array); + this.createFromTexture(size, texture); + return this; + } + + /** + * fill this texture by a texture2D, which is a 360 panorama image + * @param size assign the cube texture size + * @param texture the image texture + * @returns + */ + public createFromTexture(size: number, texture: Texture): this { + this.width = this.height = size; + this.textureBindingLayout.viewDimension = 'cube'; + let mipmapSize = this.width; + this.mipmapCount = 1; + while (mipmapSize > 16) { + mipmapSize /= 2; + this.mipmapCount++; + } + + this.createTextureDescriptor(size, size, this.mipmapCount, this.format); + + this.textureDescriptor.size = { width: size, height: size, depthOrArrayLayers: 6 }; + this.textureDescriptor.dimension = '2d'; + this.gpuSampler = webGPUContext.device.createSampler(this); + + this.uploadErpTexture(texture); + return this; + } + + /** + * fill this texture by a texture2D, which is a 360 panorama image + * @param texture a panorama image + * @returns + */ + public uploadErpTexture(texture: Texture): this { + let gpuSource = this.getGpuSource(0); + ErpImage2CubeMap.makeTextureCube(texture, this.width, gpuSource.v); + // this.uploadMipmap(0, maxSize, faceTextures); + // this.generateMipmap(); + this.generateMipmap(texture); + return this; + } + + /** + * fill this texture by a texture2D, which is a 360 panorama image + * assign mipmap level + * @param mip mipmap level + * @param texture a panorama image + * @returns + */ + public uploadTexture(mip: number, texture: Texture): this { + let gpuSource = this.getGpuSource(mip); + ErpImage2CubeMap.makeTextureCube(texture, this.width, gpuSource.v); + return this; + } + + /** + * get GPU texture raw data + * @param mip mipmap level + * @returns GPU texture raw data, including t: GPUTexture and v: GPUTextureView + */ + private getGpuSource(mip: number): { t: GPUTexture; v: GPUTextureView } { + let source: { t: GPUTexture; v: GPUTextureView } = this.faceTextureRef[mip]; + if (!source) { + source = { + t: this.getGPUTexture(), + v: this.getGPUTexture().createView({ + format: this.format, + dimension: '2d-array', + baseMipLevel: mip, + mipLevelCount: 1, + arrayLayerCount: 6, + }), + }; + this.faceTextureRef[mip] = source; + } + return source; + } + + /** + * Generate Mipmap + * @param texture + */ + private generateMipmap(texture: Texture) { + let mipmap: number = 1; + while (mipmap < this.mipmapCount) { + this.generateMipmapAtLevel(mipmap, texture); + mipmap++; + } + } + + /** + * Generate a specified level of Mipmap + * @param mipmap mipmap level + * @param erpTexture ERP Texture Object + * @param pow power + */ + private generateMipmapAtLevel(mipmap: number, erpTexture: Texture, pow: number = 3.0): void { + let mipFaceSize = this.width / Math.pow(2, mipmap); + let image = { width: mipFaceSize, height: mipFaceSize, erpTexture: erpTexture }; + let roughness = (mipmap + 1) / this.mipmapCount; + roughness = Math.pow(roughness, pow); + let gpuSource = this.getGpuSource(mipmap); + IBLEnvMapCreator.importantSample(image, mipFaceSize, roughness, gpuSource.v); + } + + + /** + * load texture data from web url, which is a 360 panorama image + * @param url web url + * @param loaderFunctions callback function when load complete + */ + public async load(url: string, loaderFunctions?: LoaderFunctions): Promise { + this._url = url; + let loader = new FileLoader(); + let parser = await loader.load(url, RGBEParser, loaderFunctions); + return parser.getCubeTexture(); + } +} diff --git a/src/engine/textures/LDRTextureCube.ts b/src/engine/textures/LDRTextureCube.ts new file mode 100644 index 00000000..87978e2f --- /dev/null +++ b/src/engine/textures/LDRTextureCube.ts @@ -0,0 +1,147 @@ +import { ErpImage2CubeMap } from "../gfx/generate/convert/ErpImage2CubeMap"; +import { IBLEnvMapCreator } from "../gfx/generate/convert/IBLEnvMapCreator"; +import { GPUTextureFormat } from "../gfx/graphics/webGpu/WebGPUConst"; +import { webGPUContext } from "../gfx/graphics/webGpu/Context3D"; +import { Texture } from "../gfx/graphics/webGpu/core/texture/Texture"; +import { TextureCube } from "../gfx/graphics/webGpu/core/texture/TextureCube"; +import { LoaderFunctions } from "../loader/LoaderFunctions"; +import { BitmapTexture2D } from "./BitmapTexture2D"; + +/** + * LDRTextureCube : create a cube texture, it's low dynamic range texture + * @group Texture + */ +export class LDRTextureCube extends TextureCube { + private _faceTextureRef: { [key: string]: { t: GPUTexture; v: GPUTextureView } }; + + private _url: string; + /** + * constructor: create a cube texture, it's low dynamic range texture + */ + + public get ldrImageUrl() { + return this._url; + } + constructor() { + super(); + this._faceTextureRef = {}; + this.useMipmap = true; + this.format = GPUTextureFormat.rgba16float; + } + + + /** + * load texture data from web url, which is a 360 panorama image + * @param url web url + * @param loaderFunctions callback function when load complete + */ + public async load(url: string, loaderFunctions?: LoaderFunctions): Promise { + this._url = url; + let bitmapTexture: BitmapTexture2D = new BitmapTexture2D(false); + await bitmapTexture.load(url, loaderFunctions); + this.createFromLDRTexture(bitmapTexture); + return this; + } + + /** + * + * Create a texture cube + * @param srcTexture The cube texture will be created from this 2D texture + * @returns this + */ + private createFromLDRTexture(srcTexture: Texture): this { + let size = Math.log2(srcTexture.width / 4); + size = Math.pow(2, Math.round(size)); + this.createFromTexture(size, srcTexture); + return this; + } + + /** + * + * create cube texture by environment image + * @param size size of cube texture + * @param texture source texture + */ + public createFromTexture(size: number, texture: Texture): this { + this.width = this.height = size; + this.textureBindingLayout.viewDimension = 'cube'; + let mipmapSize = this.width; + this.mipmapCount = 1; + while (mipmapSize > 16) { + mipmapSize /= 2; + this.mipmapCount++; + } + + this.createTextureDescriptor(size, size, this.mipmapCount, this.format); + + this.textureDescriptor.size = { width: size, height: size, depthOrArrayLayers: 6 }; + this.textureDescriptor.dimension = '2d'; + this.gpuSampler = webGPUContext.device.createSampler(this); + + this.uploadErpTexture(texture); + return this; + } + + /** + * @private + * @param texture texture reference + * @returns this + */ + private uploadErpTexture(texture: Texture): this { + let gpuSource = this.getGpuSource(0); + ErpImage2CubeMap.makeTextureCube(texture, this.width, gpuSource.v); + this.generateMipmap(texture); + return this; + } + + /** + * @priate get GPU texture raw data + * @param mip mipmap level + * @returns GPU texture raw data, including t: GPUTexture and v: GPUTextureView + */ + private getGpuSource(mip: number): { t: GPUTexture; v: GPUTextureView } { + let source = this._faceTextureRef[mip]; + if (!source) { + source = { + t: this.getGPUTexture(), + v: this.getGPUTexture().createView({ + format: this.format, + dimension: '2d-array', + baseMipLevel: mip, + mipLevelCount: 1, + arrayLayerCount: 6, + }), + }; + this._faceTextureRef[mip] = source; + } + return source; + } + + /** + * @private generateMipmap + * @param texture texture reference + */ + private generateMipmap(texture: Texture) { + let mipmap: number = 1; + while (mipmap < this.mipmapCount) { + this.generateMipmapAtLevel(mipmap, texture); + mipmap++; + } + } + + /** + * @private Generate a specified level of Mipmap + * @param mipmap mipmap level + * @param erpTexture ERP Texture Object + * @param pow power + */ + private generateMipmapAtLevel(mipmap: number, erpTexture: Texture, pow: number = 3.0): void { + let mipFaceSize = this.width / Math.pow(2, mipmap); + let image = { width: mipFaceSize, height: mipFaceSize, erpTexture: erpTexture }; + let roughness = (mipmap + 1) / this.mipmapCount; + roughness = Math.pow(roughness, pow); + let gpuSource = this.getGpuSource(mipmap); + IBLEnvMapCreator.importantSample(image, mipFaceSize, roughness, gpuSource.v); + } + +} diff --git a/src/engine/textures/SolidColorSky.ts b/src/engine/textures/SolidColorSky.ts new file mode 100644 index 00000000..bbf4f56e --- /dev/null +++ b/src/engine/textures/SolidColorSky.ts @@ -0,0 +1,53 @@ +import { Color } from '../math/Color'; +import { defaultRes } from './DefaultRes'; +import { Float16ArrayTexture } from './Float16ArrayTexture'; +import { HDRTextureCube } from './HDRTextureCube'; + +/** + * create a cube texture, which filled by solid color. + * @group Texture + */ +export class SolidColorSky extends HDRTextureCube { + private _internalTexture: Float16ArrayTexture; + private readonly _minSize = 32; + private _skyColor: Color; + + + /** + * create a cube texture, which filled by solid color. + * @param color solid color + * @returns + */ + constructor(color: Color) { + super(); + this._skyColor = color; + this._internalTexture = new Float16ArrayTexture(); + let numbers = []; + defaultRes.fillColor(numbers, this._minSize, this._minSize, this.color.r, this.color.g, this.color.b, this.color.a); + this._internalTexture.create(this._minSize, this._minSize, numbers, false); + this.createFromTexture(this._minSize, this._internalTexture); + return this; + } + + private changeColor(color: Color): this { + this._skyColor = color; + defaultRes.fillColor(this._internalTexture.floatArray, this._minSize, this._minSize, this.color.r, this.color.g, this.color.b, this.color.a); + this._internalTexture.updateTexture(this._minSize, this._minSize, this._internalTexture.floatArray, false); + this.uploadTexture(0, this._internalTexture); + return this; + } + + public get color(): Color { + return this._skyColor; + } + + /** + * change solid color + * @param value target color + * @returns + */ + public set color(value: Color) { + this.changeColor(value); + } + +} diff --git a/src/engine/textures/Uint16Texture.ts b/src/engine/textures/Uint16Texture.ts new file mode 100644 index 00000000..128e58e6 --- /dev/null +++ b/src/engine/textures/Uint16Texture.ts @@ -0,0 +1,72 @@ +import { GPUContext } from '../..'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { TextureMipmapGenerator } from '../gfx/graphics/webGpu/core/texture/TextureMipmapGenerator'; +import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +/** + * @internal + * Uint16 texture + * @group Texture + */ +export class Uint16Texture extends Texture { + + /** + * create texture by number array, which format is uint8 + * @param width width of texture + * @param height height of texture + * @param data uint8 array + * @param useMipmap whether or not gen mipmap + * @returns + */ + public create(width: number, height: number, data: Float32Array, useMiamp: boolean = true) { + let device = webGPUContext.device; + const bytesPerRow = width * 4 * 4; + this.format = GPUTextureFormat.rgba16float; + + this.mipmapCount = Math.floor(useMiamp ? Math.log2(width) : 1); + this.createTextureDescriptor(width, height, this.mipmapCount, this.format); + + const textureDataBuffer = device.createBuffer({ + size: data.byteLength, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, + }); + + device.queue.writeBuffer(textureDataBuffer, 0, data); + const commandEncoder = GPUContext.beginCommandEncoder(); + commandEncoder.copyBufferToTexture( + { + buffer: textureDataBuffer, + bytesPerRow: bytesPerRow, + }, + { + texture: this.getGPUTexture(), + }, + { + width: width, + height: height, + depthOrArrayLayers: 1, + }, + ); + + GPUContext.endCommandEncoder(commandEncoder); + + this.minFilter = `nearest`; + this.magFilter = `nearest`; + this.mipmapFilter = `nearest`; + this.samplerBindingLayout.type = `non-filtering`; + this.textureBindingLayout.sampleType = `unfilterable-float`; + + // not suport float this + this.minFilter = `linear`; + this.magFilter = `linear`; + this.mipmapFilter = `nearest`; + this.samplerBindingLayout.type = `filtering`; + this.textureBindingLayout.sampleType = `float`; + this.gpuSampler = device.createSampler(this); + + if (this.mipmapCount > 1) { + TextureMipmapGenerator.webGPUGenerateMipmap(this); + } + } + +} diff --git a/src/engine/textures/Uint8ArrayTexture.ts b/src/engine/textures/Uint8ArrayTexture.ts new file mode 100644 index 00000000..e72b1b16 --- /dev/null +++ b/src/engine/textures/Uint8ArrayTexture.ts @@ -0,0 +1,99 @@ +import { GPUContext } from '../..'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { TextureMipmapGenerator } from '../gfx/graphics/webGpu/core/texture/TextureMipmapGenerator'; +import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; + +/** + * create texture by number array, which format is uint8 + * @group Texture + */ +export class Uint8ArrayTexture extends Texture { + private _dataBuffer: GPUBuffer; + + /** + * create texture by number array, which format is uint8 + * @param width width of texture + * @param height height of texture + * @param data uint8 array + * @param useMipmap whether or not gen mipmap + * @returns + */ + public create(width: number, height: number, data: Uint8Array, useMipmap: boolean = false): this { + let device = webGPUContext.device; + const bytesPerRow = Math.ceil((width * 4) / 256) * 256; + + this.format = GPUTextureFormat.rgba8unorm; + this.mipmapCount = Math.floor(useMipmap ? Math.log2(width) : 1); + this.createTextureDescriptor(width, height, this.mipmapCount, this.format); + + const textureDataBuffer = (this._dataBuffer = device.createBuffer({ + size: data.byteLength, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, + })); + + device.queue.writeBuffer(textureDataBuffer, 0, data); + const commandEncoder = GPUContext.beginCommandEncoder(); + commandEncoder.copyBufferToTexture( + { + buffer: textureDataBuffer, + bytesPerRow: bytesPerRow, + }, + { + texture: this.getGPUTexture(), + }, + { + width: width, + height: height, + depthOrArrayLayers: 1, + }, + ); + + GPUContext.endCommandEncoder(commandEncoder); + + if (useMipmap) { + TextureMipmapGenerator.webGPUGenerateMipmap(this); + } + return this; + } + + /** + * validate the change of this texture + */ + public updateTexture(width: number, height: number, data: Uint8Array) { + let device = webGPUContext.device; + const bytesPerRow = Math.ceil((width * 4) / 256) * 256; + this.mipmapCount = Math.floor(true ? Math.log2(width) : 1); + + this._dataBuffer && this._dataBuffer.destroy(); + this._dataBuffer = null; + const textureDataBuffer = (this._dataBuffer = device.createBuffer({ + size: data.byteLength, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, + })); + + device.queue.writeBuffer(textureDataBuffer, 0, data); + const commandEncoder = GPUContext.beginCommandEncoder(); + commandEncoder.copyBufferToTexture( + { + buffer: textureDataBuffer, + bytesPerRow: bytesPerRow, + }, + { + texture: this.getGPUTexture(), + }, + { + width: width, + height: height, + depthOrArrayLayers: 1, + }, + ); + + GPUContext.endCommandEncoder(commandEncoder); + this.gpuSampler = device.createSampler(this); + + if (this.mipmapCount > 1) { + TextureMipmapGenerator.webGPUGenerateMipmap(this); + } + } +} From b92c8b4d739c7c015db26d6ec9833fa510de40b3 Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Mon, 24 Apr 2023 14:22:24 +0800 Subject: [PATCH 030/100] feat(shader): add shader module (#38) add glsl to wgsl converter add wgsl preprocessor --- .../shader/anim/SkeletonAnimation_shader.ts | 51 + .../compute/BlurEffectCreator_compute.ts | 100 + .../gfx/graphics/webGpu/shader/ShaderStage.ts | 8 + .../webGpu/shader/converter/GLSLLexer.ts | 443 ++++ .../webGpu/shader/converter/GLSLLexerToken.ts | 425 ++++ .../shader/converter/GLSLPreprocessor.ts | 212 ++ .../webGpu/shader/converter/GLSLSyntax.ts | 123 ++ .../webGpu/shader/converter/Reader.ts | 154 ++ .../shader/converter/ShaderConverter.ts | 78 + .../webGpu/shader/converter/StatementNode.ts | 1886 +++++++++++++++++ .../webGpu/shader/converter/WGSLTranslator.ts | 293 +++ .../webGpu/shader/util/MorePassParser.ts | 139 ++ .../webGpu/shader/util/Preprocessor.ts | 225 ++ .../graphics/webGpu/shader/util/ShaderUtil.ts | 29 + 14 files changed, 4166 insertions(+) create mode 100644 src/engine/assets/shader/anim/SkeletonAnimation_shader.ts create mode 100644 src/engine/assets/shader/compute/BlurEffectCreator_compute.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/ShaderStage.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/converter/GLSLLexer.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/converter/GLSLLexerToken.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/converter/GLSLPreprocessor.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/converter/GLSLSyntax.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/converter/Reader.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/converter/ShaderConverter.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/converter/StatementNode.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/converter/WGSLTranslator.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/util/MorePassParser.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/util/Preprocessor.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/util/ShaderUtil.ts diff --git a/src/engine/assets/shader/anim/SkeletonAnimation_shader.ts b/src/engine/assets/shader/anim/SkeletonAnimation_shader.ts new file mode 100644 index 00000000..0ca8faa5 --- /dev/null +++ b/src/engine/assets/shader/anim/SkeletonAnimation_shader.ts @@ -0,0 +1,51 @@ +export class SkeletonAnimation_shader { + public static groupBindingAndFunctions(beginGroup: number, beginBinding: number) { + return /* wgsl */ ` + struct JointsMatrix { + matrix : array> + }; + + @group(${beginGroup}) @binding(${beginBinding}) + var jointsMatrixIndexTable: array; + + @group(${beginGroup}) @binding(${beginBinding+1}) + var jointsInverseMatrix: JointsMatrix; + + @group(${beginGroup}) @binding(${beginBinding+2}) + var jointsIndexMapingTable: array; + + const MAX_JOINT_NUM = 8; + fn getSkeletonWorldMatrix(joints: array, weights: array, num: u32) -> mat4x4 { + var result: mat4x4; + for(var i: u32 = 0; i < num; i = i + 1) { + let jointId = i32(joints[i]); + let jointIndex = u32(jointsIndexMapingTable[jointId]); + let jointMatrixIndex = u32(jointsMatrixIndexTable[jointIndex]); + let joint = models.matrix[jointMatrixIndex] * jointsInverseMatrix.matrix[jointId] * weights[i]; + result += joint; + } + return result; + } + + fn getSkeletonWorldMatrix_4(joints: vec4, weights: vec4) -> mat4x4 { + return getSkeletonWorldMatrix(array( + joints.x, joints.y, joints.z, joints.w, + 0, 0, 0, 0, + ), array( + weights.x, weights.y, weights.z, weights.w, + 0, 0, 0, 0, + ), 4); + } + + fn getSkeletonWorldMatrix_8(joints0: vec4, weights0: vec4, joints1: vec4, weights1: vec4) -> mat4x4 { + return getSkeletonWorldMatrix(array( + joints0.x, joints0.y, joints0.z, joints0.w, + joints1.x, joints1.y, joints1.z, joints1.w, + ), array( + weights0.x, weights0.y, weights0.z, weights0.w, + weights1.x, weights1.y, weights1.z, weights1.w, + ), 8); + } + `; + } +} diff --git a/src/engine/assets/shader/compute/BlurEffectCreator_compute.ts b/src/engine/assets/shader/compute/BlurEffectCreator_compute.ts new file mode 100644 index 00000000..ec336c78 --- /dev/null +++ b/src/engine/assets/shader/compute/BlurEffectCreator_compute.ts @@ -0,0 +1,100 @@ +/** + * @internal + */ +export class BlurEffectCreator_compute { + public static sample_rgba8unorm = /* wgsl */` + + struct ImageSize { + srcWidth : i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32, + }; + + @group(0) @binding(0) var size : ImageSize; + @group(0) @binding(1) var inputTexture : texture_2d; + @group(0) @binding(2) var outputTexture : texture_storage_2d; + + @compute @workgroup_size(8, 8, 1) + fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + var uv:vec2 = vec2(f32(GlobalInvocationID.x) / f32(size.dstWidth), f32(GlobalInvocationID.y) / f32(size.dstHeight)); + uv = uv * vec2(f32(size.srcWidth), f32(size.srcHeight)); + var dstId:vec2 = vec2(i32(GlobalInvocationID.x), i32(GlobalInvocationID.y)); + var srcId:vec2 = vec2(i32(GlobalInvocationID.x * 2u), i32(GlobalInvocationID.y * 2u)); + textureStore(outputTexture, dstId, textureLoad(inputTexture, srcId, 0)); + } + `; + + public static blur_rgba8unorm = /* wgsl */ ` + + struct ImageSize { + srcWidth : i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32, + }; + + @group(0) @binding(0) var size : ImageSize; + @group(0) @binding(1) var inputTexture : texture_2d; + @group(0) @binding(2) var outputTexture : texture_storage_2d; + + fn repeat_i32(id:i32, max:i32) -> i32 { + var ret = id; + if(id < 0) { + ret = max + id; + } + if(id >= max) { + ret = id - max; + } + return ret; + } + + fn clamp_i32(id:i32, max:i32) -> i32 { + var ret = id; + if(id < 0) { + ret = 0; + } + if(id >= max) { + ret = max - 1; + } + return ret; + } + + fn blur(idx:u32) -> vec4 { + var id:vec2; + id.y = i32(idx) / size.srcWidth; + id.x = i32(idx) - i32(id.y) * size.srcWidth; + var _BlurSpread:i32 = 1; + var result = vec4(0.0, 0.0, 0.0, 0.0); + let g:array = array(0.4026, 0.2442, 0.0545); + var uv:vec2; + for (var h:i32 = 0; h < 5; h = h + 1) { + let offsetU:i32 = (h - 2) * _BlurSpread; + uv.x = id.x + offsetU; + uv.x = clamp_i32(uv.x, size.srcWidth); + for (var v:i32 = 0; v < 5; v = v + 1) { + let offsetV:i32 = (v - 2) * _BlurSpread; + uv.y = id.y + offsetV; + uv.y = clamp(uv.y, 0, size.srcHeight); + let weightU:i32 = abs(h - 2); + let weightV:i32 = abs(v - 2); + let resultWeight:f32 = g[weightU] * g[weightV]; + var colorf32:vec4 = textureLoad(inputTexture, uv, 0); + let sampleColor:vec4 = vec4(colorf32 * resultWeight); + result = result + sampleColor; + } + } + + return result; + } + + @compute @workgroup_size(8, 8, 1) + fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + var uv:vec2 = vec2(f32(GlobalInvocationID.x) / f32(size.dstWidth), f32(GlobalInvocationID.y) / f32(size.dstHeight)); + uv = uv * vec2(f32(size.srcWidth), f32(size.srcHeight)); + let srcIdx = i32(uv.y) * size.srcWidth + i32(uv.x); + var dstId:vec2 = vec2(i32(GlobalInvocationID.x), i32(GlobalInvocationID.y)); + textureStore(outputTexture, dstId, blur(u32(srcIdx))); + } +`; +} diff --git a/src/engine/gfx/graphics/webGpu/shader/ShaderStage.ts b/src/engine/gfx/graphics/webGpu/shader/ShaderStage.ts new file mode 100644 index 00000000..d1145c87 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/ShaderStage.ts @@ -0,0 +1,8 @@ +/** +* @internal +*/ +export enum ShaderStage { + vertex, + fragment, + computer, +} diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/GLSLLexer.ts b/src/engine/gfx/graphics/webGpu/shader/converter/GLSLLexer.ts new file mode 100644 index 00000000..42442397 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/converter/GLSLLexer.ts @@ -0,0 +1,443 @@ +import { GLSLLexerToken, TokenType } from './GLSLLexerToken'; +import { GLSLPreprocessor } from './GLSLPreprocessor'; +import { Reader } from './Reader'; + +/** + * @internal + * GLSL Code Lexical Analyzer + * @group GFX + */ +export class GLSLLexer extends Reader { + private _tokenPosition: number = 0; + private _tokens: Array = []; + + constructor(input: GLSLPreprocessor) { + super(input.source); + this.parse(); + } + + public skipToken(offset: number) { + this._tokenPosition += offset; + } + + public peekToken(offset: number): GLSLLexerToken { + if (this._tokenPosition + offset >= this._tokens.length) { + return new GLSLLexerToken(TokenType.EOF, '\0'); + } + return this._tokens[this._tokenPosition + offset]; + } + + public GetNextToken(): GLSLLexerToken { + if (this._tokenPosition >= this._tokens.length) { + return new GLSLLexerToken(TokenType.EOF, '\0'); + } + let result = this._tokens[this._tokenPosition]; + this._tokenPosition++; + return result; + } + + public get currTokenPosition(): number { + return this._tokenPosition; + } + + // start to parse + private parse() { + this.readChar(); + this._tokens = new Array(); + var token: GLSLLexerToken; + do { + token = this.nextToken(); + this._tokens.push(token); + } while (token.Type != TokenType.EOF); + } + + // get next token + private nextToken(): GLSLLexerToken { + this.skipWhitespace(); + + // ignore code annotation + if (this._char === '/') { + // code annotation for single line + if (this.peekChar() === '/') { + this.skipComment(); + return this.nextToken(); + } + + // code annotation of multiple line + if (this.peekChar() === '*') { + this.skipMultilineComment(); + return this.nextToken(); + } + } + + var token = new GLSLLexerToken(); + token.Line = this._line; + token.Colume = this._column; + switch (this._char) { + case '\0': + token.Type = TokenType.EOF; + token.Literal = 'EOF'; + break; + case '.': + token.Type = TokenType.DOT; + token.Literal = '.'; + break; + case ',': + token.Type = TokenType.COMMA; + token.Literal = ','; + break; + case ':': + token.Type = TokenType.COLON; + token.Literal = ':'; + break; + case '?': + token.Type = TokenType.QUEMARK; + token.Literal = '?'; + break; + case ';': + token.Type = TokenType.SEMICOLON; + token.Literal = ';'; + break; + case '(': + token.Type = TokenType.LEFTSAMLL; + token.Literal = '('; + break; + case ')': + token.Type = TokenType.RIGHTSAMLL; + token.Literal = ')'; + break; + case '[': + token.Type = TokenType.LEFTMEDI; + token.Literal = '['; + break; + case ']': + token.Type = TokenType.RIGHTMEDI; + token.Literal = ']'; + break; + case '{': + token.Type = TokenType.LEFTBIG; + token.Literal = '{'; + break; + case '}': + token.Type = TokenType.RIGHTBIG; + token.Literal = '}'; + break; + case '+': + if (this.peekChar() === '+') { + this.readChar(); + token.Type = TokenType.INC; + token.Literal = '++'; + break; + } else if (this.peekChar() === '=') { + this.readChar(); + token.Type = TokenType.ADDASSIGN; + token.Literal = '+='; + break; + } + token.Type = TokenType.ADD; + token.Literal = '+'; + break; + case '-': + if (this.peekChar() === '-') { + this.readChar(); + token.Type = TokenType.DEC; + token.Literal = '--'; + break; + } else if (this.peekChar() === '=') { + this.readChar(); + token.Type = TokenType.SUBASSIGN; + token.Literal = '-='; + break; + } + token.Type = TokenType.SUB; + token.Literal = '-'; + break; + case '*': + if (this.peekChar() === '=') { + this.readChar(); + token.Type = TokenType.MULASSIGN; + token.Literal = '*='; + break; + } + token.Type = TokenType.MUL; + token.Literal = '*'; + break; + case '/': + if (this.peekChar() === '=') { + this.readChar(); + token.Type = TokenType.DIVASSIGN; + token.Literal = '/='; + break; + } + token.Type = TokenType.DIV; + token.Literal = '/'; + break; + case '&': + if (this.peekChar() === '&') { + this.readChar(); + token.Type = TokenType.AND; + token.Literal = '&&'; + break; + } + token.Type = TokenType.BITAND; + token.Literal = '&'; + break; + case '|': + if (this.peekChar() === '|') { + this.readChar(); + token.Type = TokenType.OR; + token.Literal = '||'; + break; + } + token.Type = TokenType.BITOR; + token.Literal = '&'; + break; + case '^': + token.Type = TokenType.BITXOR; + token.Literal = '^'; + break; + case '!': + if (this.peekChar() === '=') { + this.readChar(); + token.Type = TokenType.NOTEQUAL; + token.Literal = '!='; + break; + } + token.Type = TokenType.NOT; + token.Literal = '!'; + break; + case '>': + if (this.peekChar() === '=') { + this.readChar(); + token.Type = TokenType.GREATEREQUAL; + token.Literal = '>='; + break; + } else if (this.peekChar() === '>') { + this.readChar(); + token.Type = TokenType.BITSHIFT_R; + token.Literal = '>>'; + break; + } + token.Type = TokenType.GREATER; + token.Literal = '>'; + break; + case '=': + if (this.peekChar() === '=') { + this.readChar(); + token.Type = TokenType.EQUAL; + token.Literal = '=='; + break; + } + token.Type = TokenType.ASSIGN; + token.Literal = '='; + break; + case '<': + if (this.peekChar() === '=') { + this.readChar(); + token.Type = TokenType.LESSEQUAL; + token.Literal = '<='; + break; + } else if (this.peekChar() === '<') { + this.readChar(); + token.Type = TokenType.BITSHIFT_L; + token.Literal = '<<'; + break; + } + token.Type = TokenType.LESS; + token.Literal = '<'; + break; + default: + if (this.isDigit(this._char)) { + return this.readDecimal(); + } + token.Literal = this.readIdentifier(); + token.Type = this.lookupIdentifier(token.Literal); + + if (this.getChar() == '[' && this.peekChar() == ']' && token.isBuiltinType()) { + token.Type++; + token.Literal += '[]'; + this.readChar(); + this.readChar(); + } + + return token; + } + + this.readChar(); + return token; + } + + // read dicimal + private readDecimal(): GLSLLexerToken { + var token = new GLSLLexerToken(); + token.Line = this._line; + token.Colume = this._column; + token.Type = TokenType.LITERAL; + var integer = this.readNumber(); + + if (this._char === 'e') { + token.Literal = integer + this._char; + this.readChar(); + token.Literal += this._char; + this.readChar(); + token.Literal += this.readNumber(); + token.Type = TokenType.LITERAL; // TokenType.FLOAT; + return token; + } + + if (this._char === 'u') { + this.readChar(); + token.Type = TokenType.LITERAL; // TokenType.UINT; + token.Literal = integer + 'u'; + return token; + } + + if (this._char === 'f') { + this.readChar(); + token.Type = TokenType.LITERAL; // TokenType.FLOAT; + token.Literal = integer + 'f'; + return token; + } + + token.Type = TokenType.LITERAL; // TokenType.INT; + token.Literal = integer; + return token; + } + + private lookupIdentifier(literal: string): TokenType { + switch (literal) { + case 'void': + return TokenType.VOID; + case 'int': + return TokenType.INT; + case 'uint': + return TokenType.UINT; + case 'bool': + return TokenType.BOOL; + case 'true': + return TokenType.BOOL; + case 'false': + return TokenType.BOOL; + case 'float': + return TokenType.FLOAT; + case 'vec2': + return TokenType.VEC2; + case 'vec3': + return TokenType.VEC3; + case 'vec4': + return TokenType.VEC4; + case 'bvec2': + return TokenType.BVEC2; + case 'bvec3': + return TokenType.BVEC3; + case 'bvec4': + return TokenType.BVEC4; + case 'ivec2': + return TokenType.IVEC2; + case 'ivec3': + return TokenType.IVEC3; + case 'ivec4': + return TokenType.IVEC4; + case 'uvec2': + return TokenType.UVEC2; + case 'uvec3': + return TokenType.UVEC3; + case 'uvec4': + return TokenType.UVEC4; + case 'mat2': + return TokenType.MAT2x2; + case 'mat2x2': + return TokenType.MAT2x2; + case 'mat2x3': + return TokenType.MAT2x3; + case 'mat2x4': + return TokenType.MAT2x4; + case 'mat3': + return TokenType.MAT3x3; + case 'mat3x2': + return TokenType.MAT3x2; + case 'mat3x3': + return TokenType.MAT3x3; + case 'mat3x4': + return TokenType.MAT3x4; + case 'mat4': + return TokenType.MAT4x4; + case 'mat4x2': + return TokenType.MAT4x2; + case 'mat4x3': + return TokenType.MAT4x3; + case 'mat4x4': + return TokenType.MAT4x4; + case 'sampler': + return TokenType.SAMPLER; + case 'sampler1D': + return TokenType.SAMPLER_1D; + case 'sampler2D': + return TokenType.SAMPLER_2D; + case 'sampler3D': + return TokenType.SAMPLER_3D; + case 'samplerCube': + return TokenType.SAMPLER_CUBE; + case 'samplerShadow': + return TokenType.SAMPLER_SHADOW; + case 'sampler1DShadow': + return TokenType.SAMPLER_1D_SHADOW; + case 'sampler2DShadow': + return TokenType.SAMPLER_2D_SHADOW; + case 'texture1D': + return TokenType.TEXTURE_1D; + case 'texture2D': + return TokenType.TEXTURE_2D; + case 'texture3D': + return TokenType.TEXTURE_3D; + case 'textureCube': + return TokenType.TEXTURE_CUBE; + case 'texture1DArray': + return TokenType.TEXTURE_1D_ARRAY; + case 'texture2DArray': + return TokenType.TEXTURE_2D_ARRAY; + case 'textureCubeArray': + return TokenType.TEXTURE_CUBE_ARRAY; + + case 'const': + return TokenType.CONST; + case 'layout': + return TokenType.LAYOUT; + case 'precision': + return TokenType.PRECISION; + case 'attribute': + return TokenType.ATTRIBUTE; + case 'uniform': + return TokenType.UNIFORM; + case 'varying': + return TokenType.VARYING; + case 'invariant': + return TokenType.INVARIANT; + case 'in': + return TokenType.IN; + case 'out': + return TokenType.OUT; + case 'inout': + return TokenType.INOUT; + case 'if': + return TokenType.IF; + case 'else': + return TokenType.ELSE; + case 'for': + return TokenType.FOR; + case 'while': + return TokenType.WHILE; + case 'do': + return TokenType.DO; + case 'break': + return TokenType.BREAK; + case 'return': + return TokenType.RETURN; + case 'continue': + return TokenType.CONTINUE; + case 'struct': + return TokenType.STRUCT; + } + return TokenType.IDENT; + } +} diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/GLSLLexerToken.ts b/src/engine/gfx/graphics/webGpu/shader/converter/GLSLLexerToken.ts new file mode 100644 index 00000000..3906db88 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/converter/GLSLLexerToken.ts @@ -0,0 +1,425 @@ +/** + * @internal + * @group GFX + */ +export class GLSLLexerToken { + public Type: TokenType = 0; + public Line: number = 0; + public Colume: number = 0; + public Literal: string = ''; + constructor(type: TokenType = TokenType.EOF, literal: string = '\0') { + this.Type = type; + this.Literal = literal; + } + + /** + * @returns determin the type is same to token + */ + public isTypeEqual(type: TokenType): boolean { + return this.Type == type; + } + + /** + * @returns determin the value is same + */ + public isLiteralEqual(literal: string): boolean { + return this.Literal == literal; + } + + /** + * @returns determin it's builtin type + */ + public isBuiltinType(): boolean { + return this.Type > TokenType.BeginBuiltinType && this.Type < TokenType.EndBuiltinType; + } + + /** + * @returns determin it's a data type + */ + public isDataType(): boolean { + return this.Type == TokenType.IDENT || this.isBuiltinType(); + } + + /** + * @returns determin it's a operation + */ + public isOperation(): boolean { + return this.Type > TokenType.BeginOperation && this.Type < TokenType.EndOperation; + } + + /** + * @returns determin it's a assign operation + */ + public isAssignOperation(): boolean { + return this.Type > TokenType.BeginAssignOperation && this.Type < TokenType.EndAssignOperation; + } + + /** + * The priority of the current operator + */ + public get nOperationPriorityLevel(): number { + switch (this.Type) { + case TokenType.LEFTSAMLL: + return 1; + case TokenType.RIGHTSAMLL: + return 1; + + case TokenType.DOT: + return 2; + + case TokenType.NOT: + return 3; + case TokenType.BITNOT: + return 3; + + case TokenType.MUL: + return 4; + case TokenType.DIV: + return 4; + + case TokenType.ADD: + return 5; + case TokenType.SUB: + return 5; + + case TokenType.BITSHIFT_L: + return 6; + case TokenType.BITSHIFT_R: + return 6; + + case TokenType.GREATER: + return 7; + case TokenType.GREATEREQUAL: + return 7; + case TokenType.LESS: + return 7; + case TokenType.LESSEQUAL: + return 7; + + case TokenType.EQUAL: + return 8; + case TokenType.NOTEQUAL: + return 8; + + case TokenType.BITAND: + return 9; + + case TokenType.BITXOR: + return 10; + + case TokenType.BITOR: + return 11; + + case TokenType.AND: + return 12; + + case TokenType.XOR: + return 13; + + case TokenType.OR: + return 14; + + case TokenType.QUEMARK: + return 15; + + case TokenType.ASSIGN: + return 16; + case TokenType.ADDASSIGN: + return 16; + case TokenType.SUBASSIGN: + return 16; + case TokenType.MULASSIGN: + return 16; + case TokenType.DIVASSIGN: + return 16; + } + + return 99; + } +} + +/** + * @internal + */ +export enum TokenType { + // end-of-file + EOF, + // identifier + IDENT, + // void + VOID, + // const + CONST, + // layout + LAYOUT, + // precision + PRECISION, + // attribute + ATTRIBUTE, + // uniform + UNIFORM, + // varying + VARYING, + // invariant + INVARIANT, + // in + IN, + // out + OUT, + // inout + INOUT, + // if + IF, + // else + ELSE, + // for + FOR, + // while + WHILE, + // do + DO, + // break + BREAK, + // return + RETURN, + // continue + CONTINUE, + // struct + STRUCT, + + // , + COMMA, + // : + COLON, + // ? + QUEMARK, + // ; + SEMICOLON, + // ( + LEFTSAMLL, + // ) + RIGHTSAMLL, + // [ + LEFTMEDI, + // ] + RIGHTMEDI, + // { + LEFTBIG, + // } + RIGHTBIG, + + // Literal value + LITERAL, + + // built-in type begin + BeginBuiltinType, + // built-in type: int + INT, + // built-in type: int[] + INT_ARRAY, + // built-in type: uint + UINT, + // built-in type: uint[] + UINT_ARRAY, + // built-in type:bool + BOOL, + // built-in type:bool[] + BOOL_ARRAY, + // built-in type:float + FLOAT, + // built-in type:float[] + FLOAT_ARRAY, + // built-in type:double + DOUBLE, + // built-in type:double[] + DOUBLE_ARRAY, + // built-in type:vec2 + VEC2, + // built-in type:vec2[] + VEC2_ARRAY, + // built-in type:vec3 + VEC3, + // built-in type:vec3[] + VEC3_ARRAY, + // built-in type:vec4 + VEC4, + // built-in type:vec4[] + VEC4_ARRAY, + // built-in type:bvec2 + BVEC2, + // built-in type:bvec2[] + BVEC2_ARRAY, + // built-in type:bvec3 + BVEC3, + // built-in type:bvec3[] + BVEC3_ARRAY, + // built-in type:bvec4 + BVEC4, + // built-in type:bvec4[] + BVEC4_ARRAY, + // built-in type:ivec2 + IVEC2, + // built-in type:ivec2[] + IVEC2_ARRAY, + // built-in type:ivec3 + IVEC3, + // built-in type:ivec3[] + IVEC3_ARRAY, + // built-in type:ivec4 + IVEC4, + // built-in type:ivec4[] + IVEC4_ARRAY, + // built-in type:uvec2 + UVEC2, + // built-in type:uvec2[] + UVEC2_ARRAY, + // built-in type:uvec3 + UVEC3, + // built-in type:uvec3[] + UVEC3_ARRAY, + // built-in type:uvec4 + UVEC4, + // built-in type:uvec4[] + UVEC4_ARRAY, + // built-in type: mat2x2 + MAT2x2, + // built-in type: mat2x2[] + MAT2x2_ARRAY, + // built-in type: mat2x3 + MAT2x3, + // built-in type: mat2x3[] + MAT2x3_ARRAY, + // built-in type: mat2x4 + MAT2x4, + // built-in type: mat2x4[] + MAT2x4_ARRAY, + // built-in type: mat3x2 + MAT3x2, + // built-in type: mat3x2[] + MAT3x2_ARRAY, + // built-in type: mat3x3 + MAT3x3, + // built-in type: mat3x3[] + MAT3x3_ARRAY, + // built-in type: mat3x4 + MAT3x4, + // built-in type: mat3x4[] + MAT3x4_ARRAY, + // built-in type: mat4x2 + MAT4x2, + // built-in type: mat4x2[] + MAT4x2_ARRAY, + // built-in type: mat4x3 + MAT4x3, + // built-in type: mat4x3[] + MAT4x3_ARRAY, + // built-in type: mat4x4 + MAT4x4, + // built-in type: mat4x4[] + MAT4x4_ARRAY, + // built-in type: sampler + SAMPLER, + // built-in type: sampler1D + SAMPLER_1D, + // built-in type: sampler2D + SAMPLER_2D, + // built-in type: sampler3D + SAMPLER_3D, + // built-in type: samplerCube + SAMPLER_CUBE, + // built-in type: samplerShadow + SAMPLER_SHADOW, + // built-in type: sampler1DShadow + SAMPLER_1D_SHADOW, + // built-in type: sampler2DShadow + SAMPLER_2D_SHADOW, + // built-in type:texture1D + TEXTURE_1D, + // built-in type:texture1DArray + TEXTURE_1D_ARRAY, + // built-in type:texture2D + TEXTURE_2D, + // built-in type:texture2DArray + TEXTURE_2D_ARRAY, + // built-in type:texture3D + TEXTURE_3D, + // built-in type: textureCube + TEXTURE_CUBE, + // built-in type: textureCubeArray + TEXTURE_CUBE_ARRAY, + // built-in type end + EndBuiltinType, + + // operator begin + BeginOperation, + + // operator + + ADD, + // operator - + SUB, + // operator * + MUL, + // operator / + DIV, + + // operator && + AND, + // operator || + OR, + // operator ^^ + XOR, + // operator ! + NOT, + + // operator & + BITAND, + // operator | + BITOR, + // operator ^ + BITXOR, + // operator ~ + BITNOT, + // operator << + BITSHIFT_L, + // operator >> + BITSHIFT_R, + + // operator ++ + INC, + // operator -- + DEC, + // operator > + GREATER, + // operator >= + GREATEREQUAL, + // operator == + EQUAL, + // operator < + LESS, + // operator <= + LESSEQUAL, + // operator != + NOTEQUAL, + + // operator . + DOT, + + // operator = + ASSIGN, + + // operator end + EndOperation, + + // assigning operator begin + BeginAssignOperation, + // operator += + ADDASSIGN, + // operator -= + SUBASSIGN, + // operator *= + MULASSIGN, + // operator /= + DIVASSIGN, + // assigning operator end + EndAssignOperation, +} diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/GLSLPreprocessor.ts b/src/engine/gfx/graphics/webGpu/shader/converter/GLSLPreprocessor.ts new file mode 100644 index 00000000..4c24644a --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/converter/GLSLPreprocessor.ts @@ -0,0 +1,212 @@ +import { Reader } from './Reader'; +/** + * @internal + */ +class MacroSubstitution { + public name: string = ''; + public value: string = ''; + public args: Array = []; +} + +/** + * @internal + * GLSL code preprocessor + * @group GFX + */ +export class GLSLPreprocessor extends Reader { + private _result: string; + private _skipLine: boolean; + private _definitionTables: Map; + + constructor(source: string) { + super(source); + this._result = ''; + this._skipLine = false; + this._definitionTables = new Map(); + this.parse(); + } + + private parse() { + this.readChar(); + while (this._char !== '\0') { + this.skipWhitespace(); + + // Skip the comments + if (this._char === '/') { + // Skip single-line comments + if (this.peekChar() === '/') { + this.skipComment(); + continue; + } + // Skip multi-line comments + if (this.peekChar() === '*') { + this.skipMultilineComment(); + continue; + } + } + + // Preprocessing command + if (this._char === '#') { + this.readCharAndSkipWhitespace(); + var name = this.readIdentifier(); + switch (name) { + case 'version': + let version = this.readLine().trim(); + break; + case 'define': + this.readCharAndSkipWhitespace(); + var defineName = this.readIdentifier(); + if (this.getChar() === '(') { + let macro = new MacroSubstitution(); + this.readCharAndSkipWhitespace(); + if (this.getChar() !== ')') { + do { + var argName = this.readIdentifier(); + macro.args.push(argName); + this.skipWhitespace(); + if (this.getChar() === ',') { + this.readCharAndSkipWhitespace(); + continue; + } + } while (this.getChar() !== ')'); + } + this.readCharAndSkipWhitespace(); + macro.name = defineName; + macro.value = this.readLine().trim(); + this._definitionTables.set(defineName, macro); + this.readCharAndSkipWhitespace(); + } else { + let defineValue = this.readLine().trim(); + if (defineValue[0] == '=') { + defineValue = defineValue.substring(1); + } + this._definitionTables.set(defineName, defineValue); + } + break; + case 'if': + let condition = this.readLine().trim(); + if (condition == '0' || condition == 'false') { + this._skipLine = true; + break; + } + if (this._definitionTables.has(condition)) { + condition = this._definitionTables.get(condition); + if (condition == '0' || condition == 'false') { + this._skipLine = true; + break; + } + } + break; + case 'ifdef': + this.readCharAndSkipWhitespace(); + var value = this.readIdentifier(); + this._skipLine = !this._definitionTables.has(value); + break; + case 'else': + this._skipLine = !this._skipLine; + break; + case 'endif': + this._skipLine = false; + break; + default: + throw 'Unknown preprocessing command:' + name; + } + } else { + var line = this.readLine(); + if (!this._skipLine) { + for (let key of this._definitionTables.keys()) { + let index = line.indexOf(key); + if (index != -1) { + let value = this._definitionTables.get(key); + if (typeof value === 'string') { + line = line.replace(key, value); + } else { + let macro = value as MacroSubstitution; + let reader = new Reader(line.substring(index + key.length)); + reader.readCharAndSkipWhitespace(); + if (reader.getChar() === '(') { + reader.readCharAndSkipWhitespace(); + for (let count = 1; reader.getChar() !== '\0' && count > 0;) { + switch (reader.getChar()) { + case '(': + count++; + break; + case ')': + count--; + break; + } + reader.readCharAndSkipWhitespace(); + } + } + + let nBeginPos = index; + let nEndPos = nBeginPos + key.length + reader.currPosition; + let expr = line.substring(nBeginPos, nEndPos).trim(); + + if (macro.args.length > 0) { + let args: string[] = []; + let argsStr = expr.substring(expr.indexOf('(') + 1, expr.lastIndexOf(')')).trim(); + if (argsStr.length > 0) { + args = this.parseArgs(argsStr); + } + + let macroValue = macro.value.substring(macro.value.indexOf('(')); + for (let i = 0; i < macro.args.length; i++) { + macroValue = macroValue.replace(macro.args[i], args[i]); + } + macroValue = macro.value.substring(0, macro.value.indexOf('(')) + macroValue; + + line = line.replace(expr, macroValue); + } else { + line = line.replace(expr, macro.value); + } + } + } + } + this._result += line; + } + this.readChar(); + } + } + } + + public get source(): string { + return this._result; + } + + private parseArgs(str: string): string[] { + let result: string[] = []; + let count = 0; + let reader = new Reader(str); + let position = reader.currPosition; + reader.readCharAndSkipWhitespace(); + if (reader.getChar() !== '\0') { + reader.readCharAndSkipWhitespace(); + for (; reader.getChar() !== '\0';) { + switch (reader.getChar()) { + case '(': + count++; + break; + case ')': + count--; + break; + case ',': + if (count == 0) { + let arg = str.substring(position, reader.currPosition); + result.push(arg); + position = reader.currPosition + 1; + } + break; + } + reader.readCharAndSkipWhitespace(); + } + } + + if (position < reader.currPosition) { + let arg = str.substring(position, reader.currPosition); + result.push(arg); + } + + return result; + } +} diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/GLSLSyntax.ts b/src/engine/gfx/graphics/webGpu/shader/converter/GLSLSyntax.ts new file mode 100644 index 00000000..956859c3 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/converter/GLSLSyntax.ts @@ -0,0 +1,123 @@ +import { GLSLLexer } from './GLSLLexer'; +import { GLSLLexerToken, TokenType } from './GLSLLexerToken'; +import { SN_BinaryOperation, SN_Declaration, SN_Expression, SN_Function, SN_Identifier, SN_Layout, SN_Precision, SN_Struct, StatementNode } from './StatementNode'; + +/** + * @internal + * GLSL code parser + * @group GFX + */ +export class GLSLSyntax { + private _lexer: GLSLLexer; + private _rootNode: StatementNode; + + constructor(input: GLSLLexer) { + this._lexer = input; + this._rootNode = new StatementNode(); + this.parse(); + } + + public get lexer(): GLSLLexer { + return this._lexer; + } + + private parse() { + while (this.peekToken(0).Type !== TokenType.EOF) { + if (this.peekToken(0).Type == TokenType.SEMICOLON) { + this.skipToken(1); + continue; + } + + let node = this.parseStatement(); + if (node !== null) { + this._rootNode.addNode(node); + } + } + } + + private parseStatement(): StatementNode { + let first = this.peekToken(); + + /** + * layout(location = 0) in vec2 v_Uv; + * layout(location = 0) out vec4 o_Target; + * layout(set = 1, binding = 1) uniform texture2D ColorMaterial_texture; + */ + if (first.Type == TokenType.LAYOUT && this.peekToken(1).Type == TokenType.LEFTSAMLL) { + let layoutNode = SN_Layout.parse(this._lexer); + return layoutNode; + } else if (first.Type == TokenType.STRUCT) { + /** + * Declaration of structure + */ + this.skipToken(1); + let structNode = SN_Struct.parse(this._lexer); + return structNode; + } else if ( + /** + * function declaration + */ + (first.isBuiltinType() || first.Type == TokenType.VOID) && + this.peekToken(1).Type == TokenType.IDENT && + this.peekToken(2).Type == TokenType.LEFTSAMLL + ) { + let functionDec = SN_Function.parse(this._lexer); + return functionDec; + } else if ( + /** + * Constant declaration + * const int a = ...; + */ + first.Type == TokenType.CONST && + this.peekToken(1).isDataType() + ) { + let declarationNode = SN_Declaration.parse(this._lexer); + return declarationNode; + } else if ( + /** + * Declaration of variables + * int a = ...; + */ + first.isDataType() && + this.peekToken(1).Type == TokenType.IDENT + ) { + let declarationNode = SN_Declaration.parse(this._lexer); + return declarationNode; + } else if ( + /** + * Declaration of variables + * out float a = ...; + */ + first.Type == TokenType.OUT && + this.peekToken(1).isDataType() && + this.peekToken(2).Type == TokenType.IDENT + ) { + let declarationNode = SN_Declaration.parse(this._lexer); + return declarationNode; + } else if (first.Type == TokenType.PRECISION) { + /** + * precision mediump float; + */ + let precisionNode = SN_Precision.parse(this._lexer); + return precisionNode; + } + + throw 'Error parsing statement: Unexpected character'; + } + + private skipToken(offset: number) { + this._lexer.skipToken(offset); + } + + private peekToken(offset: number = 0): GLSLLexerToken { + return this._lexer.peekToken(offset); + } + + private getNextToken(): GLSLLexerToken { + return this._lexer.GetNextToken(); + } + + public get ASTRoot(): StatementNode { + return this._rootNode; + } +} diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/Reader.ts b/src/engine/gfx/graphics/webGpu/shader/converter/Reader.ts new file mode 100644 index 00000000..e4e1ff27 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/converter/Reader.ts @@ -0,0 +1,154 @@ +/** + * @internal + * @group GFX + */ +export class Reader { + protected _char: string; + protected _line: number; + protected _column: number; + protected _source: string; + protected _currPosition: number; + protected _nextPosition: number; + + constructor(source: string) { + this.reset(source); + } + + public reset(source: string) { + this._char = ''; + this._line = 0; + this._column = 0; + this._source = source; + this._currPosition = 0; + this._nextPosition = 0; + } + + public get source(): string { + return this._source; + } + + public getChar(): string { + return this._char; + } + + public get currPosition(): number { + return this._currPosition; + } + + public peekChar(): string { + return this._nextPosition >= this._source.length ? '\0' : this._source[this._nextPosition]; + } + + public readChar() { + this._char = this._nextPosition >= this._source.length ? '\0' : this._source[this._nextPosition]; + if (this._char !== '\n') { + this._column++; + } else { + this._line++; + this._column = 0; + } + this._currPosition = this._nextPosition; + this._nextPosition++; + } + + public readCharAndSkipWhitespace() { + this.readChar(); + this.skipWhitespace(); + } + + public readIdentifier(): string { + var pos = this._currPosition; + while (this.isIdentifier(this._char)) { + this.readChar(); + } + return this._source.substring(pos, this._currPosition); + } + + public isIdentifier(char: string): boolean { + var code = char.charCodeAt(0); + // ('a' <= code && code <= 'z') || ('A' <= code && code <= 'Z') || ('0' <= code && code <= '9') || code == '_'; + return (0x61 <= code && code <= 0x7a) || (0x41 <= code && code <= 0x5a) || (0x30 <= code && code <= 0x39) || code == 0x5f; + } + + public skipWhitespace() { + while (this.IsWhitespace(this._char)) { + this.readChar(); + } + } + + public IsWhitespace(char: string): boolean { + return char === ' ' || char === '\t' || char === '\r' || char === '\n'; + } + + public skipComment() { + while (this._char !== '\n' && this._char !== '\0') { + this.readChar(); + } + this.skipWhitespace(); + } + + public skipMultilineComment() { + if (this._char !== '/' && this.peekChar() !== '*') { + return; + } + this.readChar(); + this.readChar(); + + for (let nCount: number = 1; nCount > 0 && this._char !== '\0';) { + this.readChar(); + if (this._char === '/' && this.peekChar() === '*') { + nCount++; + this.readChar(); + continue; + } else if (this._char === '*' && this.peekChar() === '/') { + nCount--; + this.readChar(); + continue; + } + } + + this.readChar(); + this.readChar(); + this.skipWhitespace(); + } + + public isDigit(char: string): boolean { + var code = char.charCodeAt(0); + // ('0' <= code && code <= '9') ; + return 0x30 <= code && code <= 0x39; + } + + public readNumber(): string { + var pos = this._currPosition; + while (this.isDigit(this._char)) { + this.readChar(); + } + if (this._char === '.') { + this.readChar(); + while (this.isDigit(this._char)) { + this.readChar(); + } + } + return this._source.substring(pos, this._currPosition); + } + + public readValue(): string { + if (this.isDigit(this._char)) { + return this.readNumber(); + } + return this.readIdentifier(); + } + + public readLine(): string { + var pos = this._currPosition; + var index = this._source.indexOf('\n', this._currPosition); + if (index == -1) { + index = this._source.length; + } + this._line++; + this._column = 0; + this._currPosition = index; + this._nextPosition = index + 1; + return this._source.substring(pos, index + 1); + } +} diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/ShaderConverter.ts b/src/engine/gfx/graphics/webGpu/shader/converter/ShaderConverter.ts new file mode 100644 index 00000000..ca0ae261 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/converter/ShaderConverter.ts @@ -0,0 +1,78 @@ +import { GLSLLexer } from './GLSLLexer'; +import { GLSLPreprocessor } from './GLSLPreprocessor'; +import { GLSLSyntax } from './GLSLSyntax'; +import { WGSLTranslator } from './WGSLTranslator'; + +/** + * @internal + * Shader converter + * @group GFX + */ +export class ShaderConverter { + /** + * Shader type: Vertex stage + */ + static VertexShader: string = 'VertexShader'; + + /** + * Shader type: Fragment stage + */ + static FragmentShader: string = 'FragmentShader'; + + /** + * Convert GLSL code to WGSL + * @param source GLSL + * @returns WGSL + */ + static convertGLSL(source: string): ShaderConverterResult { + // source -> Preprocessor -> NewSource + var preprocessor = new GLSLPreprocessor(source); + + // NewSource -> Lexer -> Tokens + var lexer = new GLSLLexer(preprocessor); + + // Tokens -> Syntax -> AST + var syntax = new GLSLSyntax(lexer); + + // AST -> WGSLTranslator -> Result + var translator = new WGSLTranslator(syntax); + + return translator.generateWGSL(); + } +} + +/** + * @internal + * @group GFX + */ +export class ShaderUniformInfo { + public setID: number = 0; + public bindingID: number = 0; + public name: string = ''; + public type: string = ''; +} + +/** + * @internal + * @group GFX + */ +export class ShaderAttributeInfo { + public name: string = ''; + public type: string = ''; + public locationID: number = 0; + public builtinName: string = ''; + public isBuiltinAttribute(): boolean { + return this.builtinName != ''; + } +} + +/** + * @internal + * @group GFX + */ +export class ShaderConverterResult { + public uniformInfo: Array = []; + public inputAttribute: Array = []; + public outputAttribute: Array = []; + public sourceCode: string = ''; +} diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/StatementNode.ts b/src/engine/gfx/graphics/webGpu/shader/converter/StatementNode.ts new file mode 100644 index 00000000..7151bbab --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/converter/StatementNode.ts @@ -0,0 +1,1886 @@ +import { GLSLLexer } from './GLSLLexer'; +import { GLSLLexerToken, TokenType } from './GLSLLexerToken'; +import { TranslatorContext } from './WGSLTranslator'; + +/** + * @internal + * Statement node + * @group GFX + */ +export class StatementNode { + public nodes: Array = []; + + constructor() { } + + public addNode(node: StatementNode) { + this.nodes.push(node); + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + return ''; + } +} + +/** + * @internal + * Statement node: struct + * @group GFX + */ +export class SN_Struct extends StatementNode { + public name: string = ''; + public fields: Array = []; + + constructor(name: string) { + super(); + this.name = name; + } + + public static parse(r: GLSLLexer): SN_Struct { + if (r.peekToken(0).Type == TokenType.IDENT && r.peekToken(1).Type == TokenType.LEFTBIG) { + let result = new SN_Struct(r.peekToken(0).Literal); + r.skipToken(2); + + while (r.peekToken(0).Type != TokenType.RIGHTBIG) { + let field = SN_Declaration.parse(r); + result.fields.push(field); + } + + if (r.peekToken(0).Type == TokenType.RIGHTBIG) { + r.skipToken(1); + } + + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + } + + return result; + } + + throw 'Error parsing structure: Unexpected character'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let result: string = ''; + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + result += prefix + 'struct ' + this.name + ' {\r\n'; + for (let field of this.fields) { + if (field.arraySize.nodes.length <= 0) { + result += prefix + ' ' + field.name + ': ' + toWGSLType(field.type) + ',\r\n'; + } else { + if (field.arraySize.nodes[0] instanceof SN_Constant) { + result += prefix + ' ' + field.name + ': array<' + toWGSLType(field.type) + ', ' + field.arraySize.nodes[0].value + '>' + ',\r\n'; + } else { + result += prefix + ' ' + field.name + ': array<' + toWGSLType(field.type) + ', ' + field.arraySize.nodes[0].formatToWGSL(context, 0) + '>' + ',\r\n'; + } + } + } + result += prefix + '};\r\n'; + return result; + } +} + +/** + * @internal + * Statement node: function + * @group GFX + */ +export class SN_Function extends StatementNode { + public name: string; + public args: Array; + public body: SN_CodeBlock; + public returnType: string; + + constructor(name: string, args: Array, body: SN_CodeBlock, returnType: string) { + super(); + this.name = name; + this.args = args; + this.body = body; + this.returnType = returnType; + } + + public static parse(r: GLSLLexer): SN_Function { + if ((r.peekToken(0).isBuiltinType() || r.peekToken(0).Type == TokenType.VOID) && r.peekToken(1).Type == TokenType.IDENT && r.peekToken(2).Type == TokenType.LEFTSAMLL) { + // Parsing return types + let returnType = r.peekToken(0).Literal; + + // Parse function name + let name = r.peekToken(1).Literal; + r.skipToken(2); + + // Parse the parameter list + let args = new Array(); + if (r.peekToken(0).Type != TokenType.LEFTSAMLL) { + throw 'Error parsing function parameter list: Unexpected character'; + } else { + r.skipToken(1); + while (r.peekToken(0).Type != TokenType.EOF) { + if (r.peekToken(0).Type == TokenType.RIGHTSAMLL) { + r.skipToken(1); + break; + } + + if (r.peekToken(0).Type == TokenType.INOUT) { + r.skipToken(1); + } else if (r.peekToken(0).Type == TokenType.IN) { + r.skipToken(1); + } else if (r.peekToken(0).Type == TokenType.OUT) { + r.skipToken(1); + } + + let arg = SN_Declaration.parse(r); + args.push(arg); + + if (r.peekToken(0).Type == TokenType.COMMA) { + r.skipToken(1); + } + } + } + + // Parse function body + let body = SN_CodeBlock.parse(r); + + return new SN_Function(name, args, body, returnType); + } + + throw 'Error parsing function: Unexpected character'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let result: string = ''; + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + let outStructName: string; + let hasOutStruct: boolean = context.layoutsOut.length > 0 || context.builtinOut.length > 0; + + switch (context.stage) { + case 'compute': + outStructName = 'ComputeOutput'; + break; + case 'vertex': + outStructName = 'VertexOutput'; + break; + case 'fragment': + outStructName = 'FragmentOutput'; + break; + default: + outStructName = 'StructOutput'; + break; + } + + // Processing the output structure + if (this.name == 'main' && hasOutStruct) { + result += 'struct ' + outStructName + ' {\r\n'; + for (let item of context.layoutsOut) { + if (item.nodes[0] instanceof SN_Declaration) { + let arg = item.nodes[0]; + if (item.qualifier.size == 1 && item.qualifier.has('location')) { + result += ' @location(' + item.qualifier.get('location') + ') '; + } + result += arg.name + ': ' + toWGSLType(arg.type) + ',\r\n'; + context.addIdentifier(arg.name, 'stout.' + arg.name); + } + } + + let builtinOut = context.builtinOut; + for (let item of builtinOut) { + result += ' ' + item + ',\r\n'; + } + + result += '};\r\n\r\n'; + } + + // Generate function header + let header: string = ''; + if (this.name == 'main') { + if (context.workGroupSize != undefined) { + header += '@' + context.stage + ' ' + context.workGroupSize.formatToWGSL(context, 0) + ' \r\n'; + } else { + header += '@' + context.stage + '\r\n'; + } + } + context = new TranslatorContext(context); + header += prefix + 'fn ' + this.name + '('; + if (this.name != 'main') { + for (let i = 0; i < this.args.length; i++) { + let arg = this.args[i]; + if (i > 0) { + header += ', '; + } + header += arg.name + ': ' + toWGSLType(arg.type); + context.addIdentifier(arg.name, arg.name); + } + header += ') -> ' + toWGSLType(this.returnType); + } else { + let layoutsIn = context.layoutsIn; + for (let i = 0; i < layoutsIn.length; i++) { + let item = layoutsIn[i]; + if (i > 0) { + header += ',\r\n '; + } else { + header += '\r\n '; + } + if (item.nodes[0] instanceof SN_Declaration) { + let arg = item.nodes[0]; + if (item.qualifier.size == 1 && item.qualifier.has('location')) { + header += '@location(' + item.qualifier.get('location') + ') '; + } + header += arg.name + ': ' + toWGSLType(arg.type); + context.addIdentifier(arg.name, arg.name); + } + } + if (layoutsIn.length > 0) { + header += ',\r\n '; + } + + let builtinIn = context.builtinIn; + for (let item of builtinIn) { + header += item + ',\r\n '; + } + + if (hasOutStruct) { + header += ') -> ' + outStructName; + } else { + header += ') '; + } + } + + // Generating function body + let bodyResult: string = ''; + if (this.name == 'main' && hasOutStruct) { + bodyResult += ' var stout: ' + outStructName + ' ;\r\n'; + } + for (let statement of this.body.nodes) { + bodyResult += statement.formatToWGSL(context, depth + 1); + if (!(statement instanceof SN_IFBranch) && !(statement instanceof SN_WhileLoop) && !(statement instanceof SN_ForLoop)) { + bodyResult += ';\r\n'; + } + } + if (this.name == 'main' && hasOutStruct) { + bodyResult += ' return stout;\r\n'; + } + + // Result of assembly + result += header + ' {\r\n'; + result += bodyResult; + result += prefix + '}\r\n'; + result += '\r\n'; + return result; + } +} + +/** + * @internal + * Statement node: functionArg + * @group GFX + */ +export class SN_FunctionArgs extends StatementNode { + public args: Array = []; + + constructor() { + super(); + } + + public static parse(r: GLSLLexer): SN_FunctionArgs { + if (r.peekToken(0).Type == TokenType.LEFTSAMLL) { + r.skipToken(1); + + let result = new SN_FunctionArgs(); + + while (r.peekToken(0).Type != TokenType.EOF) { + if (r.peekToken(0).Type == TokenType.RIGHTSAMLL) { + r.skipToken(1); + break; + } + + let arg = SN_Expression.parse(r); + result.args.push(arg); + + if (r.peekToken(0).Type == TokenType.COMMA) { + r.skipToken(1); + } + } + + return result; + } + + throw 'Error parsing function argument table: Unexpected character'; + } +} + +/** + * @internal + * Statement node: functionCall + * @group GFX + */ +export class SN_FunctionCall extends StatementNode { + public name: string; + public args: SN_FunctionArgs; + + constructor(name: string, args: SN_FunctionArgs) { + super(); + this.name = name; + this.args = args; + } + + public static parse(r: GLSLLexer): SN_FunctionCall { + // a(...) + if (r.peekToken(0).isDataType() && r.peekToken(1).Type == TokenType.LEFTSAMLL) { + // Parse function name + let name = r.peekToken(0).Literal; + r.skipToken(1); + + // Parse the argument table + let args = SN_FunctionArgs.parse(r); + + return new SN_FunctionCall(name, args); + } + + throw 'Error parsing function argument table: Unexpected character'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let result: string = ''; + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + + if (this.name == 'texture' && this.args.args[0].nodes[0] instanceof SN_FunctionCall) { + let callNode = this.args.args[0].nodes[0]; + if (callNode.name == 'sampler2D') { + result += prefix + 'textureSample('; + + for (let i = 0; i < callNode.args.args.length; i++) { + let arg = callNode.args.args[i]; + if (i > 0) { + result += ', '; + } + result += arg.formatToWGSL(context, 0); + } + + for (let i = 1; i < this.args.args.length; i++) { + let arg = this.args.args[i]; + if (i > 0) { + result += ', '; + } + result += arg.formatToWGSL(context, 0); + } + + result += ')'; + return result; + } + } + + result += prefix + toWGSLType(this.name) + '('; + for (let i = 0; i < this.args.args.length; i++) { + let arg = this.args.args[i]; + if (i > 0) { + result += ', '; + } + result += arg.formatToWGSL(context, 0); + } + result += ')'; + return result; + } +} + +/** + * @internal + * Statement node: declaration + * @group GFX + */ +export class SN_Declaration extends StatementNode { + public type: string; + public name: string; + public arraySize: SN_Expression; + public hasIn: boolean; + public hasOut: boolean; + public hasConst: boolean; + + constructor(type: string, name: string, arraySize: SN_Expression = new SN_Expression()) { + super(); + this.type = type; + this.name = name; + this.hasIn = false; + this.hasOut = false; + this.hasConst = false; + this.arraySize = arraySize; + } + + public static parse(r: GLSLLexer): SN_Declaration { + let result: SN_Declaration = new SN_Declaration('', ''); + + let first = r.peekToken(0); + + // const + if (first.Type == TokenType.CONST) { + r.skipToken(1); + result.hasConst = true; + } + // in + else if (first.Type == TokenType.IN) { + r.skipToken(1); + result.hasIn = true; + } + // out + else if (first.Type == TokenType.OUT) { + r.skipToken(1); + result.hasOut = true; + } + // inout + else if (first.Type == TokenType.INOUT) { + r.skipToken(1); + result.hasIn = true; + result.hasOut = true; + } else if (!first.isDataType()) { + throw 'Error parsing declaration expression: Unexpected character(' + first.Literal + ')'; + } + + first = r.peekToken(0); + + // float[xxx] a + if (first.isDataType() && r.peekToken(1).Type == TokenType.LEFTMEDI) { + result.type = first.Literal; + + r.skipToken(2); + + result.arraySize = SN_Expression.parse(r); + + if (r.peekToken(0).Type == TokenType.RIGHTMEDI) { + r.skipToken(1); + } + + if (r.peekToken(0).Type != TokenType.IDENT) { + throw 'Unexpected'; + } + + result.name = r.peekToken(0).Literal; + r.skipToken(1); + } + // float a[xxx] + else if (first.isDataType() && r.peekToken(1).Type == TokenType.IDENT && r.peekToken(2).Type == TokenType.LEFTMEDI) { + result.type = r.peekToken(0).Literal; + result.name = r.peekToken(1).Literal; + r.skipToken(3); + + if (r.peekToken(0).Type == TokenType.RIGHTMEDI) { + r.skipToken(1); + } else { + result.arraySize = SN_Expression.parse(r); + if (r.peekToken(0).Type == TokenType.RIGHTMEDI) { + r.skipToken(1); + } + } + } + // float a + else if (first.isDataType() && r.peekToken(1).Type == TokenType.IDENT) { + result.type = r.peekToken(0).Literal; + result.name = r.peekToken(1).Literal; + r.skipToken(2); + } else throw 'Error parsing declaration expression: Unexpected character(' + first.Literal + ')'; + + first = r.peekToken(0); + if (first.Type == TokenType.SEMICOLON) { + r.skipToken(1); + return result; + } else if (first.Type == TokenType.RIGHTSAMLL) { + return result; + } else if (first.Type == TokenType.ASSIGN) { + let op = r.peekToken(0); + r.skipToken(1); + let lValue = new SN_Identifier(result.name); + let rValue = SN_Expression.parse(r); + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + } + result.addNode(new SN_BinaryOperation(op, lValue, rValue)); + return result; + } else if (first.Type == TokenType.COMMA) { + // float a, b = 0, c = 1 + 2 + while (r.peekToken(0).Type == TokenType.COMMA && r.peekToken(1).Type == TokenType.IDENT) { + let declaration = new SN_Declaration(result.type, r.peekToken(1).Literal); + result.addNode(declaration); + r.skipToken(2); + if (r.peekToken(0).Type == TokenType.ASSIGN) { + r.skipToken(-1); + declaration.addNode(SN_Expression.parse(r)); + } + } + return result; + } + + throw 'Error parsing declaration expression: Unexpected character(' + r.peekToken(0).Literal + ')'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let result: string = ''; + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + + if (this.hasConst) { + result += prefix + 'let '; + } else { + result += prefix + 'var '; + } + + context.addIdentifier(this.name, this.name); + if (this.arraySize.nodes.length <= 0) { + result += this.name + ': ' + toWGSLType(this.type); + } else { + if (this.arraySize.nodes[0] instanceof SN_Constant) { + result += this.name + ': array<' + toWGSLType(this.type) + ', ' + this.arraySize.nodes[0].value + '>'; + } else { + result += this.name + ': array<' + toWGSLType(this.type) + ', ' + this.arraySize.nodes[0].formatToWGSL(context, 0) + '>'; + } + } + + if (this.nodes.length > 0 && this.nodes[0] instanceof SN_BinaryOperation) { + result += ' = ' + this.nodes[0].rightValue.formatToWGSL(context, 0); + } else if (this.nodes.length > 0 && this.nodes[0] instanceof SN_Expression && this.nodes[0].nodes[0] instanceof SN_BinaryOperation) { + result += ' = ' + this.nodes[0].nodes[0].rightValue.formatToWGSL(context, 0); + } else if (this.nodes.length > 0 && this.nodes[0] instanceof SN_Declaration) { + result += ';\r\n'; + for (let item of this.nodes) { + result += item.formatToWGSL(context, depth) + ';\r\n'; + } + } else { + result += ';\r\n'; + } + return result; + } +} + +/** + * @internal + * Statement node: for + * @group GFX + */ +export class SN_ForLoop extends StatementNode { + public expression1: StatementNode; + public condition: SN_Expression; + public expression2: SN_Expression; + public loopBody: SN_CodeBlock; + + constructor(expression1: StatementNode, condition: SN_Expression, expression2: SN_Expression, loopBody: SN_CodeBlock) { + super(); + this.expression1 = expression1; + this.condition = condition; + this.expression2 = expression2; + this.loopBody = loopBody; + } + + public static parse(r: GLSLLexer): SN_ForLoop { + if (r.peekToken(0).Type == TokenType.FOR && r.peekToken(1).Type == TokenType.LEFTSAMLL) { + r.skipToken(2); + + let expression1: StatementNode; + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + expression1 = new SN_Expression(); + } else if (r.peekToken(0).isDataType() && r.peekToken(1).Type == TokenType.IDENT && r.peekToken(2).Type == TokenType.ASSIGN) { + expression1 = new SN_Declaration(r.peekToken(0).Literal, r.peekToken(1).Literal); + r.skipToken(1); + expression1.addNode(SN_Expression.parse(r)); + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + } + } else { + expression1 = SN_Expression.parse(r); + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + } + } + + let condition: SN_Expression; + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + condition = new SN_Expression(); + } else { + condition = SN_Expression.parse(r); + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + } + } + + let expression2: SN_Expression; + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + expression2 = new SN_Expression(); + } else { + expression2 = SN_Expression.parse(r); + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + } + } + + if (r.peekToken(0).Type == TokenType.RIGHTSAMLL) { + r.skipToken(1); + } + + let loopBody: SN_CodeBlock; + if (r.peekToken(0).Type == TokenType.LEFTBIG) { + loopBody = SN_CodeBlock.parse(r); + } else { + loopBody = new SN_CodeBlock(); + } + + return new SN_ForLoop(expression1, condition, expression2, loopBody); + } + + throw 'Error parsing for loop: Unexpected character'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let result: string = ''; + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + + result += prefix + 'for ('; + result += this.expression1.formatToWGSL(context, 0) + '; '; + result += this.condition.formatToWGSL(context, 0) + '; '; + result += this.expression2.formatToWGSL(context, 0) + ')'; + + result += ' { \r\n'; + for (let item of this.loopBody.nodes) { + result += item.formatToWGSL(context, depth + 1); + if (!(item instanceof SN_IFBranch) && !(item instanceof SN_WhileLoop) && !(item instanceof SN_ForLoop)) { + result += ';\r\n'; + } + } + result += prefix + '} \r\n'; + return result; + } +} + +/** + * @internal + * Statement node: while + * @group GFX + */ +export class SN_WhileLoop extends StatementNode { + public conditionExpr: SN_Expression; + public loopBody: SN_CodeBlock; + + constructor(condition: SN_Expression, loopBody: SN_CodeBlock) { + super(); + this.conditionExpr = condition; + this.loopBody = loopBody; + } + + public static parse(r: GLSLLexer): SN_WhileLoop { + if (r.peekToken(0).Type == TokenType.WHILE) { + r.skipToken(1); + + if (r.peekToken(0).Type == TokenType.LEFTSAMLL) { + r.skipToken(1); + } + + let condition = SN_Expression.parse(r); + + if (r.peekToken(0).Type == TokenType.RIGHTSAMLL) { + r.skipToken(1); + } + + let loopBody = SN_CodeBlock.parse(r); + + return new SN_WhileLoop(condition, loopBody); + } + + throw 'Error parsing while loop: Unexpected character'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let result: string = ''; + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + + result += prefix + 'loop {\r\n'; + + result += prefix + ' if (' + this.conditionExpr.formatToWGSL(context, 0) + ') { break; }\r\n\r\n'; + + for (let item of this.loopBody.nodes) { + result += item.formatToWGSL(context, depth + 1); + if (!(item instanceof SN_IFBranch) && !(item instanceof SN_WhileLoop) && !(item instanceof SN_ForLoop)) { + result += ';\r\n'; + } + } + + result += prefix + '}\r\n'; + return result; + } +} + +/** + * @internal + * Statement node: do-while + * @group GFX + */ +export class SN_DoWhileLoop extends StatementNode { + constructor() { + super(); + } +} + +/** + * @internal + * Statement node: if + * @group GFX + */ +export class SN_IFBranch extends StatementNode { + public conditionExpr: SN_Expression; + public trueBranch: SN_CodeBlock; + public falseBranch: SN_CodeBlock; + + constructor(condition: SN_Expression, trueBranch: SN_CodeBlock, falseBranch: SN_CodeBlock) { + super(); + this.conditionExpr = condition; + this.trueBranch = trueBranch; + this.falseBranch = falseBranch; + } + + public static parse(r: GLSLLexer): SN_IFBranch { + if (r.peekToken(0).Type == TokenType.IF) { + r.skipToken(1); + + if (r.peekToken(0).Type == TokenType.LEFTSAMLL) { + r.skipToken(1); + } + + let condition = SN_Expression.parse(r); + let trueBranch: SN_CodeBlock; + let falseBranch: SN_CodeBlock = new SN_CodeBlock(); + + if (r.peekToken(0).Type == TokenType.RIGHTSAMLL) { + r.skipToken(1); + } + + if (r.peekToken(0).Type == TokenType.LEFTBIG) { + trueBranch = SN_CodeBlock.parse(r); + } else { + trueBranch = new SN_CodeBlock(); + if (r.peekToken(0).Type == TokenType.RETURN) { + trueBranch.addNode(SN_Return.parse(r)); + } else { + trueBranch.addNode(SN_Expression.parse(r)); + } + } + + if (r.peekToken(0).Type == TokenType.ELSE) { + r.skipToken(1); + + if (r.peekToken(0).Type == TokenType.LEFTBIG) { + falseBranch = SN_CodeBlock.parse(r); + } else throw 'not impl'; + } + + return new SN_IFBranch(condition, trueBranch, falseBranch); + } + + throw 'Error parsing IF branch statement: Unexpected character'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let resultl: string = ''; + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + + resultl += prefix + 'if (' + this.conditionExpr.formatToWGSL(context, 0) + ') {\r\n'; + + for (let item of this.trueBranch.nodes) { + resultl += item.formatToWGSL(context, depth + 1) + ';\r\n'; + } + + if (this.falseBranch.nodes.length > 0) { + resultl += prefix + '} else {\r\n'; + for (let item of this.falseBranch.nodes) { + resultl += item.formatToWGSL(context, depth + 1) + ';\r\n'; + } + } + + resultl += prefix + '}\r\n'; + return resultl; + } +} + +/** + * @internal + * Statement node: expression + * @group GFX + */ +export class SN_Expression extends StatementNode { + constructor() { + super(); + } + + public static parse(r: GLSLLexer): SN_Expression { + let opStack = new Array(); + let valueStack = new Array(); + let nSamllCount = 0; + while (r.peekToken(0).Type != TokenType.EOF) { + let currToken = r.peekToken(0); + + if (currToken.Type == TokenType.SEMICOLON || currToken.Type == TokenType.RIGHTMEDI) { + // r.SkipToken(1); + break; + } + + if (currToken.Type == TokenType.COMMA || currToken.Type == TokenType.COLON || currToken.Type == TokenType.RIGHTBIG) { + break; + } + + if (!currToken.isOperation()) { + if (currToken.Type == TokenType.LITERAL) { + valueStack.push(new SN_Constant(currToken.Literal)); + r.skipToken(1); + continue; + } else if (currToken.Type == TokenType.LEFTSAMLL) { + nSamllCount++; + opStack.push(currToken); + r.skipToken(1); + continue; + } else if (currToken.Type == TokenType.RIGHTSAMLL) { + if (nSamllCount <= 0) { + break; + } + nSamllCount--; + + while (SN_Expression.unionOperation(opStack, valueStack)); + + if (opStack[opStack.length - 1].Type == TokenType.LEFTSAMLL) { + opStack.pop(); + let parenExpr = new SN_ParenExpression(); + parenExpr.addNode(valueStack.pop()); + valueStack.push(parenExpr); + } + + r.skipToken(1); + continue; + } else if (currToken.Type == TokenType.IDENT) { + // a++ + if (r.peekToken(1).Type == TokenType.INC || r.peekToken(1).Type == TokenType.DEC) { + let op = r.peekToken(1); + let value = new SN_Identifier(currToken.Literal); + valueStack.push(new SN_UnaryOperation(op, value, undefined)); + r.skipToken(2); + continue; + } + // func(...) + else if (r.peekToken(1).Type == TokenType.LEFTSAMLL) { + valueStack.push(SN_FunctionCall.parse(r)); + continue; + } + // a.b + else if (r.peekToken(1).Type == TokenType.DOT) { + valueStack.push(SN_SelectOperation.parse(r)); + continue; + } + // a[xxx] + else if (r.peekToken(1).Type == TokenType.LEFTMEDI) { + valueStack.push(SN_IndexOperation.parse(r)); + continue; + } + + valueStack.push(new SN_Identifier(currToken.Literal)); + r.skipToken(1); + continue; + } else { + // type(...) + if (currToken.isBuiltinType() && r.peekToken(1).Type == TokenType.LEFTSAMLL) { + valueStack.push(SN_FunctionCall.parse(r)); + continue; + } + + // a += xxx + if (currToken.isAssignOperation()) { + let op = currToken; + r.skipToken(1); + let lValue = valueStack.pop(); + let rValue = SN_Expression.parse(r); + valueStack.push(new SN_BinaryOperation(op, lValue, rValue)); + continue; + } + + // { 1.0, 2.0, 3.0 } + if (currToken.Type == TokenType.LEFTBIG && (r.peekToken(1).Type == TokenType.LITERAL || (r.peekToken(1).Type == TokenType.SUB && r.peekToken(2).Type == TokenType.LITERAL))) { + valueStack.push(SN_ArrayConstant.parse(r)); + continue; + } + + // xx ? xx : xx + if (currToken.Type == TokenType.QUEMARK) { + if (opStack.length > 0) { + let opToken = opStack[opStack.length - 1]; + if (opToken.nOperationPriorityLevel <= currToken.nOperationPriorityLevel) { + SN_Expression.unionOperation(opStack, valueStack); + } + } + + r.skipToken(1); + + let a = valueStack.pop(); + + let b = SN_Expression.parse(r); + + if (r.peekToken(0).Type == TokenType.COLON) { + r.skipToken(1); + } + + let c = SN_Expression.parse(r); + + valueStack.push(new SN_TernaryOperation(a, b, c)); + + if (r.peekToken(-1).Type == TokenType.SEMICOLON) { + break; + } + + continue; + } + + // xxx[xxx] + if (currToken.Type == TokenType.LEFTMEDI) { + r.skipToken(1); + + let indexValue = SN_Expression.parse(r); + if (r.peekToken(0).Type == TokenType.RIGHTMEDI) { + r.skipToken(1); + } + + let lValue = valueStack.pop(); + valueStack.push(new SN_IndexOperation(lValue, indexValue)); + continue; + } + + throw 'An unexpected character'; + } + } else if (currToken.isOperation()) { + // ++a、--a + if (currToken.Type == TokenType.INC || currToken.Type == TokenType.DEC) { + let op = currToken; + r.skipToken(1); + let value = SN_Expression.parse(r); + valueStack.push(new SN_UnaryOperation(op, undefined, value)); + continue; + } else if (opStack.length > 0) { + let opToken = opStack[opStack.length - 1]; + if (opToken.nOperationPriorityLevel <= currToken.nOperationPriorityLevel) { + SN_Expression.unionOperation(opStack, valueStack); + } else if (opStack.length > 0 && opStack[opStack.length - 1].Literal == '-') { + let op = opStack.pop() as GLSLLexerToken; + let v1 = valueStack.pop() as StatementNode; + valueStack.push(new SN_UnaryOperation(op, undefined, v1)); + } + } + opStack.push(currToken); + r.skipToken(1); + } + } + + while (opStack.length > 0 && SN_Expression.unionOperation(opStack, valueStack)); + + if (opStack.length <= 0 && valueStack.length == 1) { + let expr = new SN_Expression(); + expr.addNode(valueStack.pop()); + return expr; + } + + throw 'Error parsing expression: Unexpected character(' + r.peekToken(0).Literal + ')'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + return this.nodes[0].formatToWGSL(context, depth); + } + + protected static unionOperation(opStack: Array, valueStack: Array): boolean { + if (opStack.length < 0 || valueStack.length < 2) { + if (opStack.length > 0 && opStack[opStack.length - 1].Literal == '-') { + let op = opStack.pop() as GLSLLexerToken; + let v1 = valueStack.pop() as StatementNode; + valueStack.push(new SN_UnaryOperation(op, undefined, v1)); + return true; + } + return false; + } + + if (opStack[opStack.length - 1].isOperation()) { + let v2 = valueStack.pop() as StatementNode; + let op = opStack.pop() as GLSLLexerToken; + let v1 = valueStack.pop() as StatementNode; + if (op.Type == TokenType.DOT) { + valueStack.push(new SN_SelectOperation(v1, v2)); + } else { + valueStack.push(new SN_BinaryOperation(op, v1, v2)); + } + return true; + } + + return false; + } +} + +/** + * @internal + * Statement node: Paren expression + * @group GFX + */ +export class SN_ParenExpression extends StatementNode { + constructor() { + super(); + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + let result: string = prefix + '(' + this.nodes[0].formatToWGSL(context, 0) + ')'; + return result; + } +} + +/** + * @internal + * Statement node: identifier + * @group GFX + */ +export class SN_Identifier extends StatementNode { + public name: string; + + constructor(name: string) { + super(); + this.name = name; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + return prefix + context.findIdentifier(this.name); + } +} + +/** + * @internal + * Statement node: constant + * @group GFX + */ +export class SN_Constant extends StatementNode { + public value: string; + + constructor(value: string) { + super(); + this.value = value; + } + + public static parse(r: GLSLLexer): SN_Constant { + let firstToken = r.peekToken(0); + + // -1 + if (firstToken.Type == TokenType.SUB && r.peekToken(1).Type == TokenType.LITERAL) { + let result = new SN_Constant('-' + r.peekToken(1).Literal); + r.skipToken(2); + return result; + } + // 1 + else if (firstToken.Type == TokenType.LITERAL) { + let result = new SN_Constant(firstToken.Literal); + r.skipToken(1); + return result; + } + + throw 'Error parsing literal constants: Unexpected characters(' + firstToken.Literal + ')'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + return prefix + this.value; + } +} + +/** + * @internal + * Statement node: array constant + * @group GFX + */ +export class SN_ArrayConstant extends SN_Constant { + public arrayValue: SN_Constant[]; + + constructor(value: SN_Constant[]) { + super(''); + this.arrayValue = value; + } + + public static parse(r: GLSLLexer): SN_ArrayConstant { + if ( + // { 1, 2, 3, 4 } + (r.peekToken(0).Type == TokenType.LEFTBIG && r.peekToken(1).Type == TokenType.LITERAL) || + // { -1, 2, 3, 4 } + (r.peekToken(0).Type == TokenType.LEFTBIG && r.peekToken(1).Type == TokenType.SUB && r.peekToken(2).Type == TokenType.LITERAL) + ) { + r.skipToken(1); + let arrayValue: SN_Constant[] = []; + while (r.peekToken(0).Type != TokenType.RIGHTBIG) { + if (r.peekToken(0).Type == TokenType.LEFTSAMLL) { + arrayValue.push(SN_ArrayConstant.parse(r)); + continue; + } + + arrayValue.push(SN_Constant.parse(r)); + + if (r.peekToken(0).Type == TokenType.COMMA) { + r.skipToken(1); + continue; + } else if (r.peekToken(0).Type == TokenType.RIGHTBIG) { + r.skipToken(1); + break; + } else throw 'Error parsing array constants: Unexpected characters'; + } + + return new SN_ArrayConstant(arrayValue); + } + + throw 'Error parsing array constants: Unexpected characters'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let result: string = ''; + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + if (this.arrayValue[0].value.includes('.')) { + result += prefix + 'array('; + } else { + result += prefix + 'array('; + } + for (let i: number = 0; i < this.arrayValue.length; i++) { + if (i > 0) { + result += ', '; + } + result += this.arrayValue[i].formatToWGSL(context, 0); + } + result += ')'; + return result; + } +} + +/** + * @internal + * Statement node: process control(break) + * @group GFX + */ +export class SN_Break extends StatementNode { + constructor() { + super(); + } +} + +/** + * @internal + * Statement node: process control(discard) + * @group GFX + */ +export class SN_Discard extends StatementNode { + constructor() { + super(); + } +} + +/** + * @internal + * Statement node: process control(continue) + * @group GFX + */ +export class SN_Continue extends StatementNode { + constructor() { + super(); + } + + public static parse(r: GLSLLexer): SN_Continue { + if (r.peekToken(0).Type == TokenType.CONTINUE && r.peekToken(1).Type == TokenType.SEMICOLON) { + r.skipToken(2); + return new SN_Continue(); + } + + throw 'Error parsing continue: Unexpected character'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let result: string = ''; + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + result += prefix + 'continue'; + return result; + } +} + +/** + * @internal + * Statement node: process control(return) + * @group GFX + */ +export class SN_Return extends StatementNode { + public value: SN_Expression; + + constructor(value: SN_Expression) { + super(); + this.value = value; + } + + public static parse(r: GLSLLexer): SN_Return { + if (r.peekToken(0).Type == TokenType.RETURN) { + r.skipToken(1); + let expr = SN_Expression.parse(r); + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + } + return new SN_Return(expr); + } + + throw 'Error parsing return expression: Unexpected character'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let result: string = ''; + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + result += prefix + 'return ' + this.value.formatToWGSL(context, 0); + return result; + } +} + +/** + * @internal + * Statement node: unary operation + * @group GFX + */ +export class SN_UnaryOperation extends StatementNode { + public op: GLSLLexerToken; + public leftValue: StatementNode | undefined; + public rightValue: StatementNode | undefined; + + constructor(op: GLSLLexerToken, lValue: StatementNode | undefined, rValue: StatementNode | undefined) { + super(); + this.op = op; + this.leftValue = lValue; + this.rightValue = rValue; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let result: string = ''; + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + + if (this.op.Literal == '++' || this.op.Literal == '--') { + if (this.leftValue != undefined) { + let lValue = this.leftValue.formatToWGSL(context, 0); + result += prefix + lValue + ' = ' + lValue + ' ' + this.op.Literal[0] + ' 1'; + } else { + let rValue = this.rightValue.formatToWGSL(context, 0); + result += prefix + rValue + ' = ' + rValue + ' ' + this.op.Literal[0] + ' 1'; + } + } else { + if (this.leftValue != undefined) { + result += prefix + this.leftValue.formatToWGSL(context, 0) + this.op.Literal; + } else { + result += prefix + this.op.Literal + this.rightValue.formatToWGSL(context, 0); + } + } + + return result; + } +} + +/** + * @internal + * Statement node: binary operation + * @group GFX + */ +export class SN_BinaryOperation extends StatementNode { + public op: GLSLLexerToken; + public leftValue: StatementNode; + public rightValue: StatementNode; + + constructor(op: GLSLLexerToken, lValue: StatementNode, rValue: StatementNode) { + super(); + this.op = op; + this.leftValue = lValue; + this.rightValue = rValue; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let result: string = ''; + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + result += prefix + this.leftValue.formatToWGSL(context, 0) + ' ' + this.op.Literal + ' ' + this.rightValue.formatToWGSL(context, 0); + return result; + } +} + +/** + * @internal + * Statement node: ternary operation + * @group GFX + */ +export class SN_TernaryOperation extends StatementNode { + public condition: SN_Expression; + public expression1: SN_Expression; + public expression2: SN_Expression; + + constructor(condition: SN_Expression, expression1: SN_Expression, expression2: SN_Expression) { + super(); + this.condition = condition; + this.expression1 = expression1; + this.expression2 = expression2; + } + + public static parse(r: GLSLLexer): SN_TernaryOperation { + throw 'Error parsing ternary operation expression: Unexpected character'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + return ''; + } +} + +/** + * @internal + * Statement node:Expression of select(a.b) + * @group GFX + */ +export class SN_SelectOperation extends StatementNode { + public leftValue: StatementNode; + public rightValue: StatementNode; + + constructor(lValue: StatementNode, rValue: StatementNode) { + super(); + this.leftValue = lValue; + this.rightValue = rValue; + } + + public static parse(r: GLSLLexer): SN_SelectOperation { + if (r.peekToken(0).Type == TokenType.IDENT && r.peekToken(1).Type == TokenType.DOT && r.peekToken(2).Type == TokenType.IDENT) { + let lValue = new SN_Identifier(r.peekToken(0).Literal); + let rValue = new SN_Identifier(r.peekToken(2).Literal); + r.skipToken(3); + return new SN_SelectOperation(lValue, rValue); + } + + throw 'Error parsing selection expression: Unexpected character'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + return prefix + this.leftValue.formatToWGSL(context, 0) + '.' + this.rightValue.formatToWGSL(context, 0); + } +} + +/** + * @internal + * Statement node:Expression of index(a[b]) + * @group GFX + */ +export class SN_IndexOperation extends StatementNode { + public leftValue: StatementNode; + public indexValue: StatementNode; + + constructor(lValue: StatementNode, indexValue: StatementNode) { + super(); + this.leftValue = lValue; + this.indexValue = indexValue; + } + + public static parse(r: GLSLLexer): SN_IndexOperation { + if (r.peekToken(0).Type == TokenType.IDENT && r.peekToken(1).Type == TokenType.LEFTMEDI) { + let lValue = new SN_Identifier(r.peekToken(0).Literal); + r.skipToken(2); + let indexValue = SN_Expression.parse(r); + if (r.peekToken(0).Type == TokenType.RIGHTMEDI) { + r.skipToken(1); + } + let result = new SN_IndexOperation(lValue, indexValue); + + while (r.peekToken(0).Type == TokenType.LEFTMEDI) { + r.skipToken(1); + indexValue = SN_Expression.parse(r); + if (r.peekToken(0).Type == TokenType.RIGHTMEDI) { + r.skipToken(1); + } + result = new SN_IndexOperation(result, indexValue); + } + + return result; + } + + throw 'Error parsing index expression: Unexpected character'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let prefix: string = depth <= 0 ? '' : ' '.repeat(depth); + return prefix + this.leftValue.formatToWGSL(context, 0) + '[' + this.indexValue.formatToWGSL(context, 0) + ']'; + } +} + +/** + * @internal + * Statement node: code block + * @group GFX + */ +export class SN_CodeBlock extends StatementNode { + constructor() { + super(); + } + + public static parse(r: GLSLLexer): SN_CodeBlock { + if (r.peekToken(0).Type == TokenType.LEFTBIG) { + r.skipToken(1); + let result = new SN_CodeBlock(); + + for (let count = 1; count > 0 && r.peekToken(0).Type != TokenType.EOF;) { + let currToken = r.peekToken(0); + + if (currToken.Type == TokenType.LEFTBIG) { + count++; + r.skipToken(1); + continue; + } + + if (currToken.Type == TokenType.RIGHTBIG) { + count--; + r.skipToken(1); + continue; + } + + /** + * nop + */ + if (currToken.Type == TokenType.SEMICOLON) { + r.skipToken(1); + continue; + } + /** + * Declaration of variables + */ + if (currToken.isDataType() && r.peekToken(1).Type == TokenType.IDENT) { + result.addNode(SN_Declaration.parse(r)); + continue; + } + /** + * Declaration of variables + */ + if (currToken.Type == TokenType.CONST && r.peekToken(1).isDataType() && r.peekToken(2).Type == TokenType.IDENT) { + result.addNode(SN_Declaration.parse(r)); + continue; + } else if ( + /** + * assignment expression + * a = ...; + */ + currToken.Type == TokenType.IDENT && + r.peekToken(1).Type == TokenType.ASSIGN + ) { + result.addNode(SN_Expression.parse(r)); + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + } + continue; + } else if ( + /** + * Expression of index + * a[...] + */ + currToken.Type == TokenType.IDENT && + r.peekToken(1).Type == TokenType.LEFTMEDI + ) { + let indexOperation = SN_IndexOperation.parse(r); + + // a[...] = xxx; + if (r.peekToken(0).Type == TokenType.ASSIGN) { + let op = r.peekToken(0); + r.skipToken(1); + let rValue = SN_Expression.parse(r); + if (r.peekToken(0).Type == TokenType.RIGHTMEDI) { + r.skipToken(1); + } + result.addNode(new SN_BinaryOperation(op, indexOperation, rValue)); + continue; + } + + result.addNode(indexOperation); + continue; + } else if ( + /** + * Expression of choice + * a.b + */ + currToken.Type == TokenType.IDENT && + r.peekToken(1).Type == TokenType.DOT + ) { + let expr = SN_Expression.parse(r); + result.addNode(expr); + continue; + } else if ( + /** + * Assignment operation expression + * a += ...; + */ + currToken.Type == TokenType.IDENT && + r.peekToken(1).isAssignOperation() + ) { + let op = r.peekToken(1); + let lValue = new SN_Identifier(currToken.Literal); + r.skipToken(2); + let rValue = SN_Expression.parse(r); + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + } + result.addNode(new SN_BinaryOperation(op, lValue, rValue)); + continue; + } else if ( + /** + * After the increase, after the decrease + * a++; + */ + currToken.Type == TokenType.IDENT && + (r.peekToken(1).Type == TokenType.INC || r.peekToken(1).Type == TokenType.DEC) && + r.peekToken(2).Type == TokenType.SEMICOLON + ) { + let op = r.peekToken(1); + result.addNode(new SN_UnaryOperation(op, new SN_Identifier(currToken.Literal), undefined)); + r.skipToken(3); + continue; + } else if (currToken.Type == TokenType.RETURN) { + /** + * return + */ + result.addNode(SN_Return.parse(r)); + continue; + } else if (currToken.Type == TokenType.CONTINUE) { + /** + * continue + */ + result.addNode(SN_Continue.parse(r)); + continue; + } else if (currToken.Type == TokenType.WHILE) { + /** + * while + */ + result.addNode(SN_WhileLoop.parse(r)); + continue; + } else if (currToken.Type == TokenType.FOR) { + /** + * for + */ + result.addNode(SN_ForLoop.parse(r)); + continue; + } else if (currToken.Type == TokenType.IF) { + /** + * if + */ + result.addNode(SN_IFBranch.parse(r)); + continue; + } else if ( + /** + * function call + */ + currToken.Type == TokenType.IDENT && + r.peekToken(1).Type == TokenType.LEFTSAMLL + ) { + result.addNode(SN_FunctionCall.parse(r)); + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(0); + } + continue; + } + + throw 'Error parsing block: Unexpected symbol(' + currToken.Literal + ')'; + } + + return result; + } + + throw 'Error parsing block: Unexpected symbol'; + } +} + +/** + * @internal + * Statement node:precision + * @group GFX + */ +export class SN_Precision extends StatementNode { + public type: string; + public qualifier: string; + + constructor(qualifier: string, type: string) { + super(); + this.type = type; + this.qualifier = qualifier; + } + + public static parse(r: GLSLLexer): SN_Precision { + if (r.peekToken(0).Type == TokenType.PRECISION && r.peekToken(1).Type == TokenType.IDENT && r.peekToken(2).isBuiltinType()) { + let result = new SN_Precision(r.peekToken(1).Literal, r.peekToken(2).Literal); + r.skipToken(3); + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + } + return result; + } + + throw 'Error parsing precision qualifier: Unexpected character'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + return ''; + } +} + +/** + * @internal + * Statement node: layout + * @group GFX + */ +export class SN_Layout extends StatementNode { + public scope: string = ''; + public qualifier: Map = new Map(); + + constructor() { + super(); + } + + public addQualifier(name: string, value: string = '') { + this.qualifier.set(name, value); + } + + public static parse(r: GLSLLexer): SN_Layout { + if (r.peekToken(0).Type == TokenType.LAYOUT && r.peekToken(1).Type == TokenType.LEFTSAMLL) { + let result = new SN_Layout(); + r.skipToken(2); + + do { + let currToken = r.peekToken(0); + if (currToken.Type == TokenType.IDENT) { + if (r.peekToken(1).Type == TokenType.ASSIGN && r.peekToken(2).Type == TokenType.LITERAL) { + let name = r.peekToken(0).Literal; + let value = r.peekToken(2).Literal; + result.addQualifier(name, value); + + r.skipToken(3); + if (r.peekToken(0).Type == TokenType.COMMA) { + r.skipToken(1); + continue; + } + + let token = r.peekToken(0); + token.Line = 0; + } else if (r.peekToken(1).Type == TokenType.RIGHTSAMLL) { + let name = r.peekToken(0).Literal; + result.addQualifier(name, ''); + r.skipToken(1); + break; + } else if (r.peekToken(1).Type == TokenType.COMMA) { + let name = r.peekToken(0).Literal; + result.addQualifier(name, ''); + r.skipToken(2); + continue; + } + } + } while (r.peekToken(0).Type != TokenType.RIGHTSAMLL); + + if (r.peekToken(0).Type == TokenType.RIGHTSAMLL) { + r.skipToken(1); + } + + // Scope of resolution + result.scope = r.peekToken(0).Literal; + r.skipToken(1); + + // Empty qualifier + if (r.peekToken(0).Type == TokenType.SEMICOLON) { + r.skipToken(1); + return result; + } + // Built-in type + else if (r.peekToken(0).isBuiltinType() && r.peekToken(1).Type == TokenType.IDENT && r.peekToken(2).Type == TokenType.SEMICOLON) { + let node = new SN_Declaration(r.peekToken(0).Literal, r.peekToken(1).Literal); + result.addNode(node); + r.skipToken(3); + return result; + } + // structure type + else if (r.peekToken(0).Type == TokenType.IDENT && r.peekToken(1).Type == TokenType.LEFTBIG) { + let structNode = SN_Struct.parse(r); + result.addNode(structNode); + + if (r.peekToken(0).Type == TokenType.IDENT && r.peekToken(1).Type == TokenType.SEMICOLON) { + structNode.addNode(new SN_Declaration(structNode.name, r.peekToken(0).Literal)); + r.skipToken(2); + } + + return result; + } else throw 'Error parsing layout qualifier type: Unexpected symbol(' + r.peekToken(0).Literal + ')'; + } + + throw 'Error parsing layout qualifier: Unexpected symbol'; + } + + public formatToWGSL(context: TranslatorContext, depth: number): string { + let result: string = ''; + + if (this.qualifier.size == 1 && this.qualifier.has('location')) { + result += '@location(' + this.qualifier.get('location') + ') '; + } else if (this.qualifier.size == 2 && this.qualifier.has('set') && this.qualifier.has('binding')) { + result += '@group(' + this.qualifier.get('set') + ') @binding(' + this.qualifier.get('binding') + ') '; + } else if (this.qualifier.size >= 1 && this.qualifier.has('binding')) { + result += '@group(0) @binding(' + this.qualifier.get('binding') + ') '; + } else if (this.qualifier.size == 1 && this.qualifier.has('push_constant')) { + result += '@push_constant '; + } else if (this.qualifier.size >= 1 && this.qualifier.has('local_size_x')) { + result += '@workgroup_size('; + result += this.qualifier.get('local_size_x') + ', '; + result += this.qualifier.has('local_size_y') ? this.qualifier.get('local_size_y') + ', ' : '1, '; + result += this.qualifier.has('local_size_z') ? this.qualifier.get('local_size_z') + '' : '1'; + result += ')'; + } else if (this.nodes.length <= 0) { + return ''; + } + + let item = this.nodes[0]; + if (item instanceof SN_Declaration) { + switch (item.type) { + case 'sampler': + case 'texture2D': + result += 'var '; + break; + default: + if (this.scope == 'buffer') { + if (context.stage == 'compute') { + result += 'var '; + } else { + result += 'var '; + } + } else { + result += 'var<' + this.scope + '> '; + } + break; + } + + context.addIdentifier(item.name, item.name); + result += item.name + ': ' + toWGSLType(item.type) + ';\r\n'; + } else if (item instanceof SN_Struct) { + if (this.scope == 'buffer') { + if (context.stage == 'compute') { + result += 'var '; + } else { + result += 'var '; + } + } else { + result += 'var<' + this.scope + '> '; + } + + if (item.nodes.length <= 0) { + let rename = 'unif' + context.layoutUniformCount.toString(); + while (context.hasIdentifier(rename)) { + context.layoutUniformCount++; + rename = 'unif' + context.layoutUniformCount.toString(); + } + for (let field of item.fields) { + context.addIdentifier(field.name, rename + '.' + field.name); + } + result += rename + ': ' + item.name + ';\r\n'; + context.layoutUniformCount++; + } else { + let declaration = item.nodes[0] as SN_Declaration; + result += declaration.name + ': ' + declaration.type + ';\r\n'; + } + return result; + } + return result; + } +} + +/** + * @internal + * @param type + * @returns + */ +function toWGSLType(type: string): string { + switch (type) { + case 'int': + return 'i32'; + case 'int[]': + return 'array'; + + case 'uint': + return 'u32'; + case 'uint[]': + return 'array'; + + case 'float': + return 'f32'; + case 'float[]': + return 'array'; + + case 'vec2': + return 'vec2'; + case 'vec3': + return 'vec3'; + case 'vec4': + return 'vec4'; + case 'vec2[]': + return 'array>'; + case 'vec3[]': + return 'array>'; + case 'vec4[]': + return 'array>'; + + case 'ivec2': + return 'vec2'; + case 'ivec3': + return 'vec3'; + case 'ivec4': + return 'vec4'; + case 'ivec2[]': + return 'array>'; + case 'ivec3[]': + return 'array>'; + case 'ivec4[]': + return 'array>'; + + case 'mat2': + return 'mat2x2'; + case 'mat2x2': + return 'mat2x2'; + case 'mat2x3': + return 'mat2x3'; + case 'mat2x4': + return 'mat2x4'; + case 'mat2[]': + return 'array>'; + case 'mat2x2[]': + return 'array>'; + case 'mat2x3[]': + return 'array>'; + case 'mat2x4[]': + return 'array>'; + + case 'mat3': + return 'mat3x3'; + case 'mat3x2': + return 'mat3x2'; + case 'mat3x3': + return 'mat3x3'; + case 'mat3x4': + return 'mat3x4'; + case 'mat3[]': + return 'array>'; + case 'mat3x2[]': + return 'array>'; + case 'mat3x3[]': + return 'array>'; + case 'mat3x4[]': + return 'array>'; + + case 'mat4': + return 'mat4x4'; + case 'mat4x2': + return 'mat4x2'; + case 'mat4x3': + return 'mat4x3'; + case 'mat4x4': + return 'mat4x4'; + case 'mat4[]': + return 'array>'; + case 'mat4x2[]': + return 'array>'; + case 'mat4x3[]': + return 'array>'; + case 'mat4x4[]': + return 'array>'; + + case 'texture2D': + return 'texture_2d'; + } + return type; +} diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/WGSLTranslator.ts b/src/engine/gfx/graphics/webGpu/shader/converter/WGSLTranslator.ts new file mode 100644 index 00000000..679dfece --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/converter/WGSLTranslator.ts @@ -0,0 +1,293 @@ +import { GLSLSyntax } from './GLSLSyntax'; +import { Reader } from './Reader'; +import { ShaderAttributeInfo, ShaderConverterResult, ShaderUniformInfo } from './ShaderConverter'; +import { SN_Declaration, SN_Layout, SN_Struct, StatementNode } from './StatementNode'; + +/** + * @internal + * WGSLCode Translator + * @group GFX + */ +export class WGSLTranslator { + public result: string; + public ASTRoot: StatementNode; + protected _syntax: GLSLSyntax; + + constructor(syntax: GLSLSyntax) { + this.result = ''; + this._syntax = syntax; + this.ASTRoot = syntax.ASTRoot; + } + + /** + * Generate WGSL code + * @returns WGSL code + */ + public generateWGSL(): ShaderConverterResult { + let context = new TranslatorContext(); + var result = new ShaderConverterResult(); + let layoutsBuffer: Array = []; + let layoutsUniform: Array = []; + let statements: Array = []; + + // Extract layout description + for (let item of this.ASTRoot.nodes) { + if (item instanceof SN_Layout) { + if (item.scope == 'in') { + if (item.nodes[0] instanceof SN_Declaration) { + context.layoutsIn.push(item); + let info = new ShaderAttributeInfo(); + info.name = item.nodes[0].name; + info.type = item.nodes[0].type; + info.locationID = Number.parseInt(item.qualifier.get('location')); + result.inputAttribute.push(info); + } else if (item.qualifier.has('local_size_x')) { + context.workGroupSize = item; + } else throw 'not impl'; + } else if (item.scope == 'out') { + context.layoutsOut.push(item); + if (item.nodes[0] instanceof SN_Declaration) { + let info = new ShaderAttributeInfo(); + info.name = item.nodes[0].name; + info.type = item.nodes[0].type; + info.locationID = Number.parseInt(item.qualifier.get('location')); + result.outputAttribute.push(info); + } else throw 'not impl'; + } else if (item.scope == 'uniform') { + layoutsUniform.push(item); + if (item.nodes[0] instanceof SN_Declaration) { + let info = new ShaderUniformInfo(); + info.name = item.nodes[0].name; + info.type = item.nodes[0].type; + info.setID = Number.parseInt(item.qualifier.get('set')); + info.bindingID = Number.parseInt(item.qualifier.get('binding')); + result.uniformInfo.push(info); + } else if (item.nodes[0] instanceof SN_Struct) { + let info = new ShaderUniformInfo(); + info.name = 'unif' + result.uniformInfo.length.toString(); + info.type = item.nodes[0].name; + info.setID = Number.parseInt(item.qualifier.get('set')); + info.bindingID = Number.parseInt(item.qualifier.get('binding')); + result.uniformInfo.push(info); + } else throw 'not impl'; + } else if (item.scope == 'buffer') { + layoutsBuffer.push(item); + } + } else { + statements.push(item); + } + } + + // Extracting built-in variables + context.stage = 'fragment'; + let position: number = 0; + let reader: Reader = new Reader(''); + let source: string = this._syntax.lexer.source; + let unique: Map = new Map(); + while ((position = source.indexOf('gl_', position)) != -1) { + reader.reset(source.substring(position, position + 32)); + reader.readChar(); + let name = reader.readIdentifier(); + position += name.length; + if (unique.has(name)) { + continue; + } + unique.set(name, name); + switch (name) { + case 'gl_InstanceID': + context.stage = 'vertex'; + context.builtinIn.push('@builtin(instance_index) gl_InstanceID: u32'); + break; + case 'gl_Position': + context.stage = 'vertex'; + context.builtinOut.push('@builtin(position) gl_Position: vec4'); + context.addIdentifier('gl_Position', 'stout.gl_Position'); + break; + case 'gl_VertexIndex': + context.stage = 'vertex'; + context.builtinIn.push('@builtin(vertex_index) gl_VertexIndex: u32'); + break; + + case 'gl_FrontFacing': + context.stage = 'fragment'; + context.builtinIn.push('@builtin(front_facing) gl_FrontFacing: bool'); + break; + case 'gl_FragDepth': + context.stage = 'fragment'; + context.builtinOut.push('@builtin(frag_depth) gl_FragDepth: f32'); + context.addIdentifier('gl_FragDepth', 'stout.gl_FragDepth'); + break; + + case 'gl_WorkGroupID': + context.stage = 'compute'; + context.builtinIn.push('@builtin(workgroup_id) gl_WorkGroupID: vec3'); + break; + case 'gl_NumWorkGroups': + context.stage = 'compute'; + context.builtinIn.push('@builtin(num_workgroups) gl_NumWorkGroups: vec3'); + break; + case 'gl_LocalInvocationID': + context.stage = 'compute'; + context.builtinIn.push('@builtin(local_invocation_id) gl_LocalInvocationID: vec3'); + break; + case 'gl_LocalInvocationIndex': + context.stage = 'compute'; + context.builtinIn.push('@builtin(local_invocation_index) gl_LocalInvocationIndex: u32'); + break; + case 'gl_GlobalInvocationID': + context.stage = 'compute'; + context.builtinIn.push('@builtin(global_invocation_id) gl_GlobalInvocationID: vec3'); + break; + default: + throw 'Unprocessed built-in variables: ' + name; + } + } + + // Translate to WGSL + for (let item of layoutsUniform) { + if (item.nodes[0] instanceof SN_Struct) { + result.sourceCode += item.nodes[0].formatToWGSL(context, 0); + result.sourceCode += '\r\n'; + } + } + for (let item of layoutsUniform) { + result.sourceCode += item.formatToWGSL(context, 0); + } + result.sourceCode += '\r\n'; + + for (let item of layoutsBuffer) { + if (item.nodes[0] instanceof SN_Struct) { + result.sourceCode += item.nodes[0].formatToWGSL(context, 0); + result.sourceCode += '\r\n'; + } + } + for (let item of layoutsBuffer) { + result.sourceCode += item.formatToWGSL(context, 0); + } + result.sourceCode += '\r\n'; + + for (let item of statements) { + result.sourceCode += item.formatToWGSL(context, 0); + if (item instanceof SN_Declaration) { + result.sourceCode += ';\r\n'; + } + } + return result; + } +} + +/** + * The translator context + * @internal + * @group GFX + */ +export class TranslatorContext { + protected _stage: string = 'fragment'; + protected _builtinIn: Array = []; + protected _builtinOut: Array = []; + protected _layoutsIn: Array = []; + protected _layoutsOut: Array = []; + protected _layoutUniformCount: number = 0; + protected _workGroupSize: SN_Layout = undefined; + + protected _parentContext?: TranslatorContext; + protected _identifierEnv: Map = new Map(); + + constructor(context?: TranslatorContext) { + this._parentContext = context; + } + + public get stage(): string { + if (this.parentContext != undefined) { + return this.parentContext.stage; + } + return this._stage; + } + + public set stage(value: string) { + if (this.parentContext != undefined) { + this.parentContext.stage = value; + } + this._stage = value; + } + + public get builtinIn(): Array { + if (this.parentContext != undefined) { + return this.parentContext.builtinIn; + } + return this._builtinIn; + } + + public get builtinOut(): Array { + if (this.parentContext != undefined) { + return this.parentContext.builtinOut; + } + return this._builtinOut; + } + + public get layoutsIn(): Array { + if (this.parentContext != undefined) { + return this.parentContext.layoutsIn; + } + return this._layoutsIn; + } + + public get layoutsOut(): Array { + if (this.parentContext != undefined) { + return this.parentContext.layoutsOut; + } + return this._layoutsOut; + } + + public get layoutUniformCount(): number { + if (this.parentContext != undefined) { + return this.parentContext.layoutUniformCount; + } + return this._layoutUniformCount; + } + + public set layoutUniformCount(value: number) { + if (this.parentContext != undefined) { + this.parentContext.layoutUniformCount = value; + return; + } + this._layoutUniformCount = value; + } + + public get workGroupSize(): SN_Layout { + if (this.parentContext != undefined) { + return this.parentContext.workGroupSize; + } + return this._workGroupSize; + } + + public set workGroupSize(value: SN_Layout) { + if (this.parentContext != undefined) { + this.parentContext.workGroupSize = value; + } + this._workGroupSize = value; + } + + public get parentContext(): TranslatorContext | undefined { + return this._parentContext; + } + + public findIdentifier(name: string): string { + if (this._identifierEnv.has(name)) { + return this._identifierEnv.get(name) as string; + } + if (this._parentContext != undefined) { + return this._parentContext.findIdentifier(name); + } + + return name; + } + + public addIdentifier(name: string, value: string) { + this._identifierEnv.set(name, value); + } + + public hasIdentifier(name: string): boolean { + return this._identifierEnv.has(name); + } +} diff --git a/src/engine/gfx/graphics/webGpu/shader/util/MorePassParser.ts b/src/engine/gfx/graphics/webGpu/shader/util/MorePassParser.ts new file mode 100644 index 00000000..22d9155d --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/util/MorePassParser.ts @@ -0,0 +1,139 @@ +import { Preprocessor } from "./Preprocessor"; + +export class MorePassShader { + public name: string = ''; + public passMap: Map = new Map(); +} + +export class PassShader { + public passType: string = ''; + public shaderState: Map = new Map(); + public vertexShader: string = ''; + public fragmentShader: string = ''; +} + +export class MorePassParser { + protected static passKeyword = 'pass'; + protected static shaderKeyword = 'Shader'; + protected static vertexKeyword = 'vertex'; + protected static fragmentKeyword = 'fragment'; + protected static passTypeKeyword = 'PassType'; + + public static parser(code: string, defineValue: { [name: string]: any }): MorePassShader { + code = Preprocessor.filterComment(code); + let result = new MorePassShader(); + let index1 = code.indexOf(this.shaderKeyword); + let index2 = code.indexOf("{", index1); + let block = code.substring(index1 + this.shaderKeyword.length, index2).trim(); + result.name = block.substring(1, block.length - 1); + block = code.substring(code.indexOf("{") + 1, code.lastIndexOf("}")); + let passBlocks = this.splitPassBlock(block); + for (let passCode of passBlocks) { + let passShader = this.parserPassBlock(passCode); + let passshaderList: PassShader[]; + if (result.passMap.has(passShader.passType)) { + passshaderList = result.passMap.get(passShader.passType); + } else { + passshaderList = []; + result.passMap.set(passShader.passType, passshaderList); + } + passshaderList.push(passShader); + + if (passShader.vertexShader.length > 0) { + passShader.vertexShader = Preprocessor.parse(passShader.vertexShader, defineValue); + } + if (passShader.fragmentShader.length > 0) { + passShader.fragmentShader = Preprocessor.parse(passShader.fragmentShader, defineValue); + } + } + return result; + } + + protected static splitPassBlock(code: string): string[] { + let offset = 0; + let result: string[] = []; + while (offset < code.length) { + let index = code.indexOf(this.passKeyword, offset); + if (index == -1) { + result.push(code.substring(offset)); + break; + } + if (offset != 0) { + result.push(code.substring(offset, index)); + } + offset = index + this.passKeyword.length; + } + return result; + } + + protected static parserPassBlock(code: string): PassShader { + let passShader: PassShader = new PassShader(); + let index1 = code.indexOf(this.passTypeKeyword); + let index2 = code.indexOf('"', index1); + index1 = code.indexOf('"', index2 + 1); + passShader.passType = code.substring(index1 + 1, index2).trim(); + + this.parserShaderState(passShader, code); + + index1 = code.indexOf(this.vertexKeyword); + if (index1 != -1) { + passShader.vertexShader = this.extractBlock(code.substring(index1 + this.vertexKeyword.length), '{', '}'); + } + + index1 = code.indexOf(this.fragmentKeyword); + if (index1 != -1) { + passShader.fragmentShader = this.extractBlock(code.substring(index1 + this.fragmentKeyword.length), '{', '}'); + } + return passShader; + } + + protected static parserShaderState(passShader: PassShader, code: string): boolean { + let indexL = code.indexOf("ShaderState"); + if (indexL == -1) + return false; + indexL = code.indexOf("{", indexL); + let indexR = code.indexOf("}", indexL); + let codeBlock = code.substring(indexL + 1, indexR); + let fields = codeBlock.split(','); + for (let item of fields) { + let keyValue = item.split(':'); + let key = keyValue[0].trim(); + let value = this.convertValue(keyValue[1].trim()); + passShader.shaderState.set(key, value); + } + return true; + } + + protected static convertValue(str: string): number | boolean | string { + if (str.length == 4 && str.toLowerCase() == "true") + return true; + else if (str.length == 5 && str.toLowerCase() == "false") + return false; + else if (str[0] == '"') + return str.substring(1, str.length - 1); + return Number.parseInt(str); + } + + private static extractBlock(str: string, leftStr: string, rightStr: string): string { + let indexL = str.indexOf(leftStr); + if (indexL == -1) { + return ""; + } + let depth = 0; + let indexR = 0; + str = str.substring(indexL); + for (let char of str) { + if (char == leftStr) { + depth++; + } else if (char == rightStr) { + depth--; + } + if (depth <= 0) { + break; + } + indexR++; + } + let block = str.substring(1, indexR).trim(); + return block; + } +} diff --git a/src/engine/gfx/graphics/webGpu/shader/util/Preprocessor.ts b/src/engine/gfx/graphics/webGpu/shader/util/Preprocessor.ts new file mode 100644 index 00000000..93f761ce --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/util/Preprocessor.ts @@ -0,0 +1,225 @@ +import { ShaderLib } from '../../../../../assets/shader/ShaderLib'; + +/** + * @internal + * @group GFX + */ +export class Preprocessor { + + public static parse(code: string, defineValue: { [name: string]: any }): string { + code = this.filterComment(code); + code = this.parsePreprocess(new PreprocessorContext(), code, defineValue); + code = this.parseAutoBindingForGroupX(code, 1); + return code; + } + + public static parseComputeShader(code: string, defineValue: { [name: string]: any }): string { + code = this.filterComment(code); + code = this.parsePreprocess(new PreprocessorContext(), code, defineValue); + return code; + } + + protected static parsePreprocess(context: PreprocessorContext, code: string, defineValue: { [name: string]: any }): string { + let begIndex = code.indexOf('#'); + if (begIndex == -1) { + return code; + } + let header = code.substring(0, begIndex); + let endIndex = code.indexOf('\n', code.lastIndexOf('#')); + let codeBlock = code.substring(begIndex, endIndex); + let tail = code.substring(endIndex); + return header + this.parsePreprocessCommand(context, codeBlock, defineValue) + tail; + } + + protected static parseAutoBindingForGroupX(code: string, nGroup: number): string { + let offset = 0; + let result = ''; + let group = new Map(); + while (offset < code.length) { + let nLeftIndex = code.indexOf('@group(', offset); + if (nLeftIndex == -1) { + result += code.substring(offset); + break; + } + let nRightIndex = code.indexOf(')', nLeftIndex); + let groupID = Number.parseInt(code.substring(nLeftIndex + 7, nRightIndex)); + nLeftIndex = code.indexOf('@binding(', nRightIndex); + nRightIndex = code.indexOf(')', nLeftIndex); + + // let bindingID = code.substring(nLeftIndex + 9, nRightIndex); + + result += code.substring(offset, nLeftIndex); + if (groupID == nGroup) { + if (group.has(groupID)) { + let lastBindingId = group.get(groupID) + 1; + result += `@binding(${lastBindingId})`; + group.set(groupID, lastBindingId); + } else { + result += '@binding(0)'; + group.set(groupID, 0); + } + } else { + result += code.substring(nLeftIndex, nRightIndex + 1); + } + offset = nRightIndex + 1; + } + + return result; + } + + protected static parsePreprocessCommand(context: PreprocessorContext, code: string, defineValue: { [name: string]: any }): string { + let result: string = ''; + let lines = code.split('\n'); + let stack: Array = [false]; + let stackElseif: Array = [false]; + for (let i: number = 0; i < lines.length; i++) { + let line = lines[i]; + let skip = stack[stack.length - 1]; + if (line.trim().indexOf('#') != 0) { + if (!skip) { + result += line + '\n'; + } + continue; + } + let command = line.trim(); + if (command.indexOf('#if') != -1) { + if (skip && stack.length > 1) { + stack.push(skip); + continue; + } + let condition = command.substring(3).trim(); + skip = !this.parseCondition(condition, defineValue); + stack.push(skip); + stackElseif.push(!skip); + continue; + } else if ((command.indexOf('#elseif') != -1) || (command.indexOf('#else') != -1 && command.indexOf(' if') != -1)) { + let skipElseif = stackElseif[stackElseif.length - 1]; + if (skipElseif) { + stack.pop(); + skip = true; + stack.push(skip); + continue; + } + stack.pop(); + skip = stack[stack.length - 1]; + if (skip && stack.length > 1) { + stack.push(skip); + continue; + } + let condition = command.substring(command.indexOf('if') + 2).trim(); + if (condition == '') { + console.error(`preprocess command error, conditions missing: ${command}`); + } + skip = !this.parseCondition(condition, defineValue); + stack.push(skip); + stackElseif.push(!skip); + continue; + } else if (command.indexOf('#else') != -1) { + stack.pop(); + if (skip && (stack.length > 1 && stack[stack.length - 1])) { + stack.push(skip); + } else { + stack.push(!skip); + } + continue; + } else if (command.indexOf('#endif') != -1) { + stack.pop(); + stackElseif.pop(); + continue; + } else if (command.indexOf('#include') != -1) { + let includeName = ''; + let char = command.charAt(command.length - 1); + if (char == `>`) { + includeName = this.extract(command, '<', '>'); + } else { + includeName = this.extract(command, char, char); + } + + if (!context.includeMap.has(includeName)) { + context.includeMap.set(includeName, true); + + let code = ShaderLib.getShader(includeName); + if (!code) { + throw `${command} error: '${includeName}' not found`; + } + + code = this.filterComment(code); + code = this.parsePreprocess(context, code, defineValue); + result += code + '\r\n'; + } + continue; + } else if (command.indexOf('#define ') != -1) { + let expression = command.substring(command.indexOf('#define ') + 8).trim(); + let index = expression.indexOf(' '); + let name = expression; + let value = ''; + if (index != -1) { + name = expression.substring(0, index).trim(); + value = expression.substring(index + 1).trim(); + } + defineValue[name] = value; + continue; + } else throw 'nonsupport: ' + command; + } + return result; + } + + protected static parseCondition(condition: string, defineValue: { [name: string]: any }): boolean { + let value = defineValue[condition]; + if (value == undefined) { + return false; + } + return value == true || value != 0; + } + + public static filterComment(code: string): string { + let result = ''; + let findSingleComment = true; + let findMultiComment = true; + for (let offset = 0; offset < code.length;) { + let index1 = findSingleComment ? code.indexOf('//', offset) : -1; + let index2 = findMultiComment ? code.indexOf('/*', offset) : -1; + + if (index1 == -1 && index2 == -1) { + result += code.substring(offset); + break; + } + + findSingleComment = index1 != -1; + findMultiComment = index2 != -1; + + if (index1 != -1 && index2 != -1) { + if (index1 < index2) { + index2 = -1; + } else { + index1 = -1; + } + } + + if (index1 != -1) { + index2 = code.indexOf('\n', index1); + result += code.substring(offset, index1); + offset = index2 != -1 ? index2 : code.length; + } else if (index2 != -1) { + index1 = code.indexOf('*/', index2); + result += code.substring(offset, index2); + offset = index1 + 2; + } + } + + return result; + } + + protected static extract(str: string, leftStr: string, rightStr: string): string { + let indexL = str.indexOf(leftStr) + leftStr.length; + let indexR = str.indexOf(rightStr, indexL); + return str.substring(indexL, indexR).trim(); + } +} + +class PreprocessorContext { + public includeMap = new Map(); + + constructor() { + } +} diff --git a/src/engine/gfx/graphics/webGpu/shader/util/ShaderUtil.ts b/src/engine/gfx/graphics/webGpu/shader/util/ShaderUtil.ts new file mode 100644 index 00000000..eb9ca3bb --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/util/ShaderUtil.ts @@ -0,0 +1,29 @@ +export type VertexPart = { + name: string; + vertex_in_struct: string; + vertex_out_struct: string; + vertex_buffer: string; + vertex_fun: string; + vertex_out: string; +} + +export type FragmentPart = { + name: string; + fs_textures: string; + fs_frament: string; + fs_normal: string; + fs_shadow: string; + fs_buffer: string; + fs_frameBuffers: string; +} + +export class ShaderUtil { + /** + * + * @param vsName + * @param shaderParts + */ + public static createShader(vertexParts: VertexPart, fragmentShader: FragmentPart) { + + } +} From 01990d7a16787f277dc26375dc9830d769f66568 Mon Sep 17 00:00:00 2001 From: hellmor Date: Mon, 24 Apr 2023 14:29:09 +0800 Subject: [PATCH 031/100] feat(shader): Add shader module (#43) Add shader module Add shader resource --- .../assets/shader/materials/Lambert_shader.ts | 74 ++++ src/engine/assets/shader/math/MathShader.ts | 293 ++++++++++++++++ src/engine/assets/shader/post/Bloom_shader.ts | 318 ++++++++++++++++++ .../assets/shader/post/GlobalFog_shader.ts | 84 +++++ src/engine/assets/shader/quad/Quad_shader.ts | 234 +++++++++++++ .../sky/AtmosphericScatteringSky_shader.ts | 311 +++++++++++++++++ .../assets/shader/sky/CubeSky_Shader.ts | 98 ++++++ 7 files changed, 1412 insertions(+) create mode 100644 src/engine/assets/shader/materials/Lambert_shader.ts create mode 100644 src/engine/assets/shader/math/MathShader.ts create mode 100644 src/engine/assets/shader/post/Bloom_shader.ts create mode 100644 src/engine/assets/shader/post/GlobalFog_shader.ts create mode 100644 src/engine/assets/shader/quad/Quad_shader.ts create mode 100644 src/engine/assets/shader/sky/AtmosphericScatteringSky_shader.ts create mode 100644 src/engine/assets/shader/sky/CubeSky_Shader.ts diff --git a/src/engine/assets/shader/materials/Lambert_shader.ts b/src/engine/assets/shader/materials/Lambert_shader.ts new file mode 100644 index 00000000..a0c788c2 --- /dev/null +++ b/src/engine/assets/shader/materials/Lambert_shader.ts @@ -0,0 +1,74 @@ + +export class Lambert_shader { + public static lambert_frag_wgsl = /* wgsl */ ` + #include "FragmentOutput.wgsl" + #include "LighStruct" + #include "ColorUtil_frag" + + @group(2) @binding(4) + var baseMapSampler: sampler; + @group(2) @binding(5) + var baseMap: texture_2d; + + struct StandMaterial { + transformUV1:vec4, + transformUV2:vec4, + baseColor: vec4, + dirLight: vec4, + dirLightColor: vec4, + alphaCutoff: f32, + shadowBias: f32, + }; + + @group(2) @binding(0) + var materialUniform: StandMaterial; + + fn frag(){ + var baseColor = materialUniform.baseColor; + var alphaCutoff = materialUniform.alphaCutoff; + var shadowBias = materialUniform.shadowBias; + var transformUV1 = materialUniform.transformUV1; + var transformUV2 = materialUniform.transformUV2; + + var uv = transformUV1.zw * vUv0 + transformUV1.xy; + var baseMap = textureSample(baseMap, baseMapSampler, uv).xyz; + + let viewDir = normalize(globalUniform.cameraWorldMatrix[3].xyz - vWorldPos.xyz) ; + + let lightIndex = getCluster(builtin_fragCoord); + let start = max(lightIndex.start, 0.0); + let count = max(lightIndex.count, 0.0); + let end = max(start + count , 0.0); + var color = vec3(0.0); + for(var i:i32 = i32(start) ; i < i32(end); i = i + 1 ) + { + let light = getLight(i) ; + switch (light.lightType) { + case PointLightType: { + let lightingColor = lambert_pointLight( baseMap , viewDir,vWorldNormal,vWorldPos.xyz,light); + color += lightingColor ; + } + case DirectLightType: { + let lightingColor = lambert_directLight( baseMap , viewDir,vWorldNormal,light.direction,light.lightColor,light.intensity); + color += lightingColor ; + } + case SpotLightType: { + + } + default: { + } + } + } + + ORI_FragmentOutput.color = vec4(color, 1.0); + } + `; + + public static lambert_vert_wgsl = /* wgsl */ ` + #include "Common_vert" + + fn vert(){ + + } + `; +} \ No newline at end of file diff --git a/src/engine/assets/shader/math/MathShader.ts b/src/engine/assets/shader/math/MathShader.ts new file mode 100644 index 00000000..83bb7848 --- /dev/null +++ b/src/engine/assets/shader/math/MathShader.ts @@ -0,0 +1,293 @@ +/** + * @internal + */ +export let MathShader = /* wgsl */ ` +var PI: f32 = 3.14159265359; + + +fn applyQuaternion(position:vec3, q:vec4) -> vec3{ + let x:f32 = position.x; + let y:f32 = position.y; + let z:f32 = position.z; + + let qx:f32 = q.x; + let qy:f32 = q.y; + let qz:f32 = q.z; + let qw:f32 = q.w; + + let ix:f32 = qw * x + qy * z - qz * y; + let iy:f32 = qw * y + qz * x - qx * z; + let iz:f32 = qw * z + qx * y - qy * x; + let iw:f32 = -qx * x - qy * y - qz * z; + + var ret: vec3; + ret.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + ret.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + ret.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + + return ret; +} + +fn inverse( m:mat3x3) -> mat3x3{ + var a00 = m[0][0]; + var a01 = m[0][1]; + var a02 = m[0][2]; + var a10 = m[1][0]; + var a11 = m[1][1]; + var a12 = m[1][2]; + var a20 = m[2][0]; + var a21 = m[2][1]; + var a22 = m[2][2]; + + var b01 = a22 * a11 - a12 * a21; + var b11 = -a22 * a10 + a12 * a20; + var b21 = a21 * a10 - a11 * a20; + + var det = a00 * b01 + a01 * b11 + a02 * b21 ; + return mat3x3( + vec3(b01/ det, (-a22 * a01 + a02 * a21)/ det, (a12 * a01 - a02 * a11)/ det), + vec3(b11/ det, (a22 * a00 - a02 * a20)/ det, (-a12 * a00 + a02 * a10)/ det), + vec3(b21/ det, (-a21 * a00 + a01 * a20)/ det, (a11 * a00 - a01 * a10)/ det) + ); +} + +fn dir_to_faceId(pt:vec3) -> i32 { + //**** nx px ny py nz pz + var abs_x = abs(pt.x); + var abs_y = abs(pt.y); + var abs_z = abs(pt.z); + var coord = max(max(abs_x, abs_y), abs_z); + if(coord == -pt.x){ return 0;} + if(coord == pt.x) { return 1;} + + if(coord == -pt.y){ return 2;} + if(coord == pt.y) { return 3;} + + if(coord == -pt.z) { return 4;} + return 5; + } + + fn convert_xyz_to_cube_uv(x:f32, y:f32, z:f32 ) -> vec2 + { + var dir = vec3(x, y, z); + var absX = abs(dir.x); + var absY = abs(dir.y); + var absZ = abs(dir.z); + + var isXPositive = 0; + if(dir.x > 0.0){isXPositive = 1;} + var isYPositive = 0; + if(dir.y > 0.0){isYPositive = 1;} + var isZPositive = 0; + if(dir.z > 0.0){isZPositive = 1;} + + var maxAxis:f32 = 0.0; + var uc:f32 = 0.0; + var vc:f32 = 0.0; + + // POSITIVE X + if (isXPositive == 1 && absX >= absY && absX >= absZ) { + // u (0 to 1) goes from +z to -z + // v (0 to 1) goes from -y to +y + maxAxis = absX; + uc = -z; + vc = y; + } + // NEGATIVE X + if (isXPositive ==0 && absX >= absY && absX >= absZ) { + // u (0 to 1) goes from -z to +z + // v (0 to 1) goes from -y to +y + maxAxis = absX; + uc = z; + vc = y; + } + // POSITIVE Y + if (isYPositive==1 && absY >= absX && absY >= absZ) { + // u (0 to 1) goes from -x to +x + // v (0 to 1) goes from +z to -z + maxAxis = absY; + uc = x; + vc = -z; + } + // NEGATIVE Y + if (isYPositive ==0 && absY >= absX && absY >= absZ) { + // u (0 to 1) goes from -x to +x + // v (0 to 1) goes from -z to +z + maxAxis = absY; + uc = x; + vc = z; + } + // POSITIVE Z + if (isZPositive == 1&& absZ >= absX && absZ >= absY) { + // u (0 to 1) goes from -x to +x + // v (0 to 1) goes from -y to +y + maxAxis = absZ; + uc = x; + vc = y; + } + // NEGATIVE Z + if (isZPositive ==0 && absZ >= absX && absZ >= absY) { + // u (0 to 1) goes from +x to -x + // v (0 to 1) goes from -y to +y + maxAxis = absZ; + uc = -x; + vc = y; + } + + // Convert range from -1 to 1 to 0 to 1 + var u = 0.5f * (uc / maxAxis + 1.0f); + var v = 0.5f * (vc / maxAxis + 1.0f); + + return vec2(u, v); + } + + // Returns ±1 + fn signNotZero( v1:vec2) -> vec2 { + var v:vec2 = v1; + if(v.x >= 0.0){ + v.x = 1.0; + }else{ + v.x = -1.0; + } + if(v.y >= 0.0){ + v.y = 1.0; + }else{ + v.y= -1.0; + } + return v; + } + + fn octEncode( v:vec3 ) -> vec2 { + var l1norm = abs(v.x) + abs(v.y) + abs(v.z); + var result = v.xy * (1.0 / l1norm); + if (v.z < 0.0) { + result = (1.0 - abs(result.yx)) * signNotZero(result.xy); + } + return result; + } + + // Returns a unit vector. Argument o is an octahedral vector packed via octEncode,on the [-1, +1] square*/ + fn octDecode( o:vec2 ) -> vec3 { + var v = vec3(o.x, o.y, 1.0 - abs(o.x) - abs(o.y)); + if (v.z < 0.0) { + var tmp = (1.0 - abs(v.yx)) * signNotZero(v.xy); + v.x = tmp.x; + v.y = tmp.y; + } + return normalize(v); + } + + fn Linear01Depth(z:f32,near:f32,far:f32)-> f32{ + let ZBufferZ = (-1.0+(far/near)) / far; + let ZBufferW = near /far ; + return 1.0 / (ZBufferZ * z + ZBufferW) ; + } + + + fn LinearizeDepth( depth:f32 , nearPlane:f32 , farPlane:f32 )-> f32 { + var z = depth * 2.0 - 1.0; + return (2.0 * nearPlane * farPlane) / (farPlane + nearPlane - z * (farPlane - nearPlane)); + } + + fn QuaternionToMatrix(q: vec4) -> mat4x4 { + // If q is guaranteed to be a unit quaternion, s will always + // be 1. In that case, this calculation can be optimized out. + //float norm = GetNorm (q); + //float s = (norm > 0.0) ? 2.0/norm : 0; + + var result: mat4x4; + + // Precalculate coordinate products + let x = q.x * 2.0; + let y = q.y * 2.0; + let z = q.z * 2.0; + let xx = q.x * x; + let yy = q.y * y; + let zz = q.z * z; + let xy = q.x * y; + let xz = q.x * z; + let yz = q.y * z; + let wx = q.w * x; + let wy = q.w * y; + let wz = q.w * z; + + // Calculate 3x3 matrix from orthonormal basis + result[0][0] = 1.0 - (yy + zz); + result[0][1] = xy + wz; + result[0][2] = xz - wy; + result[0][3] = 0.0; + + result[1][0] = xy - wz; + result[1][1] = 1.0 - (xx + zz); + result[1][2] = yz + wx; + result[1][3] = 0.0; + + result[2][0] = xz + wy; + result[2][1] = yz - wx; + result[2][2] = 1.0 - (xx + yy); + result[2][3] = 0.0; + + result[3][0] = 0.0; + result[3][1] = 0.0; + result[3][2] = 0.0; + result[3][3] = 1.0; + + return result; + } + + fn MakeScaleMatrix(scale: vec3) -> mat4x4 { + return mat4x4( + scale.x, 0.0, 0.0, 0.0, + 0.0, scale.y, 0.0, 0.0, + 0.0, 0.0, scale.z, 0.0, + 0.0, 0.0, 0.0, 1.0, + ); + } + + fn MakeRotationMatrix(rotationQuaternion: vec4) -> mat4x4 { + return QuaternionToMatrix(rotationQuaternion); + } + + fn MakeTranslationMatrix(translation: vec3) -> mat4x4 { + return mat4x4( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + translation.x, translation.y, translation.z, 1.0, + ); + } + + fn MakeMatrix4x4(scale: vec3, rotationQuaternion: vec4, translation: vec3) -> mat4x4 { + var scaleMat: mat4x4 = MakeScaleMatrix(scale); + var rotationMat: mat4x4 = MakeRotationMatrix(rotationQuaternion); + var translationMat: mat4x4 = MakeTranslationMatrix(translation); + return translationMat * scaleMat * rotationMat; + } + + fn mixMatrix4x4(a: mat4x4, b: mat4x4, t:f32) -> mat4x4 { + return a * (1.0 - t) + b * t; + // return mat4x4( + // mix(a[0], b[0], t), + // mix(a[1], b[1], t), + // mix(a[2], b[2], t), + // mix(a[3], b[3], t) + // ); + } + + fn decodeDepth( color:vec4 ) -> f32{ + var depth = 0.0 ; + const bitShifts = vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0); + depth = dot(color, bitShifts); + return depth; + } + + fn encodeDepth( depth:f32 ) -> vec4{ + const bitSh = vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0); + const bitMsk = vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); + var comp:vec4; + comp = depth * bitSh; + comp = fract(comp); + comp -= comp.xxyz * bitMsk; + return comp; + } +`; diff --git a/src/engine/assets/shader/post/Bloom_shader.ts b/src/engine/assets/shader/post/Bloom_shader.ts new file mode 100644 index 00000000..f1b1539d --- /dev/null +++ b/src/engine/assets/shader/post/Bloom_shader.ts @@ -0,0 +1,318 @@ +export class Bloom_shader { + public static Bloom_Brightness_frag_wgsl: string = /* wgsl */ ` + struct uniformData { + luminosityThreshold: f32 + }; + + struct FragmentOutput { + @location(0) o_Target: vec4 + }; + + var fragUV1: vec2; + var o_Target: vec4; + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d; + @group(2) @binding(0) + var global: uniformData; + + fn Brightness(c: vec3) -> f32 { + var c1: vec3; + + c1 = c; + let e8: vec3 = c1; + let e10: vec3 = c1; + let e12: vec3 = c1; + let e14: vec3 = c1; + let e17: vec3 = c1; + let e19: vec3 = c1; + let e21: vec3 = c1; + let e23: vec3 = c1; + let e25: vec3 = c1; + let e28: vec3 = c1; + return max(max(e23.x, e25.y), e28.z); + } + + fn main1() { + var uv: vec2; + var LinearColor: vec4; + var TotalLuminance: f32; + var BloomLuminance: f32; + var BloomAmount: f32; + + let e6: vec2 = fragUV1; + uv = e6.xy; + let e11: vec2 = uv; + uv.y = (1.0 - e11.y); + let e15: vec2 = uv; + let e16: vec4 = textureSample(baseMap, baseMapSampler, e15); + LinearColor = e16; + let e18: vec4 = LinearColor; + let e27: vec4 = LinearColor; + let e36: vec4 = LinearColor; + let e38: vec3 = min(vec3(f32(65000), f32(65000), f32(65000)), e36.xyz); + LinearColor.x = e38.x; + LinearColor.y = e38.y; + LinearColor.z = e38.z; + let e45: vec4 = LinearColor; + let e47: vec4 = LinearColor; + let e49: f32 = Brightness(e47.xyz); + TotalLuminance = e49; + let e51: f32 = TotalLuminance; + let e52: f32 = global.luminosityThreshold; + BloomLuminance = (e51 - e52); + let e55: f32 = BloomLuminance; + let e60: f32 = BloomLuminance; + BloomAmount = clamp((e60 * 0.5), 0.0, 1.0); + let e67: f32 = BloomAmount; + let e68: vec4 = LinearColor; + o_Target = vec4((e67 * e68.xyz), f32(0)); + return; + } + + @fragment + fn main(@location(0) fragUV: vec2) -> FragmentOutput { + fragUV1 = fragUV; + main1(); + let e13: vec4 = o_Target; + return FragmentOutput(e13); + } + `; + + + public static Bloom_blur_frag_wgsl: string = /* wgsl */ ` + struct uniformData { + texSize: vec2, + hScale: f32, + vScale: f32, + horizontal: f32 + }; + + struct FragmentOutput { + @location(0) o_Target: vec4 + }; + + var fragUV1: vec2; + var o_Target: vec4; + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d; + @group(2) @binding(0) + var global: uniformData; + + fn main1() { + var uv: vec2; + var tex_offset: vec2; + var result: vec3; + var i: i32 = 1; + var local: array = array(0.22702699899673462, 0.194594606757164, 0.12162160128355026, 0.05405399948358536, 0.01621600054204464); + var local1: array = array(0.22702699899673462, 0.194594606757164, 0.12162160128355026, 0.05405399948358536, 0.01621600054204464); + var j: i32 = 1; + var local2: array = array(0.22702699899673462, 0.194594606757164, 0.12162160128355026, 0.05405399948358536, 0.01621600054204464); + var local3: array = array(0.22702699899673462, 0.194594606757164, 0.12162160128355026, 0.05405399948358536, 0.01621600054204464); + + let e13: vec2 = fragUV1; + uv = e13.xy; + let e18: vec2 = uv; + uv.y = (1.0 - e18.y); + let e22: vec2 = global.texSize; + tex_offset = (vec2(1.0) / vec2(e22)); + let e28: vec2 = uv; + let e29: vec4 = textureSample(baseMap, baseMapSampler, e28); + result = (e29.xyz * array(0.22702699899673462, 0.194594606757164, 0.12162160128355026, 0.05405399948358536, 0.01621600054204464)[0]); + let e35: f32 = global.horizontal; + if ((e35 > 1.0)) { + { + loop { + let e40: i32 = i; + if (!((e40 < 5))) { + break; + } + { + let e47: vec3 = result; + let e48: vec2 = uv; + let e49: vec2 = tex_offset; + let e51: i32 = i; + let e54: f32 = global.hScale; + let e59: vec2 = uv; + let e60: vec2 = tex_offset; + let e62: i32 = i; + let e65: f32 = global.hScale; + let e70: vec4 = textureSample(baseMap, baseMapSampler, (e59 + vec2(((e60.x * f32(e62)) * e65), 0.0))); + let e72: i32 = i; + let e75: f32 = local[e72]; + result = (e47 + (e70.xyz * e75)); + let e78: vec3 = result; + let e79: vec2 = uv; + let e80: vec2 = tex_offset; + let e82: i32 = i; + let e85: f32 = global.hScale; + let e90: vec2 = uv; + let e91: vec2 = tex_offset; + let e93: i32 = i; + let e96: f32 = global.hScale; + let e101: vec4 = textureSample(baseMap, baseMapSampler, (e90 - vec2(((e91.x * f32(e93)) * e96), 0.0))); + let e103: i32 = i; + let e106: f32 = local1[e103]; + result = (e78 + (e101.xyz * e106)); + } + continuing { + let e44: i32 = i; + i = (e44 + 1); + } + } + } + } + let e109: f32 = global.horizontal; + if ((e109 < 1.0)) { + { + loop { + let e114: i32 = j; + if (!((e114 < 5))) { + break; + } + { + let e121: vec3 = result; + let e122: vec2 = uv; + let e124: vec2 = tex_offset; + let e126: i32 = j; + let e129: f32 = global.vScale; + let e133: vec2 = uv; + let e135: vec2 = tex_offset; + let e137: i32 = j; + let e140: f32 = global.vScale; + let e144: vec4 = textureSample(baseMap, baseMapSampler, (e133 + vec2(0.0, ((e135.y * f32(e137)) * e140)))); + let e146: i32 = j; + let e149: f32 = local2[e146]; + result = (e121 + (e144.xyz * e149)); + let e152: vec3 = result; + let e153: vec2 = uv; + let e155: vec2 = tex_offset; + let e157: i32 = j; + let e160: f32 = global.vScale; + let e164: vec2 = uv; + let e166: vec2 = tex_offset; + let e168: i32 = j; + let e171: f32 = global.vScale; + let e175: vec4 = textureSample(baseMap, baseMapSampler, (e164 - vec2(0.0, ((e166.y * f32(e168)) * e171)))); + let e177: i32 = j; + let e180: f32 = local3[e177]; + result = (e152 + (e175.xyz * e180)); + } + continuing { + let e118: i32 = j; + j = (e118 + 1); + } + } + } + } + let e183: vec3 = result; + o_Target = vec4(e183, 1.0); + return; + } + + @fragment + fn main(@location(0) fragUV: vec2) -> FragmentOutput { + fragUV1 = fragUV; + main1(); + let e27: vec4 = o_Target; + return FragmentOutput(e27); + } + `; + + public static Bloom_composite_frag_wgsl: string = /* wgsl */ ` + struct uniformData { + bloomStrength: f32, + bloomRadius: f32 + }; + + struct FragmentOutput { + @location(0) o_Target: vec4 + }; + + var fragUV1: vec2; + var o_Target: vec4; + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d; + @group(1) @binding(2) + var blurTex1Sampler: sampler; + @group(1) @binding(3) + var blurTex1: texture_2d; + @group(1) @binding(4) + var blurTex2Sampler: sampler; + @group(1) @binding(5) + var blurTex2: texture_2d; + @group(1) @binding(6) + var blurTex3Sampler: sampler; + @group(1) @binding(7) + var blurTex3: texture_2d; + @group(1) @binding(8) + var blurTex4Sampler: sampler; + @group(1) @binding(9) + var blurTex4: texture_2d; + @group(1) @binding(10) + var blurTex5Sampler: sampler; + @group(1) @binding(11) + var blurTex5: texture_2d; + @group(2) @binding(0) + var global: uniformData; + + fn lerpBloomFactor(factor: f32) -> f32 { + var factor1: f32; + var mirrorFactor: f32; + + factor1 = factor; + let e23: f32 = factor1; + mirrorFactor = (1.2000000476837158 - e23); + let e29: f32 = factor1; + let e30: f32 = mirrorFactor; + let e31: f32 = global.bloomRadius; + return mix(e29, e30, e31); + } + + fn main1() { + var uv: vec2; + var source: vec4; + + let e20: vec2 = fragUV1; + uv = e20.xy; + let e25: vec2 = uv; + uv.y = (1.0 - e25.y); + let e29: vec2 = uv; + let e30: vec4 = textureSample(baseMap, baseMapSampler, e29); + source = e30; + let e32: vec4 = source; + let e33: f32 = global.bloomStrength; + let e38: f32 = lerpBloomFactor(array(1.0, 0.800000011920929, 0.6000000238418579, 0.4000000059604645, 0.20000000298023224)[0]); + let e45: vec2 = uv; + let e46: vec4 = textureSample(blurTex1, blurTex1Sampler, e45); + let e52: f32 = lerpBloomFactor(array(1.0, 0.800000011920929, 0.6000000238418579, 0.4000000059604645, 0.20000000298023224)[1]); + let e59: vec2 = uv; + let e60: vec4 = textureSample(blurTex2, blurTex2Sampler, e59); + let e67: f32 = lerpBloomFactor(array(1.0, 0.800000011920929, 0.6000000238418579, 0.4000000059604645, 0.20000000298023224)[2]); + let e74: vec2 = uv; + let e75: vec4 = textureSample(blurTex3, blurTex3Sampler, e74); + let e82: f32 = lerpBloomFactor(array(1.0, 0.800000011920929, 0.6000000238418579, 0.4000000059604645, 0.20000000298023224)[3]); + let e89: vec2 = uv; + let e90: vec4 = textureSample(blurTex4, blurTex4Sampler, e89); + let e97: f32 = lerpBloomFactor(array(1.0, 0.800000011920929, 0.6000000238418579, 0.4000000059604645, 0.20000000298023224)[4]); + let e104: vec2 = uv; + let e105: vec4 = textureSample(blurTex5, blurTex5Sampler, e104); + o_Target = (e32 + (e33 * ((((((e38 * vec4(array,5>(vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0))[0], 1.0)) * e46) + ((e52 * vec4(array,5>(vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0))[1], 1.0)) * e60)) + ((e67 * vec4(array,5>(vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0))[2], 1.0)) * e75)) + ((e82 * vec4(array,5>(vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0))[3], 1.0)) * e90)) + ((e97 * vec4(array,5>(vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0))[4], 1.0)) * e105)))); + o_Target.a = e30.a ; + return; + } + + @fragment + fn main(@location(0) fragUV: vec2) -> FragmentOutput { + fragUV1 = fragUV; + main1(); + // let e81: vec4 = pow(o_Target,vec4(vec3(2.2),o_Target.w)); + return FragmentOutput(o_Target); + } + `; +} \ No newline at end of file diff --git a/src/engine/assets/shader/post/GlobalFog_shader.ts b/src/engine/assets/shader/post/GlobalFog_shader.ts new file mode 100644 index 00000000..f6b7c018 --- /dev/null +++ b/src/engine/assets/shader/post/GlobalFog_shader.ts @@ -0,0 +1,84 @@ +import GlobalUniform from "../core/common/GlobalUniform.wgsl?raw"; + +/** + * @internal + */ +export let GlobalFog_shader = /* wgsl */ ` +struct FragmentOutput { + @location(0) o_Target: vec4 +}; + +${GlobalUniform} + +#include "FastMathShader" + +struct UniformData { + fogColor : vec4, + fogType : f32 , + height : f32 , + start: f32, + end: f32, + density : f32 , + ins : f32 , +}; + +@group(1) @binding(0) +var positionMapSampler: sampler; +@group(1) @binding(1) +var positionMap: texture_2d; + +@group(1) @binding(2) +var colorMapSampler: sampler; +@group(1) @binding(3) +var colorMap: texture_2d; + +@group(1) @binding(4) +var normalMapSampler: sampler; +@group(1) @binding(5) +var normalMap: texture_2d; + + +@group(2) @binding(0) +var global : UniformData; +var varying_uv: vec2; + +@fragment +fn main(@location(0) fragUV: vec2, +@builtin(position) coord: vec4) -> FragmentOutput { + var texCoord = fragUV ; + texCoord.y = 1.0 - texCoord.y ; + + var cameraPos = globalUniform.cameraWorldMatrix[3].xyz ; + + var texPosition = textureSample(positionMap, positionMapSampler ,texCoord) ; + var texNormal = textureSample(normalMap, normalMapSampler,texCoord) ; + var texColor = textureSample(colorMap, colorMapSampler ,texCoord) ; + + let dis = texNormal.w * distance(cameraPos,texPosition.xyz); + let height = texPosition.y ; + + // var heightFactor = computeFog((dis + height) / 2.0 ); + var heightFactor = computeFog((dis)); + // visible test + if(texNormal.w<=0.5){ + return FragmentOutput(vec4(texColor.rgb,texColor.a)); + }else{ + // var emissive = mix( global.fogColor.rgb , texColor.rgb , global.ins * heightFactor ); + var emissive = mix( texColor.rgb , global.fogColor.rgb , clamp(global.ins * heightFactor,0.0,1.0) ); + return FragmentOutput(vec4(emissive.rgb,texColor.a)); + } + } + + fn computeFog(z:f32) -> f32 { + var fog = 0.0; + if( global.fogType == 0.0 ){ + fog = (global.end - z) / (global.end - global.start); + }else if(global.fogType == 1.0 ){ + fog = exp2(-global.density * z); + }else if(global.fogType == 2.0 ){ + fog = global.density * z; + fog = exp2(-fog * fog); + } + return max(fog,0.0); + } +`; diff --git a/src/engine/assets/shader/quad/Quad_shader.ts b/src/engine/assets/shader/quad/Quad_shader.ts new file mode 100644 index 00000000..2e1775c1 --- /dev/null +++ b/src/engine/assets/shader/quad/Quad_shader.ts @@ -0,0 +1,234 @@ +export class Quad_shader { + + public static FullQuad_vert_wgsl: string = /* wgsl */ ` + #include "WorldMatrixUniform" + #include "GlobalUniform" + + struct MaterialUniform { + x:f32, + y:f32, + width:f32, + height:f32, + }; + + struct VertexOutput { + @location(0) fragUV: vec2, + @builtin(position) position: vec4 + }; + + @vertex + fn main(@builtin(vertex_index) vertexIndex : u32, @builtin(instance_index) index : u32 ) -> VertexOutput { + const pos = array( + vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), + vec2(-1.0, 1.0), vec2(1.0, -1.0), vec2(1.0, 1.0), + ); + const uv = array( + vec2(1.0, 0.0), vec2(1.0, 1.0), vec2(0.0, 1.0), + vec2(1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, 0.0), + ); + + // var uvPos = position.xy ; + + let id = u32(index) ; + + // let worldMatrix = models.matrix[id]; + + // let windowSize = vec2(globalUniform.windowWidth,globalUniform.windowHeight) ; + + // let size = vec2(worldMatrix[0].x,worldMatrix[1].y) / (windowSize ) ; + + // var pos = (worldMatrix[3].xy / windowSize) * vec2(1.0,-1.0) ; + + // uvPos = uvPos * size; + + // let screenPos = vec2(((uvPos * 2.0) - vec2(1.0))) ; + + var output : VertexOutput; + output.fragUV = uv[vertexIndex] ; + output.position = vec4(pos[vertexIndex] , 0.0, 1.0) ; + return output ; + } + `; + + public static Quad_vert_wgsl: string = /* wgsl */ ` + #include "WorldMatrixUniform" + #include "GlobalUniform" + + struct MaterialUniform { + x:f32, + y:f32, + width:f32, + height:f32, + }; + + struct VertexOutput { + @location(0) fragUV: vec2, + @builtin(position) member: vec4 + }; + + @vertex + fn main(@builtin(instance_index) index : u32,@location(0) position: vec3, @location(1) TEXCOORD_1: vec2) -> VertexOutput { + let id = u32(index) ; + let worldMatrix = models.matrix[id]; + + let windowSize = vec2(globalUniform.windowWidth,globalUniform.windowHeight) ; + + // let pos = worldMatrix[3].xy ; + + let size = vec2(worldMatrix[0].x,worldMatrix[1].y) / windowSize ; + + // let offset = (size) / windowSize * 0.5 + pos / windowSize ; + + let uv = vec2(((TEXCOORD_1.xy * 2.0) - vec2(1.0))) ;// / windowSize * size - offset ; + // let suv = worldMatrix * vec4(uv, 0.0, 1.0) ; + + return VertexOutput(TEXCOORD_1, vec4(uv, 0.0, 1.0)); + } + `; + + + public static Quad_frag_wgsl: string = /* wgsl */ ` + struct FragmentOutput { + @location(0) o_Target: vec4 + }; + + var fragUV1: vec2; + var o_Target: vec4; + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d; + + @fragment + fn main(@location(0) fragUV: vec2) -> FragmentOutput { + var uv = fragUV ; + uv.y = 1.0 - uv.y ; + var color: vec4 = textureSample(baseMap, baseMapSampler, uv ); + + //test + // if(color.r <= 0.001 && color.g <= 0.001 && color.b <= 0.001 ){ + // discard ; + // } + return FragmentOutput(color); + } + `; + + public static Quad_depth2d_frag_wgsl: string = /* wgsl */ ` + struct FragmentOutput { + @location(0) o_Target: vec4 + }; + + var fragUV1: vec2; + var o_Target: vec4; + + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_depth_2d ; + + fn Linear01Depth( z : f32 ) -> f32 + { + return 1.0 / (1.0 * z + 5000.0); + } + + @fragment + fn main(@location(0) fragUV: vec2) -> FragmentOutput { + var uv = fragUV ; + uv.y = 1.0 - uv.y ; + var depth = textureSample(baseMap, baseMapSampler, uv , vec2(0) ) ; + return FragmentOutput(vec4(depth,0.0,0.0,1.0)); + } + `; + + public static Quad_depthCube_frag_wgsl: string = /* wgsl */ ` + struct FragmentOutput { + @location(0) o_Target: vec4 + }; + + var fragUV1: vec2; + var o_Target: vec4; + + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_depth_cube ; + + fn uvToXYZ( face : i32 , uv : vec2 ) -> vec3 + { + var out : vec3 ; + if(face == 0){ + out = vec3( 1.0, uv.y, -uv.x); + }else if(face == 1){ + out = vec3( -1.0, uv.y, uv.x); + }else if(face == 2){ + out = vec3( uv.x, -1.0, uv.y); + }else if(face == 3){ + out = vec3( uv.x, 1.0, -uv.y); + }else if(face == 4){ + out = vec3( uv.x, uv.y, 1.0); + }else{ + out = vec3( -uv.x, uv.y, -1.0); + } + return out ; + } + + @fragment + fn main(@location(0) fragUV: vec2) -> FragmentOutput { + var uv = fragUV ; + uv.y = 1.0 - uv.y ; + var ii = 0.16 ; + var ouv = vec3(0.0); + if(uv.x < ii * 6.0){ + ouv = uvToXYZ(5,uv/ii); + } + if(uv.x < ii * 5.0){ + ouv = uvToXYZ(4,uv/ii); + } + if(uv.x < ii * 4.0){ + ouv = uvToXYZ(3,uv/ii); + } + if(uv.x < ii * 3.0){ + ouv = uvToXYZ(2,uv/ii); + } + if(uv.x < ii * 2.0){ + ouv = uvToXYZ(1,uv/ii); + } + if(uv.x < ii * 1.0){ + ouv = uvToXYZ(0,uv/ii); + } + var depth = textureSample(baseMap, baseMapSampler, ouv ) ; + depth = 1.0 - depth; + + return FragmentOutput(vec4(depth,0.0,0.0,1.0)); + } + `; + + public static Quad_depth2dArray_frag_wgsl: string = /* wgsl */ ` + struct FragmentOutput { + @location(0) o_Target: vec4 + }; + + var fragUV1: vec2; + var o_Target: vec4; + + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d_array ; + + struct MaterialData{ + index:f32; + } + + @fragment + fn main(@location(0) fragUV: vec2) -> FragmentOutput { + var uv = fragUV ; + uv.y = 1.0 - uv.y ; + + var depth = textureSample(baseMap, baseMapSampler, ouv ) ; + depth = 1.0 - depth; + + return FragmentOutput(vec4(depth,0.0,0.0,1.0)); + } +`; +} \ No newline at end of file diff --git a/src/engine/assets/shader/sky/AtmosphericScatteringSky_shader.ts b/src/engine/assets/shader/sky/AtmosphericScatteringSky_shader.ts new file mode 100644 index 00000000..278c3d3a --- /dev/null +++ b/src/engine/assets/shader/sky/AtmosphericScatteringSky_shader.ts @@ -0,0 +1,311 @@ +/** + * @internal + */ +export class AtmosphericScatteringSky_shader { + public static cs: string = /* wgsl */ ` + struct UniformData { + width: f32, + height: f32, + sunU: f32, + sunV: f32, + eyePos: f32, + sunRadius: f32, // = 500.0; + sunRadiance: f32, // = 20.0; + mieG: f32, // = 0.76; + mieHeight: f32, // = 1200; + sunBrightness: f32, // = 1.0; + displaySun: f32, // > 0.5: true + }; + + @group(0) @binding(0) var uniformBuffer: UniformData; + @group(0) @binding(1) var outTexture : texture_storage_2d; + + var uv01: vec2; + var fragCoord: vec2; + var texSizeF32: vec2; + + var PI:f32 = 3.1415926535; + var PI_2:f32 = 0.0; + var EPSILON:f32 = 0.00001; + var SAMPLES_NUMS:i32 = 16; + + var transmittance:vec3; + var insctrMie:vec3; + var insctrRayleigh:vec3; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2(globalInvocation_id.xy); + texSizeF32 = vec2( uniformBuffer.width, uniformBuffer.height); + uv01 = vec2(globalInvocation_id.xy) / texSizeF32; + uv01.y = 1.0 - uv01.y - EPSILON; + PI_2 = PI * 2.0; + textureStore(outTexture, fragCoord , mainImage(uv01));//vec4(uv01, 0.0, 1.0)); + } + + struct ScatteringParams + { + sunRadius:f32, + sunRadiance:f32, + + mieG:f32, + mieHeight:f32, + + rayleighHeight:f32, + + waveLambdaMie:vec3, + waveLambdaOzone:vec3, + waveLambdaRayleigh:vec3, + + earthRadius:f32, + earthAtmTopRadius:f32, + earthCenter:vec3, + } + + fn ComputeSphereNormal(coord:vec2, phiStart:f32, phiLength:f32, thetaStart:f32, thetaLength:f32) -> vec3 + { + var normal:vec3; + normal.x = -sin(thetaStart + coord.y * thetaLength) * sin(phiStart + coord.x * phiLength); + normal.y = -cos(thetaStart + coord.y * thetaLength); + normal.z = -sin(thetaStart + coord.y * thetaLength) * cos(phiStart + coord.x * phiLength); + return normalize(normal); + } + + fn ComputeRaySphereIntersection(position:vec3, dir:vec3, center:vec3, radius:f32) -> vec2 + { + var origin:vec3 = position - center; + var B = dot(origin, dir); + var C = dot(origin, origin) - radius * radius; + var D = B * B - C; + + var minimaxIntersections:vec2; + if (D < 0.0) + { + minimaxIntersections = vec2(-1.0, -1.0); + } + else + { + D = sqrt(D); + minimaxIntersections = vec2(-B - D, -B + D); + } + + return minimaxIntersections; + } + + fn ComputeWaveLambdaRayleigh(lambda: vec3) -> vec3 + { + var n:f32 = 1.0003; + var N:f32 = 2.545E25; + var pn:f32 = 0.035; + var n2:f32 = n * n; + var pi3:f32 = PI * PI * PI; + var rayleighConst:f32 = (8.0 * pi3 * pow(n2 - 1.0,2.0)) / (3.0 * N) * ((6.0 + 3.0 * pn) / (6.0 - 7.0 * pn)); + return vec3(rayleighConst) / (lambda * lambda * lambda * lambda); + } + + fn ComputePhaseMie(theta: f32, g:f32) -> f32 + { + var g2 = g * g; + return (1.0 - g2) / pow(1.0 + g2 - 2.0 * g * saturate(theta), 1.5) / (4.0 * PI); + } + + fn ComputePhaseRayleigh(theta: f32) -> f32 + { + var theta2 = theta * theta; + return (theta2 * 0.75 + 0.75) / (4.0 * PI); + } + + fn ChapmanApproximation(X: f32, h: f32, cosZenith: f32) -> f32 + { + var c = sqrt(X + h); + var c_exp_h = c * exp(-h); + + if (cosZenith >= 0.0) + { + return c_exp_h / (c * cosZenith + 1.0); + } + else + { + var x0 = sqrt(1.0 - cosZenith * cosZenith) * (X + h); + var c0 = sqrt(x0); + + return 2.0 * c0 * exp(X - x0) - c_exp_h / (1.0 - c * cosZenith); + } + } + + fn GetOpticalDepthSchueler(h: f32, H: f32, earthRadius: f32, cosZenith: f32) -> f32 + { + return H * ChapmanApproximation(earthRadius / H, h / H, cosZenith); + } + + fn GetTransmittance(setting: ScatteringParams, L:vec3, V: vec3) -> vec3 + { + var ch = GetOpticalDepthSchueler(L.y, setting.rayleighHeight, setting.earthRadius, V.y); + return exp(-(setting.waveLambdaMie + setting.waveLambdaRayleigh) * ch); + } + + fn ComputeOpticalDepth(setting: ScatteringParams, samplePoint: vec3, V: vec3, L: vec3, neg: f32) -> vec2 + { + var rl = length(samplePoint); + var h = rl - setting.earthRadius; + var r: vec3 = samplePoint / rl; + + var cos_chi_sun = dot(r, L); + var cos_chi_ray = dot(r, V * neg); + + var opticalDepthSun = GetOpticalDepthSchueler(h, setting.rayleighHeight, setting.earthRadius, cos_chi_sun); + var opticalDepthCamera = GetOpticalDepthSchueler(h, setting.rayleighHeight, setting.earthRadius, cos_chi_ray) * neg; + + return vec2(opticalDepthSun, opticalDepthCamera); + } + + fn AerialPerspective(setting:ScatteringParams, start: vec3, end: vec3, V: vec3, L: vec3, infinite:i32) + { + var inf_neg:f32 = 1.0; + if( infinite == 0){ + inf_neg = -1.0; + } + + var sampleStep: vec3 = (end - start) / f32(SAMPLES_NUMS); + var samplePoint: vec3 = end - sampleStep; + var sampleLambda: vec3 = setting.waveLambdaMie + setting.waveLambdaRayleigh + setting.waveLambdaOzone; + + var sampleLength:f32 = length(sampleStep); + + var scattering:vec3 = vec3(0.0); + var lastOpticalDepth:vec2 = ComputeOpticalDepth(setting, end, V, L, inf_neg); + + for (var i:i32 = 1; i < SAMPLES_NUMS; i = i + 1) + { + var opticalDepth: vec2 = ComputeOpticalDepth(setting, samplePoint, V, L, inf_neg); + + var segment_s: vec3 = exp(-sampleLambda * (opticalDepth.x + lastOpticalDepth.x)); + var segment_t: vec3 = exp(-sampleLambda * (opticalDepth.y - lastOpticalDepth.y)); + + transmittance *= segment_t; + + scattering = scattering * segment_t; + scattering += exp(-(length(samplePoint) - setting.earthRadius) / setting.rayleighHeight) * segment_s; + + lastOpticalDepth = opticalDepth; + samplePoint = samplePoint - sampleStep; + } + + insctrMie = scattering * setting.waveLambdaMie * sampleLength; + insctrRayleigh = scattering * setting.waveLambdaRayleigh * sampleLength; + } + + fn ComputeSkyboxChapman(setting: ScatteringParams, eye:vec3, V:vec3, L:vec3) -> f32 + { + var neg:i32 = 1; + var outerIntersections: vec2 = ComputeRaySphereIntersection(eye, V, setting.earthCenter, setting.earthAtmTopRadius); + if (outerIntersections.y < 0.0){ + return 0.0; + } + var innerIntersections: vec2 = ComputeRaySphereIntersection(eye, V, setting.earthCenter, setting.earthRadius); + if (innerIntersections.x > 0.0) + { + neg = 0; + outerIntersections.y = innerIntersections.x; + } + + let eye0 = eye - setting.earthCenter; + + var start : vec3 = eye0 + V * max(0.0, outerIntersections.x); + var end : vec3= eye0 + V * outerIntersections.y; + + AerialPerspective(setting, start, end, V, L, neg); + + //bool intersectionTest = innerIntersections.x < 0.0 && innerIntersections.y < 0.0; + //return intersectionTest ? 1.0 : 0.0; + + if(innerIntersections.x < 0.0 && innerIntersections.y < 0.0){ + return 1.0; + } + return 0.0; + } + + fn ComputeSkyInscattering(setting: ScatteringParams, eye: vec3, V: vec3, L: vec3) -> vec4 + { + transmittance = vec3(1.0); + insctrMie = vec3(0.0); + insctrRayleigh = vec3(0.0); + var intersectionTest:f32 = ComputeSkyboxChapman(setting, eye, V, L); + + var phaseTheta = dot(V, L); + var phaseMie = ComputePhaseMie(phaseTheta, setting.mieG); + var phaseRayleigh = ComputePhaseRayleigh(phaseTheta); + var phaseNight = 1.0 - saturate(transmittance.x * EPSILON); + + var insctrTotalMie: vec3 = insctrMie * phaseMie; + var insctrTotalRayleigh: vec3 = insctrRayleigh * phaseRayleigh; + + var sky: vec3 = (insctrTotalMie + insctrTotalRayleigh) * setting.sunRadiance; + if(uniformBuffer.displaySun > 0.5){ + var angle:f32 = saturate((1.0 - phaseTheta) * setting.sunRadius); + var cosAngle:f32 = cos(angle * PI * 0.5); + var edge:f32 = 0.0; + if(angle >= 0.9){ + edge = smoothstep(0.9, 1.0, angle); + } + + var limbDarkening: vec3 = GetTransmittance(setting, -L, V); + limbDarkening *= pow(vec3(cosAngle), vec3(0.420, 0.503, 0.652)) * mix(vec3(1.0), vec3(1.2,0.9,0.5), edge) * intersectionTest; + sky += limbDarkening * uniformBuffer.sunBrightness; + } + return vec4(sky, phaseNight * intersectionTest); + } + + fn TonemapACES(x: vec3) -> vec3 + { + var A:f32 = 2.51f; + var B:f32 = 0.03f; + var C:f32 = 2.43f; + var D:f32 = 0.59f; + var E:f32 = 0.14f; + return (x * (A * x + B)) / (x * (C * x + D) + E); + } + + fn noise(uv:vec2) -> f32 + { + return fract(dot(sin(vec3(uv.xyx) * vec3(uv.xyy) * 1024.0), vec3(341896.483, 891618.637, 602649.7031))); + } + + fn mainImage( uv:vec2 ) -> vec4 + { + let eyePosition = uniformBuffer.eyePos; + var sun = vec2(uniformBuffer.sunU, uniformBuffer.sunV); + var V: vec3 = ComputeSphereNormal(uv, 0.0, PI_2, 0.0, PI); + var L: vec3 = ComputeSphereNormal(vec2(sun.x, sun.y), 0.0, PI_2, 0.0, PI); + + var setting: ScatteringParams; + setting.sunRadius = uniformBuffer.sunRadius;//500.0; + setting.sunRadiance = uniformBuffer.sunRadiance;//20.0; + setting.mieG = uniformBuffer.mieG;//0.76; + setting.mieHeight = uniformBuffer.mieHeight;// 1200.0; + setting.rayleighHeight = 8000.0; + setting.earthRadius = 6360000.0; + setting.earthAtmTopRadius = 6420000.0; + setting.earthCenter = vec3(0, -setting.earthRadius, 0); + setting.waveLambdaMie = vec3(0.0000002); + + // wavelength with 680nm, 550nm, 450nm + setting.waveLambdaRayleigh = ComputeWaveLambdaRayleigh(vec3(0.000000680, 0.000000550, 0.000000450)); + + // see https://www.shadertoy.com/view/MllBR2 + setting.waveLambdaOzone = vec3(1.36820899679147, 3.31405330400124, 0.13601728252538) * 0.0000006 * 2.504; + + var eye:vec3 = vec3(0,eyePosition,0); + var sky0:vec4 = ComputeSkyInscattering(setting, eye, V, L); + var sky = vec3(sky0.rgb); + + // sky = TonemapACES(sky.rgb * 2.0); + // sky = pow(sky.rgb, vec3(2.4)); // gamma + // sky.rgb += noise(uv*iTime) / 255.0; // dither + + var fragColor:vec4 = vec4(sky, 1.0); + return fragColor; + } + `; +} diff --git a/src/engine/assets/shader/sky/CubeSky_Shader.ts b/src/engine/assets/shader/sky/CubeSky_Shader.ts new file mode 100644 index 00000000..dca45731 --- /dev/null +++ b/src/engine/assets/shader/sky/CubeSky_Shader.ts @@ -0,0 +1,98 @@ +export class CubeSky_Shader { + public static sky_vs_frag_wgsl: string = /* wgsl */ ` + #include "WorldMatrixUniform" + #include "GlobalUniform" + + struct VertexOutput { + @location(0) fragUV: vec2, + @location(1) vWorldPos: vec4, + @location(2) vWorldNormal: vec3, + @builtin(position) member: vec4 + }; + + var ORI_VertexOut: VertexOutput ; + + @vertex + fn main( + @builtin(instance_index) index : u32, + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) uv: vec2 + ) -> VertexOutput { + ORI_VertexOut.fragUV = uv; + let modelMat = models.matrix[u32(index)]; + let vm = globalUniform.viewMat * modelMat; + let normalMatrix = mat3x3(vm[0].xyz,vm[1].xyz,vm[2].xyz); + ORI_VertexOut.vWorldNormal = normalize( normalMatrix * normal ); + ORI_VertexOut.vWorldPos = modelMat * vec4(position.xyz,1.0) ; + + var fixProjMat = globalUniform.projMat ; + fixProjMat[2].z = 1.0 ;//99999.0 / (99999.0 - 1.0) ; + fixProjMat[3].z = -1.0 ;//(-1.0 * 99999.0) / (99999.0 - 1.0) ; + + var fixViewMat = globalUniform.viewMat ; + fixViewMat[3].x = 0.0 ; + fixViewMat[3].y = 0.0 ; + fixViewMat[3].z = 0.0 ; + + var clipPos = fixProjMat * fixViewMat * ORI_VertexOut.vWorldPos; + ORI_VertexOut.member = clipPos; + return ORI_VertexOut; + } + ` + + public static sky_fs_frag_wgsl: string = /* wgsl */ ` + #include "GlobalUniform" + + struct uniformData { + exposure: f32, + roughness: f32 + }; + + struct FragmentOutput { + @location(0) o_Target: vec4, + #if USE_WORLDPOS + @location(1) o_Position: vec4, + #endif + #if USEGBUFFER + @location(2) o_Normal: vec4, + @location(3) o_Material: vec4 + #endif + }; + + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_cube; + + @group(2) @binding(0) + var global: uniformData; + + fn LinearToGammaSpace(linRGB: vec3) -> vec3 { + var linRGB1 = max(linRGB, vec3(0.0)); + linRGB1 = pow(linRGB1, vec3(0.4166666567325592)); + return max(((1.0549999475479126 * linRGB1) - vec3(0.054999999701976776)), vec3(0.0)); + } + + @fragment + fn main(@location(0) fragUV: vec2, @location(1) vWorldPos: vec4, @location(2) vWorldNormal: vec3) -> FragmentOutput { + let maxLevel: u32 = textureNumLevels(baseMap); + let textureColor:vec3 = textureSampleLevel(baseMap, baseMapSampler, normalize(vWorldPos.xyz), global.roughness * f32(maxLevel) ).xyz; + let o_Target: vec4 = vec4(LinearToGammaSpace(textureColor),1.0) * globalUniform.skyExposure ; + var normal_rgba8unorm = (vWorldNormal + 1.0) * 0.5; + normal_rgba8unorm = clamp(normal_rgba8unorm, vec3(0.0), vec3(1.0)); + + return FragmentOutput( + o_Target, + #if USE_WORLDPOS + vWorldPos, + #endif + #if USEGBUFFER + vec4(normal_rgba8unorm,0.0), + vec4(0.0,1.0,0.0,0.0) + #endif + ); + } + `; + +} \ No newline at end of file From d806f5047cb4e08025187883a6b12aee85d7f822 Mon Sep 17 00:00:00 2001 From: hellmor Date: Mon, 24 Apr 2023 14:29:47 +0800 Subject: [PATCH 032/100] feat(io): Add io files (#41) Add user input response script --- src/engine/io/InputSystem.ts | 678 ++++++++++++++++++++++++++++ src/engine/io/PickFire.ts | 250 ++++++++++ src/engine/io/PickResult.ts | 70 +++ src/engine/io/RayCastMeshDetail.ts | 159 +++++++ src/engine/io/TouchData.ts | 68 +++ src/engine/io/picker/PickCompute.ts | 77 ++++ 6 files changed, 1302 insertions(+) create mode 100644 src/engine/io/InputSystem.ts create mode 100644 src/engine/io/PickFire.ts create mode 100644 src/engine/io/PickResult.ts create mode 100644 src/engine/io/RayCastMeshDetail.ts create mode 100644 src/engine/io/TouchData.ts create mode 100644 src/engine/io/picker/PickCompute.ts diff --git a/src/engine/io/InputSystem.ts b/src/engine/io/InputSystem.ts new file mode 100644 index 00000000..5eb5d8e9 --- /dev/null +++ b/src/engine/io/InputSystem.ts @@ -0,0 +1,678 @@ +import { PointerEvent3D } from '../..'; +import { CEvent } from '../event/CEvent'; +import { CEventDispatcher } from '../event/CEventDispatcher'; +import { CResizeEvent } from '../event/CResizeEvent'; +import { KeyEvent } from '../event/eventConst/KeyEvent'; +import { KeyCode } from '../event/KeyCode'; +import { MouseCode } from '../event/MouseCode'; +import { Vector3 } from '../math/Vector3'; +import { Time } from '../util/Time'; +import { TouchData } from './TouchData'; + +/** + * + * Processing input devices, such as mouse, keyboard, and touch. + * If the current event does not occur within the View3D, it will not be dispatched + * @group IO + */ +export class InputSystem extends CEventDispatcher { + /** + * coord x of canvas + */ + public canvasX: number = 0; + /** + * coord y of canvas + */ + public canvasY: number = 0; + + /** + * whether the mouse is down now + */ + public isMouseDown: boolean = false; + + /** + * whether the mouse right key is down now + */ + public isRightMouseDown: boolean = false; + + /** + * referrence of canvas + */ + public canvas: HTMLCanvasElement; + + /** + * current mouse coordinate x of Canvas + */ + public mouseX: number = 0; + + /** + * current mouse coordinate y of Canvas + */ + public mouseY: number = 0; + + /** + * the delta value when mouse wheeled + */ + public wheelDelta: number = 0; + + /** + * the delta value of mouse x + */ + public mouseOffsetX: number = 0; + + /** + * the delta value of mouse y + */ + public mouseOffsetY: number = 0; + + /** + * the history value of mouse x + */ + public mouseLastX: number = 0; + + /** + * + * the history value of mouse y + * + */ + public mouseLastY: number = 0; + + private _time: number = 0; + + private _keyStatus: { [key: number]: boolean }; + private _mouseStatus: { [key: number]: boolean }; + private _isTouchStart: boolean; + protected _keyEvent3d: KeyEvent; + protected _pointerEvent3D: PointerEvent3D; + protected _windowsEvent3d: CEvent; + + /** + * + * 游戏手柄Stick1事件侦听函数。 + * + */ + private _onGamepadStick1: Function = null; + + /** + * + * 游戏手柄Stick2事件侦听函数。 + * + */ + private _onGamepadStick2: Function = null; + + /** + * init the input system + * @param canvas the referrence of canvas + */ + public initCanvas(canvas: HTMLCanvasElement) { + this.canvas = canvas; + // canvas.style.position = 'absolute'; + // canvas.style.zIndex = '0'; + canvas.onpointerdown = (ev: PointerEvent) => { + if (ev.button == 0) { + this.mouseStart(ev); + } else if (ev.button == 1) { + this.middleDown(ev); + } else if (ev.button == 2) { + this.mouseStart(ev); + } + } + canvas.onpointerup = (ev: PointerEvent) => { + if (ev.button == 0) { + this.mouseEnd(ev); + } else if (ev.button == 1) { + this.middleUp(ev); + } else if (ev.button == 2) { + this.mouseEnd(ev); + } + } + canvas.onpointerenter = (ev: PointerEvent) => { + this.mouseOver(ev); + } + + canvas.onpointermove = (ev: PointerEvent) => { + this.mouseMove(ev); + } + canvas.onpointercancel = (ev: PointerEvent) => { + this.mouseEnd(ev); + } + canvas.onpointerleave = (ev: PointerEvent) => { + this.mouseEnd(ev); + } + canvas.onpointerout = (ev: PointerEvent) => { + this.mouseEnd(ev); + } + + canvas.addEventListener( + 'click', + (e: MouseEvent) => { + //if right click + if (e.button == 2) { + this.isRightMouseDown = false; + this.rightClick(e); + } else if (e.button == 0) { + this.isMouseDown = false; + this.mouseClick(e); + } + }, + true, + ); + + + canvas.addEventListener(`wheel`, (e: WheelEvent) => this.mouseWheel(e), { passive: false }); + + window.addEventListener('keydown', (e: KeyboardEvent) => this.keyDown(e), true); + + window.addEventListener('keyup', (e: KeyboardEvent) => this.keyUp(e), true); + + canvas.oncontextmenu = function () { + return false; + }; + + //window.addEventListener("resize", (e: UIEvent) => this.onWindowsResize(e), true); + let rect: DOMRect = this.canvas.getBoundingClientRect(); + + this.canvasX = rect.left; // parseInt( this.canvas.style.left.split("px")[0] ); + this.canvasY = rect.top; //rect parseInt(this.canvas.style.top.split("px")[0]); + + this._keyStatus = {}; + this._mouseStatus = {}; + this._isTouchStart = false; + this._keyEvent3d = new KeyEvent(); + this._pointerEvent3D = new PointerEvent3D(); + this._windowsEvent3d = new CEvent(); + } + + /** + * @private + * + * 获取按键是否压下 + * @param code 按键码 {@link KeyCode} + * + */ + private getKeyPress(code: KeyCode): boolean { + return this._keyStatus[code]; + } + + /** + * @private + * + * 获取鼠标是否压下 + * @param code 鼠标按钮码 {@link MouseCode} + * + */ + private getMousePress(code: MouseCode): boolean { + return this._mouseStatus[code]; + } + + private _gp: boolean = false; + private ongamepaddisconnected(e: GamepadEvent) { + //Debug.instance.trace("Gamepad disconnected!"); + this._gp = false; + } + private ongamepadconnected(e: GamepadEvent) { + //Debug.instance.trace("Gamepad connected!"); + this._gp = true; + } + + /** + * + * 游戏手柄按钮是否按下。 + * + * @param index {number} + * @returns {boolean} + */ + private getGamepadButtonState(index: number): boolean { + return navigator.getGamepads()[0].buttons[index].pressed; + } + + /** + * + * 游戏手柄摇杆方向 Stick1 。 + * + * @returns {Vector3D} + */ + private getGamepadStick1(): Vector3 { + return new Vector3(navigator.getGamepads()[0].axes[0], navigator.getGamepads()[0].axes[1], 0); + } + + /** + * + * 游戏手柄摇杆方向 Stick2 。 + * + * @returns {Vector3D} + */ + private getGamepadStick2(): Vector3 { + return new Vector3(navigator.getGamepads()[0].axes[2], navigator.getGamepads()[0].axes[3], 0); + } + + private onPinch(x1: number, y1: number, x2: number, y2: number) { + this._oldPosition1 = new Vector3(x1, y1); + this._oldPosition2 = new Vector3(x2, y2); + } + + private onSwipe(x: number, y: number) { + this.mouseX = x; + this.mouseY = y; + + this._oldPosition1 = null; + this._oldPosition2 = null; + + this._time = new Date().getTime(); + } + + private touchStart(e: TouchEvent) { + this.isMouseDown = true; + if (e && e.changedTouches && e.changedTouches.length > 0) { + // x1 y1 最新的触摸点 + var newX: number = e.changedTouches[0].clientX - this.canvasX; //- Input.canvas.x + Input.canvas.offsetX; + var newY: number = e.changedTouches[0].clientY - this.canvasY; // Input.canvas.y + Input.canvas.offsetY; + } + + if (e.targetTouches && e.targetTouches.length == 2) { + var oldX: number = e.targetTouches[0].clientX - this.canvasX; // - Input.canvas.x + Input.canvas.offsetX; + var oldY: number = e.targetTouches[0].clientY - this.canvasY; // - Input.canvas.y + Input.canvas.offsetY; + this.onPinch(oldX, oldY, newX, newY); + } else if (e.targetTouches && e.targetTouches.length == 1) { + this.onSwipe(newX, newY); + this._mouseStatus[MouseCode.MOUSE_LEFT] = true; + } + + this._pointerEvent3D.reset(); + this._pointerEvent3D.targetTouches = this.GetTargetTouches(e.targetTouches); + this._pointerEvent3D.changedTouches = this.GetTargetTouches(e.changedTouches); + this._pointerEvent3D.touches = this.GetTargetTouches(e.touches); + // this._pointerEvent3D.target = this; + this.mouseX = e.targetTouches[0].clientX - this.canvasX; /*- Input.canvas.x + Input.canvas.offsetX*/ + this.mouseY = e.targetTouches[0].clientY - this.canvasY; /*- Input.canvas.y + Input.canvas.offsetY*/ + this._pointerEvent3D.mouseX = this.mouseX; + this._pointerEvent3D.mouseY = this.mouseY; + // if (!this._isTouchStart) { + this._isTouchStart = true; + this._pointerEvent3D.type = PointerEvent3D.POINTER_DOWN; + this.dispatchEvent(this._pointerEvent3D); + // } + this._downTime = Time.time; + } + + private _oldPosition1: Vector3 = null; + private _oldPosition2: Vector3 = null; + + private touchEnd(e: TouchEvent) { + this.isMouseDown = false; + if (e.targetTouches.length > 1) { + var x: number = e.targetTouches[0].clientX - this.canvasX; //- Input.canvas.x + Input.canvas.offsetX; + var y: number = e.targetTouches[0].clientY - this.canvasY; //- Input.canvas.y + Input.canvas.offsetY; + var x1: number = e.targetTouches[1].clientX - this.canvasX; //- Input.canvas.x + Input.canvas.offsetX; + var y1: number = e.targetTouches[1].clientY - this.canvasY; // Input.canvas.y + Input.canvas.offsetY; + this.onPinch(x, y, x1, y1); + } else if (e.targetTouches.length == 1) { + this.onSwipe(e.targetTouches[0].clientX - this.canvasX /*- Input.canvas.x + Input.canvas.offsetX*/, e.targetTouches[0].clientY - this.canvasY /*- Input.canvas.y + Input.canvas.offsetY*/); + this._mouseStatus[MouseCode.MOUSE_LEFT] = false; + } else { + this._oldPosition1 = null; + this._oldPosition2 = null; + this._time = 0; + } + this._pointerEvent3D.reset(); + this._isTouchStart = false; + this._pointerEvent3D.targetTouches = this.GetTargetTouches(e.targetTouches); + this._pointerEvent3D.changedTouches = this.GetTargetTouches(e.changedTouches); + this._pointerEvent3D.touches = this.GetTargetTouches(e.touches); + // this._pointerEvent3D.target = this; + this._pointerEvent3D.type = PointerEvent3D.POINTER_UP; + this._pointerEvent3D.mouseX = this.mouseX; + this._pointerEvent3D.mouseY = this.mouseY; + this.dispatchEvent(this._pointerEvent3D); + if (Time.time - this._downTime < 200) { + this._pointerEvent3D.type = PointerEvent3D.POINTER_CLICK; + this.dispatchEvent(this._pointerEvent3D); + } + } + + private touchMove(e: TouchEvent) { + this.mouseLastX = this.mouseX; + this.mouseLastY = this.mouseY; + + this.mouseX = e.targetTouches[0].clientX - this.canvasX; /*- Input.canvas.x + Input.canvas.offsetX*/ + this.mouseY = e.targetTouches[0].clientY - this.canvasY; /*- Input.canvas.y + Input.canvas.offsetY*/ + + this.mouseOffsetX = this.mouseX - this.mouseLastX; + this.mouseOffsetY = this.mouseY - this.mouseLastY; + + // e.preventDefault(); + // this.mouseClick.apply(this, e); + // this._touchEvent3d.reset(); + //e.preventDefault(); + + if (e.targetTouches.length > 1) { + var newPosition1: Vector3 = new Vector3(this.mouseX, this.mouseY); + var newPosition2: Vector3 = new Vector3(e.targetTouches[1].clientX - this.canvasX /*- Input.canvas.x + Input.canvas.offsetX*/, e.targetTouches[1].clientY - this.canvasY /*- Input.canvas.y + Input.canvas.offsetY*/); + + if (this._oldPosition1 == null) this._oldPosition1 = newPosition1; + if (this._oldPosition2 == null) this._oldPosition2 = newPosition2; + + if (this.isEnlarge(this._oldPosition1, this._oldPosition2, newPosition1, newPosition2)) this.wheelDelta = 120; + else this.wheelDelta = -120; + + this._oldPosition1 = newPosition1; + this._oldPosition2 = newPosition2; + } else { + } + + this._pointerEvent3D.reset(); + this._pointerEvent3D.targetTouches = this.GetTargetTouches(e.targetTouches); + this._pointerEvent3D.changedTouches = this.GetTargetTouches(e.changedTouches); + this._pointerEvent3D.touches = this.GetTargetTouches(e.touches); + this._pointerEvent3D.mouseX = this.mouseX; + this._pointerEvent3D.mouseY = this.mouseY; + // this._pointerEvent3D.target = this; + this._pointerEvent3D.type = PointerEvent3D.POINTER_MOVE; + this.dispatchEvent(this._pointerEvent3D); + } + + private GetTargetTouches(targetTouches: TouchList): Array { + var array: Array = new Array(); + for (var i = 0; i < targetTouches.length; i++) { + var touchData = new TouchData(targetTouches[i]); + array.push(touchData); + } + return array; + } + + private rightClick(e: MouseEvent) { + this._pointerEvent3D.reset(); + this._pointerEvent3D.mouseCode = e.button; + this._pointerEvent3D.mouseX = e.clientX - this.canvasX; + this._pointerEvent3D.mouseY = e.clientY - this.canvasY; + // this._pointerEvent3D.target = this; + this._pointerEvent3D.type = PointerEvent3D.POINTER_RIGHT_CLICK; + + this._pointerEvent3D.ctrlKey = e.ctrlKey; + this._pointerEvent3D.altKey = e.altKey; + this._pointerEvent3D.shiftKey = e.shiftKey; + this.dispatchEvent(this._pointerEvent3D); + } + + private middleDown(e: PointerEvent) { + this._pointerEvent3D.reset(); + this._pointerEvent3D.mouseCode = e.button; + this._pointerEvent3D.mouseX = e.clientX - this.canvasX; + this._pointerEvent3D.mouseY = e.clientY - this.canvasY; + // this._pointerEvent3D.target = this; + this._pointerEvent3D.type = PointerEvent3D.POINTER_MID_DOWN; + this._pointerEvent3D.ctrlKey = e.ctrlKey; + this._pointerEvent3D.altKey = e.altKey; + this._pointerEvent3D.shiftKey = e.shiftKey; + this._pointerEvent3D.pointerId = e.pointerId; + this._pointerEvent3D.pointerType = e.pointerType; + this._pointerEvent3D.isPrimary = e.isPrimary; + this._pointerEvent3D.pressure = e.pressure; + this.dispatchEvent(this._pointerEvent3D); + } + + private middleUp(e: PointerEvent) { + this._pointerEvent3D.reset(); + this._pointerEvent3D.mouseCode = e.button; + this._pointerEvent3D.mouseX = e.clientX - this.canvasX; + this._pointerEvent3D.mouseY = e.clientY - this.canvasY; + this._pointerEvent3D.type = PointerEvent3D.POINTER_MID_UP; + this._pointerEvent3D.ctrlKey = e.ctrlKey; + this._pointerEvent3D.altKey = e.altKey; + this._pointerEvent3D.shiftKey = e.shiftKey; + this._pointerEvent3D.pointerId = e.pointerId; + this._pointerEvent3D.pointerType = e.pointerType; + this._pointerEvent3D.isPrimary = e.isPrimary; + this._pointerEvent3D.pressure = e.pressure; + this.dispatchEvent(this._pointerEvent3D); + } + + private mouseClick(e: MouseEvent) { + this._pointerEvent3D.reset(); + this._pointerEvent3D.mouseCode = e.button; + this._pointerEvent3D.mouseX = e.clientX - this.canvasX; + this._pointerEvent3D.mouseY = e.clientY - this.canvasY; + this._pointerEvent3D.type = PointerEvent3D.POINTER_CLICK; + this._pointerEvent3D.ctrlKey = e.ctrlKey; + this._pointerEvent3D.altKey = e.altKey; + this._pointerEvent3D.shiftKey = e.shiftKey; + + this.dispatchEvent(this._pointerEvent3D); + } + + private _downTime = 0; + private mouseEnd(e: PointerEvent) { + + this.isMouseDown = false; + + this.mouseLastX = this.mouseX; + this.mouseLastY = this.mouseY; + + this.mouseX = e.clientX - this.canvasX; /*- Input.canvas.x + Input.canvas.offsetX*/ + this.mouseY = e.clientY - this.canvasY; /*- Input.canvas.y + Input.canvas.offsetY*/ + + this.mouseOffsetX = this.mouseX - this.mouseLastX; + this.mouseOffsetY = this.mouseY - this.mouseLastY; + this._pointerEvent3D.reset(); + this._pointerEvent3D.mouseCode = e.button; + + this._mouseStatus[this._pointerEvent3D.mouseCode] = false; + this._pointerEvent3D.type = PointerEvent3D.POINTER_UP; + this._pointerEvent3D.ctrlKey = e.ctrlKey; + this._pointerEvent3D.altKey = e.altKey; + this._pointerEvent3D.shiftKey = e.shiftKey; + this._pointerEvent3D.pointerId = e.pointerId; + this._pointerEvent3D.pointerType = e.pointerType; + this._pointerEvent3D.isPrimary = e.isPrimary; + this._pointerEvent3D.pressure = e.pressure; + this._pointerEvent3D.mouseX = this.mouseX; + this._pointerEvent3D.mouseY = this.mouseY; + + this.dispatchEvent(this._pointerEvent3D); + } + + private isMobile(pointerType: string): boolean { + // return /Mobile/i.test(navigator.userAgent); + return "touch" == pointerType; + } + + private mouseStart(e: PointerEvent) { + this.isMouseDown = true; + + this.mouseLastX = this.mouseX; + this.mouseLastY = this.mouseY; + + this.mouseX = e.clientX - this.canvasX; /*- Input.canvas.x + Input.canvas.offsetX*/ + this.mouseY = e.clientY - this.canvasY; /*- Input.canvas.y + Input.canvas.offsetY*/ + + this.mouseOffsetX = this.mouseX - this.mouseLastX; + this.mouseOffsetY = this.mouseY - this.mouseLastY; + + this._pointerEvent3D.reset(); + this._pointerEvent3D.mouseCode = e.button; + this._pointerEvent3D.ctrlKey = e.ctrlKey; + this._pointerEvent3D.altKey = e.altKey; + this._pointerEvent3D.shiftKey = e.shiftKey; + this._pointerEvent3D.pointerId = e.pointerId; + this._pointerEvent3D.pointerType = e.pointerType; + this._pointerEvent3D.isPrimary = e.isPrimary; + this._pointerEvent3D.pressure = e.pressure; + this._pointerEvent3D.mouseX = this.mouseX; + this._pointerEvent3D.mouseY = this.mouseY; + // if (!this._mouseStatus[this._touchEvent3d.mouseCode]) { + // this._mouseStatus[this._touchEvent3d.mouseCode] = true; + this._pointerEvent3D.type = PointerEvent3D.POINTER_DOWN; + this.dispatchEvent(this._pointerEvent3D); + // } + } + + private mouseMove(e: PointerEvent) { + this.mouseLastX = this.mouseX; + this.mouseLastY = this.mouseY; + + this.mouseX = e.clientX - this.canvasX; /*- Input.canvas.x + Input.canvas.offsetX*/ + this.mouseY = e.clientY - this.canvasY; /*- Input.canvas.y + Input.canvas.offsetY*/ + + this.mouseOffsetX = this.mouseX - this.mouseLastX; + this.mouseOffsetY = this.mouseY - this.mouseLastY; + + this._pointerEvent3D.reset(); + this._pointerEvent3D.type = PointerEvent3D.POINTER_MOVE; + this._pointerEvent3D.ctrlKey = e.ctrlKey; + this._pointerEvent3D.altKey = e.altKey; + this._pointerEvent3D.shiftKey = e.shiftKey; + this._pointerEvent3D.pointerId = e.pointerId; + this._pointerEvent3D.pointerType = e.pointerType; + this._pointerEvent3D.isPrimary = e.isPrimary; + this._pointerEvent3D.pressure = e.pressure; + this._pointerEvent3D.mouseX = this.mouseX; + this._pointerEvent3D.mouseY = this.mouseY; + + this._pointerEvent3D.movementX = e.movementX; + this._pointerEvent3D.movementY = e.movementY; + this.dispatchEvent(this._pointerEvent3D); + } + + private mouseOver(e: PointerEvent) { + + this.isMouseDown = false; + + this.mouseLastX = this.mouseX; + this.mouseLastY = this.mouseY; + + this.mouseX = e.clientX - this.canvasX; /*- Input.canvas.x + Input.canvas.offsetX*/ + this.mouseY = e.clientY - this.canvasY; /*- Input.canvas.y + Input.canvas.offsetY*/ + + this.mouseOffsetX = this.mouseX - this.mouseLastX; + this.mouseOffsetY = this.mouseY - this.mouseLastY; + + this._pointerEvent3D.reset(); + this._pointerEvent3D.type = PointerEvent3D.POINTER_OVER; + this._pointerEvent3D.ctrlKey = e.ctrlKey; + this._pointerEvent3D.altKey = e.altKey; + this._pointerEvent3D.shiftKey = e.shiftKey; + this._pointerEvent3D.pointerId = e.pointerId; + this._pointerEvent3D.pointerType = e.pointerType; + this._pointerEvent3D.isPrimary = e.isPrimary; + this._pointerEvent3D.pressure = e.pressure; + this._pointerEvent3D.mouseX = this.mouseX; + this._pointerEvent3D.mouseY = this.mouseY; + this.dispatchEvent(this._pointerEvent3D); + } + + private mouseWheel(e: WheelEvent) { + // e.stopImmediatePropagation(); + e.preventDefault(); + + this.mouseLastX = this.mouseX; + this.mouseLastY = this.mouseY; + + this.mouseX = e.clientX - this.canvasX; /*- Input.canvas.x + Input.canvas.offsetX*/ + this.mouseY = e.clientY - this.canvasY; /*- Input.canvas.y + Input.canvas.offsetY*/ + + this.mouseOffsetX = this.mouseX - this.mouseLastX; + this.mouseOffsetY = this.mouseY - this.mouseLastY; + + if (`wheelDelta` in e) { + this._pointerEvent3D.delay = e[`wheelDelta`] as number; + this.wheelDelta = e[`wheelDelta`] as number; + } else if (`delta` in e) { + this.wheelDelta = e[`delta`] as number; + } + + this._pointerEvent3D.reset(); + this._pointerEvent3D.type = PointerEvent3D.POINTER_WHEEL; + this._pointerEvent3D.ctrlKey = e.ctrlKey; + this._pointerEvent3D.altKey = e.altKey; + this._pointerEvent3D.shiftKey = e.shiftKey; + this._pointerEvent3D.mouseX = this.mouseX; + this._pointerEvent3D.mouseY = this.mouseY; + this._pointerEvent3D.deltaX = e.deltaX; + this._pointerEvent3D.deltaY = e.deltaY; + this._pointerEvent3D.deltaZ = e.deltaZ; + this.dispatchEvent(this._pointerEvent3D); + } + + private keyDown(e: KeyboardEvent) { + this._keyEvent3d.reset(); + this._keyEvent3d.keyCode = e.keyCode; + this._keyEvent3d.ctrlKey = e.ctrlKey; + this._keyEvent3d.altKey = e.altKey; + this._keyEvent3d.shiftKey = e.shiftKey; + + if (!this._keyStatus[e.keyCode]) { + this._keyStatus[e.keyCode] = true; + this._keyEvent3d.type = KeyEvent.KEY_DOWN; + this.dispatchEvent(this._keyEvent3d); + } + } + + private keyUp(e: KeyboardEvent) { + this._keyEvent3d.reset(); + this._keyEvent3d.keyCode = e.keyCode; + this._keyStatus[e.keyCode] = false; + this._keyEvent3d.type = KeyEvent.KEY_UP; + this.dispatchEvent(this._keyEvent3d); + } + + private onWindowsResize(e: UIEvent) { + let rect: DOMRect = this.canvas.getBoundingClientRect(); + + this.canvasX = rect.left; // parseInt( this.canvas.style.left.split("px")[0] ); + this.canvasY = rect.top; //rect parseInt(this.canvas.style.top.split("px")[0]); + this._windowsEvent3d.type = CResizeEvent.RESIZE; + this.dispatchEvent(this._windowsEvent3d); + } + + //返回角度 + private GetSlideAngle(dx: number, dy: number) { + return (Math.atan2(dy, dx) * 180) / Math.PI; + } + + /** + * + * 根据起点和终点返回方向 + * @param startX {Number} 起点X坐标 + * @param startY {Number} 起点Y坐标 + * @param endX {Number} 终点X坐标 + * @param endY {Number} 终点Y坐标 + * @returns result {number} 1:向上,2:向下,3:向左,4:向右,0:未滑动 + */ + public GetSlideDirection(startX: number, startY: number, endX: number, endY: number): number { + var dy = startY - endY; + var dx = endX - startX; + var result = 0; + + //如果滑动距离太短 + if (Math.abs(dx) < 2 && Math.abs(dy) < 2) { + return result; + } + + var angle = this.GetSlideAngle(dx, dy); + if (angle >= -45 && angle < 45) { + result = 4; + } else if (angle >= 45 && angle < 135) { + result = 1; + } else if (angle >= -135 && angle < -45) { + result = 2; + } else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) { + result = 3; + } + + return result; + } + + private isEnlarge(op1: Vector3, op2: Vector3, np1: Vector3, np2: Vector3): boolean { + //函数传入上一次触摸两点的位置与本次触摸两点的位置计算出用户的手势 + var leng1 = Math.sqrt((op1.x - op2.x) * (op1.x - op2.x) + (op1.y - op2.y) * (op1.y - op2.y)); + var leng2 = Math.sqrt((np1.x - np2.x) * (np1.x - np2.x) + (np1.y - np2.y) * (np1.y - np2.y)); + + if (leng1 < leng2) { + //放大手势 + return true; + } else { + //缩小手势 + return false; + } + } +} diff --git a/src/engine/io/PickFire.ts b/src/engine/io/PickFire.ts new file mode 100644 index 00000000..e39aa915 --- /dev/null +++ b/src/engine/io/PickFire.ts @@ -0,0 +1,250 @@ +import { PointerEvent3D, View3D } from '../..'; +import { ColliderComponent } from '../components/colliders/ColliderComponent'; +import { Camera3D } from '../core/Camera3D'; +import { Engine3D } from '../Engine3D'; +import { MouseCode } from '../event/MouseCode'; +import { CEventDispatcher } from '../event/CEventDispatcher'; +import { Ray } from '../math/Ray'; +import { Vector3 } from '../math/Vector3'; +import { PickCompute } from './picker/PickCompute'; +/** + * Management and triggering for picking 3D objects + * @group IO + */ +export class PickFire extends CEventDispatcher { + /** + * The ray used to pick 3D objects + */ + public ray: Ray; + + /** + * whether it's touching + */ + public isTouching: boolean = false; + private _mouseCode: MouseCode; + + private _pickEvent: PointerEvent3D; + private _outEvent: PointerEvent3D; + private _overEvent: PointerEvent3D; + private _upEvent: PointerEvent3D; + private _downEvent: PointerEvent3D; + private _mouseMove: PointerEvent3D; + private _pickCompute: PickCompute; + + //Recently Objects, picked by mousedown + private _lastDownTarget: ColliderComponent; + + /** + * a map records the association information between meshID(matrix id) and ColliderComponent + */ + public mouseEnableMap: Map; + private _view: View3D; + + constructor(view: View3D) { + super(); + this._view = view; + this.init(); + } + + /** + * Initialize the pickup initiator and call it internally during engine initialization + */ + private init(): void { + this.ray = new Ray(); + + this.mouseEnableMap = new Map(); + + this._pickEvent = new PointerEvent3D(PointerEvent3D.PICK_CLICK); + this._outEvent = new PointerEvent3D(PointerEvent3D.PICK_OUT); + this._overEvent = new PointerEvent3D(PointerEvent3D.PICK_OVER); + this._mouseMove = new PointerEvent3D(PointerEvent3D.PICK_MOVE); + this._upEvent = new PointerEvent3D(PointerEvent3D.PICK_UP); + this._downEvent = new PointerEvent3D(PointerEvent3D.PICK_DOWN); + } + + /** + * start this manager + */ + public start() { + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_DOWN, this.onTouchStart, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_UP, this.onTouchEnd, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_CLICK, this.onTouchOnce, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_MOVE, this.onTouchMove, this); + + if (Engine3D.setting.pick.mode == `pixel`) { + this._pickCompute = new PickCompute(); + this._pickCompute.init(); + } + } + + + /** + * stop this manager + */ + public stop() { + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_DOWN, this.onTouchStart, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_UP, this.onTouchEnd, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_CLICK, this.onTouchOnce, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_MOVE, this.onTouchMove, this); + } + + private onTouchStart(e: PointerEvent3D) { + // console.log(e) + this.isTouching = true; + this._mouseCode = e.mouseCode; + + this.collectEntities(); + this.pick(this._colliderOut, this._view.camera); + let target = this.findNearestObj(this._interestList, this._view.camera); + this._lastDownTarget = target; + if (target) { + this._downEvent.target = target.object3D; + this._downEvent.ctrlKey = e.ctrlKey; + this._downEvent.data = { pick: target, pickInfo: this.getPickInfo(), mouseCode: this._mouseCode }; + this.dispatchEvent(this._downEvent); + + if (target.object3D.containEventListener(PointerEvent3D.PICK_DOWN)) { + target.object3D.dispatchEvent(this._downEvent); + } + } + + } + + private onTouchEnd(e: PointerEvent3D) { + this.isTouching = false; + this._mouseCode = e.mouseCode; + + this.collectEntities(); + this.pick(this._colliderOut, this._view.camera); + let target = this.findNearestObj(this._interestList, this._view.camera); + if (target) { + this._upEvent.target = target.object3D; + this._upEvent.ctrlKey = e.ctrlKey; + this._upEvent.data = { pick: target, pickInfo: this.getPickInfo(), mouseCode: this._mouseCode }; + this.dispatchEvent(this._upEvent); + if (target.object3D.containEventListener(PointerEvent3D.PICK_UP)) { + target.object3D.dispatchEvent(this._upEvent); + } + } + + } + + private _lastFocus: ColliderComponent; + + private getPickInfo() { + return { + worldPos: this._pickCompute.getPickWorldPosition(), + screenUv: this._pickCompute.getPickScreenUV(), + meshID: this._pickCompute.getPickMeshID(), + }; + } + + private onTouchMove(e: PointerEvent3D) { + this.isTouching = true; + this._mouseCode = e.mouseCode; + this.collectEntities(); + this.pick(this._colliderOut, this._view.camera); + let target = this.findNearestObj(this._interestList, this._view.camera); + if (target) { + this._mouseMove.target = target.object3D; + this._mouseMove.ctrlKey = e.ctrlKey; + this._mouseMove.data = { pick: target, pickInfo: this.getPickInfo(), mouseCode: this._mouseCode }; + this.dispatchEvent(this._mouseMove); + if (target.object3D.containEventListener(PointerEvent3D.PICK_MOVE)) { + target.object3D.dispatchEvent(this._mouseMove); + } + } + + if (target != this._lastFocus) { + if (this._lastFocus && this._lastFocus.object3D) { + this._outEvent.target = target.object3D; + this._outEvent.data = { pick: this._lastFocus, pickInfo: this.getPickInfo(), mouseCode: this._mouseCode }; + this._outEvent.ctrlKey = e.ctrlKey; + this.dispatchEvent(this._outEvent); + if (this._lastFocus.object3D.containEventListener(PointerEvent3D.PICK_OUT)) { + this._lastFocus.object3D.dispatchEvent(this._outEvent); + } + } + if (target) { + this._overEvent.target = target.object3D; + this._overEvent.ctrlKey = e.ctrlKey; + this._overEvent.data = { pick: target, pickInfo: this.getPickInfo(), mouseCode: this._mouseCode }; + this.dispatchEvent(this._overEvent); + if (target.object3D.containEventListener(PointerEvent3D.PICK_OVER)) { + target.object3D.dispatchEvent(this._overEvent); + } + } + } + this._lastFocus = target; + } + + private onTouchOnce(e: PointerEvent3D) { + this.isTouching = true; + this._mouseCode = e.mouseCode; + this.collectEntities(); + this.pick(this._colliderOut, this._view.camera); + let target = this.findNearestObj(this._interestList, this._view.camera); + if (target) { + let info = Engine3D.setting.pick.mode == `pixel` ? this.getPickInfo() : null; + this._pickEvent.target = target.object3D; + this._pickEvent.ctrlKey = e.ctrlKey; + this._pickEvent.data = { pick: target, pickInfo: info, mouseCode: this._mouseCode }; + this.dispatchEvent(this._pickEvent); + + if (target === this._lastDownTarget && target.object3D.containEventListener(PointerEvent3D.PICK_CLICK)) { + target.object3D.dispatchEvent(this._pickEvent); + } + } + + this._lastDownTarget = null; + } + + private findNearestObj(list: ColliderComponent[], camera: Camera3D): ColliderComponent { + let target: ColliderComponent = null; + let minDistance: number = Number.MAX_VALUE; + for (const item of list) { + let curDistance = Vector3.distance(item.object3D.transform.worldPosition, camera.transform.worldPosition); + if (curDistance < minDistance) { + target = item; + minDistance = curDistance; + } + } + return target; + } + + private _colliderOut: ColliderComponent[] = []; + + private collectEntities(): ColliderComponent[] { + this._colliderOut.length = 0; + this._view.scene.getComponents(ColliderComponent, this._colliderOut); + return this._colliderOut; + } + + private _interestList: ColliderComponent[] = []; + + private pick(colliders: ColliderComponent[], camera: Camera3D) { + this._interestList.length = 0; + if (Engine3D.setting.pick.mode == `pixel`) { + this._pickCompute.compute(this._view); + let meshID = this._pickCompute.getPickMeshID(); + let iterator = this.mouseEnableMap.get(meshID); + if (iterator) { + this._interestList.push(iterator); + } + } else if (Engine3D.setting.pick.mode == `bound`) { + this.ray = camera.screenPointToRay(Engine3D.inputSystem.mouseX, Engine3D.inputSystem.mouseY); + let intersect: { intersect: boolean; intersectPoint?: Vector3; distance: number }; + for (const iterator of colliders) { + intersect = iterator.enable && iterator.rayPick(this.ray); + if (intersect) { + this._interestList.push(iterator); + } + } + } + } +} + +// /** +// * @internal +// */ +// export let pickFire: PickFire = new PickFire(); diff --git a/src/engine/io/PickResult.ts b/src/engine/io/PickResult.ts new file mode 100644 index 00000000..6573216d --- /dev/null +++ b/src/engine/io/PickResult.ts @@ -0,0 +1,70 @@ +import { Color } from '../math/Color'; +import { Triangle } from '../math/Triangle'; +import { Vector2 } from '../math/Vector2'; +import { Vector3 } from '../math/Vector3'; +/** + * Pick up result information, including target Object3D, position, UV + * @internal + * @group IO + */ +export class PickResult { + /** + * the intersection point (local coordinates) on the model. + */ + public localPosition: Vector3 = new Vector3(); + + /** + * the intersection point (world coordinates) on the model. + */ + public worldPosition: Vector3 = new Vector3(); + + /** + * the uv on the model. + * Only when the PickType of the object is UVPick and the model has UV will it be valid + * @see PickType + */ + public uv: Vector2 = new Vector2(); + + /** + * the triangle index at the intersection position of mesh + */ + public faceIndex: number; + + public isIn: boolean = false; + public t: number = 0; + public u: number = 0; + public v: number = 0; + + /** + * the triangle at the intersection position of mesh + */ + public triangle: Triangle; + + /** + * @internal + * the uv0 at the intersection position of mesh + */ + public v0: number; + + /** + * @internal + * the uv1 at the intersection position of mesh + */ + public v1: number; + + /** + * @internal + * 相交面顶点2索引 + */ + public v2: number; + + /** + * @internal + */ + public pickList: any; + + /** + * @internal + */ + public color: Color; //= new Color(); +} diff --git a/src/engine/io/RayCastMeshDetail.ts b/src/engine/io/RayCastMeshDetail.ts new file mode 100644 index 00000000..ea3856a2 --- /dev/null +++ b/src/engine/io/RayCastMeshDetail.ts @@ -0,0 +1,159 @@ +import { Triangle } from '../math/Triangle'; +import { dot } from '../math/MathUtil'; +import { Ray } from '../math/Ray'; +import { Vector2 } from '../math/Vector2'; +import { Vector3 } from '../math/Vector3'; +import { PickResult } from './PickResult'; +/** + * @internal + * @group IO + */ +export class RayCastMeshDetail { + /** + * define a tiny number + */ + public static EPS: number = 1e-4; + + /** + * define a maximum float + */ + public static FLT_MAX: number = 3.402823466e38; + + /** + * calculate the distance between a point and a plane(defined by point a, point b, point c) + */ + public static distPtTri(p: Vector3, a: Vector3, b: Vector3, c: Vector3): number { + let v0 = new Vector3(); + let v1 = new Vector3(); + let v2 = new Vector3(); + c.subtract(a, v0); + b.subtract(a, v1); + p.subtract(a, v2); + + let dot00 = dot(v0, v0); + let dot01 = dot(v0, v1); + let dot02 = dot(v0, v2); + let dot11 = dot(v1, v1); + let dot12 = dot(v1, v2); + + // Compute barycentric coordinates + let invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01); + let u = (dot11 * dot02 - dot01 * dot12) * invDenom; + let v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + // If point lies inside the triangle, return interpolated y-coord. + if (u >= -RayCastMeshDetail.EPS && v >= -RayCastMeshDetail.EPS && u + v <= 1 + RayCastMeshDetail.EPS) { + let y = a[1] + v0[1] * u + v1[1] * v; + return Math.abs(y - p[1]); + } + return RayCastMeshDetail.FLT_MAX; + } + + private static _info: PickResult = new PickResult(); + // Determine whether a ray intersect with a triangle + // Parameters + // orig: origin of the ray + // dir: direction of the ray + // v0, v1, v2: vertices of triangle + // t(out): weight of the intersection for the ray + // u(out), v(out): barycentric coordinate of intersection + public static IntersectTriangle(ray: Ray, face: Triangle, backfaceCulling: boolean): PickResult { + let v0 = face.v1; + let v1 = face.v2; + let v2 = face.v3; + + // E1 + let E1 = v1.subtract(v0, Vector3.HELP_3); + + // E2 + let E2 = v2.subtract(v0, Vector3.HELP_4); + + // P + let P = ray.direction.cross(E2, Vector3.HELP_5); + + // determinant + let det = dot(E1, P); + + // keep det > 0, modify T accordingly + let T: Vector3; + if (det > 0) { + if (backfaceCulling) { + return null; + } + T = ray.origin.subtract(v0, Vector3.HELP_2); + } else { + T = v0.subtract(ray.origin, Vector3.HELP_2); + det = -det; + } + + // If determinant is near zero, ray lies in plane of triangle + if (det < 0.0001) { + this._info.isIn = false; + this._info.t = 0; + this._info.u = 0; + this._info.v = 0; + return this._info; + } + + // Calculate u and make sure u <= 1 + let u = dot(T, P); + if (u < 0.0 || u > det) { + this._info.isIn = false; + this._info.t = 0; + this._info.u = 0; + this._info.v = 0; + return this._info; + } + + // Q + let Q = T.cross(E1, Vector3.HELP_1); + + // Calculate v and make sure u + v <= 1 + let v = dot(ray.direction, Q); + if (v < 0.0 || u + v > det) { + this._info.isIn = false; + this._info.t = 0; + this._info.u = 0; + this._info.v = 0; + return this._info; + } + + // Calculate t, scale parameters, ray intersects triangle + let t = dot(E2, Q); + + let fInvDet = 1.0 / det; + t *= fInvDet; + u *= fInvDet; + v *= fInvDet; + + this._info.isIn = true; + this._info.t = t; + this._info.u = u; + this._info.v = v; + + //(1 - u - v)V0 + uV1 + vV2 + let d = 1 - u - v; + + this._u0.copyFrom(face.u1); + this._u0.scale(d); + + this._u1.copyFrom(face.u2); + this._u1.scale(u); + + this._u2.copyFrom(face.u3); + this._u2.scale(v); + + this._info.uv.copyFrom(this._u0); + this._info.uv.add(this._u1, this._info.uv); + this._info.uv.add(this._u2, this._info.uv); + + // this.info.uv.copyFrom(face.u1); + this._info.localPosition.copyFrom(ray.direction).multiplyScalar(t); + this._info.localPosition.add(ray.origin, this._info.localPosition); + return this._info; + } + + private static _u0: Vector2 = new Vector2(); + private static _u1: Vector2 = new Vector2(); + private static _u2: Vector2 = new Vector2(); +} diff --git a/src/engine/io/TouchData.ts b/src/engine/io/TouchData.ts new file mode 100644 index 00000000..4936a3ce --- /dev/null +++ b/src/engine/io/TouchData.ts @@ -0,0 +1,68 @@ +/** + * the param of touch event。 + * Save as the basic data for touch events in touch event. see InputSystem. + * @internal + * @group IO + */ +export class TouchData { + constructor(touch: Touch) { + this.canvasX = touch.clientX; //- Input.canvas.x + Input.canvas.offsetX; + this.canvasY = touch.clientY; // Input.canvas.y + Input.canvas.offsetY; + this.identifier = touch.identifier; + this.clientX = touch.clientX; + this.clientY = touch.clientY; + this.pageX = touch.pageX; + this.pageY = touch.pageY; + this.screenX = touch.screenX; + this.screenY = touch.screenY; + } + + /** + * The horizontal offset relative to the position of the upper left corner of Canvas. + */ + public canvasX: number; + + /** + * The vertical offset relative to the position of the upper left corner of Canvas. + */ + public canvasY: number; + + /** + * touch id + */ + public identifier: number; + + /** + * The horizontal offset relative to the top left corner of the browser content area + * It will change with the movement of the scroll bar. + */ + public clientX: number; + + /** + * The ertical offset relative to the top left corner of the browser content area + * It will change with the movement of the scroll bar. + */ + public clientY: number; + + /** + * The horizontal offset relative to the top left corner of the browser content area + * It won't change with the movement of the scroll bar. + */ + public pageX: number; + + /** + * The ertical offset relative to the top left corner of the browser content area + * It won't change with the movement of the scroll bar. + */ + public pageY: number; + + /** + * The horizontal offset relative to the position of the top left corner of the user screen. + */ + public screenX: number; + + /** + * The vertical offset relative to the position of the top left corner of the user screen. + */ + public screenY: number; +} diff --git a/src/engine/io/picker/PickCompute.ts b/src/engine/io/picker/PickCompute.ts new file mode 100644 index 00000000..d56e65f0 --- /dev/null +++ b/src/engine/io/picker/PickCompute.ts @@ -0,0 +1,77 @@ +import { GBufferFrame, GPUTextureFormat, RTResourceConfig, View3D } from '../../..'; +import Picker_CsShader from '../../assets/shader/compute/Picker_CsShader.wgsl?raw'; +import { Camera3D } from '../../core/Camera3D'; +import { GlobalBindGroup } from '../../gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { ComputeGPUBuffer } from '../../gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer'; +import { ComputeShader } from '../../gfx/graphics/webGpu/shader/ComputeShader'; +import { GPUContext } from '../../gfx/renderJob/GPUContext'; +import { Vector2 } from '../../math/Vector2'; +import { Vector3 } from '../../math/Vector3'; +/** + * @internal + * @group IO + */ +export class PickCompute { + private _computeShader: ComputeShader; + private _outBuffer: ComputeGPUBuffer; + constructor() { } + + public init() { + + let rtFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer"); + + this._computeShader = new ComputeShader(Picker_CsShader); + + + + this._outBuffer = new ComputeGPUBuffer(32); + this._computeShader.setStorageBuffer('outBuffer', this._outBuffer); + this._computeShader.setSamplerTexture('visibleMap', rtFrame.getPositionMap()); + + this._outBuffer.debug(); + } + + compute(view: View3D) { + let stand = GlobalBindGroup.getCameraGroup(view.camera); + this._computeShader.setStorageBuffer('standUniform', stand.uniformGPUBuffer); + + let command = GPUContext.beginCommandEncoder(); + GPUContext.computeCommand(command, [this._computeShader]); + GPUContext.endCommandEncoder(command); + this._outBuffer.readBuffer(); + } + + /** + * Returns matrix id belongs to this model + * @returns + */ + public getPickMeshID(): number { + var meshID = this._outBuffer.outFloat32Array[0] + 0.1; + return Math.floor(meshID); + } + + /** + * Returns world position of pick result + * @returns + */ + public getPickWorldPosition(target?: Vector3): Vector3 { + target ||= new Vector3(); + var x = this._outBuffer.outFloat32Array[4]; + var y = this._outBuffer.outFloat32Array[5]; + var z = this._outBuffer.outFloat32Array[6]; + target.set(x, y, z); + return target; + } + + /** + * Returns screen coord of mouse + * @returns + */ + public getPickScreenUV(target?: Vector2): Vector2 { + target ||= new Vector2(); + var x = this._outBuffer.outFloat32Array[2]; + var y = this._outBuffer.outFloat32Array[3]; + target.set(x, y); + return target; + } +} From 2da23630f436eadc02ef91dda24def4ec5d04abf Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Mon, 24 Apr 2023 14:37:33 +0800 Subject: [PATCH 033/100] feat(textureArray): add array texture (#48) add renderTargetTexture add about depth texture --- src/engine/textures/BitmapTexture2DArray.ts | 132 ++++++++++++++++ src/engine/textures/Depth2DTextureArray.ts | 62 ++++++++ src/engine/textures/DepthCubeArrayTexture.ts | 62 ++++++++ src/engine/textures/DepthCubeTexture.ts | 77 ++++++++++ src/engine/textures/VirtualTexture.ts | 153 +++++++++++++++++++ 5 files changed, 486 insertions(+) create mode 100644 src/engine/textures/BitmapTexture2DArray.ts create mode 100644 src/engine/textures/Depth2DTextureArray.ts create mode 100644 src/engine/textures/DepthCubeArrayTexture.ts create mode 100644 src/engine/textures/DepthCubeTexture.ts create mode 100644 src/engine/textures/VirtualTexture.ts diff --git a/src/engine/textures/BitmapTexture2DArray.ts b/src/engine/textures/BitmapTexture2DArray.ts new file mode 100644 index 00000000..3abe4d09 --- /dev/null +++ b/src/engine/textures/BitmapTexture2DArray.ts @@ -0,0 +1,132 @@ +import { GPUFilterMode, GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +import { ITexture } from '../gfx/graphics/webGpu/core/texture/ITexture'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { BitmapTexture2D } from './BitmapTexture2D'; +import { GPUContext } from '../..'; + +/** + * Type BitmapTexture 2D Array , Use in GPU + * @internal + * @group Texture + */ +export class BitmapTexture2DArray extends Texture implements ITexture { + + private _bitmapTextures: BitmapTexture2D[]; + + constructor(width: number, height: number, numberLayer: number) { + super(width, height, numberLayer); + + this.visibility = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; + + // texture_depth_2d_array + this.format = GPUTextureFormat.rgba8unorm; + this.mipmapCount = 1; + + this._bitmapTextures = []; + + this.init(); + } + + /** + * fill self by set texture list + * @param texs array of BitmapTexture2D + * @returns + */ + public setTextures(texs: BitmapTexture2D[]) { + this._bitmapTextures.length = 0; + for (let i = 0; i < texs.length; i++) { + const tex = texs[i]; + this.addTexture(tex); + } + } + + /** + * add one BitmapTexture2D to this + * @param bitmapTexture the bitmapTexture2D be added + * @returns + */ + public addTexture(bitmapTexture: BitmapTexture2D) { + if (bitmapTexture.width != this.width || bitmapTexture.height != this.height) { + console.error("bitmap texture muse match bitmapTextureArray size!"); + } + if (this._bitmapTextures.indexOf(bitmapTexture) == -1) { + bitmapTexture.pid = this._bitmapTextures.length; + this._bitmapTextures.push(bitmapTexture); + this.updateTexture(); + } + } + + /** + * remove one BitmapTexture2D from this + * @param bitmapTexture the bitmapTexture2D be removed + * @returns + */ + public removeTexture(bitmapTexture: BitmapTexture2D) { + let index = this._bitmapTextures.indexOf(bitmapTexture); + if (index != -1) { + this._bitmapTextures.splice(index, 1); + for (let i = 0; i < this._bitmapTextures.length; i++) { + const bitmapTexture = this._bitmapTextures[i]; + bitmapTexture.pid = i; + } + } + } + + /** + * @internal + */ + private updateTexture() { + let encoder = GPUContext.beginCommandEncoder(); + for (let i = 0; i < this._bitmapTextures.length; i++) { + let bitmapTexture = this._bitmapTextures[i]; + encoder.copyTextureToTexture( + { + texture: bitmapTexture.getGPUTexture(), + mipLevel: 0, + origin: { x: 0, y: 0, z: 0 }, + }, + { + texture: this.getGPUTexture(), + mipLevel: 0, + origin: { x: 0, y: 0, z: i }, + }, + { + width: this.width, + height: this.height, + depthOrArrayLayers: 1, + }, + ); + } + GPUContext.endCommandEncoder(encoder); + } + + internalCreateBindingLayoutDesc() { + this.textureBindingLayout.viewDimension = `2d-array`; + this.samplerBindingLayout.type = `filtering`; + + this.minFilter = GPUFilterMode.linear; + this.magFilter = GPUFilterMode.linear; + } + + internalCreateTexture() { + this.textureDescriptor = { + format: this.format, + size: { width: this.width, height: this.height, depthOrArrayLayers: this.numberLayer }, + dimension: '2d', + usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING, + } + this.gpuTexture = webGPUContext.device.createTexture(this.textureDescriptor); + } + + internalCreateView() { + this.viewDescriptor = { + dimension: `2d-array`, + }; + this.view = this.gpuTexture.createView(this.viewDescriptor); + } + + internalCreateSampler() { + this.gpuSampler = webGPUContext.device.createSampler(this); + } +} diff --git a/src/engine/textures/Depth2DTextureArray.ts b/src/engine/textures/Depth2DTextureArray.ts new file mode 100644 index 00000000..9ce82643 --- /dev/null +++ b/src/engine/textures/Depth2DTextureArray.ts @@ -0,0 +1,62 @@ +import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +import { ITexture } from '../gfx/graphics/webGpu/core/texture/ITexture'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +/** + * Depth 2D TextureArray + * @internal + * @group Texture + */ +export class Depth2DTextureArray extends Texture implements ITexture { + + /** + * @constructor + * @width texture width (pixel) + * @width texture height (pixel) + * @width texture format, default value is depth32float + */ + constructor(width: number, height: number, format: GPUTextureFormat = GPUTextureFormat.depth32float) { + super(width, height, 4); + + this.visibility = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; + + // texture_depth_2d_array + this.format = format; + this.mipmapCount = 1; + + this.init(); + } + + internalCreateBindingLayoutDesc() { + this.textureBindingLayout.sampleType = `depth`; + this.textureBindingLayout.viewDimension = `2d-array`; + this.samplerBindingLayout.type = `filtering`; + this.sampler_comparisonBindingLayout.type = `comparison`; + } + + internalCreateTexture() { + this.textureDescriptor = { + format: this.format, + size: { width: this.width, height: this.height, depthOrArrayLayers: this.numberLayer }, + dimension: '2d', + usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING, + } + this.gpuTexture = webGPUContext.device.createTexture(this.textureDescriptor); + } + + internalCreateView() { + this.viewDescriptor = { + dimension: `2d-array`, + }; + this.view = this.gpuTexture.createView(this.viewDescriptor); + } + + internalCreateSampler() { + this.gpuSampler = webGPUContext.device.createSampler({}); + this.gpuSampler_comparison = webGPUContext.device.createSampler({ + compare: 'less', + label: "sampler_comparison" + }); + } + +} diff --git a/src/engine/textures/DepthCubeArrayTexture.ts b/src/engine/textures/DepthCubeArrayTexture.ts new file mode 100644 index 00000000..4cfdb8ff --- /dev/null +++ b/src/engine/textures/DepthCubeArrayTexture.ts @@ -0,0 +1,62 @@ +import { GPUFilterMode, GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +import { ITexture } from '../gfx/graphics/webGpu/core/texture/ITexture'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +/** + * depth cube array texture + * @internal + * @group Texture + */ +export class DepthCubeArrayTexture extends Texture implements ITexture { + + /** + * @constructor + */ + constructor(width: number, height: number, numberLayer: number) { + super(width, height, numberLayer); + + this.visibility = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; + + // texture_depth_2d_array + this.format = GPUTextureFormat.depth32float; + this.mipmapCount = 1; + + this.init(); + } + + internalCreateBindingLayoutDesc() { + this.textureBindingLayout.sampleType = `depth`; + this.textureBindingLayout.viewDimension = `cube-array`; + this.samplerBindingLayout.type = `filtering`; + this.sampler_comparisonBindingLayout.type = `comparison`; + } + + internalCreateTexture() { + this.textureDescriptor = { + format: this.format, + size: { width: this.width, height: this.height, depthOrArrayLayers: 6 * this.numberLayer }, + dimension: '2d', + usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING, + } + this.gpuTexture = webGPUContext.device.createTexture(this.textureDescriptor); + } + + internalCreateView() { + this.viewDescriptor = { + dimension: `cube-array`, + }; + this.view = this.gpuTexture.createView(this.viewDescriptor); + } + + internalCreateSampler() { + this.gpuSampler = webGPUContext.device.createSampler({ + minFilter: GPUFilterMode.linear, + magFilter: GPUFilterMode.linear, + }); + this.gpuSampler_comparison = webGPUContext.device.createSampler({ + compare: 'less', + label: "sampler_comparison" + }); + } + +} diff --git a/src/engine/textures/DepthCubeTexture.ts b/src/engine/textures/DepthCubeTexture.ts new file mode 100644 index 00000000..dd19734d --- /dev/null +++ b/src/engine/textures/DepthCubeTexture.ts @@ -0,0 +1,77 @@ +import { webGPUContext } from "../gfx/graphics/webGpu/Context3D"; +import { GPUTextureFormat } from "../gfx/graphics/webGpu/WebGPUConst"; +import { ITexture } from "../gfx/graphics/webGpu/core/texture/ITexture"; +import { Texture } from "../gfx/graphics/webGpu/core/texture/Texture"; + +/** + * cube texture witch data if for depth + * @internal + * @group Texture + */ +export class DepthCubeTexture extends Texture implements ITexture { + + /** + * texture width, default value is 4 + */ + public width: number = 4; + + /** + * texture height, default value is 4 + */ + public height: number = 4; + + /** + * depth or array layers, default value is 6 + */ + public depthOrArrayLayers: number = 6; + + /** + * GPUShaderStage + */ + public visibility: number = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; + + /** + * @constructor + */ + constructor(width: number, height: number) { + super(width, height, 6); + + // texture_depth_2d_array + this.format = GPUTextureFormat.depth24plus; + this.mipmapCount = 1; + + this.init(); + } + + public internalCreateBindingLayoutDesc() { + this.samplerBindingLayout.type = `non-filtering`; + this.textureBindingLayout.sampleType = `unfilterable-float`; + this.textureBindingLayout.viewDimension = 'cube'; + } + + public internalCreateTexture() { + this.textureDescriptor = { + format: `depth24plus`, + size: { width: this.width, height: this.height, depthOrArrayLayers: 6 }, + dimension: '2d', + usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING, + } + this.gpuTexture = webGPUContext.device.createTexture(this.textureDescriptor); + } + + public internalCreateView() { + this.viewDescriptor = { + dimension: `cube`, + }; + this.view = this.gpuTexture.createView(this.viewDescriptor); + } + + public internalCreateSampler() { + this.gpuSampler = webGPUContext.device.createSampler({}); + this.gpuSampler_comparison = webGPUContext.device.createSampler({ + compare: 'less', + label: "sampler_comparison" + }); + } + +} diff --git a/src/engine/textures/VirtualTexture.ts b/src/engine/textures/VirtualTexture.ts new file mode 100644 index 00000000..d648033a --- /dev/null +++ b/src/engine/textures/VirtualTexture.ts @@ -0,0 +1,153 @@ +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { GPUAddressMode, GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +import { GPUContext } from '../gfx/renderJob/GPUContext'; +import { UUID } from '../util/Global'; +/** + * @internal + * Render target texture + * Render what we want to render onto a texture instead of rendering it onto the screen as we usually do + * @group Texture + */ +export class VirtualTexture extends Texture { + public resolveTarget: GPUTextureView; + // storeOp: string = 'store'; + // loadOp: GPULoadOp = `load`; + // clearValue: GPUColor = [0, 0, 0, 0]; + + /** + * create virtual texture + * @param width width of texture + * @param height height of texture + * @param format GPUTextureFormat, default value is rgba8unorm + * @param useMipmap whether or not gen mipmap + * @returns + */ + constructor(width: number, height: number, format: GPUTextureFormat = GPUTextureFormat.rgba8unorm, useMipMap: boolean = false, usage?: number, textureCount: number = 1, sampleCount: number = 0, clear: boolean = true) { + super(width, height, textureCount); + let device = webGPUContext.device; + this.name = UUID(); + + if (usage != undefined) { + this.usage = usage; + } else { + this.usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST; + } + + this.createTextureDescriptor(width, height, 1, format, this.usage, textureCount, sampleCount); + + // this.loadOp = clear ? `clear` : `load` + // this.loadOp = `clear` + + this.useMipmap = false; + + this.visibility = GPUShaderStage.COMPUTE | GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT; + + if (format == GPUTextureFormat.rgba32float) { + this.samplerBindingLayout.type = `non-filtering`; + this.textureBindingLayout.sampleType = `unfilterable-float`; + this.gpuSampler = device.createSampler({}); + } else if (format == GPUTextureFormat.depth32float) { + this.samplerBindingLayout.type = `filtering`; + this.sampler_comparisonBindingLayout.type = `comparison`; + this.textureBindingLayout.sampleType = `depth`; + this.gpuSampler = webGPUContext.device.createSampler({}); + this.gpuSampler_comparison = webGPUContext.device.createSampler({ + compare: 'less', + label: "sampler_comparison" + }); + } else if (format == GPUTextureFormat.depth24plus) { + this.samplerBindingLayout = { + type: `filtering`, + } + this.sampler_comparisonBindingLayout = { + type: 'comparison', + } + this.textureBindingLayout.sampleType = `depth`; + this.gpuSampler = webGPUContext.device.createSampler({}); + this.gpuSampler_comparison = webGPUContext.device.createSampler({ + compare: 'less', + label: "sampler_comparison" + }); + } else { + this.samplerBindingLayout.type = `filtering`; + this.textureBindingLayout.sampleType = `float`; + if (sampleCount > 0) { + this.textureBindingLayout.multisampled = true; + } + this.minFilter = 'linear'; + this.magFilter = 'linear'; + this.mipmapFilter = `linear`; + this.maxAnisotropy = 16; + + this.addressModeU = GPUAddressMode.clamp_to_edge; + this.addressModeV = GPUAddressMode.clamp_to_edge; + // this.visibility = GPUShaderStage.FRAGMENT; + this.gpuSampler = device.createSampler(this); + } + } + + /** + * create rt texture + * @param width texture width + * @param height texture height + * @param data texture pixel data + * @param useMipmap texture use mipmap switch + * @returns + */ + public create(width: number, height: number, useMiamp: boolean = true) { + let device = webGPUContext.device; + const bytesPerRow = width * 4; + let td = new Float32Array(width * height * 4); + + const textureDataBuffer = device.createBuffer({ + size: td.byteLength, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, + }); + + device.queue.writeBuffer(textureDataBuffer, 0, td); + const commandEncoder = GPUContext.beginCommandEncoder(); + commandEncoder.copyBufferToTexture( + { + buffer: textureDataBuffer, + bytesPerRow: bytesPerRow, + }, + { + texture: this.getGPUTexture(), + }, + { + width: width, + height: height, + depthOrArrayLayers: 1, + }, + ); + + GPUContext.endCommandEncoder(commandEncoder); + } + + public readTextureToImage() { + let device = webGPUContext.device; + let w = webGPUContext.windowWidth; + let h = webGPUContext.windowHeight; + const bytesPerRow = w * 4; + let td = new Float32Array(w * h * 4); + + const textureBuffer = device.createBuffer({ + size: td.byteLength, + usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, + }); + const commandEncoder = GPUContext.beginCommandEncoder(); + commandEncoder.copyTextureToBuffer( + { + texture: this.getGPUTexture() + }, + { + buffer: textureBuffer + }, + [w, h] + ); + + let arryBuffer = textureBuffer.getMappedRange(0, td.byteLength); + } + +} From a6dbca0ff9fc1faad611a5bda2deaa6120c7294a Mon Sep 17 00:00:00 2001 From: hellmor Date: Mon, 24 Apr 2023 14:38:50 +0800 Subject: [PATCH 034/100] feat(component): Add other component files (#47) Add other component files into engine --- src/engine/components/ColliderComponent.ts | 65 ++++ .../components/shape/BoxColliderShape.ts | 57 ++++ .../components/shape/CapsuleColliderShape.ts | 26 ++ src/engine/components/shape/ColliderShape.ts | 89 ++++++ .../components/shape/MeshColliderShape.ts | 21 ++ .../components/shape/SphereColliderShape.ts | 58 ++++ src/engine/core/pool/ObjectPool.ts | 37 +++ .../core/tree/kdTree/IKDTreeUserData.ts | 12 + src/engine/core/tree/kdTree/KDTreeEntity.ts | 62 ++++ src/engine/core/tree/kdTree/KDTreeNode.ts | 289 ++++++++++++++++++ src/engine/core/tree/kdTree/KDTreeSpace.ts | 72 +++++ 11 files changed, 788 insertions(+) create mode 100644 src/engine/components/ColliderComponent.ts create mode 100644 src/engine/components/shape/BoxColliderShape.ts create mode 100644 src/engine/components/shape/CapsuleColliderShape.ts create mode 100644 src/engine/components/shape/ColliderShape.ts create mode 100644 src/engine/components/shape/MeshColliderShape.ts create mode 100644 src/engine/components/shape/SphereColliderShape.ts create mode 100644 src/engine/core/pool/ObjectPool.ts create mode 100644 src/engine/core/tree/kdTree/IKDTreeUserData.ts create mode 100644 src/engine/core/tree/kdTree/KDTreeEntity.ts create mode 100644 src/engine/core/tree/kdTree/KDTreeNode.ts create mode 100644 src/engine/core/tree/kdTree/KDTreeSpace.ts diff --git a/src/engine/components/ColliderComponent.ts b/src/engine/components/ColliderComponent.ts new file mode 100644 index 00000000..d408ce81 --- /dev/null +++ b/src/engine/components/ColliderComponent.ts @@ -0,0 +1,65 @@ +import { Engine3D } from '../../Engine3D'; +import { Ray } from '../../math/Ray'; +import { Vector3 } from '../../math/Vector3'; +import { ComponentType } from '../../util/SerializeDefine'; +import { ComponentBase } from '../ComponentBase'; +import { BoxColliderShape } from './shape/BoxColliderShape'; +import { ColliderShape } from './shape/ColliderShape'; + +/** + * collider component + * @group Components + */ +export class ColliderComponent extends ComponentBase { + private _shape: ColliderShape; + + constructor() { + super(); + this._shape = new BoxColliderShape(); + this.componentType = ComponentType.collider; + } + /** + * @internal + */ + protected start(): void { + if (Engine3D.setting.pick.mode == `pixel`) { + this.transform.scene3D.view.pickFire.mouseEnableMap.set(this.transform.worldMatrix.index, this); + } + } + + /** + * Returns the shape of collider + */ + public get shape(): ColliderShape { + return this._shape; + } + + /** + * Set the shape of collider + */ + public set shape(value: ColliderShape) { + this._shape = value; + } + + /** + * @internal + * @param ray + * @returns + */ + public rayPick(ray: Ray): { intersect: boolean; intersectPoint?: Vector3; distance: number } { + if (this._enable) { + return this._shape.rayPick(ray, this.transform.worldMatrix); + } + return null; + } + /** + * @internal + */ + public destroy() { + if (Engine3D.setting.pick.mode == `pixel`) { + this.transform.scene3D.view.pickFire.mouseEnableMap.delete(this.transform.worldMatrix.index); + } + super.destroy(); + } + +} diff --git a/src/engine/components/shape/BoxColliderShape.ts b/src/engine/components/shape/BoxColliderShape.ts new file mode 100644 index 00000000..4f1e090b --- /dev/null +++ b/src/engine/components/shape/BoxColliderShape.ts @@ -0,0 +1,57 @@ +import { BoundingBox } from '../../../core/bound/BoundingBox'; +import { Matrix4 } from '../../../math/Matrix4'; +import { Ray } from '../../../math/Ray'; +import { Vector3 } from '../../../math/Vector3'; +import { ColliderShape, ColliderShapeType } from './ColliderShape'; + +/** + * Box shaped collision body. + * It is a basic box shaped primitive collision body. + * @group Collider + */ +export class BoxColliderShape extends ColliderShape { + private _pickRet: { intersect: boolean; intersectPoint?: Vector3; distance: number }; + private readonly box: BoundingBox; + + private static v3_help_0: Vector3 = new Vector3(); + private static helpMatrix: Matrix4 = new Matrix4(); + private static helpRay: Ray = new Ray(); + + /** + * @constructor + */ + constructor() { + super(); + this._shapeType = ColliderShapeType.Box; + this.box = new BoundingBox(new Vector3(), new Vector3()); + } + + /** + * @internal + * @param ray + * @param fromMatrix + * @returns + */ + public rayPick(ray: Ray, fromMatrix: Matrix4): { intersect: boolean; intersectPoint?: Vector3; distance: number } { + let box = this.box; + box.setFromCenterAndSize(this.center, this.size); + + let helpMatrix = BoxColliderShape.helpMatrix; + helpMatrix.copyFrom(fromMatrix).invert(); + + let helpRay = BoxColliderShape.helpRay.copy(ray); + helpRay.applyMatrix(helpMatrix); + + let pick = helpRay.intersectBox(this.box, BoxColliderShape.v3_help_0); + if (pick) { + if (!this._pickRet) { + this._pickRet = { intersect: false, intersectPoint: new Vector3(), distance: 0 }; + } + this._pickRet.intersect = true; + this._pickRet.intersectPoint = pick; + this._pickRet.distance = Vector3.distance(helpRay.origin, BoxColliderShape.v3_help_0); + return this._pickRet; + } + return null; + } +} diff --git a/src/engine/components/shape/CapsuleColliderShape.ts b/src/engine/components/shape/CapsuleColliderShape.ts new file mode 100644 index 00000000..5cb4cf76 --- /dev/null +++ b/src/engine/components/shape/CapsuleColliderShape.ts @@ -0,0 +1,26 @@ +import { ColliderShape, ColliderShapeType } from './ColliderShape'; +/** + * Capsule collision body. + * Composed of two hemispheres connected to a cylinder. + * @group Collider + */ +export class CapsuleColliderShape extends ColliderShape { + /** + * The radius of the local width of the collision body. + */ + public radius: number = 2.5; + /** + * The total height of the collision body. + */ + public height: number = 10; + + constructor() { + super(); + this._shapeType = ColliderShapeType.Capsule; + } + // constructor(center: Vector3, radius: number, height: number) { + // super(center, new Vector3(radius, radius, radius)); + // this.radius = radius; + // this.height = height; + // } +} diff --git a/src/engine/components/shape/ColliderShape.ts b/src/engine/components/shape/ColliderShape.ts new file mode 100644 index 00000000..eadbec52 --- /dev/null +++ b/src/engine/components/shape/ColliderShape.ts @@ -0,0 +1,89 @@ +import { Matrix4 } from '../../../math/Matrix4'; +import { Ray } from '../../../math/Ray'; +import { Vector3 } from '../../../math/Vector3'; + +export enum ColliderShapeType { + None, + Box, + Capsule, + Sphere, + Mesh, +} + +/** + * Shape of collider body, Base class of collider shape + * @group Collider + */ +export class ColliderShape { + private _center: Vector3; + private _size: Vector3; + private _halfSize: Vector3; + protected _shapeType: ColliderShapeType = ColliderShapeType.None; + + constructor() { + this._center = new Vector3(); + this._size = new Vector3(); + this._halfSize = new Vector3(); + } + + public get shapeType() { + return this._shapeType; + } + + /** + * Set the position and size of collision objects + * @param ct The position of the collision object in the local space of the object. + * @param sz The size of the collision body in the X, Y, and Z directions. + * @returns + */ + public setFromCenterAndSize(ct?: Vector3, sz?: Vector3): this { + ct && this._center.copy(ct); + sz && this._size.copy(sz); + return this; + } + + /** + * The position of the collision object in the local space of the object. + */ + public get center(): Vector3 { + return this._center; + } + + public set center(value: Vector3) { + this._center.copy(value); + } + + /** + * + * The size of the collision body in the X, Y, and Z directions. + * @returns Vector3 + */ + public get size(): Vector3 { + return this._size; + } + + public set size(value: Vector3) { + this._size.copy(value); + this._halfSize.copy(value).multiplyScalar(0.5); + } + + /** + * Half the size of the collision body. + */ + public get halfSize(): Vector3 { + return this._halfSize; + } + + /** + * Ray pickup.Emit a ray from a designated location to detect objects colliding with the ray. + * @param ray emit ray + * @param fromMatrix matrix + * @returns Pick result intersect: whether to collide; + * IntersectPoint: collision point; + * Distance: The distance from the origin of the ray to the collision point. + */ + public rayPick(ray: Ray, fromMatrix: Matrix4): { intersect: boolean; intersectPoint?: Vector3; distance: number } { + return null; + } + +} diff --git a/src/engine/components/shape/MeshColliderShape.ts b/src/engine/components/shape/MeshColliderShape.ts new file mode 100644 index 00000000..fdc76cbe --- /dev/null +++ b/src/engine/components/shape/MeshColliderShape.ts @@ -0,0 +1,21 @@ +import { MeshComponent } from '../../renderer/MeshComponent'; +import { ColliderShape, ColliderShapeType } from './ColliderShape'; +/** + * Mesh collision body + * @group Collider + */ +export class MeshColliderShape extends ColliderShape { + /** + * meshComponent + */ + public mesh: MeshComponent; + + constructor() { + super(); + this._shapeType = ColliderShapeType.Mesh; + } + // constructor(mesh: MeshComponent) { + // super(new Vector3(0, 0, 0), new Vector3(0, 0, 0)); + // this.mesh = mesh; + // } +} diff --git a/src/engine/components/shape/SphereColliderShape.ts b/src/engine/components/shape/SphereColliderShape.ts new file mode 100644 index 00000000..5daf06bf --- /dev/null +++ b/src/engine/components/shape/SphereColliderShape.ts @@ -0,0 +1,58 @@ +import { ColliderShape, ColliderShapeType } from './ColliderShape'; +import { Matrix4 } from '../../../math/Matrix4'; +import { Ray } from '../../../math/Ray'; +import { Vector3 } from '../../../math/Vector3'; +import { BoundingSphere } from '../../../core/bound/BoundingSphere'; + +/** + * Spherical collision body + * @group Collider + */ +export class SphereColliderShape extends ColliderShape { + + private _pickRet: { intersect: boolean; intersectPoint?: Vector3; distance: number }; + private readonly box: BoundingSphere; + + private static v3_help_0: Vector3 = new Vector3(); + private static helpMatrix: Matrix4 = new Matrix4(); + private static helpRay: Ray = new Ray(); + + /** + * radius of this collider + */ + public radius: number = 0.5; + + /** + * @constructor + * @param radius radius of this collider + */ + constructor(radius: number) { + super(); + this._shapeType = ColliderShapeType.Sphere; + this.radius = radius; + this.box = new BoundingSphere(new Vector3(), 1); + } + + public rayPick(ray: Ray, fromMatrix: Matrix4): { intersect: boolean; intersectPoint?: Vector3; distance: number } { + let box = this.box; + box.setFromCenterAndSize(this.center, this.radius); + + let helpMatrix = SphereColliderShape.helpMatrix; + helpMatrix.copyFrom(fromMatrix).invert(); + + let helpRay = SphereColliderShape.helpRay.copy(ray); + helpRay.applyMatrix(helpMatrix); + + let pick = helpRay.intersectSphere(helpRay.origin, helpRay.direction, this.box.center, this.box.radius); + if (pick) { + if (!this._pickRet) { + this._pickRet = { intersect: false, intersectPoint: new Vector3(), distance: 0 }; + } + this._pickRet.intersect = true; + this._pickRet.intersectPoint = pick; + this._pickRet.distance = Vector3.distance(helpRay.origin, SphereColliderShape.v3_help_0); + return this._pickRet; + } + return null; + } +} diff --git a/src/engine/core/pool/ObjectPool.ts b/src/engine/core/pool/ObjectPool.ts new file mode 100644 index 00000000..d2ed3f72 --- /dev/null +++ b/src/engine/core/pool/ObjectPool.ts @@ -0,0 +1,37 @@ + +export class PoolNode { + private _use: T[]; + private _unUse: T[]; + + constructor() { + this._use = []; + this._unUse = []; + } + + public pushBack(node: T) { + let index = this._use.indexOf(node); + if (index != -1) { + this._use.splice(index, 1); + this._unUse.push(node); + } + } + + public getOne(instance: { new (): T }): T { + let node: T; + if (this._unUse.length > 0) { + node = this._unUse[0]; + this._unUse.splice(0, 1); + this._use.push(node); + return node; + } else { + node = new instance(); + this._use.push(node); + } + + return node; + } + + public hasFree(): boolean { + return this._unUse.length > 0; + } +} diff --git a/src/engine/core/tree/kdTree/IKDTreeUserData.ts b/src/engine/core/tree/kdTree/IKDTreeUserData.ts new file mode 100644 index 00000000..2beb6754 --- /dev/null +++ b/src/engine/core/tree/kdTree/IKDTreeUserData.ts @@ -0,0 +1,12 @@ +import { RenderNode } from '../../../components/renderer/RenderNode'; +import { KDTreeEntity } from '../kdTree/KDTreeEntity'; +/** + * @internal + * @group Core + */ +export class IKDTreeUserData { + get data(): RenderNode { + return null; + } + entity: KDTreeEntity; +} diff --git a/src/engine/core/tree/kdTree/KDTreeEntity.ts b/src/engine/core/tree/kdTree/KDTreeEntity.ts new file mode 100644 index 00000000..2a18b638 --- /dev/null +++ b/src/engine/core/tree/kdTree/KDTreeEntity.ts @@ -0,0 +1,62 @@ + +import { Ray } from '../../../math/Ray'; +import { Vector3 } from '../../../math/Vector3'; +import { BoundingBox } from '../../bound/BoundingBox'; +import { IKDTreeUserData } from './IKDTreeUserData'; +import { KDTreeNode, KDTreeUUID } from './KDTreeNode'; +/** + * @internal + * @group Core + */ +export class KDTreeEntity extends KDTreeUUID { + public readonly userData: IKDTreeUserData; + public node: KDTreeNode; + + public constructor(data: IKDTreeUserData) { + super(); + this.userData = data; + } + + public centerValue(dimension: string): number { + return 0; + } + + public isInNode(node: KDTreeNode, dimension: string): boolean { + return false; + } + + public entityContainPoint(point: { [p: string]: number }): boolean { + return false; + } + + public squareDistanceTo(point: { [p: string]: number }, dimensions: string[]): number { + return Number.MAX_VALUE; + } + + public entityIntersectsBox(box: BoundingBox): boolean { + return false; + } + + public entityIntersectsRay(ray: Ray, target: Vector3): boolean { + return false; + } + + public attachTreeNode(node: KDTreeNode): boolean { + if (this.node) this.detachTreeNode(); + this.node = node; + return this.node.pushEntity(this); + } + + public detachTreeNode(): boolean { + let success = this.node.removeEntity(this); + this.node = null; + return success; + } + + public updateNode(root: KDTreeNode): void { + let lastNode = this.node; + if (lastNode) this.detachTreeNode(); + root.updateEntity(this); + if (lastNode) lastNode.autoClear(); + } +} diff --git a/src/engine/core/tree/kdTree/KDTreeNode.ts b/src/engine/core/tree/kdTree/KDTreeNode.ts new file mode 100644 index 00000000..0b3aafce --- /dev/null +++ b/src/engine/core/tree/kdTree/KDTreeNode.ts @@ -0,0 +1,289 @@ + +import { Ray } from '../../../math/Ray'; +import { Vector3 } from '../../../math/Vector3'; +import { BoundingBox } from '../../bound/BoundingBox'; +import { IKDTreeUserData } from './IKDTreeUserData'; +import { KDTreeEntity } from './KDTreeEntity'; +import { KDTreeSpace } from './KDTreeSpace'; +/** + * @internal + * @group Core + */ +class KDTreeConfig { + public static readonly MaxEntityCountInLeaf = 4; + public static readonly MaxLayer = 10; + public static readonly ClearLeafLayer = KDTreeConfig.MaxLayer - 4; +} +/** + * @internal + * @group Core + */ +export class KDTreeUUID { + private static UUID = 0; + public readonly uuid: string = '0'; + public constructor() { + this.uuid = (KDTreeUUID.UUID++).toString(); + } +} +/** + * @internal + * @group Core + */ +class KDTreeNodeMap { + public map: { [key: string]: KDTreeEntity } = {}; + private _count: number = 0; + public get count(): number { + return this._count; + } + + public push(entity: KDTreeEntity): boolean { + let last = this.map[entity.uuid]; + if (!last) { + this.map[entity.uuid] = entity; + this._count++; + return true; + } + return false; + } + + public remove(uuid: string): boolean { + let last = this.map[uuid]; + if (last) { + delete this.map[uuid]; + this._count--; + return true; + } + return false; + } +} +/** + * @internal + * @group Core + */ +export class KDTreeNode extends KDTreeUUID { + protected _dimensionIndex: number = 0; + protected _dimensions: string[]; + protected _dimension: string; + + protected _left: KDTreeNode; + protected _right: KDTreeNode; + + protected _space: KDTreeSpace; + protected _parent: KDTreeNode; + protected _entities: KDTreeNodeMap; + protected readonly layer; + + public get dimension(): string { + return this._dimension; + } + + constructor(layer: number = 0) { + super(); + this.layer = layer; + KDTreeNode.nodeCount++; + // console.log('auto create', KDTreeNode.nodeCount); + } + + public initNode(parent: KDTreeNode, dimensions: string[], index: number): this { + this._dimensions = dimensions; + this._dimensionIndex = index; + this._dimension = dimensions[index]; + this._space = new KDTreeSpace().initSpace(dimensions); + if (parent) this._space.copySpace(parent._space); + this._parent = parent; + this._entities = new KDTreeNodeMap(); + return this; + } + + public updateEntity(entity: KDTreeEntity): void { + if (entity.isInNode(this, this._dimension)) { + entity.attachTreeNode(this); + this.autoSplit(); + if (this._left && this._right) { + let nextIndex = (this._dimensionIndex + 1) % this._dimensions.length; + let nextDimension: string = this._dimensions[nextIndex]; + if (entity.isInNode(this._right, nextDimension)) { + this._right.updateEntity(entity); + } else if (entity.isInNode(this._left, nextDimension)) { + this._left.updateEntity(entity); + } + } + } + } + + public buildRoot(list: IKDTreeUserData[]) { + for (const obj of list) { + obj.entity.attachTreeNode(this); + } + this.autoSplit(); + } + + private _splitEntityList: KDTreeEntity[] = []; + protected autoSplit(): void { + if (this._entities.count > KDTreeConfig.MaxEntityCountInLeaf && !this._right && !this._left && this.layer < KDTreeConfig.MaxLayer) { + let tempList = this._splitEntityList; + let nextIndex = (this._dimensionIndex + 1) % this._dimensions.length; + let nextDimension: string = this._dimensions[nextIndex]; + let divide: number = 0; + for (const key in this._entities.map) { + let entity = this._entities.map[key]; + divide += entity.centerValue(nextDimension); + tempList.push(entity); + } + + divide /= this._entities.count; + this._left = new KDTreeNode(this.layer + 1); + this._right = new KDTreeNode(this.layer + 1); + + this._left.initNode(this, this._dimensions, nextIndex); + this._right.initNode(this, this._dimensions, nextIndex); + this._left.setSpace(true, divide); + this._right.setSpace(false, divide); + + for (let entity of tempList) { + if (entity.isInNode(this._right, nextDimension)) { + entity.attachTreeNode(this._right); + } else if (entity.isInNode(this._left, nextDimension)) { + entity.attachTreeNode(this._left); + } + } + } + + this._left && this._left.autoSplit(); + this._right && this._right.autoSplit(); + } + + protected setSpace(less: boolean, value: number): this { + if (this._parent) { + this._space.splitSpace(this._dimension, less, value); + } + return this; + } + + protected isEmpty(): boolean { + return this._left == null && this._right == null && this._entities.count == 0; + } + + public pushEntity(entity: KDTreeEntity): boolean { + return this._entities.push(entity); + } + + public removeEntity(entity: KDTreeEntity): boolean { + return this._entities.remove(entity.uuid); + } + + public static nodeCount: number = 0; + public autoClear(): void { + let that: KDTreeNode = this; + while (that && that.layer > KDTreeConfig.ClearLeafLayer && that.clearLeaf()) { + that = that._parent; + } + } + + protected clearLeaf(): boolean { + let isEmpty0 = !this._left && !this._right; + let isEmpty1 = !isEmpty0 && this._left.isEmpty() && this._right.isEmpty(); + if (isEmpty1) { + this._left = this._right = null; + KDTreeNode.nodeCount -= 2; + // console.log('auto clear', KDTreeNode.nodeCount); + } + return isEmpty0 || isEmpty1; + } + + public isContain(value: number): boolean { + return this._space.isContain(this._dimension, value); + } + + private static rangeBox: BoundingBox = new BoundingBox(new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE), new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE)); + protected nodeIntersectsBox(box: BoundingBox): boolean { + let x = this._space.getRange('x'); + let y = this._space.getRange('y'); + let z = this._space.getRange('z'); + let rangeBox = KDTreeNode.rangeBox; + rangeBox.min.set(x.min, y.min, z.min); + rangeBox.max.set(x.max, y.max, z.max); + return rangeBox.intersectsBox(box); + } + + protected nodeIntersectsRay(ray: Ray): boolean { + let x = this._space.getRange('x'); + let y = this._space.getRange('y'); + let z = this._space.getRange('z'); + let rangeBox = KDTreeNode.rangeBox; + rangeBox.min.set(x.min, y.min, z.min); + rangeBox.max.set(x.max, y.max, z.max); + // return ray.intersectsBox(rangeBox); + return true; + } + + public pointCast(point: { [key: string]: number }, squareDistance: number = 0, ret?: KDTreeEntity[]) { + ret = ret || []; + if (this._entities.count > 0) { + let map: { [key: string]: KDTreeEntity } = this._entities.map; + for (let key in map) { + let entity = map[key]; + let success = entity.entityContainPoint(point); + if (!success && squareDistance > 0) { + success = entity.squareDistanceTo(point, this._dimensions) <= squareDistance; + } + if (success) { + ret.push(entity); + } + } + } + if (this._left && this._left.isContain(point[this._left.dimension])) { + this._left.pointCast(point, squareDistance, ret); + } + + if (this._right && this._right.isContain(point[this._right.dimension])) { + this._right.pointCast(point, squareDistance, ret); + } + } + + public boxCast(box: BoundingBox, ret?: KDTreeEntity[]) { + ret = ret || []; + if (this._entities.count > 0) { + let map: { [key: string]: KDTreeEntity } = this._entities.map; + for (let key in map) { + let entity = map[key]; + if (entity.entityIntersectsBox(box)) { + ret.push(entity); + } + } + } + + if (this._left && this._left.nodeIntersectsBox(box)) { + this._left.boxCast(box, ret); + } + + if (this._right && this._right.nodeIntersectsBox(box)) { + this._right.boxCast(box, ret); + } + } + + private pointIntersect: Vector3 = new Vector3(); + public rayCast(ray: Ray, ret?: KDTreeEntity[], pts?: Vector3[]) { + ret = ret || []; + pts = pts || []; + let target = this.pointIntersect; + if (this._entities.count > 0) { + let map: { [key: string]: KDTreeEntity } = this._entities.map; + for (let key in map) { + let entity = map[key]; + if (entity.entityIntersectsRay(ray, target)) { + pts.push(new Vector3().copyFrom(target)); + ret.push(entity); + } + } + } + + if (this._left && this._left.nodeIntersectsRay(ray)) { + this._left.rayCast(ray, ret, pts); + } + + if (this._right && this._right.nodeIntersectsRay(ray)) { + this._right.rayCast(ray, ret, pts); + } + } +} diff --git a/src/engine/core/tree/kdTree/KDTreeSpace.ts b/src/engine/core/tree/kdTree/KDTreeSpace.ts new file mode 100644 index 00000000..30715f63 --- /dev/null +++ b/src/engine/core/tree/kdTree/KDTreeSpace.ts @@ -0,0 +1,72 @@ +/** + * @internal + * @group Core + */ +export class KDTreeRange { + public min: number = 0; + public max: number = 0; + + public set(min: number, max: number): this { + this.max = max; + this.min = min; + return this; + } + + public copy(src: KDTreeRange): this { + this.max = src.max; + this.min = src.min; + return this; + } + + public isInterestRange(src: KDTreeRange): boolean { + let fail = this.max > src.min || src.max < this.min; + return !fail; + } +} + +/** + * @internal + * @group Core + */ +export class KDTreeSpace { + protected _spaceDesc: { [key: string]: KDTreeRange }; + + public getRange(dimension: string): KDTreeRange { + return this._spaceDesc[dimension]; + } + + public initSpace(dimensions: string[]): this { + this._spaceDesc = {}; + for (let dimension of dimensions) { + let range = (this._spaceDesc[dimension] = new KDTreeRange()); + range.set(-Number.MAX_VALUE, Number.MAX_VALUE); + } + return this; + } + + public isContain(dimension: string, value: number): boolean { + let range = this._spaceDesc[dimension]; + return value >= range.min && value < range.max; + } + + public isInterestRange(dimension: string, range1: KDTreeRange): boolean { + let range2 = this._spaceDesc[dimension]; + if (range2) return range1.isInterestRange(range2); + return false; + } + + public splitSpace(dimension: string, less: boolean, value: number): this { + let range = this._spaceDesc[dimension]; + if (less) range.max = value; + else range.min = value; + return this; + } + + public copySpace(space: KDTreeSpace): this { + for (let key in space._spaceDesc) { + let d = space._spaceDesc[key]; + this._spaceDesc[key].copy(d); + } + return this; + } +} From b1cb13f3dd46d03dd72899b136650184f3fdec4f Mon Sep 17 00:00:00 2001 From: hellmor Date: Mon, 24 Apr 2023 14:40:05 +0800 Subject: [PATCH 035/100] feats(loaderAndParser): Add loader and parser files (#32) Add loader and parser files --- src/engine/loader/FileLoader.ts | 87 ++++ src/engine/loader/LoaderBase.ts | 179 ++++++++ src/engine/loader/LoaderData.ts | 125 ++++++ src/engine/loader/LoaderFunctions.ts | 37 ++ src/engine/loader/LoaderManager.ts | 95 +++++ src/engine/loader/parser/AtlasParser.ts | 46 +++ src/engine/loader/parser/B3DMParser.ts | 135 ++++++ src/engine/loader/parser/FntParser.ts | 175 ++++++++ src/engine/loader/parser/I3DMParser.ts | 24 ++ src/engine/loader/parser/OBJParser.ts | 380 +++++++++++++++++ src/engine/loader/parser/ParserBase.ts | 49 +++ src/engine/loader/parser/RGBEParser.ts | 387 ++++++++++++++++++ src/engine/loader/parser/b3dm/B3DMLoader.ts | 94 +++++ .../loader/parser/b3dm/B3DMLoaderBase.ts | 80 ++++ src/engine/loader/parser/b3dm/FeatureTable.ts | 166 ++++++++ .../loader/parser/b3dm/arrayToString.ts | 6 + .../loader/parser/b3dm/readMagicBytes.ts | 29 ++ src/engine/loader/parser/i3dm/I3DMLoader.ts | 163 ++++++++ .../loader/parser/i3dm/I3DMLoaderBase.ts | 82 ++++ .../loader/parser/tileRenderer/TileSet.ts | 34 ++ .../parser/tileRenderer/TilesRenderer.ts | 116 ++++++ 21 files changed, 2489 insertions(+) create mode 100644 src/engine/loader/FileLoader.ts create mode 100644 src/engine/loader/LoaderBase.ts create mode 100644 src/engine/loader/LoaderData.ts create mode 100644 src/engine/loader/LoaderFunctions.ts create mode 100644 src/engine/loader/LoaderManager.ts create mode 100644 src/engine/loader/parser/AtlasParser.ts create mode 100644 src/engine/loader/parser/B3DMParser.ts create mode 100644 src/engine/loader/parser/FntParser.ts create mode 100644 src/engine/loader/parser/I3DMParser.ts create mode 100644 src/engine/loader/parser/OBJParser.ts create mode 100644 src/engine/loader/parser/ParserBase.ts create mode 100644 src/engine/loader/parser/RGBEParser.ts create mode 100644 src/engine/loader/parser/b3dm/B3DMLoader.ts create mode 100644 src/engine/loader/parser/b3dm/B3DMLoaderBase.ts create mode 100644 src/engine/loader/parser/b3dm/FeatureTable.ts create mode 100644 src/engine/loader/parser/b3dm/arrayToString.ts create mode 100644 src/engine/loader/parser/b3dm/readMagicBytes.ts create mode 100644 src/engine/loader/parser/i3dm/I3DMLoader.ts create mode 100644 src/engine/loader/parser/i3dm/I3DMLoaderBase.ts create mode 100644 src/engine/loader/parser/tileRenderer/TileSet.ts create mode 100644 src/engine/loader/parser/tileRenderer/TilesRenderer.ts diff --git a/src/engine/loader/FileLoader.ts b/src/engine/loader/FileLoader.ts new file mode 100644 index 00000000..a3127d54 --- /dev/null +++ b/src/engine/loader/FileLoader.ts @@ -0,0 +1,87 @@ +import { LoaderBase } from './LoaderBase'; +import { LoaderFunctions } from './LoaderFunctions'; +import { ParserBase } from './parser/ParserBase'; +import { Ctor } from "../util/Global"; + +/** + * @internal + * @group Loader + */ +export class FileLoader extends LoaderBase { + /** + * Load the file from the URL + * @param url file URL + * @param c File parser + * @param loaderFunctions loader callback + * @see LoaderFunctions + * @returns + */ + public async load(url: string, c: Ctor, loaderFunctions?: LoaderFunctions, userData?: any): Promise { + switch (c[`format`]) { + case `bin`: + { + return new Promise(async (succ, fail) => { + this.loadBinData(url, loaderFunctions).then(async (data) => { + let parser = new c(); + parser.userData = userData; + parser.baseUrl = this.baseUrl; + parser.initUrl = url; + await parser.parseBuffer(data); + if (parser.verification()) { + succ(parser); + } else { + throw new Error('parser error'); + } + }).catch((e) => { + fail(e); + }) + }); + } + break; + case `json`: + { + return new Promise((succ, fail) => { + this.loadJson(url, loaderFunctions) + .then(async (ret) => { + let parser = new c(); + parser.userData = userData; + parser.baseUrl = this.baseUrl; + parser.initUrl = url; + parser.loaderFunctions = loaderFunctions; + await parser.parserJson(ret); + succ(parser); + }) + .catch((e) => { + fail(e); + }); + }); + } + break; + case `text`: + { + return new Promise((succ, fail) => { + this.loadTxt(url, loaderFunctions) + .then(async (ret) => { + let parser = new c(); + parser.userData = userData; + parser.baseUrl = this.baseUrl; + parser.initUrl = url; + parser.loaderFunctions = loaderFunctions; + if (!ret[`data`]) { + fail(`text load is empty!`); + } else { + await parser.parserString(ret[`data`]); + succ(parser); + } + }) + .catch((e) => { + fail(e); + }); + }); + } + break; + default: + break; + } + } +} diff --git a/src/engine/loader/LoaderBase.ts b/src/engine/loader/LoaderBase.ts new file mode 100644 index 00000000..3cdf6393 --- /dev/null +++ b/src/engine/loader/LoaderBase.ts @@ -0,0 +1,179 @@ +import { Engine3D } from '../Engine3D'; +import { BitmapTexture2D } from '../textures/BitmapTexture2D'; +import { StringUtil } from '../util/StringUtil'; +import { LoaderFunctions } from './LoaderFunctions'; + +/** + * @internal + * @group Loader + */ +export class LoaderBase { + public baseUrl: string = ''; + public initUrl: string; + private _progress: number = 0; + + constructor() { + } + + /** + * @private + */ + public async loadBinData(url: string, loaderFunctions?: LoaderFunctions): Promise { + this.baseUrl = StringUtil.getPath(url); + this.initUrl = url; + return new Promise(async (succ, fail) => { + fetch(url, { headers: loaderFunctions?.headers }) + .then(async (response) => { + if (response.ok) { + let chunks = await LoaderBase.read(url, response, loaderFunctions); + let buffer = chunks.buffer; + chunks = null; + succ(buffer); + } + else { + throw Error("request rejected with status " + response.status) + } + + }) + .catch((e) => { + if (loaderFunctions.onError) { + loaderFunctions.onError(e); + } + fail(e); + }); + + }); + } + + /** + * + * @private + */ + public async loadAsyncBitmapTexture(url: string, loaderFunctions?: LoaderFunctions) { + this.baseUrl = StringUtil.getPath(url); + this.initUrl = url; + let bitmapTexture = new BitmapTexture2D(); + bitmapTexture.url = url; + bitmapTexture.name = StringUtil.getURLName(url); + await bitmapTexture.load(url, loaderFunctions); + Engine3D.res.addTexture(url, bitmapTexture); + return bitmapTexture; + } + + /** + * + * @private + */ + public async loadJson(url: string, loaderFunctions?: LoaderFunctions): Promise { + this.baseUrl = StringUtil.getPath(url); + this.initUrl = url; + return new Promise(async (succ, fail) => { + fetch(url, { headers: loaderFunctions?.headers }) + .then(async (response) => { + if (response.ok) { + let chunks = await LoaderBase.read(url, response, loaderFunctions); + let utf8decoder = new TextDecoder('utf-8'); + const jsonString = utf8decoder.decode(chunks); + chunks = null; + succ(JSON.parse(jsonString)); + } + else { + throw Error("request rejected with status" + response.status) + } + + }) + .catch((e) => { + if (loaderFunctions.onError) { + loaderFunctions.onError(e); + } + fail(e); + }); + + }); + } + + /** + * @private + */ + public async loadTxt(url: string, loaderFunctions?: LoaderFunctions): Promise { + this.baseUrl = StringUtil.getPath(url); + return new Promise(async (succ, fail) => { + fetch(url) + .then(async (response) => { + if (response.ok) { + let chunks = await LoaderBase.read(url, response, loaderFunctions); + let utf8decoder = new TextDecoder('utf-8'); + const textString = utf8decoder.decode(chunks); + chunks = null; + succ({ data: textString }); + } + else { + throw Error("request rejected with status" + response.status) + } + + }) + .catch((e) => { + if (loaderFunctions.onError) { + loaderFunctions.onError(e); + } + fail(e); + }); + + }); + } + + + /** + * @private + */ + public static async read(url: string, response, loaderFunctions?: LoaderFunctions): Promise { + const reader = response.body.getReader(); + const contentLength = +response.headers.get('Content-Length'); + let receivedLength = 0; + let chunks = []; + let receivedArr = []; + while (true) { + const { done, value } = await reader.read(); + if (done) { + if (contentLength > 0) { + if (loaderFunctions && loaderFunctions.onComplete) { + loaderFunctions.onComplete.call(this, url); + } + } + break; + } + chunks.push(value); + receivedLength += value.length; + + if (contentLength > 0) { + if (loaderFunctions && loaderFunctions.onProgress) { + loaderFunctions.onProgress.call(this, receivedLength, contentLength, url); + } + } else { + receivedArr.push(value.length); + } + } + if (receivedArr.length > 0) { + for (let i = 0; i < chunks.length; i++) { + console.log(receivedArr[i]); + if (loaderFunctions && loaderFunctions.onProgress) { + loaderFunctions.onProgress.call(this, receivedArr[i], receivedLength, url); + } + + if (receivedArr[i] == receivedLength) { + if (loaderFunctions && loaderFunctions.onComplete) { + loaderFunctions.onComplete.call(this, url); + } + } + } + } + + let chunksAll = new Uint8Array(receivedLength); + let position = 0; + for (let chunk of chunks) { + chunksAll.set(chunk, position); + position += chunk.length; + } + return chunksAll; + } +} diff --git a/src/engine/loader/LoaderData.ts b/src/engine/loader/LoaderData.ts new file mode 100644 index 00000000..fbbba8d1 --- /dev/null +++ b/src/engine/loader/LoaderData.ts @@ -0,0 +1,125 @@ +import { Color } from '../math/Color'; +import { Quaternion } from '../math/Quaternion'; +import { Vector2 } from '../math/Vector2'; +import { Vector3 } from '../math/Vector3'; + +/** + * @internal + * @group Loader + */ +export class BufferInfo { + public name: string; + public start: number; + public count: number; +} + +/** + * @internal + * @group Loader + */ +export class TextureScaleInfo { + public texSc: Vector2; + public texOff: Vector2; +} + +/** + * @internal + * @group Loader + */ +export class TextureInfo { + public name: string; + public fileName: string; + public useMipmap: boolean; + public wrapMode: number; + public filterMode: number; +} + +/** + * @internal + * @group Loader + */ +export class LightmapInfo { + public mapNames: string[]; +} + +/** + * @internal + * @group Loader + */ +export class SubMeshInfo { + public start: number; + public count: number; +} + +/** + * @internal + * @group Loader + */ +export class MeshInfo { + public name: string; + public att_p: number = -1; + public p_s: number = -1; + public att_n: number = -1; + public n_s: number = -1; + public att_t: number = -1; + public t_s: number = -1; + public att_u1: number = -1; + public u1_s: number = -1; + public att_u2: number = -1; + public u2_s: number = -1; + public att_c: number = -1; + public c_s: number = -1; + public dm: number = 0; + public subms: SubMeshInfo[]; + public bv: BufferInfo[]; +} + +/** + * @internal + * @group Loader + */ +export class MaterialInfo { + public name: string; + public shader: string; + public metalic: number; + public roughnees: number; + public bc: Color; + public bTex: string; + public bSc: TextureScaleInfo; + public nTex: string; + public nSc: TextureScaleInfo; + public rTex: string; + public rSc: TextureScaleInfo; + public remaTex: string; + public remaSc: TextureScaleInfo; + public eTex: string; + public eSc: TextureScaleInfo; + public ec: Color; + public aoTex: string; + public aoSc: TextureScaleInfo; + public aoIn: number; + public lIndex: number; + public lSc: Color; + public blendMode: number; + public cull: number; + public alphaBlend: number; + public recshadow: boolean; + public castshadow: boolean; +} + +/** + * @internal + * @group Loader + */ +export class Object3DInfo { + public name: string; + public p: Vector3; + public r: Vector3; + public s: Vector3; + public q: Quaternion; + public parent: string; + public b_anis: string[]; + public b_mes: string[]; + public b_mats: string[]; + public b_texs: string[]; +} diff --git a/src/engine/loader/LoaderFunctions.ts b/src/engine/loader/LoaderFunctions.ts new file mode 100644 index 00000000..131054f7 --- /dev/null +++ b/src/engine/loader/LoaderFunctions.ts @@ -0,0 +1,37 @@ +/** + * Loader callback functions + * @group Assets + */ +export type LoaderFunctions = { + /** + * The callback function in the load + * @param receivedLength Number of bytes loaded + * @param contentLength Total number of bytes of resources + * @param url resources URL + */ + onProgress?: Function; + + /** + * Load the completed callback function + * @param url resources URL + */ + onComplete?: Function; + + /** + * The callback function for which a load error occurred + * @param error Error object + */ + onError?: Function; + + /** + * The URL modification callback allows you to modify the original url and return a custom path + * @param url Original resource URL + * @return The new URL after modification + */ + onUrl?: Function; + + /** + * Customize headers, you can modify/add fetch header information + */ + headers?: {}; +}; diff --git a/src/engine/loader/LoaderManager.ts b/src/engine/loader/LoaderManager.ts new file mode 100644 index 00000000..f1ee005e --- /dev/null +++ b/src/engine/loader/LoaderManager.ts @@ -0,0 +1,95 @@ +import { CEventDispatcher } from '../event/CEventDispatcher'; +import { ParserBase } from './parser/ParserBase'; + +/** + * @internal + * Load management classes + * @group Loader + */ +export class LoaderManager extends CEventDispatcher { + private static _instance: LoaderManager; + private _maxRetry = 3; + + /** + * Load multiple resources of the same type simultaneously + * @param urls URL list + * @param c Type of resource parser + * @returns + */ + public loadAll(urls: string[], c: { new(): T }): Promise { + return new Promise((succ, fail) => { + let count = urls.length; + let ret: T[] = []; + urls.forEach((url, index) => { + let parser = new c(); + this.load(url, c).then((data) => { + parser.parse(data); + ret.push(parser); + count--; + if (count === 0) { + succ(ret); + } + }); + }); + }); + } + + public constructor() { + super(); + if (LoaderManager._instance) { + throw new Error('LoadManager is singleton class...'); + } + } + + public static getInstance(): LoaderManager { + return this._instance || (this._instance = new LoaderManager()); + } + + public loadUrls(urls: string[], c: { new(): ParserBase }): Promise { + return new Promise((succ, fail) => { + let count = urls.length; + let ret: ParserBase[] = []; + urls.forEach((url, index) => { + this.load(url, c).then((data) => { + ret.push(data); + count--; + if (count === 0) { + succ(ret); + } + if (count < 0) { + console.error(`loadUrls ${urls} error`); + } + }); + }); + }); + } + + public get maxRetry(): number { + return this._maxRetry; + } + + public set maxRetry(value: number) { + this._maxRetry = value; + } + + // public set retry(value: number) { + // this._maxRetry = value; + // } + + // public get retry():number { + // return this._maxRetry; + // } + + public load(url: string, c: { new(): T }): Promise { + return new Promise((succ, fail) => { + switch (c[`format`]) { + case `bin`: + break; + case `json`: + break; + default: + break; + } + }); + } +} diff --git a/src/engine/loader/parser/AtlasParser.ts b/src/engine/loader/parser/AtlasParser.ts new file mode 100644 index 00000000..9031b5d4 --- /dev/null +++ b/src/engine/loader/parser/AtlasParser.ts @@ -0,0 +1,46 @@ +import { GUIAtlasTexture } from "../../components/gui/core/GUIAtlasTexture"; +import { GUITextureSource } from "../../components/gui/core/GUISubTexture"; +import { Engine3D } from "../../Engine3D"; +import { Texture } from "../../gfx/graphics/webGpu/core/texture/Texture"; +import { ParserBase } from "../../loader/parser/ParserBase"; + +export class AtlasParser extends ParserBase { + static format: string = 'text'; + + private _json: any; + private _texture: Texture; + + public async parserString(data: string) { + this._json = JSON.parse(data); + let textureUrl = this.userData.replace('.json', '.png'); + this._texture = await Engine3D.res.loadTexture(textureUrl, null, true); + + this.data = { json: this._json, texture: this._texture }; + this.parseAtlas(); + } + + /** + * Verify parsing validity + * @param ret + * @returns + */ + public verification(): boolean { + if (this.data) { + return true; + } + throw new Error('Method not implemented.'); + } + + private parseAtlas() { + let atlas: GUIAtlasTexture = new GUIAtlasTexture(); + let source: GUITextureSource = new GUITextureSource(this._texture); + atlas.textureSize.set(this._json.size.x, this._json.size.y); + + let atlasInfo = this._json.atlas; + for (const key in atlasInfo) { + atlas.setTexture(source, key, atlasInfo[key]); + } + Engine3D.res.addAtlas(this.baseUrl, atlas); + this.data = atlas; + } +} diff --git a/src/engine/loader/parser/B3DMParser.ts b/src/engine/loader/parser/B3DMParser.ts new file mode 100644 index 00000000..8db9b531 --- /dev/null +++ b/src/engine/loader/parser/B3DMParser.ts @@ -0,0 +1,135 @@ +import { ParserBase } from './ParserBase'; + +export class B3DMParser extends ParserBase { + static format: string = 'bin'; + + public async parseBuffer(buffer: ArrayBuffer) { + let loader = new B3DMLoader(); + loader.adjustmentTransform = this.userData; + this.data = await loader.parse(buffer); + } + + /** + * Verify parsing validity + * @param ret + * @returns + */ + public verification(): boolean { + if (this.data) { + return true; + } + throw new Error('Method not implemented.'); + } +} + +import { B3DMLoader } from './b3dm/B3DMLoader'; +import { GLBParser, Object3D } from '../../..'; + +const BINARY_EXTENSION_HEADER_MAGIC = 'glTF'; +const BINARY_EXTENSION_HEADER_LENGTH = 12; +const BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4e4f534a, BIN: 0x004e4942 }; +const EXTENSIONS = { + KHR_BINARY_GLTF: 'KHR_binary_glTF', + KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression', + KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual', + KHR_MATERIALS_CLEARCOAT: 'KHR_materials_clearcoat', + KHR_MATERIALS_IOR: 'KHR_materials_ior', + KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness', + KHR_MATERIALS_SHEEN: 'KHR_materials_sheen', + KHR_MATERIALS_SPECULAR: 'KHR_materials_specular', + KHR_MATERIALS_TRANSMISSION: 'KHR_materials_transmission', + KHR_MATERIALS_UNLIT: 'KHR_materials_unlit', + KHR_MATERIALS_VOLUME: 'KHR_materials_volume', + KHR_TEXTURE_BASISU: 'KHR_texture_basisu', + KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform', + KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization', + EXT_TEXTURE_WEBP: 'EXT_texture_webp', + EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression', +}; + +export class GLTFBinaryExtension { + name: string; + content: string; + body: ArrayBuffer; + header: { magic: string; length: number; version: number }; + + constructor(data: ArrayBuffer) { + this.name = EXTENSIONS.KHR_BINARY_GLTF; + this.content = null; + this.body = null; + + const headerView = new DataView(data, 0, BINARY_EXTENSION_HEADER_LENGTH); + + this.header = { + magic: B3DMLoader.decodeText(new Uint8Array(data.slice(0, 4))), + version: headerView.getUint32(4, true), + length: headerView.getUint32(8, true), + }; + + if (this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC) { + throw new Error('GLTFLoader: Unsupported glTF-Binary header.'); + } else if (this.header.version < 2.0) { + throw new Error('GLTFLoader: Legacy binary file detected.'); + } + + const chunkContentsLength = this.header.length - BINARY_EXTENSION_HEADER_LENGTH; + const chunkView = new DataView(data, BINARY_EXTENSION_HEADER_LENGTH); + let chunkIndex = 0; + + while (chunkIndex < chunkContentsLength) { + const chunkLength = chunkView.getUint32(chunkIndex, true); + chunkIndex += 4; + + const chunkType = chunkView.getUint32(chunkIndex, true); + chunkIndex += 4; + + if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON) { + const contentArray = new Uint8Array(data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength); + this.content = B3DMLoader.decodeText(contentArray); + } else if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN) { + const byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex; + this.body = data.slice(byteOffset, byteOffset + chunkLength); + } + + chunkIndex += chunkLength; + } + + if (this.content === null) { + throw new Error('GLTFLoader: JSON content not found.'); + } + } +} + +export class B3DMParseUtil { + private _binary: ArrayBufferLike; + + public async parseBinary(bytes: ArrayBuffer) { + this._binary = bytes; + const magic = B3DMLoader.decodeText(new Uint8Array(this._binary, 0, 4)); + const extensions = {}; + let content; + let info: GLTFBinaryExtension; + + if (magic === BINARY_EXTENSION_HEADER_MAGIC) { + try { + info = extensions[EXTENSIONS.KHR_BINARY_GLTF] = new GLTFBinaryExtension(this._binary); + } catch (error) { + // if ( onError ) onError( error ); + return; + } + + content = extensions[EXTENSIONS.KHR_BINARY_GLTF].content; + } else { + content = B3DMLoader.decodeText(new Uint8Array(this._binary)); + } + const json = JSON.parse(content); + let obj3d = await this.parseGLB(json, info.body); + return obj3d; + } + + private async parseGLB(json: object, bin: ArrayBuffer): Promise { + let loader = new GLBParser(); + let obj3d: Object3D = await loader.parseJsonAndBuffer(json, bin); + return obj3d; + } +} diff --git a/src/engine/loader/parser/FntParser.ts b/src/engine/loader/parser/FntParser.ts new file mode 100644 index 00000000..059e6654 --- /dev/null +++ b/src/engine/loader/parser/FntParser.ts @@ -0,0 +1,175 @@ +import { GUISubTexture, GUITextureSource } from '../../components/gui/core/GUISubTexture'; +import { fonts } from '../../../engine/assets/Fonts'; +import { ParserBase } from '../../../engine/loader/parser/ParserBase'; +import { Engine3D } from '../../Engine3D'; + +export class FontInfo { + public face: string = ''; + public size: number = 0; + public bold: boolean = false; + public italic: boolean = false; + public stretchH: number = 0; + public spacing: string = ''; + public outline: number = 0; + public lineHeight: number = 0; + public base: number = 0; + public scaleW: number = 0; + public scaleH: number = 0; + public pages: number = 0; + public packed: number = 0; + public alphaChnl: number = 0; + public redChnl: number = 0; + public greenChnl: number = 0; + public blueChnl: number = 0; + public count: number = 0; + + public fontPage: FontPage[] = []; + public fontChar: { [key: string]: FontChar } = {}; + + constructor() { } +} + +export class FontPage { + public id: number = 0; + public file: string = ''; +} + +export class FontChar { + public id: number = -1; + public x: number = 0; + public y: number = 0; + public width: number = 0; + public height: number = 0; + public xoffset: number = 0; + public yoffset: number = 0; + public xadvance: number = 0; + public page: number = 0; + public chnl: number = 0; +} + +export class FntParser extends ParserBase { + static format: string = 'text'; + + public static parserSubTexture(sources: GUITextureSource[], fontData: FontInfo) { + for (const key in fontData.fontChar) { + if (Object.prototype.hasOwnProperty.call(fontData.fontChar, key)) { + const charInfo = fontData.fontChar[key]; + let subTexture = new GUISubTexture(); + subTexture.id = charInfo.id.toString(); + subTexture.offsetSize.set(0, 0, charInfo.width, charInfo.height); + subTexture.trimSize.set(charInfo.width, charInfo.height); + subTexture.width = charInfo.width; + subTexture.height = charInfo.height; + subTexture.xadvance = charInfo.xadvance; + subTexture.xoffset = charInfo.xoffset; + subTexture.yoffset = charInfo.yoffset; + subTexture.sourceTexture = sources[charInfo.page]; + subTexture.uvRec.set(charInfo.x / fontData.scaleW, (fontData.scaleH - (charInfo.y + charInfo.height)) / fontData.scaleH, charInfo.width / fontData.scaleW, charInfo.height / fontData.scaleH); + fonts.addFnt(fontData.face, fontData.size, subTexture.id, subTexture); + } + } + } + + /** + * Verify parsing validity + * @param ret + * @returns + */ + public verification(): boolean { + if (this.data) { + return true; + } + throw new Error('Method not implemented.'); + } + + public async parserString(data: string) { + let newLine = this.getNewLine(data); + let fnt: string = data; + let fontData: FontInfo = new FontInfo(); + fnt.trim() + .split(newLine) + .forEach((v, i) => { + if (i < 2) { + FntParser.readLineProperty(v, fontData); + } else { + if (i < fontData.pages + 2) { + let page = new FontPage(); + FntParser.readLineProperty(v, page); + fontData.fontPage.push(page); + } else if (i < fontData.pages + 3) { + FntParser.readLineProperty(v, fontData); + } else { + if (fontData.count > 0) { + let char = new FontChar(); + FntParser.readLineProperty(v, char); + fontData.fontChar[char.id] = char; + fontData.count--; + } + } + } + }); + fnt = ''; + this.data = fontData; + + await this.loadFontTextures(); + } + + private getNewLine(value: string): string { + if (value.indexOf('\r\n') != -1) return '\r\n'; + else if (value.indexOf('\r') != -1) return '\r'; + else return '\n'; + } + + private async loadFontTextures() { + let images: GUITextureSource[] = []; + let fontData: FontInfo = this.data; + for (const fontPage of fontData.fontPage) { + let texturePath = this.baseUrl + fontPage.file; + await Engine3D.res.loadTexture(texturePath, null, true); + let texture = Engine3D.res.getTexture(texturePath); + let source: GUITextureSource = new GUITextureSource(texture); + images.push(source); + } + FntParser.parserSubTexture(images, fontData); + //check empty + if (!fontData.fontChar[' ']) { + FntParser.insertSpaceChar(fontData, images[0]); + } + } + + private static insertSpaceChar(fontData: FontInfo, texture: GUITextureSource): void { + let subTexture = new GUISubTexture(); + let width = fontData.size * 0.5; + let height = fontData.lineHeight * 0.5; + subTexture.id = ' '; + subTexture.offsetSize.set(0, 0, fontData.size, fontData.size); + subTexture.trimSize.set(width, height); + subTexture.width = width; + subTexture.height = height; + subTexture.xadvance = 0; + subTexture.xoffset = 0; + subTexture.yoffset = 0; + subTexture.sourceTexture = texture; + subTexture.uvRec.set(0, 0, 0.000001, 0.000001); + fonts.addFnt(fontData.face, fontData.size, subTexture.id, subTexture); + } + + private static readLineProperty(line: string, data: any) { + line.trim() + .split(' ') + .forEach((v, i) => { + let strArr = v.split('='); + if (strArr.length > 1) { + let key = strArr[0]; + let value = strArr[1]; + if (Object.prototype.hasOwnProperty.call(data, key)) { + if (value.indexOf('"') == -1) { + data[key] = parseFloat(strArr[1]); + } else { + data[key] = value.replace('"', '').replace('"', ''); + } + } + } + }); + } +} diff --git a/src/engine/loader/parser/I3DMParser.ts b/src/engine/loader/parser/I3DMParser.ts new file mode 100644 index 00000000..f1b402a8 --- /dev/null +++ b/src/engine/loader/parser/I3DMParser.ts @@ -0,0 +1,24 @@ +import { ParserBase } from './ParserBase'; +import { I3DMLoader } from "./i3dm/I3DMLoader"; + +export class I3DMParser extends ParserBase { + static format: string = 'bin'; + + async parseBuffer(buffer: ArrayBuffer) { + let loader = new I3DMLoader(); + loader.adjustmentTransform = this.userData; + this.data = await loader.parse(buffer); + } + + /** + * Verify parsing validity + * @param ret + * @returns + */ + public verification(): boolean { + if (this.data) { + return true; + } + throw new Error('Method not implemented.'); + } +} \ No newline at end of file diff --git a/src/engine/loader/parser/OBJParser.ts b/src/engine/loader/parser/OBJParser.ts new file mode 100644 index 00000000..9604de1a --- /dev/null +++ b/src/engine/loader/parser/OBJParser.ts @@ -0,0 +1,380 @@ +import { StringUtil } from '../../util/StringUtil'; +import { FileLoader } from '../FileLoader'; +import { ParserBase } from './ParserBase'; +import { + Engine3D, + GeometryBase, + LitMaterial, + MeshRenderer, + Object3D, + VertexAttributeName +} from '../../..'; + +type MatData = { + name?: string, + Kd?: string[], + Ks?: string[], + Tr?: string, + d?: string[], + Tf?: string[], + Pr?: string, + Pm?: string, + Pc?: string, + Pcr?: string, + Ni?: string, + Kr?: string[], + illum?: string, + map_Kd?: string, + textures?: string[] +} + +type GeometryData = { + name: string, + type: string, + + vertex_arr?: number[], + normal_arr?: number[], + uv_arr?: number[], + indeice_arr?: number[], + index?: number, + + + source_mat: string, + source_faces: Face[], +} + +type Face = { + indices: string[], + texture: string[], + normal: string[] +} + +/** + * OBJ file parser + * @internal + * @group Loader + */ +export class OBJParser extends ParserBase { + static format: string = 'text'; + private textData: string = ''; + + private source_vertices: number[][]; + private source_normals: number[][]; + private source_tangents: number[][]; + private source_textureCoords: number[][]; + // private source_faces:Face[]; + + // public faces: { + // indices: string[], + // texture: string[], + // normal: string[] + // }[]; + + public matLibs: { [name: string]: MatData }; + + public geometrys: { [name: string]: GeometryData }; + private activeGeo: GeometryData; + + public facesMaterialsIndex: { + materialName: string, + materialStartIndex: number + }[]; + + public mtl: string; + mtlUrl: string; + // public geometryDatas:GeometryData[]; + + async parserString(obj: string) { + this.source_vertices = []; + this.source_normals = []; + this.source_tangents = []; + this.source_textureCoords = []; + + this.matLibs = {}; + this.geometrys = {}; + + this.textData = obj; + // load bin & texture together + await Promise.all([this.parserOBJ(), this.loadMTL()]); + this.parser_mesh(); + return `null`; + } + + private applyVector2(fi: number, sourceData: number[][], destData: number[]) { + if (sourceData[fi] && sourceData[fi].length > 0) { + destData.push(sourceData[fi][0]); + destData.push(sourceData[fi][1]); + } else { + destData.push(0); + destData.push(0); + } + } + + private applyVector3(fi: number, sourceData: number[][], destData: number[]) { + destData.push(sourceData[fi][0]); + destData.push(sourceData[fi][1]); + destData.push(sourceData[fi][2]); + } + + private applyVector4(fi: number, sourceData: number[][], destData: number[]) { + destData.push(sourceData[fi][0]); + destData.push(sourceData[fi][1]); + destData.push(sourceData[fi][2]); + destData.push(sourceData[fi][3]); + } + + private async loadMTL() { + let fileLoad = new FileLoader(); + let sourceData = await fileLoad.loadTxt(this.baseUrl + this.mtlUrl); + let sourceStr: string = sourceData[`data`]; + + let mat: MatData; + + let str = sourceStr.split("\r\n"); + for (let i = 0; i < str.length; i++) { + let line = str[i]; + var commentStart = line.indexOf("#"); + if (commentStart != -1) { + line = line.substring(0, commentStart); + } + line = line.trim(); + var splitedLine = line.split(/\s+/); + if (splitedLine[0] === 'newmtl') { + mat = { name: splitedLine[1] }; + this.matLibs[splitedLine[1]] = mat; + } else { + if (splitedLine[0].indexOf(`map_`) != -1) { + mat[splitedLine[0]] = splitedLine[1]; + if (!mat.textures) { + mat.textures = [splitedLine[splitedLine.length - 1]]; + } + mat.textures.push(splitedLine[splitedLine.length - 1]); + } else if (splitedLine.length == 2) { + mat[splitedLine[0]] = Number(splitedLine[1]); + } else if (splitedLine.length == 3) { + mat[splitedLine[0]] = [Number(splitedLine[1]), Number(splitedLine[2])]; + } else if (splitedLine.length == 4) { + mat[splitedLine[0]] = [Number(splitedLine[1]), Number(splitedLine[2]), Number(splitedLine[3])]; + } + } + } + + for (const key in this.matLibs) { + const mat = this.matLibs[key]; + if (mat.textures && mat.textures.length > 0) { + for (let i = 0; i < mat.textures.length; i++) { + const texUrl = StringUtil.normalizePath(this.baseUrl + mat.textures[i]); + await Engine3D.res.loadTexture(texUrl); + } + } + } + + sourceData = null; + return true; + } + + private async load_textures() { + + } + + private parserLine(line: string) { + /*Not include comment*/ + var commentStart = line.indexOf("#"); + if (commentStart != -1) { + if (line.indexOf(`# object`) != -1) { + var splitedLine = line.split(/\s+/); + let type = splitedLine[1]; + let geoName = splitedLine[2]; + this.activeGeo = { + type: type, + name: geoName[1], + source_mat: ``, + source_faces: [] + } + this.geometrys[geoName] = this.activeGeo; + } + line = line.substring(0, commentStart); + } + line = line.trim(); + var splitedLine = line.split(/\s+/); + + if (splitedLine[0] === 'v') { + var vertex = [Number(splitedLine[1]), Number(splitedLine[2]), Number(splitedLine[3]), splitedLine[4] ? 1 : Number(splitedLine[4])]; + this.source_vertices.push(vertex); + } + else if (splitedLine[0] === 'vt') { + var textureCoord = [Number(splitedLine[1]), Number(splitedLine[2]), splitedLine[3] ? 1 : Number(splitedLine[3])] + this.source_textureCoords.push(textureCoord); + } + else if (splitedLine[0] === 'vn') { + var normal = [Number(splitedLine[1]), Number(splitedLine[2]), Number(splitedLine[3])]; + this.source_normals.push(normal); + } + else if (splitedLine[0] === 'f') { + var face: Face = { + indices: [], + texture: [], + normal: [] + }; + + for (var i = 1; i < splitedLine.length; ++i) { + var dIndex = splitedLine[i].indexOf('//'); + var splitedFaceIndices = splitedLine[i].split(/\W+/); + + if (dIndex > 0) { + /*Vertex Normal Indices Without Texture Coordinate Indices*/ + face.indices.push(splitedFaceIndices[0]); + face.normal.push(splitedFaceIndices[1]); + } + else { + if (splitedFaceIndices.length === 1) { + /*Vertex Indices*/ + face.indices.push(splitedFaceIndices[0]); + } + else if (splitedFaceIndices.length === 2) { + /*Vertex Texture Coordinate Indices*/ + face.indices.push(splitedFaceIndices[0]); + face.texture.push(splitedFaceIndices[1]); + } + else if (splitedFaceIndices.length === 3) { + /*Vertex Normal Indices*/ + face.indices.push(splitedFaceIndices[0]); + face.texture.push(splitedFaceIndices[1]); + face.normal.push(splitedFaceIndices[2]); + } + } + } + + this.activeGeo.source_faces.push(face); + } else if (splitedLine[0] === "usemtl") { + this.activeGeo.source_mat = splitedLine[1]; + } else if (splitedLine[0] === `mtllib`) { + this.mtlUrl = splitedLine[1]; + } + } + + private async parserOBJ() { + let str = this.textData.split("\r\n"); + for (let i = 0; i < str.length; i++) { + const element = str[i]; + this.parserLine(element); + } + this.textData = ``; + return true; + } + + private async parser_mesh() { + for (const key in this.geometrys) { + const geoData = this.geometrys[key]; + + geoData.vertex_arr = []; + geoData.normal_arr = []; + geoData.uv_arr = []; + geoData.indeice_arr = []; + + let index = 0; + for (let i = 0; i < geoData.source_faces.length; i++) { + const face = geoData.source_faces[i]; + + let f0 = parseInt(face.indices[0]) - 1; + let f1 = parseInt(face.indices[1]) - 1; + let f2 = parseInt(face.indices[2]) - 1; + + let n0 = parseInt(face.normal[0]) - 1; + let n1 = parseInt(face.normal[1]) - 1; + let n2 = parseInt(face.normal[2]) - 1; + + let u0 = parseInt(face.texture[0]) - 1; + let u1 = parseInt(face.texture[1]) - 1; + let u2 = parseInt(face.texture[2]) - 1; + + this.applyVector3(f0, this.source_vertices, geoData.vertex_arr); + this.applyVector3(n0, this.source_normals, geoData.normal_arr); + this.applyVector2(u0, this.source_textureCoords, geoData.uv_arr); + geoData.indeice_arr[index] = index++; + + this.applyVector3(f1, this.source_vertices, geoData.vertex_arr); + this.applyVector3(n1, this.source_normals, geoData.normal_arr); + this.applyVector2(u1, this.source_textureCoords, geoData.uv_arr); + geoData.indeice_arr[index] = index++; + + this.applyVector3(f2, this.source_vertices, geoData.vertex_arr); + this.applyVector3(n2, this.source_normals, geoData.normal_arr); + this.applyVector2(u2, this.source_textureCoords, geoData.uv_arr); + geoData.indeice_arr[index] = index++; + + if (face.indices.length > 3) { + let f3 = parseInt(face.indices[3]) - 1; + let n3 = parseInt(face.normal[3]) - 1; + let u3 = parseInt(face.texture[3]) - 1; + this.applyVector3(f0, this.source_vertices, geoData.vertex_arr); + this.applyVector3(n0, this.source_normals, geoData.normal_arr); + this.applyVector2(u0, this.source_textureCoords, geoData.uv_arr); + geoData.indeice_arr[index] = index++; + + this.applyVector3(f2, this.source_vertices, geoData.vertex_arr); + this.applyVector3(n2, this.source_normals, geoData.normal_arr); + this.applyVector2(u2, this.source_textureCoords, geoData.uv_arr); + geoData.indeice_arr[index] = index++; + + this.applyVector3(f3, this.source_vertices, geoData.vertex_arr); + this.applyVector3(n3, this.source_normals, geoData.normal_arr); + this.applyVector2(u3, this.source_textureCoords, geoData.uv_arr); + geoData.indeice_arr[index] = index++; + } + } + + let root = new Object3D(); + for (const key in this.geometrys) { + const geoData = this.geometrys[key]; + let geo: GeometryBase = new GeometryBase(); + // let att_info: GeometryAttribute = {}; + // att_info[VertexAttributeName.position] = { name: VertexAttributeName.position, data: new Float32Array(geoData.vertex_arr) }; + // att_info[VertexAttributeName.normal] = { name: VertexAttributeName.normal, data: new Float32Array(geoData.normal_arr) }; + // att_info[VertexAttributeName.uv] = { name: VertexAttributeName.uv, data: new Float32Array(geoData.uv_arr) }; + // att_info[VertexAttributeName.TEXCOORD_1] = { name: VertexAttributeName.TEXCOORD_1, data: new Float32Array(geoData.uv_arr) }; + // att_info[VertexAttributeName.indices] = { name: VertexAttributeName.indices, data: new Uint32Array(geoData.indeice_arr) }; + // geo.setAttributes(geo.name + UUID(), att_info); + // geo.geometrySource = new SerializeGeometrySource().setObjGeometry(this.initUrl, key); + + geo.setIndices(new Uint32Array(geoData.indeice_arr)); + geo.setAttribute(VertexAttributeName.position, new Float32Array(geoData.vertex_arr)); + geo.setAttribute(VertexAttributeName.normal, new Float32Array(geoData.normal_arr)); + geo.setAttribute(VertexAttributeName.uv, new Float32Array(geoData.uv_arr)); + geo.setAttribute(VertexAttributeName.TEXCOORD_1, new Float32Array(geoData.uv_arr)); + + geo.addSubGeometry({ + indexStart: 0, + indexCount: geoData.indeice_arr.length, + vertexStart: 0, + index: 0, + }); + + let mat = new LitMaterial(); + let matData = this.matLibs[geoData.source_mat]; + mat.baseMap = Engine3D.res.getTexture(StringUtil.normalizePath(this.baseUrl + matData.map_Kd)); + + let obj = new Object3D(); + let mr = obj.addComponent(MeshRenderer); + mr.geometry = geo; + mr.material = mat; + root.addChild(obj); + } + + // root.renderLayer = RenderLayer.StaticBatch; + this.data = root; + } + } + + /** + * Verify parsing validity + * @param ret + * @returns + */ + public verification(): boolean { + if (this.data) { + return true; + } + throw new Error('Method not implemented.'); + } +} diff --git a/src/engine/loader/parser/ParserBase.ts b/src/engine/loader/parser/ParserBase.ts new file mode 100644 index 00000000..6d911d4e --- /dev/null +++ b/src/engine/loader/parser/ParserBase.ts @@ -0,0 +1,49 @@ +import { Texture } from '../../gfx/graphics/webGpu/core/texture/Texture'; +import { LoaderFunctions } from '../LoaderFunctions'; + +/** + * @internal + * @group Loader + */ +export class ParserBase { + static format: string = 'bin'; + public baseUrl: string; + public initUrl: string; + public loaderFunctions?: LoaderFunctions; + public userData?: any; + public data: any; + + public parserString(str: string) { } + + public parserJson(obj: object) { } + + public parseBuffer(buffer: ArrayBuffer) { } + + public parserTexture(buffer: ArrayBuffer): Texture { + throw this.parserError('Method not implemented.', -1); + } + + public parse(data: any) { } + + public verification(ret: void): boolean { + throw this.parserError('Method not implemented.', -1); + } + + protected parserError(info: string, id: number) { + console.error(`error id:${id} ${info}`); + } + + // public static getTypedArrayTypeFromGLType(componentType:number){ + // switch (componentType) { + // case 5126: + // return Float32Array; + // break; + // case 5125: + // return Uint8Array; + // break; + // default: + // break; + // } + + // } +} diff --git a/src/engine/loader/parser/RGBEParser.ts b/src/engine/loader/parser/RGBEParser.ts new file mode 100644 index 00000000..36c64e6b --- /dev/null +++ b/src/engine/loader/parser/RGBEParser.ts @@ -0,0 +1,387 @@ +import { Texture } from '../../gfx/graphics/webGpu/core/texture/Texture'; +import { GPUTextureFormat } from '../../gfx/graphics/webGpu/WebGPUConst'; +import { HDRTexture } from '../../textures/HDRTexture'; +import { HDRTextureCube } from '../../textures/HDRTextureCube'; +import { toHalfFloat } from '../../util/Convert'; +import { ParserBase } from './ParserBase'; + +/** + * @internal + */ +export enum RGBEErrorCode { + RGBE_RETURN_FAILURE = -1, + rgbe_read_error = 1, + rgbe_write_error = 2, + rgbe_format_error = 3, + rgbe_memory_error = 4, +} + +/** + * @internal + * @group Loader + */ +export class RGBEHeader { + valid: number; + string: string; + comments: string; + programtype: string; + format: string; + gamma: number; + exposure: number; + width: number; + height: number; +} + +/** + * RGBE parser + * @internal + * @group Loader + */ +export class RGBEParser extends ParserBase { + static format: string = 'bin'; + private _rgbeArray: Uint8Array; + private _width: number; + private _height: number; + private _RGBE_RETURN_FAILURE: number = -1; + // parserType: GPUTextureFormat = GPUTextureFormat.rgba16float; + private _parserType: GPUTextureFormat = GPUTextureFormat.rgba8uint; + + public parseBuffer(buffer: ArrayBuffer) { + let ret_texture: Texture; + let byteArray = new Uint8Array(buffer); + byteArray['pos'] = 0; + + const rgbe_header_info: RGBEHeader | number = this.paserHeader(byteArray); + if (rgbe_header_info instanceof RGBEHeader) { + const w = (this._width = rgbe_header_info.width); + const h = (this._height = rgbe_header_info.height); + let image_rgba_data = this.parserPixel(byteArray.subarray(byteArray['pos']), w, h); + if (image_rgba_data instanceof Uint8Array) { + this._rgbeArray = image_rgba_data; + + let data; + let numElements; + + switch ( + this._parserType + // case GPUTextureFormat.rgba8uint: + // data = image_rgba_data; + // ret_texture = new Uint8ArrayTexture(); + // ret_texture.format = GPUTextureFormat.rgba8uint; + // if (ret_texture instanceof Uint8ArrayTexture) ret_texture.create(rgbe_header_info.width, rgbe_header_info.height, data, true); + // break; + // + // case GPUTextureFormat.rgba32float: + // numElements = (image_rgba_data.length / 4) * 4; + // const floatArray = new Float32Array(numElements); + // + // for (let j = 0; j < numElements; j++) { + // this.rbgeToFloat(image_rgba_data, j * 4, floatArray, j * 4); + // } + // + // data = floatArray; + // + // ret_texture = new Float32ArrayTexture(); + // ret_texture.format = GPUTextureFormat.rgba32float; + // if (ret_texture instanceof Float32ArrayTexture) ret_texture.create(rgbe_header_info.width, rgbe_header_info.height, data); + // break; + // + // case GPUTextureFormat.rgba16float: + // { + // numElements = (image_rgba_data.length / 4) * 4; + // const halfArray = new Uint16Array(numElements); + // + // for (let j = 0; j < numElements; j++) { + // this.rbgeToHalfFloat(image_rgba_data, j * 4, halfArray, j * 4); + // } + // + // data = halfArray; + // + // let hdrTexture = (ret_texture = new HDRTexture()); + // hdrTexture.create(rgbe_header_info.width, rgbe_header_info.height, data, true); + // } + // break; + // default: + // throw new Error('unsupported type'); + ) { + } + + this.data = ret_texture; + return ret_texture; + } + } + + return null; + } + + /** + * Verify parsing validity + * @param ret + * @returns + */ + public verification(): boolean { + if (this.data && this.data instanceof Texture) { + return true; + } else if (this._rgbeArray) { + return true; + } + throw new Error('Method not implemented.'); + } + + public getTexture(): Texture { + return this.data as Texture; + } + + public getCubeTexture() { + let size = this._width / 4; + let cubeTexture = new HDRTextureCube().createFromHDRData(size, { + width: this._width, + height: this._height, + array: this._rgbeArray, + }); + return cubeTexture; + } + + public getHDRTexture() { + let texture = new HDRTexture().create(this._width, this._height, this._rgbeArray); + return texture; + } + + protected parseError(rgbe_error_code, msg) { + switch (rgbe_error_code) { + case RGBEErrorCode.rgbe_read_error: + console.error('Read Error: ' + (msg || '')); + break; + + case RGBEErrorCode.rgbe_write_error: + console.error('Write Error: ' + (msg || '')); + break; + + case RGBEErrorCode.rgbe_format_error: + console.error('Bad File Format: ' + (msg || '')); + break; + + default: + case RGBEErrorCode.rgbe_memory_error: + console.error('Error: ' + (msg || '')); + } + return RGBEErrorCode.RGBE_RETURN_FAILURE; + } + + protected parserBlock(buffer: Uint8Array, lineLimit?: number, consume?: boolean) { + const chunkSize = 128; + lineLimit = !lineLimit ? 1024 : lineLimit; + let p = buffer['pos'], + i = -1, + len = 0, + s = '', + chunk = String.fromCharCode.apply(null, new Uint16Array(buffer.subarray(p, p + chunkSize))); + + const next = '\n'; + while (0 > (i = chunk.indexOf(next)) && len < lineLimit && p < buffer.byteLength) { + s += chunk; + len += chunk.length; + p += chunkSize; + chunk += String.fromCharCode.apply(null, new Uint16Array(buffer.subarray(p, p + chunkSize))); + } + + if (-1 < i) { + if (false !== consume) buffer['pos'] += len + i + 1; + return s + chunk.slice(0, i); + } + + return false; + } + + protected paserHeader(buffer: Uint8Array): RGBEHeader | number { + // regexes to parse header info fields + const magic_token_re = /^#\?(\S+)/, + gamma_re = /^\s*GAMMA\s*=\s*(\d+(\.\d+)?)\s*$/, + exposure_re = /^\s*EXPOSURE\s*=\s*(\d+(\.\d+)?)\s*$/, + format_re = /^\s*FORMAT=(\S+)\s*$/, + dimensions_re = /^\s*\-Y\s+(\d+)\s+\+X\s+(\d+)\s*$/, + // RGBE format header struct + header = new RGBEHeader(); + + let line, match; + + if (buffer['pos'] >= buffer.byteLength || !(line = this.parserBlock(buffer))) { + return this.parseError(RGBEErrorCode.rgbe_read_error, 'no header found'); + } + /* if you want to require the magic token then uncomment the next line */ + + if (!(match = line.match(magic_token_re))) { + return this.parseError(RGBEErrorCode.rgbe_format_error, 'bad initial token'); + } + + const RGBE_VALID_PROGRAMTYPE = 1; + const RGBE_VALID_FORMAT = 2; + const RGBE_VALID_DIMENSIONS = 4; + + header.valid |= RGBE_VALID_PROGRAMTYPE; + header.programtype = match[1]; + header.string += line + '\n'; + + while (true) { + line = this.parserBlock(buffer); + if (false === line) break; + header.string += line + '\n'; + + if ('#' === line.charAt(0)) { + header.comments += line + '\n'; + continue; // comment line + } + + if ((match = line.match(gamma_re))) { + header.gamma = Math.floor(parseFloat(match[1]) * 10) / 10; + } + + if ((match = line.match(exposure_re))) { + header.exposure = Math.floor(parseFloat(match[1]) * 10) / 10; + } + + if ((match = line.match(format_re))) { + header.valid |= RGBE_VALID_FORMAT; + header.format = match[1]; //'32-bit_rle_rgbe'; + } + + if ((match = line.match(dimensions_re))) { + header.valid |= RGBE_VALID_DIMENSIONS; + header.height = parseInt(match[1], 10); + header.width = parseInt(match[2], 10); + } + + if (header.valid & RGBE_VALID_FORMAT && header.valid & RGBE_VALID_DIMENSIONS) break; + } + + if (!(header.valid & RGBE_VALID_FORMAT)) { + this.parseError(RGBEErrorCode.rgbe_format_error, 'missing format specifier'); + return null; + } + + if (!(header.valid & RGBE_VALID_DIMENSIONS)) { + this.parseError(RGBEErrorCode.rgbe_format_error, 'missing image size specifier'); + return null; + } + + return header; + } + + protected parserPixel(buffer, w, h) { + const scanline_width = w; + + if ( + // run length encoding is not allowed so read flat + scanline_width < 8 || + scanline_width > 0x7fff || // this file is not run length encoded + 2 !== buffer[0] || + 2 !== buffer[1] || + buffer[2] & 0x80 + ) { + // return the flat buffer + return new Uint8Array(buffer); + } + + if (scanline_width !== ((buffer[2] << 8) | buffer[3])) { + return this.parseError(RGBEErrorCode.rgbe_format_error, 'wrong scanline width'); + } + + const data_rgba = new Uint8Array(4 * w * h); + + if (!data_rgba.length) { + return this.parseError(RGBEErrorCode.rgbe_memory_error, 'unable to allocate buffer space'); + } + + let offset = 0, + pos = 0; + const ptr_end = 4 * scanline_width; + const rgbeStart = new Uint8Array(4); + const scanline_buffer = new Uint8Array(ptr_end); + let num_scanlines = h; // read in each successive scanline + + while (num_scanlines > 0 && pos < buffer.byteLength) { + if (pos + 4 > buffer.byteLength) { + return this.parseError(RGBEErrorCode.rgbe_read_error, ''); + } + + rgbeStart[0] = buffer[pos++]; + rgbeStart[1] = buffer[pos++]; + rgbeStart[2] = buffer[pos++]; + rgbeStart[3] = buffer[pos++]; + + if (2 != rgbeStart[0] || 2 != rgbeStart[1] || ((rgbeStart[2] << 8) | rgbeStart[3]) != scanline_width) { + return this.parseError(RGBEErrorCode.rgbe_format_error, 'bad rgbe scanline format'); + } // read each of the four channels for the scanline into the buffer + // first red, then green, then blue, then exponent + + let ptr = 0, + count; + + while (ptr < ptr_end && pos < buffer.byteLength) { + count = buffer[pos++]; + const isEncodedRun = count > 128; + if (isEncodedRun) count -= 128; + + if (0 === count || ptr + count > ptr_end) { + return this.parseError(RGBEErrorCode.rgbe_format_error, 'bad scanline data'); + } + + if (isEncodedRun) { + // a (encoded) run of the same value + const byteValue = buffer[pos++]; + + for (let i = 0; i < count; i++) { + scanline_buffer[ptr++] = byteValue; + } //ptr += count; + } else { + // a literal-run + scanline_buffer.set(buffer.subarray(pos, pos + count), ptr); + ptr += count; + pos += count; + } + } // now convert data from buffer into rgba + // first red, then green, then blue, then exponent (alpha) + + const l = scanline_width; //scanline_buffer.byteLength; + + for (let i = 0; i < l; i++) { + let off = 0; + data_rgba[offset] = scanline_buffer[i + off]; + off += scanline_width; //1; + + data_rgba[offset + 1] = scanline_buffer[i + off]; + off += scanline_width; //1; + + data_rgba[offset + 2] = scanline_buffer[i + off]; + off += scanline_width; //1; + + data_rgba[offset + 3] = scanline_buffer[i + off]; + offset += 4; + } + + num_scanlines--; + } + + return data_rgba; + } + + protected rbgeToFloat(sourceArray, sourceOffset, destArray, destOffset) { + const e = sourceArray[sourceOffset + 3]; + const scale = Math.pow(2.0, e - 128.0) / 255.0; + destArray[destOffset + 0] = sourceArray[sourceOffset + 0] * scale; + destArray[destOffset + 1] = sourceArray[sourceOffset + 1] * scale; + destArray[destOffset + 2] = sourceArray[sourceOffset + 2] * scale; + destArray[destOffset + 3] = 1.0; + } + + protected rbgeToHalfFloat(sourceArray, sourceOffset, destArray, destOffset) { + const e = sourceArray[sourceOffset + 3]; + + const scale = Math.pow(2.0, e - 128.0) / 255.0; + + destArray[destOffset + 0] = toHalfFloat(sourceArray[sourceOffset + 0] * scale); + destArray[destOffset + 1] = toHalfFloat(sourceArray[sourceOffset + 1] * scale); + destArray[destOffset + 2] = toHalfFloat(sourceArray[sourceOffset + 2] * scale); + destArray[destOffset + 3] = toHalfFloat(1.0); + } +} diff --git a/src/engine/loader/parser/b3dm/B3DMLoader.ts b/src/engine/loader/parser/b3dm/B3DMLoader.ts new file mode 100644 index 00000000..1ed98e69 --- /dev/null +++ b/src/engine/loader/parser/b3dm/B3DMLoader.ts @@ -0,0 +1,94 @@ +import {B3DMLoaderBase} from "./B3DMLoaderBase"; +import {B3DMParseUtil} from "../B3DMParser"; +import { Matrix4, Orientation3D, Transform, Vector3 } from "../../../.."; + + +export class B3DMLoader extends B3DMLoaderBase { + public adjustmentTransform: Matrix4; + private gltfBuffer: ArrayBufferLike; + private static tempMatrix: Matrix4; + + constructor() { + super(); + this.adjustmentTransform = new Matrix4().identity(); + B3DMLoader.tempMatrix ||= new Matrix4().identity(); + } + + async parse(buffer: ArrayBuffer) { + const b3dm = await super.parse(buffer); + this.gltfBuffer = b3dm.glbBytes.slice().buffer; + let glbLoader = new B3DMParseUtil(); + + let model = await glbLoader.parseBinary(this.gltfBuffer); + + let {batchTable, featureTable} = b3dm; + + const rtcCenter = featureTable.getData('RTC_CENTER'); + if (rtcCenter) { + + model.x += rtcCenter[0]; + model.y += rtcCenter[1]; + model.z += rtcCenter[2]; + + } + + let transform = model.getComponent(Transform); + transform.updateWorldMatrix(); + + let tempMatrix = B3DMLoader.tempMatrix; + tempMatrix.compose(transform.localPosition, transform.localRotQuat, transform.localScale); + tempMatrix.multiply(this.adjustmentTransform); + let prs: Vector3[] = tempMatrix.decompose(Orientation3D.QUATERNION); + + transform.localRotQuat.copyFrom(prs[1]); + transform.localRotQuat = transform.localRotQuat; + + transform.localPosition.copyFrom(prs[0]); + transform.localPosition = transform.localPosition; + + transform.localScale.copyFrom(prs[2]); + transform.localScale = transform.localScale; + + transform.updateWorldMatrix(); + + model['batchTable'] = batchTable; + model['featureTable'] = featureTable; + + return model as any; + } + + + static decodeText(array) { + + if (typeof TextDecoder !== 'undefined') { + + return new TextDecoder().decode(array); + + } + + // Avoid the String.fromCharCode.apply(null, array) shortcut, which + // throws a "maximum call stack size exceeded" error for large arrays. + + let s = ''; + + for (let i = 0, il = array.length; i < il; i++) { + + // Implicitly assumes little-endian. + s += String.fromCharCode(array[i]); + + } + + try { + + // merges multi-byte utf-8 characters. + + return decodeURIComponent(escape(s)); + + } catch (e) { // see #16358 + + return s; + + } + + } +} diff --git a/src/engine/loader/parser/b3dm/B3DMLoaderBase.ts b/src/engine/loader/parser/b3dm/B3DMLoaderBase.ts new file mode 100644 index 00000000..3d96514e --- /dev/null +++ b/src/engine/loader/parser/b3dm/B3DMLoaderBase.ts @@ -0,0 +1,80 @@ +import { FeatureTable, BatchTable } from './FeatureTable.js'; +import { readMagicBytes } from "./readMagicBytes"; + +export class B3DMLoaderBase { + + async parse( buffer: ArrayBuffer ) { + + // TODO: this should be able to take a uint8array with an offset and length + const dataView = new DataView( buffer ); + + // 28-byte header + + // 4 bytes + const magic = readMagicBytes( dataView ); + + console.assert( magic === 'b3dm' ); + + // 4 bytes + const version = dataView.getUint32( 4, true ); + + console.assert( version === 1 ); + + // 4 bytes + const byteLength = dataView.getUint32( 8, true ); + + console.assert( byteLength === buffer.byteLength ); + + // 4 bytes + const featureTableJSONByteLength = dataView.getUint32( 12, true ); + + // 4 bytes + const featureTableBinaryByteLength = dataView.getUint32( 16, true ); + + // 4 bytes + const batchTableJSONByteLength = dataView.getUint32( 20, true ); + + // 4 bytes + const batchTableBinaryByteLength = dataView.getUint32( 24, true ); + + // Feature Table + const featureTableStart = 28; + const featureTableBuffer = buffer.slice( + featureTableStart, + featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength, + ); + const featureTable = new FeatureTable( + featureTableBuffer, + 0, + featureTableJSONByteLength, + featureTableBinaryByteLength, + ); + + // Batch Table + const batchTableStart = featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength; + const batchTableBuffer = buffer.slice( + batchTableStart, + batchTableStart + batchTableJSONByteLength + batchTableBinaryByteLength, + ); + const batchTable = new BatchTable( + batchTableBuffer, + featureTable.getData( 'BATCH_LENGTH' ), + 0, + batchTableJSONByteLength, + batchTableBinaryByteLength, + ); + + const glbStart = batchTableStart + batchTableJSONByteLength + batchTableBinaryByteLength; + const glbBytes = new Uint8Array( buffer, glbStart, byteLength - glbStart ); + + return { + version, + featureTable, + batchTable, + glbBytes, + }; + + } + +} + diff --git a/src/engine/loader/parser/b3dm/FeatureTable.ts b/src/engine/loader/parser/b3dm/FeatureTable.ts new file mode 100644 index 00000000..b7ebe4a6 --- /dev/null +++ b/src/engine/loader/parser/b3dm/FeatureTable.ts @@ -0,0 +1,166 @@ +import { arrayToString } from './arrayToString.js'; + +export class FeatureTable { + private buffer: any; + private binOffset: any; + private binLength: any; + private header: any; + + constructor( buffer, start, headerLength, binLength ) { + + this.buffer = buffer; + this.binOffset = start + headerLength; + this.binLength = binLength; + + let header = null; + if ( headerLength !== 0 ) { + + const headerData = new Uint8Array( buffer, start, headerLength ); + header = JSON.parse( arrayToString( headerData ) ); + + } else { + + header = {}; + + } + this.header = header; + + } + + getKeys() { + + return Object.keys( this.header ); + + } + + getData( key, count?, defaultComponentType = null, defaultType = null ) { + + const header = this.header; + + if ( ! ( key in header ) ) { + + return null; + + } + + const feature = header[ key ]; + if ( ! ( feature instanceof Object ) ) { + + return feature; + + } else if ( Array.isArray( feature ) ) { + + return feature; + + } else { + + const { buffer, binOffset, binLength } = this; + const byteOffset = feature.byteOffset || 0; + const featureType = feature.type || defaultType; + const featureComponentType = feature.componentType || defaultComponentType; + + if ( 'type' in feature && defaultType && feature.type !== defaultType ) { + + throw new Error( 'FeatureTable: Specified type does not match expected type.' ); + + } + + let stride; + switch ( featureType ) { + + case 'SCALAR': + stride = 1; + break; + + case 'VEC2': + stride = 2; + break; + + case 'VEC3': + stride = 3; + break; + + case 'VEC4': + stride = 4; + break; + + default: + throw new Error( `FeatureTable : Feature type not provided for "${ key }".` ); + + } + + let data; + const arrayStart = binOffset + byteOffset; + const arrayLength = count * stride; + + switch ( featureComponentType ) { + + case 'BYTE': + data = new Int8Array( buffer, arrayStart, arrayLength ); + break; + + case 'UNSIGNED_BYTE': + data = new Uint8Array( buffer, arrayStart, arrayLength ); + break; + + case 'SHORT': + data = new Int16Array( buffer, arrayStart, arrayLength ); + break; + + case 'UNSIGNED_SHORT': + data = new Uint16Array( buffer, arrayStart, arrayLength ); + break; + + case 'INT': + data = new Int32Array( buffer, arrayStart, arrayLength ); + break; + + case 'UNSIGNED_INT': + data = new Uint32Array( buffer, arrayStart, arrayLength ); + break; + + case 'FLOAT': + data = new Float32Array( buffer, arrayStart, arrayLength ); + break; + + case 'DOUBLE': + data = new Float64Array( buffer, arrayStart, arrayLength ); + break; + + default: + throw new Error( `FeatureTable : Feature component type not provided for "${ key }".` ); + + } + + const dataEnd = arrayStart + arrayLength * data.BYTES_PER_ELEMENT; + if ( dataEnd > binOffset + binLength ) { + + throw new Error( 'FeatureTable: Feature data read outside binary body length.' ); + + } + + return data; + + } + + } + +} + +export class BatchTable extends FeatureTable { + private batchSize: any; + + constructor( buffer, batchSize, start, headerLength, binLength ) { + + super( buffer, start, headerLength, binLength ); + this.batchSize = batchSize; + + } + + getData( key, componentType = null, type = null ) { + + return super.getData( key, this.batchSize, componentType, type ); + + } + +} diff --git a/src/engine/loader/parser/b3dm/arrayToString.ts b/src/engine/loader/parser/b3dm/arrayToString.ts new file mode 100644 index 00000000..2a2ad71f --- /dev/null +++ b/src/engine/loader/parser/b3dm/arrayToString.ts @@ -0,0 +1,6 @@ +export function arrayToString( array ) { + + const utf8decoder = new TextDecoder(); + return utf8decoder.decode( array ); + +} diff --git a/src/engine/loader/parser/b3dm/readMagicBytes.ts b/src/engine/loader/parser/b3dm/readMagicBytes.ts new file mode 100644 index 00000000..391453b8 --- /dev/null +++ b/src/engine/loader/parser/b3dm/readMagicBytes.ts @@ -0,0 +1,29 @@ +export function readMagicBytes( bufferOrDataView ) { + + let view; + if ( bufferOrDataView instanceof DataView ) { + + view = bufferOrDataView; + + } else { + + view = new DataView( bufferOrDataView ); + + } + + if ( String.fromCharCode( view.getUint8( 0 ) ) === '{' ) { + + return null; + + } + + let magicBytes = ''; + for ( let i = 0; i < 4; i ++ ) { + + magicBytes += String.fromCharCode( view.getUint8( i ) ); + + } + + return magicBytes; + +} diff --git a/src/engine/loader/parser/i3dm/I3DMLoader.ts b/src/engine/loader/parser/i3dm/I3DMLoader.ts new file mode 100644 index 00000000..82ba38dc --- /dev/null +++ b/src/engine/loader/parser/i3dm/I3DMLoader.ts @@ -0,0 +1,163 @@ + +import { I3DMLoaderBase } from './I3DMLoaderBase'; +import { InstancedMesh } from '../../../core/entities/InstancedMesh'; +import { B3DMParseUtil } from "../B3DMParser"; +import { Matrix4 } from '../../../math/Matrix4'; +import { MeshRenderer } from '../../../components/renderer/MeshRenderer'; +import { Object3D } from '../../../core/entities/Object3D'; +import { Quaternion } from '../../../math/Quaternion'; +import { Vector3 } from '../../../math/Vector3'; + +export class I3DMLoader extends I3DMLoaderBase { + public static tempFwd = new Vector3(); + public static tempUp = new Vector3(); + public static tempRight = new Vector3(); + public static tempPos = new Vector3(); + public static tempQuat = new Quaternion(); + public static tempSca = new Vector3(); + public static tempMat = new Matrix4(); + public adjustmentTransform: Matrix4; + private _gltfBuffer: ArrayBufferLike; + + constructor() { + super(); + this.adjustmentTransform = new Matrix4().identity(); + } + + public async parse(buffer: ArrayBuffer) { + const i3dm = await super.parse(buffer); + this._gltfBuffer = i3dm.glbBytes.slice().buffer; + let glbLoader = new B3DMParseUtil(); + + let model = await glbLoader.parseBinary(this._gltfBuffer); + let { batchTable, featureTable } = i3dm; + + const adjustmentTransform = this.adjustmentTransform; + + const INSTANCES_LENGTH = featureTable.getData('INSTANCES_LENGTH'); + const POSITION = featureTable.getData('POSITION', INSTANCES_LENGTH, 'FLOAT', 'VEC3'); + const NORMAL_UP = featureTable.getData('NORMAL_UP', INSTANCES_LENGTH, 'FLOAT', 'VEC3'); + const NORMAL_RIGHT = featureTable.getData('NORMAL_RIGHT', INSTANCES_LENGTH, 'FLOAT', 'VEC3'); + const SCALE_NON_UNIFORM = featureTable.getData('SCALE_NON_UNIFORM', INSTANCES_LENGTH, 'FLOAT', 'VEC3'); + const SCALE = featureTable.getData('SCALE', INSTANCES_LENGTH, 'FLOAT', 'SCALAR'); + + // [ + // 'RTC_CENTER', + // 'QUANTIZED_VOLUME_OFFSET', + // 'QUANTIZED_VOLUME_SCALE', + // 'EAST_NORTH_UP', + // 'POSITION_QUANTIZED', + // 'NORMAL_UP_OCT32P', + // 'NORMAL_RIGHT_OCT32P', + // ].forEach(feature => { + // + // if (feature in featureTable.header) { + // + // console.warn(`I3DMLoader: Unsupported FeatureTable feature "${feature}" detected.`); + // + // } + // + // }); + + const instanceMap = new Map(); + const instances: InstancedMesh[] = []; + + model.traverse((child: Object3D) => { + let renderer: MeshRenderer; + renderer = child ? child.getComponent(MeshRenderer) : null; + if (renderer) { + const { geometry, material } = renderer; + const instancedMesh = new InstancedMesh(geometry, material, INSTANCES_LENGTH); + + instancedMesh.localPosition = instancedMesh.localPosition.copy(child.localPosition); + instancedMesh.localRotation = instancedMesh.localRotation.copy(child.localRotation); + instancedMesh.localScale = instancedMesh.localScale.copy(child.localScale); + + + instances.push(instancedMesh); + instanceMap.set(child, instancedMesh); + } + }); + + const averageVector = new Vector3(); + for (let i = 0; i < INSTANCES_LENGTH; i++) { + averageVector.x += POSITION[i * 3 + 0] / INSTANCES_LENGTH; + averageVector.y += POSITION[i * 3 + 1] / INSTANCES_LENGTH; + averageVector.z += POSITION[i * 3 + 2] / INSTANCES_LENGTH; + } + + // replace the meshes with instanced meshes + instanceMap.forEach((instancedMesh: InstancedMesh, oldObject: Object3D) => { + const parent = oldObject.parent ? oldObject.parentObject : null; + if (parent) { + // Mesh have no children + parent.removeChild(oldObject); + parent.addChild(instancedMesh); + + // Center the instance around an average point to avoid jitter at large scales. + // Transform the average vector by matrix world so we can account for any existing + // transforms of the instanced mesh. + instancedMesh.transform.updateWorldMatrix(); + // let v = instancedMesh.localPosition.copy(averageVector); + // instancedMesh.transform.worldMatrix.transformVector(v, v); + + // instancedMesh.transform.localPosition.copy(averageVector); + instancedMesh.transform.worldMatrix.transformVector4(averageVector, instancedMesh.localPosition); + + } + }); + + const temp = I3DMLoader; + for (let i = 0; i < INSTANCES_LENGTH; i++) { + temp.tempMat.identity(); + // position + temp.tempPos.set( + POSITION[i * 3 + 0] - averageVector.x, + POSITION[i * 3 + 1] - averageVector.y, + POSITION[i * 3 + 2] - averageVector.z, + ); + + // rotation + if (NORMAL_UP) { + temp.tempUp.set(NORMAL_UP[i * 3 + 0], NORMAL_UP[i * 3 + 1], NORMAL_UP[i * 3 + 2]); + temp.tempRight.set(NORMAL_RIGHT[i * 3 + 0], NORMAL_RIGHT[i * 3 + 1], NORMAL_RIGHT[i * 3 + 2]); + temp.tempRight.cross(temp.tempUp, temp.tempFwd).normalize(); + temp.tempMat.makeBasis(temp.tempRight, temp.tempUp, temp.tempFwd); + temp.tempQuat.setFromRotationMatrix(temp.tempMat); + } else { + temp.tempQuat.set(0, 0, 0, 1); + } + + // scale + if (SCALE) { + temp.tempSca.setScalar(SCALE[i]); + } else if (SCALE_NON_UNIFORM) { + temp.tempSca.set( + SCALE_NON_UNIFORM[i * 3 + 0], + SCALE_NON_UNIFORM[i * 3 + 1], + SCALE_NON_UNIFORM[i * 3 + 2], + ); + } else { + temp.tempSca.set(1, 1, 1); + } + temp.tempMat.compose(temp.tempPos, temp.tempQuat, temp.tempSca); + + // temp.tempMat.appendScale(temp.tempSca.x,temp.tempSca.y,temp.tempSca.z) + // temp.tempMat.appendTranslation(temp.tempPos.x, temp.tempPos.y, temp.tempPos.z); + // temp.tempMat.multiply(adjustmentTransform); + + temp.tempMat.multiplyMatrices(temp.tempMat, adjustmentTransform); + + for (let j = 0, l = instances.length; j < l; j++) { + const instance = instances[j]; + instance.setMatrixAt(i, temp.tempMat); + } + + } + + model['batchTable'] = batchTable; + model['featureTable'] = featureTable; + + return model as any; + } +} diff --git a/src/engine/loader/parser/i3dm/I3DMLoaderBase.ts b/src/engine/loader/parser/i3dm/I3DMLoaderBase.ts new file mode 100644 index 00000000..cd3524b8 --- /dev/null +++ b/src/engine/loader/parser/i3dm/I3DMLoaderBase.ts @@ -0,0 +1,82 @@ +import { readMagicBytes } from "../b3dm/readMagicBytes"; +import { BatchTable, FeatureTable } from "../b3dm/FeatureTable"; + +export class I3DMLoaderBase { + + public async parse(buffer: ArrayBuffer) { + + const dataView = new DataView(buffer); + + // 32-byte header + + // 4 bytes + const magic = readMagicBytes(dataView); + + console.assert(magic === 'i3dm'); + + // 4 bytes + const version = dataView.getUint32(4, true); + + console.assert(version === 1); + + // 4 bytes + const byteLength = dataView.getUint32(8, true); + + console.assert(byteLength === buffer.byteLength); + + // 4 bytes + const featureTableJSONByteLength = dataView.getUint32(12, true); + + // 4 bytes + const featureTableBinaryByteLength = dataView.getUint32(16, true); + + // 4 bytes + const batchTableJSONByteLength = dataView.getUint32(20, true); + + // 4 bytes + const batchTableBinaryByteLength = dataView.getUint32(24, true); + + // 4 bytes + const gltfFormat = dataView.getUint32(28, true); + + // Feature Table + const featureTableStart = 32; + const featureTableBuffer = buffer.slice( + featureTableStart, + featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength, + ); + const featureTable = new FeatureTable( + featureTableBuffer, + 0, + featureTableJSONByteLength, + featureTableBinaryByteLength, + ); + + // Batch Table + const batchTableStart = featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength; + const batchTableBuffer = buffer.slice( + batchTableStart, + batchTableStart + batchTableJSONByteLength + batchTableBinaryByteLength, + ); + const batchTable = new BatchTable( + batchTableBuffer, + featureTable.getData('INSTANCES_LENGTH'), + 0, + batchTableJSONByteLength, + batchTableBinaryByteLength, + ); + + const glbStart = batchTableStart + batchTableJSONByteLength + batchTableBinaryByteLength; + const glbBytes = new Uint8Array(buffer, glbStart, byteLength - glbStart); + + return { + version, + featureTable, + batchTable, + glbBytes, + }; + + } + +} + diff --git a/src/engine/loader/parser/tileRenderer/TileSet.ts b/src/engine/loader/parser/tileRenderer/TileSet.ts new file mode 100644 index 00000000..61d830f8 --- /dev/null +++ b/src/engine/loader/parser/tileRenderer/TileSet.ts @@ -0,0 +1,34 @@ +export class TileSet { + public asset: { generatetool: string, version: string, gltfUpAxis?: any }; + public extras: { scenetree: string }; + public geometricError: number + public properties: any; + public refine: any; + public root: TileSetRoot; +} + +export class TileSetRoot { + public boundingVolume: { box: number[] }; + public children: TileSetChild[]; + public geometricError: number; + public transform: number[]; +} + +export class TileSetChild { + public boundingVolume: { box: number[] }; + public geometricError: number; + public refine: string; + public content: { uri: string }; + public contents: TileSetChildContent[] +} + +export class TileSetChildContent { + public uri: string; + public group: number; + public metadata: TileSetChildContentMetaData; +} + +export class TileSetChildContentMetaData { + public class: string; + public properties: { vertices: number, materials: number } +} diff --git a/src/engine/loader/parser/tileRenderer/TilesRenderer.ts b/src/engine/loader/parser/tileRenderer/TilesRenderer.ts new file mode 100644 index 00000000..187d9085 --- /dev/null +++ b/src/engine/loader/parser/tileRenderer/TilesRenderer.ts @@ -0,0 +1,116 @@ +import { Transform } from "../../../components/Transform"; +import { Matrix4 } from "../../../math/Matrix4"; +import { Vector3 } from "../../../math/Vector3"; +import { Orientation3D } from "../../../math/Orientation3D"; +import { Object3D } from "../../../core/entities/Object3D"; +import { TileSet } from "../../../loader/parser/tileRenderer/TileSet"; +import { Engine3D } from "../../../Engine3D"; + +export class TilesRenderer { + public readonly group: Object3D; + private _modelList: Object3D[]; + private _tileSet: TileSet; + private _rootPath: string; + + constructor() { + this.group = new Object3D(); + } + + public async loadTileSet(rootPath: string, file: string) { + this._modelList = []; + this._rootPath = rootPath; + let combinePath = rootPath + '/' + file; + this._tileSet = (await Engine3D.res.loadJSON(combinePath)) as TileSet; + if (this._tileSet.root.transform) { + let rootMatrix = new Matrix4(); + for (let i = 0; i < 16; i++) { + rootMatrix.rawData[i] = this._tileSet.root.transform[i]; + } + // this.applyTransform(this.group.transform, rootMatrix); + + } + + let adjustmentTransform: Matrix4 = new Matrix4() + const upAxis = this._tileSet.asset && this._tileSet.asset.gltfUpAxis || 'y'; + + switch (upAxis.toLowerCase()) { + + case 'x': + adjustmentTransform.makeRotationAxis(Vector3.Y_AXIS, -Math.PI / 2); + break; + + case 'y': + adjustmentTransform.makeRotationAxis(Vector3.X_AXIS, Math.PI / 2); + break; + + case 'z': + adjustmentTransform.identity(); + break; + } + let invertMatrix = adjustmentTransform.clone(); + invertMatrix.invert(); + this.applyTransform(this.group.transform, invertMatrix); + for (let item of this._tileSet.root.children) { + let uriList: string[] = []; + if (item.content && item.content.uri) { + uriList.push(item.content.uri); + } + if (item.contents) { + for (let c of item.contents) { + uriList.push(c.uri); + } + } + for (let uriPath of uriList) { + let url = this._rootPath + '/' + uriPath; + let functions = { + onProgress: (e) => this.onLoadProgress(e), + onComplete: (e) => this.onComplete(e) + }; + let tileObject3D: Object3D; + if (url.endsWith('.glb')) { + tileObject3D = (await Engine3D.res.loadGltf(url, functions)) as Object3D; + this.applyTransform(tileObject3D.transform, adjustmentTransform) + } else if (url.endsWith('tileset.json')) { + let childTilesetUrl = url.replace('/tileset.json', ''); + let tilesRenderer = new TilesRenderer(); + await tilesRenderer.loadTileSet(childTilesetUrl, 'tileset.json'); + tileObject3D = tilesRenderer.group; + } else if (url.endsWith('.i3dm')) { + tileObject3D = (await Engine3D.res.loadI3DM(url, functions, adjustmentTransform)) as Object3D; + } else if (url.endsWith('.b3dm')) { + tileObject3D = (await Engine3D.res.loadB3DM(url, functions, adjustmentTransform)) as Object3D; + } + + if (tileObject3D) { + this._modelList.push(tileObject3D); + this.group.addChild(tileObject3D); + } + + + } + + + } + + } + + private onLoadProgress(e) { + } + + private onComplete(e) { + } + + private applyTransform(transform: Transform, matrix: Matrix4) { + let prs: Vector3[] = matrix.decompose(Orientation3D.QUATERNION); + + transform.localRotQuat.copyFrom(prs[1]); + transform.localRotQuat = transform.localRotQuat; + + transform.localPosition.copyFrom(prs[0]); + transform.localPosition = transform.localPosition; + + transform.localScale.copyFrom(prs[2]); + transform.localScale = transform.localScale; + } + +} \ No newline at end of file From d3e4b11244deee31084032119bed9d298a702e1c Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Mon, 24 Apr 2023 14:55:29 +0800 Subject: [PATCH 036/100] feat(memory-struct): add struct (#52) add auto struct reflection --- src/engine/util/struct/Struct.ts | 124 ++++++++++++++++++++++++ src/engine/util/struct/StructValue.ts | 11 +++ src/engine/util/struct/Vector3Struct.ts | 11 +++ 3 files changed, 146 insertions(+) create mode 100644 src/engine/util/struct/Struct.ts create mode 100644 src/engine/util/struct/StructValue.ts create mode 100644 src/engine/util/struct/Vector3Struct.ts diff --git a/src/engine/util/struct/Struct.ts b/src/engine/util/struct/Struct.ts new file mode 100644 index 00000000..6edb1a58 --- /dev/null +++ b/src/engine/util/struct/Struct.ts @@ -0,0 +1,124 @@ +/** + * @internal + * @auth sirxu + * Basic data structure class + * Reasonable arrangement of data structure can accelerate computing performance + * @group Util + */ +import { Ctor } from "../Global"; + +export class Struct { + private __refection: { + name: string; + type: string; + }[]; + + private __size: number = 0; + + /** + * get reflection name + * @returns + */ + public getValueType() { + if (!this.__refection) { + let self = this; + this.__refection = []; + for (const key in self) { + if (!key.includes(`__`)) { + const element = self[key]; + let att = { + name: key, + type: element.constructor.name, + }; + this.__refection.push(att); + } + } + } + return this.__refection; + } + + /** + * get any type value memory size + * @param value any type value + * @returns + */ + public static getValueSize(value: any) { + let type = value.constructor.name; + switch (type) { + case `Boolean`: + return 1 * 4; + + case `Number`: + return 1 * 4; + + case `f32`: + return 1 * 4; + + case `i32`: + return 1 * 4; + + case `u32`: + return 1 * 4; + + case `Float32Array`: + return value.byteLength * 4; + + case `Vector2`: + return 2 * 4; + + case `Vector3`: + return 4 * 4; + + case `Vector4`: + return 4 * 4; + + case `Color`: + return 4 * 4; + + case `Array`: + let singleSize = 0; + for (let i = 0, c = value.length; i < c; i++) { + singleSize += Struct.getValueSize(value[i]); + } + return singleSize; + } + return 0; + } + + private static __cacheStruct: Map = new Map(); + + public static Ref(c: Ctor) { + let struct = this.Get(c); + let ref = struct.getValueType(); + return ref; + } + + public static Get(c: Ctor) { + let struct = Struct.__cacheStruct.get(c.prototype); + if (!struct) { + struct = new c(); + Struct.__cacheStruct.set(c.prototype, struct); + } + return struct; + } + + /** + * get any struct memory size + * @returns + */ + public static GetSize(c: Ctor) { + let struct = this.Get(c); + if (struct.__size == 0) { + for (const key in struct) { + if (key.indexOf(`__`) == -1) { + const element = struct[key]; + struct.__size += Struct.getValueSize(element); + } + } + if (struct.__size > 4) { + struct.__size = Math.ceil(struct.__size / 4) * 4; + } + } + return struct.__size; + } +} diff --git a/src/engine/util/struct/StructValue.ts b/src/engine/util/struct/StructValue.ts new file mode 100644 index 00000000..b32ed962 --- /dev/null +++ b/src/engine/util/struct/StructValue.ts @@ -0,0 +1,11 @@ +export class f32 extends Number { + +} + +export class i32 extends Number { + +} + +export class u32 extends Number { + +} \ No newline at end of file diff --git a/src/engine/util/struct/Vector3Struct.ts b/src/engine/util/struct/Vector3Struct.ts new file mode 100644 index 00000000..c029ed75 --- /dev/null +++ b/src/engine/util/struct/Vector3Struct.ts @@ -0,0 +1,11 @@ +import { Struct } from './Struct'; +/** + * @internal + * @group Util + */ +export class Vector3Struct extends Struct { + public x: number = 0; + public y: number = 0; + public z: number = 0; + public w: number = 0; +} From 8c4bcb80d0f3f286bfc50d94c9f6b24b233446d7 Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Mon, 24 Apr 2023 14:58:51 +0800 Subject: [PATCH 037/100] feat(util): add util files (#49) add AxisObject add BytesStream add CameraUtil add UUID add KelvinUtil add Object3DUtil --- src/engine/util/AxisObject.ts | 68 +++++ src/engine/util/BytesStream.ts | 12 + src/engine/util/CameraUtil.ts | 123 +++++++++ src/engine/util/Convert.ts | 52 ++++ src/engine/util/GeometryUtil.ts | 12 + src/engine/util/Global.ts | 40 +++ src/engine/util/KelvinUtil.ts | 79 ++++++ src/engine/util/Object3DUtil.ts | 48 ++++ src/engine/util/ProfilerUtil.ts | 99 +++++++ src/engine/util/StringUtil.ts | 450 ++++++++++++++++++++++++++++++++ src/engine/util/Time.ts | 36 +++ src/engine/util/Vector3Ex.ts | 160 ++++++++++++ src/engine/util/ZSorterUtil.ts | 64 +++++ 13 files changed, 1243 insertions(+) create mode 100644 src/engine/util/AxisObject.ts create mode 100644 src/engine/util/BytesStream.ts create mode 100644 src/engine/util/CameraUtil.ts create mode 100644 src/engine/util/Convert.ts create mode 100644 src/engine/util/GeometryUtil.ts create mode 100644 src/engine/util/Global.ts create mode 100644 src/engine/util/KelvinUtil.ts create mode 100644 src/engine/util/Object3DUtil.ts create mode 100644 src/engine/util/ProfilerUtil.ts create mode 100644 src/engine/util/StringUtil.ts create mode 100644 src/engine/util/Time.ts create mode 100644 src/engine/util/Vector3Ex.ts create mode 100644 src/engine/util/ZSorterUtil.ts diff --git a/src/engine/util/AxisObject.ts b/src/engine/util/AxisObject.ts new file mode 100644 index 00000000..841a8928 --- /dev/null +++ b/src/engine/util/AxisObject.ts @@ -0,0 +1,68 @@ +import { MeshRenderer } from '../components/renderer/MeshRenderer'; +import { Object3D } from '../core/entities/Object3D'; +import { LitMaterial } from '../materials/LitMaterial'; +import { UnLitMaterial } from '../materials/UnLitMaterial'; +import { Color } from '../math/Color'; +import { Vector3 } from '../math/Vector3'; +import { BoxGeometry } from '../shape/BoxGeometry'; +import { defaultRes } from '../textures/DefaultRes'; + +/** + * @internal + * @group Util + */ +export class AxisObject extends Object3D { + public length: number = 100; + + public thickness: number = 0.1; + constructor(length: number, thickness: number = 0.1) { + super(); + this.length = length; + this.thickness = thickness; + this.init(); + } + + public init() { + let xAx = new Object3D(); + let yAx = new Object3D(); + let zAx = new Object3D(); + + let cubeX = new BoxGeometry(2, 2, 2); + let cubeY = new BoxGeometry(2, 2, 2); + let cubeZ = new BoxGeometry(2, 2, 2); + + let matX = new UnLitMaterial(); + matX.baseColor = new Color(1.0, 0.0, 0.0); + + let matY = new UnLitMaterial(); + matY.baseColor = new Color(0.0, 1.0, 0.0); + + let matZ = new UnLitMaterial(); + matZ.baseColor = new Color(0.0, 0.0, 1.0); + + let mrx = xAx.addComponent(MeshRenderer); + let mry = yAx.addComponent(MeshRenderer); + let mrz = zAx.addComponent(MeshRenderer); + + mrx.geometry = cubeX; + mrx.material = matX; + mrx.castShadow = false; + mry.geometry = cubeY; + mry.material = matY; + mry.castShadow = false; + mrz.geometry = cubeZ; + mrz.material = matZ; + mrz.castShadow = false; + + xAx.localScale = new Vector3(this.length, this.thickness, this.thickness); + xAx.x = this.length; + yAx.localScale = new Vector3(this.thickness, this.length, this.thickness); + yAx.y = this.length; + zAx.localScale = new Vector3(this.thickness, this.thickness, this.length); + zAx.z = this.length; + + this.addChild(xAx); + this.addChild(yAx); + this.addChild(zAx); + } +} diff --git a/src/engine/util/BytesStream.ts b/src/engine/util/BytesStream.ts new file mode 100644 index 00000000..8f608c6f --- /dev/null +++ b/src/engine/util/BytesStream.ts @@ -0,0 +1,12 @@ +/** + * @internal + * @group Util + */ +export class BytesStream extends DataView { + public position: number = 0; + constructor(buffer: ArrayBufferLike, byteOffset?: number, byteLength?: number) { + super(buffer, byteOffset, byteLength); + } + + //TODO Improve read/write byte +} diff --git a/src/engine/util/CameraUtil.ts b/src/engine/util/CameraUtil.ts new file mode 100644 index 00000000..e4d72890 --- /dev/null +++ b/src/engine/util/CameraUtil.ts @@ -0,0 +1,123 @@ +import { Camera3D } from '../core/Camera3D'; +import { Object3D } from '../core/entities/Object3D'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +import { Matrix4 } from '../math/Matrix4'; +import { Vector3 } from '../math/Vector3'; + +/** + * Camera3D tool class + * @group Util + */ +export class CameraUtil { + /** + * create a Camera3D component + * @param parent parent object3D + * @param name set name to the owner of this camera3D + * @returns + */ + public static createCamera3DObject(parent?: Object3D, name?: string): Camera3D { + return this.createCamera3D(null, parent, name); + } + + /** + * @internal + * @param object3D + * @param parent + * @param name + * @returns + */ + public static createCamera3D(object3D?: Object3D, parent?: Object3D, name?: string): Camera3D { + object3D ||= new Object3D(); + parent && parent.addChild(object3D); + name && (object3D.name = name); + return object3D.getOrAddComponent(Camera3D); + } + + /** + * @internal + * @param sX + * @param sY + * @param sZ + * @param camera + * @returns + */ + public static UnProjection(sX: number, sY: number, sZ: number = 1, camera?: Camera3D) { + let mouse = new Vector3(sX, sY, 0); + let sc = 1; + let ina: Vector3 = Vector3.HELP_0; + + let ox = webGPUContext.canvas.offsetLeft; + let oy = webGPUContext.canvas.offsetTop; + let w = webGPUContext.canvas.clientWidth; + let h = webGPUContext.canvas.clientHeight; + ina.x = (((mouse.x - ox) * sc) / w - 0.5) * 2; + ina.y = -(((mouse.y - oy) * sc) / h - 0.5) * 2; + ina.z = sZ; + + let outP = new Vector3(0, 0, 0); + let projectWorld = Matrix4.helpMatrix2; + projectWorld.copyFrom(camera.projectionMatrix); + projectWorld.invert(); + let cameraToWorld = Matrix4.helpMatrix; + cameraToWorld.identity(); + cameraToWorld.multiply(projectWorld); + cameraToWorld.multiply(camera.transform.worldMatrix); + cameraToWorld.perspectiveMultiplyPoint3(ina, outP); + return outP; + } + + /** + * @internal + * @param point + * @param camera + * @param target + * @returns + */ + public static Projection(point: Vector3, camera: Camera3D, target?: Vector3) { + let outP = target ? target : new Vector3(0, 0, 0); + let cameraToWorld = Matrix4.helpMatrix; + cameraToWorld.copyFrom(camera.viewMatrix); + cameraToWorld.multiply(camera.projectionMatrix); + cameraToWorld.perspectiveMultiplyPoint3(point, outP); + + // let ox = webGPUContext.canvas.offsetLeft; + // let oy = webGPUContext.canvas.offsetTop; + let w = webGPUContext.canvas.clientWidth / 2; + let h = webGPUContext.canvas.clientHeight / 2; + + // let w = camera.viewPort.width / 2; + // let h = camera.viewPort.height / 2; + outP.x = outP.x * w + w; + outP.y = h - outP.y * h; + return outP; + } + + /** + * @internal + * @param sceneX + * @param sceneY + * @param z + * @param camera + * @param target + * @returns + */ + public static UnProjection2(sceneX: number, sceneY: number, z: number, camera: Camera3D, target: Vector3) { + let outP = target ? target : new Vector3(0, 0, 0); + let cameraToWorld = Matrix4.helpMatrix; + cameraToWorld.copyFrom(camera.pvMatrixInv); + + // let w = camera.viewPort.width / 2; + // let h = camera.viewPort.height / 2; + + let w = webGPUContext.canvas.clientWidth / 2; + let h = webGPUContext.canvas.clientHeight / 2; + + outP.x = (sceneX - w) / w; + outP.y = (h - sceneY) / h; + outP.z = z; + + cameraToWorld.perspectiveMultiplyPoint3(outP, outP); + + return outP; + } +} diff --git a/src/engine/util/Convert.ts b/src/engine/util/Convert.ts new file mode 100644 index 00000000..2a66b624 --- /dev/null +++ b/src/engine/util/Convert.ts @@ -0,0 +1,52 @@ +//TODO FIXED this need change toHalfFloat +const _floatView = new Float32Array(1); +const _int32View = new Int32Array(_floatView.buffer); + +/** + * @internal + * @param val + * @returns + * @group Util + */ +export let toHalfFloat = function (val) { + // Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410 + + /* This method is faster than the OpenEXR implementation (very often + * used, eg. in Ogre), with the additional benefit of rounding, inspired + * by James Tursa?s half-precision code. */ + + _floatView[0] = val; + const x = _int32View[0]; + + let bits = (x >> 16) & 0x8000; /* Get the sign */ + let m = (x >> 12) & 0x07ff; /* Keep one extra bit for rounding */ + const e = (x >> 23) & 0xff; /* Using int is faster here */ + + /* If zero, or denormal, or exponent underflows too much for a denormal + * half, return signed zero. */ + if (e < 103) return bits; + + /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */ + if (e > 142) { + bits |= 0x7c00; + /* If exponent was 0xff and one mantissa bit was set, it means NaN, + * not Inf, so make sure we set one mantissa bit too. */ + bits |= (e == 255 ? 1 : 0) && x & 0x007fffff; + return bits; + } + + /* If exponent underflows but not too much, return a denormal */ + if (e < 114) { + m |= 0x0800; + /* Extra rounding may overflow and set mantissa to 0 and exponent + * to 1, which is OK. */ + bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1); + return bits; + } + + bits |= ((e - 112) << 10) | (m >> 1); + /* Extra rounding. An overflow will set mantissa to 0 and increment + * the exponent, which is OK. */ + bits += m & 1; + return bits; +}; diff --git a/src/engine/util/GeometryUtil.ts b/src/engine/util/GeometryUtil.ts new file mode 100644 index 00000000..b8c318d2 --- /dev/null +++ b/src/engine/util/GeometryUtil.ts @@ -0,0 +1,12 @@ +import { GeometryBase } from '../core/geometry/GeometryBase'; +import { ShaderReflection } from '../gfx/graphics/webGpu/shader/value/ShaderReflectionInfo'; +/** + * @internal + */ +export class GeometryUtil { + public static merge() { } + + public static generateNormal() { } + public static generateTangent() { } + public static packUV() { } +} diff --git a/src/engine/util/Global.ts b/src/engine/util/Global.ts new file mode 100644 index 00000000..80102289 --- /dev/null +++ b/src/engine/util/Global.ts @@ -0,0 +1,40 @@ +/** + * UUID + * @param len + * @param radix + * @returns + * @group Util + */ +export let UUID = function (len = 16, radix = 16) { + var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); + var uuid = [], + i; + radix = radix || chars.length; + + if (len) { + // Compact form + for (i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)]; + } else { + // rfc4122, version 4 form + var r; + + // rfc4122 requires these characters + uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; + uuid[14] = '4'; + + // Fill in random data. At i==19 set the high bits of clock sequence as + // per rfc4122, sec. 4.1.5 + for (i = 0; i < 36; i++) { + if (!uuid[i]) { + r = 0 | (Math.random() * 16); + uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r]; + } + } + } + return uuid.join(''); +}; + +/** + * Constructor + */ +export type Ctor = { new(any?): T, prototype: any }; diff --git a/src/engine/util/KelvinUtil.ts b/src/engine/util/KelvinUtil.ts new file mode 100644 index 00000000..75884f4a --- /dev/null +++ b/src/engine/util/KelvinUtil.ts @@ -0,0 +1,79 @@ +import { Color } from '../math/Color'; + +/** + * Temperature Color Converter + * @group Util + */ +export class KelvinUtil { + /** + * Convert color temperature to color object + * @param color_temperature_Kelvin Color temperature value + * @returns + */ + static color_temperature_to_rgb(color_temperature_Kelvin: number) { + if (color_temperature_Kelvin < 1000) { + color_temperature_Kelvin = 1000; + } else if (color_temperature_Kelvin > 40000) { + color_temperature_Kelvin = 40000; + } + let tmp_internal = color_temperature_Kelvin / 100.0; + let red = this.get_red(tmp_internal); + let green = this.get_green(tmp_internal); + let blue = this.get_blue(tmp_internal); + // return { r: red / 255, g: green / 255, b: blue / 255 }; + return new Color(red / 255, green / 255, blue / 255, 1.0); + } + + /** + * Return red component [0-255] + * @param temperature + * @returns + */ + static get_red(temperature: number): number { + if (temperature <= 66) return 255; + let tmp_red = 329.698727446 * Math.pow(temperature - 60, -0.1332047592); + return this.bound(tmp_red); + } + /** + * Return green component [0-255] + * @param temperature + * @returns + */ + static get_green(temperature: number): number { + let green = 0; + if (temperature <= 66) { + green = 99.4708025861 * Math.log(temperature) - 161.1195681661; + } else { + green = 288.1221695283 * Math.pow(temperature - 60, -0.0755148492); + } + return this.bound(green); + } + /** + * Return blue component [0-255] + * @param temperature + * @returns + */ + static get_blue(temperature: number): number { + let blue = 0; + if (temperature >= 66) { + return 255; + } + if (temperature <= 19) { + return 0; + } + blue = 138.5177312231 * Math.log(temperature - 10) - 305.0447927307; + return this.bound(blue); + } + + /** + * @internal + * @param color_component + * @param minimum + * @param maximum + * @returns + */ + static bound(color_component: number, minimum: number = 0, maximum: number = 255): number { + let color_component_out = Math.max(color_component, minimum); + return Math.min(color_component_out, maximum); + } +} diff --git a/src/engine/util/Object3DUtil.ts b/src/engine/util/Object3DUtil.ts new file mode 100644 index 00000000..66162876 --- /dev/null +++ b/src/engine/util/Object3DUtil.ts @@ -0,0 +1,48 @@ +import { Vector3 } from '.././math/Vector3'; +import { BoundingBox } from '../core/bound/BoundingBox'; +import { Object3D } from '../core/entities/Object3D'; +import { MeshRenderer } from '../components/renderer/MeshRenderer'; + +export class Object3DUtil { + private static readonly genMeshMinVector = Vector3.ZERO.clone(); + private static readonly genMeshMaxVector = Vector3.ZERO.clone(); + private static readonly genMeshVectorList8: Vector3[] = [new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3()]; + /** + * Merge the bounding boxes that have been added to the world matrix based on the mesh of the children node + */ + public static genMeshBounds(obj: Object3D) { + let tempMin = this.genMeshMinVector; + let tempMax = this.genMeshMaxVector; + let tempPoints = this.genMeshVectorList8; + let min: Vector3 = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); + let max: Vector3 = min.clone().mul(-1); + let bound = new BoundingBox(Vector3.ZERO, Vector3.ZERO); + bound.setFromMinMax(min.clone(), max.clone()); + + let cmpts = obj.getComponents(MeshRenderer); + for (const cmpt of cmpts) { + if (cmpt && cmpt.geometry) { + let matrix = cmpt.object3D.transform.worldMatrix; + tempMin.copy(cmpt.geometry.bounds.min); + tempMax.copy(cmpt.geometry.bounds.max); + + tempPoints[0].set(tempMin.x, tempMin.y, tempMin.z); // 000 + tempPoints[1].set(tempMin.x, tempMin.y, tempMax.z); // 001 + tempPoints[2].set(tempMin.x, tempMax.y, tempMin.z); // 010 + tempPoints[3].set(tempMin.x, tempMax.y, tempMax.z); // 011 + tempPoints[4].set(tempMax.x, tempMin.y, tempMin.z); // 100 + tempPoints[5].set(tempMax.x, tempMin.y, tempMax.z); // 101 + tempPoints[6].set(tempMax.x, tempMax.y, tempMin.z); // 110 + tempPoints[7].set(tempMax.x, tempMax.y, tempMax.z); // 111 + + for (const p of tempPoints) { + matrix.transformPoint(p, p); + bound.expandByPoint(p); + } + } + } + bound.setFromMinMax(bound.min, bound.max); + + return bound; + } +} diff --git a/src/engine/util/ProfilerUtil.ts b/src/engine/util/ProfilerUtil.ts new file mode 100644 index 00000000..a79a9f07 --- /dev/null +++ b/src/engine/util/ProfilerUtil.ts @@ -0,0 +1,99 @@ +export type ProfilerLabel2 = { + lable:string , + start:number , + end:number , + total:number , + count:number , +} + + +export type ProfilerLabel = { + lable:string , + start:number , + end:number , + total:number , + count:number , + child:Map +} + +export class ProfilerUtil { + private static profilerLabelMap:Map = new Map(); + + public static start(id:string){ + let profilerLabel = this.profilerLabelMap.get(id); + if(!profilerLabel){ + profilerLabel = { + lable : id , + start : 0 , + end : 0, + total: 0 , + count : 0 , + child :new Map() + } + this.profilerLabelMap.set(id,profilerLabel); + } + profilerLabel.start = performance.now() ; + profilerLabel.end = performance.now() ; + profilerLabel.count = 0 ; + profilerLabel.child.clear(); + } + + public static end( id:string ){ + let profilerLabel = this.profilerLabelMap.get(id); + if(profilerLabel){ + profilerLabel.end = performance.now() ; + profilerLabel.total = profilerLabel.end - profilerLabel.start ; + } + } + + public static countStart( id:string , id2:string = "" ){ + let profilerLabel = this.profilerLabelMap.get(id); + if(profilerLabel){ + profilerLabel.count++ ; + if(id2 != "" ){ + let node = profilerLabel.child.get(id2); + if(!node){ + node = { + lable : id2 , + start : 0 , + end : 0, + total: 0 , + count : 0 , + } + } + node.start = performance.now() ; + node.end = performance.now() ; + node.count = 0 ; + profilerLabel.child.set(id2,node); + } + } + } + + public static countEnd( id:string , id2:string ){ + let profilerLabel = this.profilerLabelMap.get(id); + if(profilerLabel){ + if(id2 != "" ){ + let node = profilerLabel.child.get(id2); + if(!node){ + node = { + lable : id2 , + start : 0 , + end : 0, + total: 0 , + count : 0 , + } + } + node.end = performance.now() ; + node.total = node.end - node.start ; + node.count++ ; + } + } + } + + public static print(id:string){ + let profilerLabel = this.profilerLabelMap.get(id); + if(profilerLabel){ + console.log( "performance" , id , profilerLabel.total + " ms" ); + } + } +} diff --git a/src/engine/util/StringUtil.ts b/src/engine/util/StringUtil.ts new file mode 100644 index 00000000..743cec63 --- /dev/null +++ b/src/engine/util/StringUtil.ts @@ -0,0 +1,450 @@ +/** + * String processing tool class + * @group Util + */ +export class StringUtil { + private static _filterChar: string[] = [' ', ' ', ';', '\n', '\r', '\t', '\n', '\r', '\t']; + + /** + * + * Does the string exist + * @param fields List of detected string + * @param str source string + * @returns Return the index position where it is located. If it does not exist, return -1 + */ + public static hasString(fields: Array, str: string): number { + for (var i: number = 0; i < fields.length; ++i) { + if (fields[i] == str) { + return i; + } + } + + return -1; + } + + /** + * Gets an ellipsis terminated string representation that exceeds the range + * @param str source string + * @param len range of string + * @returns result string + */ + public static getEllipsis(str, len: number = 4): string { + let name = str; + if (name.length > len) name = name.slice(0, len) + '...'; + + return name; + } + + /** + * get name based on URL + * @param url source url + * @returns name + */ + public static getURLName(url: string): string { + var urlArray: string[]; + urlArray = url.split('/'); + let name = urlArray[urlArray.length - 1]; + name = name.split('.')[0]; + return name; + } + + + /** + * get suffix of file name from url + * @param url source url + * @returns suffix + */ + public static getFileFormat(url: string): string { + var startPos: number = url.lastIndexOf('.'); + startPos++; + var endPos = url.length; + if (url.indexOf('?', startPos) !== -1) { + endPos = url.indexOf('?', startPos); + } + var fileFormat: string = url.substr(startPos, endPos - startPos); + fileFormat = fileFormat.toLowerCase(); + return fileFormat; + } + + /** + * get information stored in a string + * @param line source string + * @param data result data reference + */ + public static readLineProperty(line: string, data: any) { + line.trim() + .split(' ') + .forEach((v, i) => { + let strArr = v.split('='); + if (strArr.length > 1) { + let key = strArr[0]; + let value = strArr[1]; + if (Object.prototype.hasOwnProperty.call(data, key)) { + if (value.indexOf('"') == -1) { + data[key] = parseFloat(strArr[1]); + } else { + data[key] = value.replace('"', '').replace('"', ''); + } + } + } + }); + } + + public static getPath(url: string): string { + var s_pos: number = url.lastIndexOf('/'); + s_pos++; + return url.substring(0, s_pos); + } + + public static normalizePath(url: string): string { + var tmp: string = url.replaceAll(`//`, `\/`); + tmp = tmp.replaceAll(`\\`, `\/`); + return tmp; + } + + // public static ab2str(byte: ByteArray, block:number = 65535):string { + // // return String.fromCharCode.apply(null, new Uint8Array(buf)); + // var str: string = ""; + // var oldPos: number = byte.position; + // var length: number = block; + // while (byte.position < byte.length) { + // length = block; + // if (byte.length - byte.position < length) { + // length = byte.length - byte.position; + // } + // str += byte.readUTFBytes(length); + // } + // byte.position = oldPos; + + // return str; + // } + + // public static str2ab(str: string):ByteArray { + // var byte: ByteArray = new ByteArray(); + + // byte.writeUTFBytes(str); + // return byte; + // } + + /** + * Used to cut specified characters + * @param str source string + * @param char cut string + * @returns result string array + */ + public static getStringList(str: string, char: string = ';'): string[] { + return str.split(char); + } + + /** + * Format timestamp data + * @param time timestamp + * @returns + */ + public static formatTime(time: number): string[] { + let t = time / 1000; + let temp = t / 60; + let m = Math.floor(temp); + let s = Math.floor(temp - m); + + return [m.toString(), s.toString()]; + } + + /** + * trim + * @param str source string + * @returns result string + */ + static trim(str) { + return str.replace(/^\s+/g, '').replace(/\s+$/g, ''); + } + + /** + * Determine if the string is empty, null, '' or 'null' + * @param value source string + * @returns boolean + */ + static isEmpty(value) { + return !value || typeof value == 'undefined' || value == null || (typeof value === 'string' && this.trim(value) === '') || value === 'null'; + } + + /** + * Handle strings that exceed the length range, such as adding strings that exceed the range + * @param str source string + * @param len length + * @returns result string + */ + static strCut(str, len): string { + if (str.length * 2 <= len) { + return str; + } + var strlen = 0; + var s = ''; + for (var i = 0; i < str.length; i++) { + s = s + str.charAt(i); + if (str.charCodeAt(i) > 128) { + strlen = strlen + 2; + if (strlen >= len) { + return s.substring(0, s.length - 1) + '...'; + } + } else { + strlen = strlen + 1; + if (strlen >= len) { + return s.substring(0, s.length - 2) + '...'; + } + } + } + return s; + } + + /** + * According to the splicing request parameters + * @param key key string + * @param value value string + * @param isEncodeURI isEncodeURI + * @returns result string + */ + static toQueryPair(key, value, isEncodeURI = false): string { + return key + '=' + (isEncodeURI ? encodeURIComponent(value) : value); + } + + /** + * format a string + * @param str source string + * @param params Pass in a regular processing parameter array + * @returns result string + */ + static stringFormat(str: string, ...params): string { + if (arguments.length === 0) throw new Error('please give arg at least one !'); + + if (arguments.length === 2 && typeof arguments[1] === 'object') { + for (let key in arguments[1]) { + let reg = new RegExp('({' + key + '})', 'g'); + str = str.replace(reg, arguments[1][key]); + } + } else { + for (let i = 0; i < params.length; i++) { + if (params[i] == undefined) { + return str; + } else { + let reg = new RegExp('({[' + i + ']})', 'g'); + str = str.replace(reg, params[i]); + } + } + } + return str; + } + + /** + * Convert JSON objects to strings + * @param json object of json + * @param options + * @returns result string + */ + static parseJson2String(json, options?): string { + let reg = null, + formatted = '', + pad = 0, + PADDING = ' '; + options = options || {}; + options.newlineAfterColonIfBeforeBraceOrBracket = options.newlineAfterColonIfBeforeBraceOrBracket === true ? true : false; + options.spaceAfterColon = options.spaceAfterColon === false ? false : true; + if (typeof json !== 'string') { + json = JSON.stringify(json); + } else { + json = JSON.parse(json); + json = JSON.stringify(json); + } + reg = /([\{\}])/g; + json = json.replace(reg, '\r\n$1\r\n'); + reg = /([\[\]])/g; + json = json.replace(reg, '\r\n$1\r\n'); + reg = /(\,)/g; + json = json.replace(reg, '$1\r\n'); + reg = /(\r\n\r\n)/g; + json = json.replace(reg, '\r\n'); + reg = /\r\n\,/g; + json = json.replace(reg, ','); + + if (!options.newlineAfterColonIfBeforeBraceOrBracket) { + reg = /\:\r\n\{/g; + json = json.replace(reg, ':{'); + reg = /\:\r\n\[/g; + json = json.replace(reg, ':['); + } + if (options.spaceAfterColon) { + reg = /\:/g; + json = json.replace(reg, ':'); + } + json.split('\r\n').forEach(function (node, index) { + let i = 0, + indent = 0, + padding = ''; + + if (node.match(/\{$/) || node.match(/\[$/)) { + indent = 1; + } else if (node.match(/\}/) || node.match(/\]/)) { + if (pad !== 0) { + pad -= 1; + } + } else { + indent = 0; + } + + for (i = 0; i < pad; i++) { + padding += PADDING; + } + + formatted += padding + node + '\r\n'; + pad += indent; + }); + return formatted; + } + + /** + * Compatibility mode - version comparison + * @param v1 Version 1 + * @param v2 Version 2 + * @returns Returns 1, -1, or 0, indicating that the version number is greater, less, or equal, respectively + */ + static compareVersion(v1, v2) { + v1 = v1.split('.'); + v2 = v2.split('.'); + let len = Math.max(v1.length, v2.length); + + while (v1.length < len) { + v1.push('0'); + } + while (v2.length < len) { + v2.push('0'); + } + + for (let i = 0; i < len; i++) { + let num1 = parseInt(v1[i]); + let num2 = parseInt(v2[i]); + + if (num1 > num2) { + return 1; + } else if (num1 < num2) { + return -1; + } + } + + return 0; + } + + /** + * Generate non repeating random string codes + * @returns result + */ + static buildRandomCode() { + let words = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + let len = words.length; + let str = ''; + for (let i = 0; i < 26; i++) { + let rand = Math.floor(Math.random() * len); + str += words.charAt(rand); + } + let millisecond = new Date().getTime(); + return `${millisecond}-${str}`; + } + + /** + * UUID + * @returns UUID + */ + static UUID() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = (Math.random() * 16) | 0, + v = c == 'x' ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); + } + + /** + * make hash code + * @param str source value + * @returns hash code + */ + public static stringToHash(str) { + let hash = 0; + if (str.length == 0) return hash; + for (let i = 0; i < str.length; i++) { + const char = str.charCodeAt(i); + hash = (hash << 5) - hash + char; + hash = hash & hash; // Convert to 32bit integer + } + return hash; + } + + /** + * Convert GLTF URL Address + * @param base baseURL + * @param url source url + * @returns result url + */ + public static parseUrl(base: string, url: string) { + return url.match(/^(blob|http|https):/) ? url : base + url + } + // public static readLineProperty(line:string){ + // fnt.trim().split('\r\n').forEach((v,i)=>{ + // if(i<2){ + // FntParser.readLineProperty(v,fontData); + // }else{ + // if(i0){ + // let char = new FontChar(); + // FntParser.readLineProperty(v,char); + // fontData.fontChar[char.id] = char ; + // fontData.count--; + // } + // } + // } + // }) + // } +} + +//export class XMLParser { +// private _parser: any; +// private _isSupportDOMParser: boolean = false; +// constructor() { +// if (window["DOMParser"]) { +// this._isSupportDOMParser = true; +// this._parser = new DOMParser(); +// } else { +// this._isSupportDOMParser = false; +// } +// } + +// public parse(textxml:string) { +// // get a reference to the requested corresponding xml file +// var xmlDoc; +// if (this._isSupportDOMParser) { +// xmlDoc = this._parser.parseFromString(textxml, "text/xml"); +// } else { +// // Internet Explorer (untested!) +// xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); +// xmlDoc.async = "false"; +// xmlDoc.loadXML(textxml); +// } +// return xmlDoc; +// } + +// public eachXmlAttr(item: Node, fun: Function): void { +// if (item == null || fun == null) +// return; +// var attr: Attr; +// for (var i: number = 0, count = item.attributes.length; i < count; i++) { +// attr = item.attributes[i]; +// fun(attr.name, attr.value); +// } +// } +//} + +//export let xmlPaser = new XMLParser(); diff --git a/src/engine/util/Time.ts b/src/engine/util/Time.ts new file mode 100644 index 00000000..959dfc94 --- /dev/null +++ b/src/engine/util/Time.ts @@ -0,0 +1,36 @@ +/** + * Tool of time + * @group Util + */ +export class Time { + /** + * The time the engine has been running + */ + public static time: number = 0; + /** + * the frame count engine is running + */ + public static frame: number = 0; + /** + * Time from previous frame to present + */ + public static delta: number = 0; + + private static _startTime: number = 0; + private static _timeLabel: string = ``; + /** + * @internal + * @param label + */ + public static start(label: string) { + this._startTime = performance.now(); + this._timeLabel = label; + } + + /** + * @internal + */ + public static end() { + console.log(this._timeLabel, performance.now() - this._startTime); + } +} diff --git a/src/engine/util/Vector3Ex.ts b/src/engine/util/Vector3Ex.ts new file mode 100644 index 00000000..c914d604 --- /dev/null +++ b/src/engine/util/Vector3Ex.ts @@ -0,0 +1,160 @@ +import { Vector3 } from '../math/Vector3'; + +/** + * extra function of vector3 + * @group Util + */ +export class Vector3Ex { + /** + * vector3 add + * @param v1 + * @param v2 + * @param target + * @returns + */ + public static add(v1: Vector3, v2: Vector3, target?: Vector3): Vector3 { + if (!target) { + target = new Vector3(); + } + target.x = v1.x + v2.x; + target.y = v1.y + v2.y; + target.z = v1.z + v2.z; + return target; + } + + /** + * vector3 sub + * @param v1 + * @param v2 + * @param target + * @returns + */ + public static sub(v1: Vector3, v2: Vector3, target?: Vector3): Vector3 { + if (!target) { + target = new Vector3(); + } + target.x = v1.x - v2.x; + target.y = v1.y - v2.y; + target.z = v1.z - v2.z; + return target; + } + + /** + * vector3 mul + * @param v1 + * @param v2 + * @param target + * @returns + */ + public static mul(v1: Vector3, v2: Vector3, target?: Vector3): Vector3 { + if (!target) { + target = new Vector3(); + } + target.x = v1.x * v2.x; + target.y = v1.y * v2.y; + target.z = v1.z * v2.z; + return target; + } + + /** + * vector3 mul + * @param v1 + * @param v2 + * @param target + * @returns + */ + public static mulScale(v1: Vector3, v: number, target?: Vector3): Vector3 { + if (!target) { + target = new Vector3(); + } + target.x = v1.x * v; + target.y = v1.y * v; + target.z = v1.z * v; + return target; + } + + /** + * vector3 div + * @param v1 + * @param v2 + * @param target + * @returns + */ + public static div(v1: Vector3, v2: Vector3, target?: Vector3): Vector3 { + if (!target) { + target = new Vector3(); + } + target.x = v1.x / v2.x; + target.y = v1.y / v2.y; + target.z = v1.z / v2.z; + return target; + } + + /** + * normalize + * @param v1 source vector + * @returns result vector + */ + public static normalize(v1: Vector3) { + let t = v1.clone(); + return t.normalize(); + } + + /** + * dot + * @param v1 first vector + * @param v2 second vector + * @returns result + */ + public static dot(v1: Vector3, v2: Vector3): number { + let v = Vector3.HELP_0; + v.copyFrom(v1); + return v.dotProduct(v2); + } + + /** + * Calculate the angle between two vectors + * @param v1 first vector + * @param v2 second vector + * @returns Angle result in radians + */ + public static calculateVectorAngle_xz(v1: Vector3, v2: Vector3) { + //acos return radian,we should transform it into degree + // return acos((x1*x2 + y1*y2) / sqrt((x1*x1 + y1*y1)*(x2*x2 + y2*y2)) * 180 / 3.14; + return Math.acos((v1.x * v2.x + v1.y * v2.y) / Math.sqrt((v1.x * v1.x + v1.y * v1.y) * (v2.x * v2.x + v2.y * v2.y))); + } + + /** + * + * Calculate the distance between two points + * @static + * @param {Vector3} v1 first vector + * @param {Vector3} v2 second vector + * @return {*} distance + */ + public static distance(v1: Vector3, v2: Vector3) { + return Vector3.distance(v1, v2); + } + + /** + * make a Random 3D Vector + * @param min The min random value of vector components + * @param max The max random value of vector components + * @returns random vector + */ + public static getRandomXYZ(min: number = -100, max: number = 100): Vector3 { + return new Vector3(Math.random() * max + min, Math.random() * max + min, Math.random() * max + min); + } + + /** + * make a Random 3D Vector + * @param min The min random value of vector component-x + * @param max The max random value of vector component-x + * @param yMin The min random value of vector component-y + * @param yMax The max random value of vector component-y + * @returns random vector + */ + public static getRandomV3(min: number = -100, max: number = 100, yMin: number, yMax: number): Vector3 { + return new Vector3(Math.random() * max + min, Math.random() * yMax + yMin, Math.random() * max + min); + } +} diff --git a/src/engine/util/ZSorterUtil.ts b/src/engine/util/ZSorterUtil.ts new file mode 100644 index 00000000..f57dcb4f --- /dev/null +++ b/src/engine/util/ZSorterUtil.ts @@ -0,0 +1,64 @@ +import { Camera3D } from '../core/Camera3D'; +import { Object3D } from '../core/entities/Object3D'; +import { Vector3 } from '../math/Vector3'; + +type ZSortItemObject3D = { obj3d: Object3D; z: number; userData: any }; + +/** + * Sort a data with world coordinates based on the camera's camera by z + * @group Util + */ +export class ZSorterUtil { + private _pool: ZSortItemObject3D[] = []; + private _worldPosition: Vector3 = new Vector3(); + private _viewPosition: Vector3 = new Vector3(); + private _zSortList: ZSortItemObject3D[] = []; + + private pop(): ZSortItemObject3D { + return this._pool.pop() || ({} as any); + } + + private recycle() { + for (let item of this._zSortList) { + item.z = 0; + item.userData = null; + item.obj3d = null; + this._pool.push(item); + } + this._zSortList.length = 0; + } + + /** + * Sort userDataList by z based on the view coordinates of camera3D + * @param camera3D camera3D + * @param userDataList List of objects that users need to sort + * @param getObject3D Obtain the function of the Object 3D reference based on userData + * @param result Returns a list of userData, and if passed in as null, instantiates one + * @returns + */ + public sort(camera3D: Camera3D, userDataList: any[], getObject3D: (userData: any) => Object3D, result?: any[]) { + this._zSortList = []; + for (let userData of userDataList) { + let zSortItemObject3D = this.pop(); + zSortItemObject3D.userData = userData; + zSortItemObject3D.obj3d = getObject3D(userData); + this._worldPosition.copyFrom(zSortItemObject3D.obj3d.transform.worldPosition); + camera3D.worldToScreenPoint(this._worldPosition, this._viewPosition); + zSortItemObject3D.z = this._viewPosition.z; + this._zSortList.push(zSortItemObject3D); + } + + this._zSortList.sort((a, b) => { + return a.z - b.z > 0 ? 1 : -1; + }); + + result ||= []; + for (let item of this._zSortList) { + result.push(item.userData); + } + this.recycle(); + return result; + } +} + +export let zSorterUtil: ZSorterUtil = new ZSorterUtil(); From d60c87d0e4193df5a82a2f2caf9f1698b45714a5 Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Mon, 24 Apr 2023 15:06:48 +0800 Subject: [PATCH 038/100] feat(parser): add gltf parser (#51) add GLBParser add GLTFParser --- src/engine/loader/parser/gltf/GLBParser.ts | 176 +++++ src/engine/loader/parser/gltf/GLTFInfo.ts | 177 +++++ src/engine/loader/parser/gltf/GLTFParser.ts | 233 ++++++ .../loader/parser/gltf/GLTFSubParser.ts | 663 ++++++++++++++++++ .../loader/parser/gltf/GLTFSubParserCamera.ts | 61 ++ .../parser/gltf/GLTFSubParserConverter.ts | 415 +++++++++++ .../parser/gltf/GLTFSubParserMaterial.ts | 160 +++++ .../loader/parser/gltf/GLTFSubParserMesh.ts | 208 ++++++ .../parser/gltf/GLTFSubParserSkeleton.ts | 112 +++ .../loader/parser/gltf/GLTFSubParserSkin.ts | 80 +++ src/engine/loader/parser/gltf/TypeArray.ts | 103 +++ .../extends/KHR_draco_mesh_compression.ts | 174 +++++ .../gltf/extends/KHR_lights_punctual.ts | 8 + .../gltf/extends/KHR_materials_clearcoat.ts | 28 + .../KHR_materials_emissive_strength.ts | 17 + .../parser/gltf/extends/KHR_materials_ior.ts | 8 + .../gltf/extends/KHR_materials_sheen.ts | 8 + .../gltf/extends/KHR_materials_specular.ts | 8 + .../extends/KHR_materials_transmission.ts | 8 + .../gltf/extends/KHR_materials_unlit.ts | 16 + .../gltf/extends/KHR_materials_variants.ts | 8 + .../gltf/extends/KHR_materials_volume.ts | 8 + .../gltf/extends/KHR_mesh_quantization.ts | 8 + .../parser/gltf/extends/KHR_texture_basisu.ts | 8 + .../gltf/extends/KHR_texture_transform.ts | 8 + 25 files changed, 2703 insertions(+) create mode 100644 src/engine/loader/parser/gltf/GLBParser.ts create mode 100644 src/engine/loader/parser/gltf/GLTFInfo.ts create mode 100644 src/engine/loader/parser/gltf/GLTFParser.ts create mode 100644 src/engine/loader/parser/gltf/GLTFSubParser.ts create mode 100644 src/engine/loader/parser/gltf/GLTFSubParserCamera.ts create mode 100644 src/engine/loader/parser/gltf/GLTFSubParserConverter.ts create mode 100644 src/engine/loader/parser/gltf/GLTFSubParserMaterial.ts create mode 100644 src/engine/loader/parser/gltf/GLTFSubParserMesh.ts create mode 100644 src/engine/loader/parser/gltf/GLTFSubParserSkeleton.ts create mode 100644 src/engine/loader/parser/gltf/GLTFSubParserSkin.ts create mode 100644 src/engine/loader/parser/gltf/TypeArray.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_draco_mesh_compression.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_lights_punctual.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_materials_clearcoat.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_materials_emissive_strength.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_materials_ior.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_materials_sheen.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_materials_specular.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_materials_transmission.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_materials_unlit.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_materials_variants.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_materials_volume.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_mesh_quantization.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_texture_basisu.ts create mode 100644 src/engine/loader/parser/gltf/extends/KHR_texture_transform.ts diff --git a/src/engine/loader/parser/gltf/GLBParser.ts b/src/engine/loader/parser/gltf/GLBParser.ts new file mode 100644 index 00000000..0848da4b --- /dev/null +++ b/src/engine/loader/parser/gltf/GLBParser.ts @@ -0,0 +1,176 @@ +import { BitmapTexture2D } from '../../../textures/BitmapTexture2D'; +import { ParserBase } from '../ParserBase'; +import { GLTF_Info } from './GLTFInfo'; +import { GLTFSubParser } from './GLTFSubParser'; + +/** + * @internal + * @group Loader + */ +export class GLBHeader { + magic: number; + version: number; + length: number; +} + +/** + * @internal + * @group Loader + */ +export class GLBChunk { + chunkLength: number; + chunkType: number; + chunkData: Uint8Array; +} + +/** + * GLB file parser + * @internal + * @group Loader + */ +export class GLBParser extends ParserBase { + static format: string = 'bin'; + + private _gltf: GLTF_Info; + + public async parseBuffer(buffer: ArrayBuffer) { + let byteArray = new Uint8Array(buffer); + byteArray['pos'] = 0; + + const fileHeader: GLBHeader = this.parseHeader(byteArray); + + if (fileHeader.magic != 0x46546c67) { + console.error(`invalid GLB file`); + return false; + } + + if (fileHeader.version !== 2.0) { + console.error(`GLBParser only support glTF 2.0 for now! Received glTF version: ${fileHeader.version}`); + return false; + } + + let chunks: Array = []; + while (byteArray['pos'] < byteArray.length) { + let chunk = this.parseChunk(byteArray); + chunks.push(chunk); + } + + if (chunks[0].chunkType != 0x4e4f534a) { + console.error(`invalid GLBChunk`); + return false; + } + + let time = performance.now(); + let gltfJSON = ''; + let maxCount = 65535; + let chunkJSONData = chunks[0].chunkData; + for (let i = 0; i < chunkJSONData.length; i += maxCount) { + let count = chunkJSONData.length - i; + count = Math.min(count, maxCount); + let newUint = chunkJSONData.subarray(i, i + count); + gltfJSON += String.fromCharCode(...newUint); + } + console.log(performance.now() - time); + + // let gltfJSON = String.fromCharCode(...chunks[0].chunkData) ;//.apply(null, chunks[0].chunkData); + let obj = JSON.parse(gltfJSON) as object; + this._gltf = new GLTF_Info(); + this._gltf = { ...this._gltf, ...obj }; + this._gltf.resources = {}; + for (let i = 0; i < this._gltf.buffers.length; i++) { + let buffer = this._gltf.buffers[i]; + buffer.isParsed = true; + buffer.dbuffer = chunks[i + 1].chunkData.buffer; + } + + if (this._gltf.images) { + for (let i = 0; i < this._gltf.images.length; i++) { + let image = this._gltf.images[i]; + image.name = image.name || 'bufferView_' + image.bufferView.toString(); + const bufferView = this._gltf.bufferViews[image.bufferView]; + const buffer = this._gltf.buffers[bufferView.buffer]; + let dataBuffer = new Uint8Array(buffer.dbuffer, bufferView.byteOffset, bufferView.byteLength); + let imgData = new Blob([dataBuffer], { type: image.mimeType }); + let dtexture = new BitmapTexture2D(); + await dtexture.loadFromBlob(imgData); + dtexture.name = image.name; + dtexture.textureSource.setGLBImage(this.initUrl, i); + this._gltf.resources[image.name] = dtexture; + } + } + + let subParser = new GLTFSubParser(); + let nodes = await subParser.parse(this.initUrl, this._gltf, this._gltf.scene); + if (nodes) { + this.data = nodes.rootNode; + return nodes.rootNode; + } + return null; + } + + public async parseJsonAndBuffer(obj: object, bin: ArrayBuffer) { + this._gltf = new GLTF_Info(); + this._gltf = { ...this._gltf, ...obj }; + this._gltf.resources = {}; + let dbuffer = this._gltf.buffers[0]; + dbuffer.isParsed = true; + dbuffer.dbuffer = bin; + + if (this._gltf.images) { + for (let i = 0; i < this._gltf.images.length; i++) { + let image = this._gltf.images[i]; + image.name = image.name || 'bufferView_' + image.bufferView.toString(); + const bufferView = this._gltf.bufferViews[image.bufferView]; + const buffer = this._gltf.buffers[bufferView.buffer]; + let dataBuffer = new Uint8Array(buffer.dbuffer, bufferView.byteOffset, bufferView.byteLength); + let imgData = new Blob([dataBuffer], { type: image.mimeType }); + let dtexture = new BitmapTexture2D(); + dtexture.textureSource.setGLBImage(this.initUrl, i); + await dtexture.loadFromBlob(imgData); + dtexture.name = image.name; + this._gltf.resources[image.name] = dtexture; + } + } + + let subParser = new GLTFSubParser(); + let nodes = await subParser.parse(this.initUrl, this._gltf, this._gltf.scene); + if (nodes) { + this.data = nodes.rootNode; + return nodes.rootNode; + } + return null; + } + + public verification(): boolean { + if (this.data) { + return true; + } + throw new Error('Method not implemented.'); + } + + private parseHeader(buffer: Uint8Array): GLBHeader { + let pos = buffer['pos']; + let result = new GLBHeader(); + let data = new Uint32Array(buffer.buffer, pos, 3); + buffer['pos'] += data.byteLength; + result.magic = data[0]; + result.version = data[1]; + result.length = data[2]; + return result; + } + + private parseChunk(buffer: Uint8Array): GLBChunk { + let pos = buffer['pos']; + let result = new GLBChunk(); + let data = new Uint32Array(buffer.buffer, pos, 2); + pos = buffer['pos'] += data.byteLength; + result.chunkLength = data[0]; + result.chunkType = data[1]; + result.chunkData = new Uint8Array(buffer.buffer, pos, result.chunkLength); + const bytes = new Uint8Array(result.chunkLength); + for (let i = 0; i < result.chunkLength; i++) bytes[i] = result.chunkData[i]; + result.chunkData = bytes; + buffer['pos'] += result.chunkLength; + return result; + } +} diff --git a/src/engine/loader/parser/gltf/GLTFInfo.ts b/src/engine/loader/parser/gltf/GLTFInfo.ts new file mode 100644 index 00000000..72801b98 --- /dev/null +++ b/src/engine/loader/parser/gltf/GLTFInfo.ts @@ -0,0 +1,177 @@ +/** + * @internal + * @group Loader + */ +export class GLTF_Info { + public asset: { + generator: string; + version: string; + minVersion: string; + }; + + public accessors: GLTF_Accessors[]; + + public buffers: { + isParsed: boolean; + dbuffer: any; + byteLength: number; + uri: string; + }[]; + + public bufferViews: { + isParsed: boolean; + buffer: number; + byteOffset: number; + dbufferView: any; + byteStride: number; + byteLength: number; + }[]; + + public materials: { + name: string; + alphaModel: string; + alphaCutoff: number; + }[]; + + public meshes: GLTF_Mesh[]; + + public nodes: GLTF_Node[]; + + public scene: number = 0; + + public scenes: GLTF_Scene; + + public textures: { + isParsed: boolean; + sampler: number; + source: number; + name: string; + dtexture: any; + }[]; + cameras: any; + skins: any; + resources: { [uri: string]: any }; + images: { + uri: string; + name: string; + isParsed: any; + dsampler: any; + dimage: any; + mimeType: string; + bufferView: number; + }[]; + samplers: { + minFilter: number; + magFilter: number; + wrapS: number; + wrapT: number; + }[]; + animations: any; + + extensions: { + KHR_lights_punctual: { + lights: GLTF_Light[]; + }; + }; +} + +/** + * @internal + * @group Loader + */ +export class GLTF_Scene { + public nodes: number[]; +} + +/** + * @internal + * @group Loader + */ +export class GLTF_Light { + name: string; + type: string; + color: number[]; + intensity: number; + range: number; + spot: { + outerConeAngle: number; + }; + + isParsed: boolean; +} + +/** + * @internal + * @group Loader + */ +export class GLTF_Node { + public name: string; + public rotation: number[]; + public scale: number[]; + public translation: number[]; + public children: number[]; + public matrix: number[]; + mesh: number = -1; + isParsed: any; + dnode: any; + camera: any; + skin: any; + nodeId: any; + primitives: any; + extensions: any; + light: GLTF_Light; +} + +/** + * @internal + * @group Loader + */ +export class GLTF_Primitives { + public attributes: { + POSITION: number; + NORMAL: number; + TANGENT: number; + TEXCOORD_0: number; + TEXCOORD_1: number; + }; + + public indices: number; + public material: number; + public mode: any; + public name: any; + public targets: any; + public extensions: any; + public morphTargetsRelative: boolean; +} + +/** + * @internal + * @group Loader + */ +export class GLTF_Mesh { + public name: string; + public primitives: GLTF_Primitives[]; + isParsed: any; + dprimitives: any; + weights: any; + extras: any; +} + +/** + * @internal + * @group Loader + */ +export class GLTF_Accessors { + public bufferView: number; + public componentType: number; + public count: number; + public type: string; + public max: number[]; + public min: number[]; + isParsed: any; + daccessor: any; + normalized: any; + sparse: any; + byteOffset: number; + computeResult: { typedArray: any; arrayType: any; numComponents: number }; +} diff --git a/src/engine/loader/parser/gltf/GLTFParser.ts b/src/engine/loader/parser/gltf/GLTFParser.ts new file mode 100644 index 00000000..bf09f225 --- /dev/null +++ b/src/engine/loader/parser/gltf/GLTFParser.ts @@ -0,0 +1,233 @@ +import { StringUtil } from '../../../util/StringUtil'; +import { FileLoader } from '../../FileLoader'; +import { ParserBase } from '../ParserBase'; +import { GLTF_Info } from './GLTFInfo'; +import { GLTFSubParser } from './GLTFSubParser'; + +/** + * GLTF file Parser + * @internal + * @group Loader + */ +export class GLTFParser extends ParserBase { + static format: string = 'json'; + private _gltf: GLTF_Info; + + public async parserJson(obj: object) { + this._gltf = new GLTF_Info(); + this._gltf = { ...this._gltf, ...obj }; + this._gltf.resources = {}; + // load bin & texture together + await Promise.all([this.load_gltf_bin(), this.load_gltf_textures()]) + //step 0: load bin + //step 1: parser mesh + //await this.load_gltf_bin(); + //step 2: load texture + //await this.load_gltf_textures(); + let subParser = new GLTFSubParser(); + let nodes = await subParser.parse(this.initUrl, this._gltf, this._gltf.scene); + subParser.destory(); + subParser = null + if (nodes) { + this.data = nodes.rootNode; + return nodes.rootNode; + } + this._gltf = null; + return null; + } + + /** + * Verify parsing validity + * @param ret + * @returns + */ + public verification(): boolean { + if (this.data) { + return true; + } + throw new Error('Method not implemented.'); + } + + public static readonly GLTF_NODE_INDEX_PROPERTY: 'GLTF_NODE_INDEX'; + + public static readonly BASE_COLOR_UNIFORM = 'u_baseColorFactor'; + + public static readonly BASE_COLOR_TEXTURE_UNIFORM = 'u_baseColorSampler'; + + public static readonly METALROUGHNESS_UNIFORM = 'u_metallicRoughnessValues'; + + public static readonly METALROUGHNESS_TEXTURE_UNIFORM = 'u_metallicRoughnessSampler'; + + public static readonly NORMAL_TEXTURE_UNIFORM = 'u_normalSampler'; + + public static readonly NORMAL_SCALE_UNIFORM = 'u_normalScale'; + + public static readonly EMISSIVE_TEXTURE_UNIFORM = 'u_emissiveSampler'; + + public static readonly EMISSIVE_FACTOR_UNIFORM = 'u_emissiveFactor'; + + public static readonly OCCLUSION_TEXTURE_UNIFORM = 'u_occlusionSampler'; + + public static readonly OCCLUSION_FACTOR_UNIFORM = 'u_occlusionFactor'; + + public static readonly MAX_MORPH_TARGETS = 8; + + public static readonly MORPH_POSITION_PREFIX = 'a_morphPositions_'; + + public static readonly MORPH_NORMAL_PREFIX = 'a_morphNormals_'; + + public static readonly MORPH_TANGENT_PREFIX = 'a_morphTangents_'; + + public static readonly MORPH_WEIGHT_UNIFORM = 'u_morphWeights'; + + public static readonly SCENE_ROOT_SKELETON = 'SCENE_ROOT'; + + public static readonly IDENTITY_INVERSE_BIND_MATRICES = 'IDENTITY_IBM'; + + public static readonly JOINT_MATRICES_UNIFORM = 'u_jointMatrix'; + + public static readonly ALPHA_CUTOFF_UNIFORM = 'u_alphaCutoff'; + + private static _counter = 0; + public static getMeshNameCounter() { + return function getMeshNameCounter() { + return `GLTF_NO_NAME_PRIMITIVE_${GLTFParser._counter++}`; + }; + } + + public static getModelNameCounter() { + let counter = 0; + + return function getModelNameCounter() { + return `GLTF_NO_NAME_MESH_${counter++}`; + }; + } + + public static getTexCoordDefine(texNum) { + return `UV_NUM ${texNum}`; + } + + public static getVertexColorDefine(num) { + return `HAS_VERTEXCOLOR ${num}`; + } + + public static getBaseColorTextureDefine() { + return 'HAS_BASECOLORMAP'; + } + + public static getMetalRoughnessDefine() { + return 'HAS_METALROUGHNESSMAP'; + } + + public static getNormalMapDefine() { + return 'HAS_NORMALMAP'; + } + + public static getEmissiveMapDefine() { + return 'HAS_EMISSIVEMAP'; + } + + public static getOcclusionMapDefine() { + return 'HAS_OCCLUSIONMAP'; + } + + public static getMorphTargetsDefine(targetNum) { + return `MORPH_TARGET_NUM ${targetNum}`; + } + + public static getMorphtargetPositionDefine() { + return 'HAS_MORPH_POSITION'; + } + + public static getMorphtargetNormalDefine() { + return 'HAS_MORPH_NORMAL'; + } + + public static getMorphtargetTangentDefine() { + return 'HAS_MORPH_TANGENT'; + } + + public static getJointsNumDefine(num) { + return `JOINTS_NUM ${num}`; + } + + public static getJointVec8Define() { + return 'JOINT_VEC8'; + } + + public static getHasNormalDefine() { + return 'HAS_NORMAL'; + } + + public static getHasTangentDefine() { + return 'HAS_TANGENT'; + } + + public static getHasNormalMapDefine() { + return 'HAS_NORMAL_MAP'; + } + + public static getAlphaMaskDefine() { + return 'ALPHA_MASK'; + } + + public static getAlphaBlendDefine() { + return 'ALPHA_BLEND'; + } + + public static readonly defaultMaterial = { + name: 'GLTF_DEFAULT_MATERIAL', + alphaCutoff: 0.33, + alphaMode: 'MASK', + pbrMetallicRoughness: { + name: 'GLTF_DEFAULT_MATERIAL', + defines: [], + doubleSided: false, + baseColorFactor: [1, 1, 1, 1], + metallicFactor: 1, + roughnessFactor: 1, + emissiveFactor: [0, 0, 0], + }, + }; + + private async load_gltf_bin() { + if (this._gltf.buffers && this._gltf.buffers.length > 0) { + let binArray = [] + for (let i = 0; i < this._gltf.buffers.length; i++) { + const element = this._gltf.buffers[i]; + if (element.uri.substring(0, 5) !== 'data:') { + let url = StringUtil.parseUrl(this.baseUrl, element.uri) + if (this.loaderFunctions?.onUrl) + url = await this.loaderFunctions.onUrl(url) + let promise = new FileLoader().loadBinData(url, this.loaderFunctions).then(loader => { + this._gltf.resources[element.uri] = loader; + }) + binArray.push(promise); + } + } + await Promise.all(binArray) + } + } + + private async load_gltf_textures() { + let gltf = this._gltf; + if (this._gltf.images) { + let textureArray = [] + for (let i = 0; i < this._gltf.images.length; i++) { + const element = this._gltf.images[i]; + if (element.uri) { + let url = StringUtil.parseUrl(this.baseUrl, element.uri) + if (this.loaderFunctions?.onUrl) + url = await this.loaderFunctions.onUrl(url) + let promise = new FileLoader().loadAsyncBitmapTexture(url, this.loaderFunctions).then(texture => { + texture.name = StringUtil.getURLName(element.uri); + this._gltf.resources[texture.name] = texture; + texture.textureSource.setGLTFImage(this.initUrl, i, url); + }) + textureArray.push(promise) + } + } + await Promise.all(textureArray) + } + } +} diff --git a/src/engine/loader/parser/gltf/GLTFSubParser.ts b/src/engine/loader/parser/gltf/GLTFSubParser.ts new file mode 100644 index 00000000..a3ed32f4 --- /dev/null +++ b/src/engine/loader/parser/gltf/GLTFSubParser.ts @@ -0,0 +1,663 @@ +import { Skeleton } from '../../../components/anim/skeletonAnim/Skeleton'; +import { SkeletonAnimationComponent } from '../../../components/SkeletonAnimationComponent'; +import { SkeletonAnimationClip } from '../../../components/anim/skeletonAnim/SkeletonAnimationClip'; +import { DirectLight } from '../../../components/lights/DirectLight'; +import { PointLight } from '../../../components/lights/PointLight'; +import { SpotLight } from '../../../components/lights/SpotLight'; +import { MeshRenderer } from '../../../components/renderer/MeshRenderer'; +import { SkinnedMeshRenderer } from '../../../components/renderer/SkinnedMeshRenderer'; +import { Object3D } from '../../../core/entities/Object3D'; +import { GeometryBase } from '../../../core/geometry/GeometryBase'; +import { VertexAttributeName } from '../../../core/geometry/VertexAttributeName'; +import { Engine3D } from '../../../Engine3D'; +import { BlendMode } from '../../../materials/BlendMode'; +import { MaterialBase } from '../../../materials/MaterialBase'; +import { PhysicMaterial } from '../../../materials/PhysicMaterial'; +import { Color } from '../../../math/Color'; +import { RADIANS_TO_DEGREES } from '../../../math/MathUtil'; +import { Quaternion } from '../../../math/Quaternion'; +import { defaultRes } from '../../../textures/DefaultRes'; +import { UUID } from '../../../util/Global'; +import { StringUtil } from '../../../util/StringUtil'; +import { KHR_materials_clearcoat } from './extends/KHR_materials_clearcoat'; +import { KHR_materials_unlit } from './extends/KHR_materials_unlit'; +import { GLTF_Info, GLTF_Node } from './GLTFInfo'; +import { GLTFParser } from './GLTFParser'; +import { getTypedArrayTypeFromGLType } from './TypeArray'; +import { KHR_draco_mesh_compression } from './extends/KHR_draco_mesh_compression'; +import { KHR_materials_emissive_strength } from './extends/KHR_materials_emissive_strength'; +import { BitmapTexture2D } from '../../../textures/BitmapTexture2D'; +import { LitMaterial } from '../../../materials/LitMaterial'; +import { GLTFSubParserCamera } from './GLTFSubParserCamera'; +import { GLTFSubParserMesh } from './GLTFSubParserMesh'; +import { GLTFSubParserMaterial } from './GLTFSubParserMaterial'; +import { GLTFSubParserSkin } from './GLTFSubParserSkin'; +import { GLTFSubParserSkeleton } from './GLTFSubParserSkeleton'; +import { GLTFSubParserConverter } from './GLTFSubParserConverter'; + +/** + * @internal + */ +export class GLTFSubParser { + public currentSceneName: any; + public gltf: GLTF_Info; + public initUrl: string; + private _generator: string; + private _version: string; + private _BASE64_MARKER = ';base64,'; + private _cameraParser: GLTFSubParserCamera = null; + private _meshParser: GLTFSubParserMesh = null; + private _materialParser: GLTFSubParserMaterial = null; + private _skinParser: GLTFSubParserSkin = null; + private _skeletonParser: GLTFSubParserSkeleton = null; + private _converter: GLTFSubParserConverter = null; + + constructor() { + } + + public get version() { + if (this.version) + return this.version; + else if (this.gltf) { + if (!this.gltf.asset) + return this.errorMiss('asset'); + + this._version = this.gltf.asset.version; + + if (this.gltf.asset.minVersion) + this._version += `\r minVersion${this.gltf.asset.minVersion}`; + + return this.version; + } + + console.warn('glTF not loaded.'); + return null; + } + + public async parse(initUrl: string, gltf: GLTF_Info, sceneId: number) { + this.gltf = gltf; + this.initUrl = initUrl; + const { version, generator } = this.gltf.asset; + this._generator = generator; + if (version !== '2.0') { + console.error(`GLTFParser only support glTF 2.0 for now! Received glTF version: ${this.version}`); + return false; + } + + const result = { + nodes: await this.parseScene(sceneId), + animations: this.parseAnimations(), + name: this.currentSceneName, + }; + + return await this.convertToNode(result); + } + + public destory() { + KHR_draco_mesh_compression.unload(this.gltf) + this.gltf = null + } + + private async parseScene(sceneId: number) { + const loadScene = sceneId || this.gltf.scene || 0; + const scene = this.gltf.scenes[loadScene]; + + if (typeof scene === 'undefined') + return this.errorMiss('scene', loadScene); + + this.currentSceneName = scene.name || 'GLTF_NO_NAME_SCENE'; + + const result = []; + const nodes = scene.nodes; + for (let i = 0; i < nodes.length; i++) { + const node = await this.parseNode(nodes[i]); + if (node) result.push(node); + } + + return result; + } + + private async parseNode(nodeId: number) { + const node = this.gltf.nodes[nodeId]; + if (!node) + return this.errorMiss('node', nodeId); + + if (node.isParsed) + return node.dnode; + + const { name, matrix, translation, rotation, scale } = node; + + const dnode = { + name, + matrix, + translation, + rotation, + scale, + nodeId, + camera: null, + primitives: null, + skin: null, + children: null, + light: null, + }; + + if (node.camera !== undefined) + dnode.camera = this.parseCamera(node.camera); + + if (node.mesh !== undefined) + dnode.primitives = await this.parseMesh(node.mesh); + + if (node.extensions !== undefined) + this.applyNodeExtensions(node, dnode); + + if (node.skin !== undefined) { + const skin = this.parseSkin(node.skin); + if (skin) dnode.skin = skin; + } + + dnode.children = []; + if (node.children) for (let i = 0; i < node.children.length; i++) { + dnode.children.push(await this.parseNode(node.children[i])); + } + + node.dnode = dnode; + node.isParsed = true; + + return node.dnode; + } + + private errorMiss(e, info?) { + throw new Error(e + info); + } + + private parseCamera(cameraId: number) { + if (!this._cameraParser) { + this._cameraParser = new GLTFSubParserCamera(this.gltf); + } + return this._cameraParser.parse(cameraId); + } + + private async parseMesh(meshId: number) { + if (!this._meshParser) { + this._meshParser = new GLTFSubParserMesh(this); + } + return this._meshParser.parse(meshId); + } + + public async parseTexture(index: number) { + let textureInfo = this.gltf.textures[index]; + if (textureInfo && !textureInfo.dtexture) { + if (textureInfo && textureInfo.source != null) { + let image = this.gltf.images[textureInfo.source]; + if (image.uri) { + let name = image.uri; + name = StringUtil.getURLName(name); + textureInfo.dtexture = this.gltf.resources[name]; + } else if (image.bufferView) { + let buffer = this.parseBufferView(image.bufferView); + let bitmapTexture = new BitmapTexture2D(); + let img = new Blob([buffer], { type: image.mimeType }); + await bitmapTexture.loadFromBlob(img); + textureInfo.dtexture = bitmapTexture; + } else { + textureInfo.dtexture = this.gltf.resources[image.name]; + } + } else if (textureInfo.name) { + let name = StringUtil.getURLName(textureInfo.name); + textureInfo.dtexture = this.gltf.resources[name]; + } + } + if (!textureInfo.dtexture) { + console.log("miss texture , please check texture!", index, textureInfo); + } + return textureInfo.dtexture; + } + + public async parseMaterial(materialId) { + if (!this._materialParser) { + this._materialParser = new GLTFSubParserMaterial(this); + } + return this._materialParser.parse(materialId); + } + + private parseAnimations() { + const result = []; + // const animations = this.gltf.animations; + // if (animations) + // for (let i = 0; i < animations.length; i++) { + // const animation = animations[i]; + // const { name, channels, samplers } = animation; + // const clips = []; + // if (channels && samplers) + // for (let j = 0; j < channels.length; j++) { + // const channel = channels[j]; + // const sampler = samplers[channel.sampler]; + // if (!sampler) { + + // this.errorMiss(`animations[${i}].channels[${j}].sampler`, channel.sampler); + // continue; + + // } + + // const input = this.parseAccessor(sampler.input).data; + // const outputData = this.parseAccessor(sampler.output); + // const output = outputData.data; + // const numComponents = outputData.numComponents; + // const interpolation = sampler.interpolation || 'LINEAR'; + // const gltfNodeIdx = channel.target.node; + // const path = channel.target.path; + + // if (!input || !output) continue; + + // let combinedOutput = output; + // if (numComponents !== 1 || input.length !== output.length) { + + // const numComp = output.length / input.length; + // combinedOutput = []; + // for (let k = 0; k < input.length; k++) + // combinedOutput.push(output.slice(numComp * k, numComp * (k + 1))); + + // } + + // let nodeProperty = path; + // const extras = {}; + // switch (path) { + + // case 'translation': + // nodeProperty = 'position'; + // break; + // case 'rotation': + // nodeProperty = 'quaternion'; + // break; + // case 'scale': + // nodeProperty = 'scale'; + // break; + // case 'weights': + // nodeProperty = 'weights'; + // // extras.uniformName = GLTFParser.MORPH_WEIGHT_UNIFORM; + // break; + // default: + // console.error(`unsupported animation sampler path ${path}`); + // nodeProperty = false; + // } + + // if (!nodeProperty) continue; + + // const clip = { + // times: input, + // values: combinedOutput, + // findFlag: GLTFParser.GLTF_NODE_INDEX_PROPERTY, + // findValue: gltfNodeIdx, + // targetProp: nodeProperty, + // method: interpolation, + // extras, + // }; + + // clips.push(clip); + + // } + + // result.push({ + // name: name || String(i), + // clips, + // }); + + // } + return result; + } + + private async parseObject3D(nodeInfo: GLTF_Node, parentNode) { + if (!this._converter) { + this._converter = new GLTFSubParserConverter(this); + } + return this._converter.convertNodeToObject3D(nodeInfo, parentNode); + } + + public parseSkeleton(skeletonID: number) { + if (!this._skeletonParser) { + this._skeletonParser = new GLTFSubParserSkeleton(this); + } + return this._skeletonParser.parse(skeletonID); + } + + public parseSkeletonAnimation(skeleton: Skeleton, animation) { + if (!this._skeletonParser) { + this._skeletonParser = new GLTFSubParserSkeleton(this); + } + return this._skeletonParser.parseSkeletonAnimation(skeleton, animation); + } + + private async trivarse(parentNode, nodeInfos) { + for (let i = 0; i < nodeInfos.length; i++) { + const node = await this.parseObject3D(nodeInfos[i], parentNode); + await this.trivarse(node, nodeInfos[i].children); + } + } + + private async convertToNode(infos) { + const rootNode = new Object3D(); + rootNode.name = infos.name; + const nodes = infos.nodes; + const animations = infos.animations; + const textures = []; + const skins = []; + const cameras = []; + await this.trivarse(rootNode, nodes); + + let animas; + // apply skins + // if ( skins.length ) { + + // const handlers = []; // help uglify use different name + // for ( let i = 0; i < skins.length; i ++ ) { + + // const { + // joints, skeleton, inverseBindMatrices, models, + // } = skins[ i ]; + + // const jointNum = joints.length; + // const globalJointTransformNodes = []; + // for ( let j = 0; j < jointNum; j ++ ) + // globalJointTransformNodes[ j ] = rootNode.findInChildren( GLTFParser.GLTF_NODE_INDEX_PROPERTY, joints[ j ] ); + + // let skeletonNode; + // if ( skeleton !== GLTFParser.SCENE_ROOT_SKELETON ) + // skeletonNode = rootNode.findInChildren( GLTFParser.GLTF_NODE_INDEX_PROPERTY, skeleton ); + // else + // skeletonNode = rootNode; + // skins[ i ].skeletonNode = skeletonNode; // do not know how to use it + + // const frag = new Array( 16 ); + // const fragWorld = new Array( 16 ); + // handlers[ i ] = function updateJointUniformFunc() { + + // for ( let k = 0; k < models.length; k ++ ) { + + // const model = models[ k ]; + // const globalTransformNode = model.node; + // let jointMats = []; + // Matrix4.invert( fragWorld, globalTransformNode.transform.getWorldMatrix() ); + + // for ( let n = 0; n < jointNum; n ++ ) { + + // Matrix4.mult( frag, fragWorld, globalJointTransformNodes[ n ].transform.getWorldMatrix() ); + // if ( inverseBindMatrices[ n ] !== GLTFParser.IDENTITY_INVERSE_BIND_MATRICES ) + // Matrix4.mult( frag, frag, inverseBindMatrices[ n ] ); + // jointMats = jointMats.concat( frag ); + + // } + + // const uniformObj = {}; + // uniformObj[ GLTFParser.JOINT_MATRICES_UNIFORM ] = jointMats; + // model.setUniformObj( uniformObj ); + + // } + + // }; + + // rootNode.afterUpdateMatrix.push( { + // type: 'skin', skinName: skins[ i ].name, handler: handlers[ i ], trigerNodes: [ skeletonNode, ...globalJointTransformNodes ], + // } ); + + // } + + // } + + // // animations + // for ( let i = 0; i < animations.length; i ++ ) { + + // const { clips } = animations[ i ]; + // let animateMaxTime = Number.NEGATIVE_INFINITY; + // let animateMinTime = Number.POSITIVE_INFINITY; + // for ( let j = 0; j < clips.length; j ++ ) { + + // const { + // findFlag, findValue, targetProp, times, extras, // method, + // } = clips[ j ]; + + // const node = rootNode.findInChildren( findFlag, findValue ); + // let targetNodes = [ node ]; + // if ( ! node.model && node.gltfPrimitives ) + // targetNodes = node.gltfPrimitives; + + // let setTarget; + // let resetTarget; + // if ( targetProp === 'weights' ) { + + // const resetObj = {}; + // resetObj[ GLTFParser.MORPH_WEIGHT_UNIFORM ] = targetNodes[ 0 ].model.uniformObj[ GLTFParser.MORPH_WEIGHT_UNIFORM ]; + // resetTarget = function () { + + // targetNodes.forEach( ( n ) => { + + // n.model.setUniformObj( resetObj ); + + // } ); + + // }; + + // setTarget = function ( v ) { + + // const uniformobj = {}; + // uniformobj[ extras.uniformName ] = v; + + // targetNodes.forEach( ( n ) => { + + // n.model.setUniformObj( uniformobj ); + + // } ); + + // }; + + // } else { + + // const defaultValues = []; + // for ( let m = 0; m < targetNodes.length; m ++ ) + // defaultValues[ m ] = targetNodes[ m ][ targetProp ]; + + // resetTarget = function () { + + // for ( let m = 0; m < targetNodes.length; m ++ ) + // targetNodes[ m ][ targetProp ] = defaultValues[ m ]; + + // }; + + // setTarget = function ( v ) { + + // targetNodes.forEach( ( n ) => { + + // n[ targetProp ] = v; // eslint-disable-line + + // } ); + + // }; + + // } + + // animateMinTime = animateMinTime < times[ 0 ] ? animateMinTime : times[ 0 ]; + // animateMaxTime = animateMaxTime > times[ times.length - 1 ] ? animateMaxTime : times[ times.length - 1 ]; + + // Object.assign( clips[ j ], { setTarget, resetTarget } ); + + // } + + // Object.assign( animations[ i ], { animateMinTime, animateMaxTime } ); + + // } + + // animas = { animations, type: 'gltf' }; + + return { + rootNode, + textures, + animations: animas, + cameras, + }; + } + + private parseSkin(skinId: number) { + if (!this._skinParser) { + this._skinParser = new GLTFSubParserSkin(this); + } + return this._skinParser.parse(skinId); + } + + public parseAccessor(accessorId: number) { + const accessor = this.gltf.accessors[accessorId]; + if (!accessor) return this.errorMiss('accessor', accessorId); + + if (accessor.isParsed) return accessor.daccessor; + + accessor.isParsed = true; + accessor.daccessor = false; + + const normalize = !!accessor.normalized; + // accessor.bufferView = accessor.bufferView ? accessor.bufferView : accessorId; + const bufferView = this.gltf.bufferViews[accessor.bufferView]; + const byteStride = bufferView && bufferView.byteStride; + const arrayType = getTypedArrayTypeFromGLType(accessor.componentType); + let numComponents = 1; + switch (accessor.type) { + case 'SCALAR': + numComponents = 1; + break; + case 'VEC2': + numComponents = 2; + break; + case 'VEC3': + numComponents = 3; + break; + case 'VEC4': + case 'MAT2': + numComponents = 4; + break; + case 'MAT3': + numComponents = 9; + break; + case 'MAT4': + numComponents = 16; + break; + default: + numComponents = 0; + break; + } + if (numComponents === 0) { + console.error(`glTF has unknown data type in accessor: ${accessor.type}`); + return false; + } + const componentsBytes = numComponents * arrayType.BYTES_PER_ELEMENT; + + let buffer; + if (bufferView !== undefined) { + buffer = this.parseBufferView(accessor.bufferView); + if (!buffer) return accessor.daccessor; + } else buffer = new Uint8Array(componentsBytes * accessor.count).buffer; + + let typedArray = this.getTypedArrayFromArrayBuffer(buffer, byteStride, accessor.byteOffset || 0, arrayType, numComponents, accessor.count); + + if (accessor.sparse) { + const { count, indices, values } = accessor.sparse; + typedArray = new arrayType(typedArray); // eslint-disable-line + + const indicesByteOffset = indices.byteOffset || 0; + const indicesBufferView = this.gltf.bufferViews[indices.bufferView]; + const indicesArrayType = getTypedArrayTypeFromGLType(indices.componentType); + const indicesBuffer = this.parseBufferView(indices.bufferView); + const indicesArray = this.getTypedArrayFromArrayBuffer(indicesBuffer, indicesBufferView.byteStride, indicesByteOffset, indicesArrayType, 1, count); + + const valuesByteOffset = values.byteOffset || 0; + const valuesBufferView = this.gltf.bufferViews[values.bufferView]; + const valuesBuffer = this.parseBufferView(values.bufferView); + const valuesArray = this.getTypedArrayFromArrayBuffer(valuesBuffer, valuesBufferView.byteStride, valuesByteOffset, arrayType, numComponents, count); + + for (let i = 0; i < indicesArray.length; i++) typedArray.set(valuesArray.slice(i * numComponents, i * numComponents + numComponents), indicesArray[i] * numComponents); + } + + accessor.computeResult = { + typedArray, + arrayType, + numComponents, + }; + accessor.daccessor = { + data: typedArray, + numComponents, + normalize, + }; + + return accessor.daccessor; + } + + private getTypedArrayFromArrayBuffer(buffer, byteStride, byteOffset, arrayType, numComponents, count) { + let typedArray; + const componentsBytes = numComponents * arrayType.BYTES_PER_ELEMENT; + if (byteStride && componentsBytes !== byteStride) { + const arrayLength = numComponents * count; + typedArray = new arrayType(arrayLength); // eslint-disable-line + for (let i = 0; i < count; i++) { + const componentVals = new arrayType(buffer, byteOffset + i * byteStride, numComponents); // eslint-disable-line + for (let j = 0; j < numComponents; j++) typedArray[i * numComponents + j] = componentVals[j]; + } + } else typedArray = new arrayType(buffer, byteOffset, count * numComponents); // eslint-disable-line + + return typedArray; + } + + public parseBufferView(bufferViewId: number) { + const bufferView = this.gltf.bufferViews[bufferViewId]; + if (!bufferView) return this.errorMiss('bufferView', bufferViewId); + + if (bufferView.isParsed) return bufferView.dbufferView; + + bufferView.isParsed = true; + bufferView.dbufferView = false; + + const buffer = this.parseBuffer(bufferView.buffer); + if (buffer) { + const { byteOffset, byteLength } = bufferView; + const bufferArray = new Uint8Array(buffer, byteOffset || 0, byteLength); + bufferView.dbufferView = new Uint8Array(bufferArray).buffer; + } + + return bufferView.dbufferView; + } + + private parseBuffer(bufferId: number) { + const buffer = this.gltf.buffers[bufferId]; + if (!buffer) return this.errorMiss('buffer', bufferId); + + if (buffer.isParsed) return buffer.dbuffer; + + buffer.isParsed = true; + buffer.dbuffer = false; + + if (buffer.uri.substring(0, 5) !== 'data:') { + const uri = buffer.uri; + const arrayBuffer = this.gltf.resources[uri]; + if (arrayBuffer) + if (arrayBuffer.byteLength === buffer.byteLength) { + buffer.dbuffer = this.gltf.resources[uri]; + } else console.error(`load gltf resource "${uri}" at buffers[${bufferId} failed, ArrayBuffer.byteLength not equals buffer's byteLength]`); + else console.error(`load gltf resource "${uri}" at buffers[${bufferId}] failed`); + } else { + const base64Idx = buffer.uri.indexOf(this._BASE64_MARKER) + this._BASE64_MARKER.length; + const blob = window.atob(buffer.uri.substring(base64Idx)); + const bytes = new Uint8Array(blob.length); + for (let i = 0; i < blob.length; i++) bytes[i] = blob.charCodeAt(i); + buffer.dbuffer = bytes.buffer; + } + + return buffer.dbuffer; + } + + private getLight(lightID: number) { + let info = this.gltf.extensions.KHR_lights_punctual.lights[lightID]; + return info; + } + + private applyNodeExtensions(node: any, dNode: any) { + let extensions = node.extensions; + if (extensions[`KHR_lights_punctual`] && this.gltf.extensions.KHR_lights_punctual) { + dNode.light = this.getLight(extensions[`KHR_lights_punctual`].light); + } + } +} diff --git a/src/engine/loader/parser/gltf/GLTFSubParserCamera.ts b/src/engine/loader/parser/gltf/GLTFSubParserCamera.ts new file mode 100644 index 00000000..2e482357 --- /dev/null +++ b/src/engine/loader/parser/gltf/GLTFSubParserCamera.ts @@ -0,0 +1,61 @@ +import { GLTF_Info } from "./GLTFInfo"; + +/** + * @internal + */ +export class GLTFSubParserCamera { + protected gltf: GLTF_Info; + + constructor(gltf: GLTF_Info) { + this.gltf = gltf; + } + + public parse(cameraId: number) { + const camera = this.gltf.cameras[cameraId]; + + if (!camera) + return this.errorMiss('camera', cameraId); + + if (camera.isParsed) + return camera.dcamera; + + camera.isParsed = true; + camera.dcamera = false; + + const { name, type, perspective, orthographic } = camera; + + if (type === 'perspective' && perspective) { + const { aspectRatio, yfov, zfar, znear } = perspective; + camera.dcamera = Object.assign( + {}, + { + name, + type, + yfov, + znear, + aspectRatio, + zfar, + }, + ); + } else if (type === 'orthographic' && orthographic) { + const { xmag, ymag, zfar, znear } = orthographic; + camera.dcamera = Object.assign( + {}, + { + name, + type, + xmag, + ymag, + zfar, + znear, + }, + ); + } + + return camera.dcamera; + } + + protected errorMiss(e, info?) { + throw new Error(e + info); + } +} diff --git a/src/engine/loader/parser/gltf/GLTFSubParserConverter.ts b/src/engine/loader/parser/gltf/GLTFSubParserConverter.ts new file mode 100644 index 00000000..75fc31a3 --- /dev/null +++ b/src/engine/loader/parser/gltf/GLTFSubParserConverter.ts @@ -0,0 +1,415 @@ +import { BlendMode, Color, DirectLight, Engine3D, GLTFParser, GeometryBase, KHR_materials_clearcoat, KHR_materials_emissive_strength, KHR_materials_unlit, LitMaterial, MaterialBase, MeshRenderer, Object3D, PhysicMaterial, PointLight, Quaternion, RADIANS_TO_DEGREES, SkeletonAnimationComponent, SkinnedMeshRenderer, SpotLight, UUID, VertexAttributeName, defaultRes } from "../../../.."; +import { GLTF_Info, GLTF_Node } from "./GLTFInfo"; +import { GLTFSubParser } from "./GLTFSubParser"; + +export class GLTFSubParserConverter { + protected gltf: GLTF_Info; + protected subParser: GLTFSubParser; + private _testCount = 8; + private _hasCastShadow = false; + + constructor(subParser: GLTFSubParser) { + this.gltf = subParser.gltf; + this.subParser = subParser; + } + + public async convertNodeToObject3D(nodeInfo: GLTF_Node, parentNode): Promise { + const node = new Object3D(); + node.name = nodeInfo.name; + node[GLTFParser.GLTF_NODE_INDEX_PROPERTY] = nodeInfo.nodeId; + nodeInfo['nodeObj'] = node; + + if (nodeInfo.matrix) { + nodeInfo.translation = [0, 0, 0]; // eslint-disable-line + nodeInfo.rotation = [0, 0, 0, 1]; // eslint-disable-line + nodeInfo.scale = [1, 1, 1]; // eslint-disable-line + ///Matrix4.decompose( nodeInfo.matrix, nodeInfo.translation, nodeInfo.rotation, nodeInfo.scale ); + } + + if (nodeInfo.translation) { + node.transform.x = nodeInfo.translation[0]; + node.transform.y = nodeInfo.translation[1]; + node.transform.z = nodeInfo.translation[2]; + } + if (nodeInfo.rotation) { + let qat = new Quaternion(); + qat.setFromArray(nodeInfo.rotation); + node.transform.localRotQuat = qat; + } + if (nodeInfo.scale) { + node.transform.scaleX = nodeInfo.scale[0]; + node.transform.scaleY = nodeInfo.scale[1]; + node.transform.scaleZ = nodeInfo.scale[2]; + } + + parentNode.addChild(node); + + if (nodeInfo.light) { + this.convertLight(nodeInfo, node); + } + + if (nodeInfo.primitives) { + this.convertprimitives(nodeInfo, node); + } + + if (nodeInfo['skeleton']) { + let skeletonAnimation = node.addComponent(SkeletonAnimationComponent); + if (skeletonAnimation) { + skeletonAnimation.skeleton = this.subParser.parseSkeleton(nodeInfo['skeleton'].skeleton); + for (let i = 0; i < this.gltf.animations.length; i++) { + let animation = this.gltf.animations[i]; + if (!animation.name) animation.name = i.toString(); + let animationClip = this.subParser.parseSkeletonAnimation(skeletonAnimation.skeleton, animation); + skeletonAnimation.addAnimationClip(animationClip); + } + } + } + + return node; + } + + private convertLight(nodeInfo: GLTF_Node, node: Object3D) { + // nodeInfo.light.name + // nodeInfo.light.intensity + // nodeInfo.light.type + switch (nodeInfo.light.type) { + case `directional`: + let directLight = node.addComponent(DirectLight); + node.name = nodeInfo.light.name; + directLight.intensity = nodeInfo.light.intensity * 0.1; + directLight.radius = Number.MAX_SAFE_INTEGER; + directLight.dirFix = -1; + if (!this._hasCastShadow) { + this._hasCastShadow = true; + directLight.castShadow = this._hasCastShadow; + } + directLight.lightColor = nodeInfo.light.color ? new Color(nodeInfo.light.color[0], nodeInfo.light.color[1], nodeInfo.light.color[2]) : new Color(1, 1, 1, 1); + directLight.debug(); + break; + case `point`: + if (this._testCount > 0) { + let point = node.addComponent(PointLight); + point.name = nodeInfo.light.name; + point.intensity = nodeInfo.light.intensity ? nodeInfo.light.intensity * 8.0 * 2 : 1.0; + point.radius = 8.0; + // point.castShadow = true ; + point.at = 2; + point.range = nodeInfo.light.range ? nodeInfo.light.range : 8; + point.lightColor = nodeInfo.light.color ? new Color(nodeInfo.light.color[0], nodeInfo.light.color[1], nodeInfo.light.color[2]) : new Color(1, 1, 1, 1); + // point.debug(); + // point.debugDraw(true); + } + + this._testCount--; + break; + case `spot`: + let spot = node.addComponent(SpotLight); + spot.name = nodeInfo.light.name; + spot.intensity = nodeInfo.light.intensity * 5.0; + spot.radius = 1.0; + spot.dirFix = -1; + spot.at = 2; + // spot.castShadow = true ; + spot.range = nodeInfo.light.range ? nodeInfo.light.range : 8; + spot.outerAngle = nodeInfo.light.spot.outerConeAngle * RADIANS_TO_DEGREES; + spot.lightColor = nodeInfo.light.color ? new Color(nodeInfo.light.color[0], nodeInfo.light.color[1], nodeInfo.light.color[2]) : new Color(1, 1, 1, 1); + // spot.debug(); + break; + default: + break; + } + // console.log(nodeInfo); + } + + private convertprimitives(nodeInfo: GLTF_Node, node: Object3D) { + // const models = []; + for (let i = 0; i < nodeInfo.primitives.length; i++) { + const primitive = nodeInfo.primitives[i]; + + let meshName = primitive.modelName; + // if (meshName.indexOf(`LOD`) != -1) { + // //LOD0 LOD1 LOD2 + // let start = meshName.indexOf('LOD') + 3; + // let end = Math.min(start, meshName.length - start); + // let num = meshName.substring(start, end); + // let value = Number.parseInt(num); + // if (value > 0) { + // continue; + // } + // } + + let md = primitive.material; + if (md.name == undefined) { + md.name = UUID(); + } + let mat: MaterialBase; + + let materialKey = `matkey_${md.name}`; + + if (md && this.gltf.resources[materialKey]) { + mat = this.gltf.resources[materialKey]; + } else { + let newMat: MaterialBase = (mat = new LitMaterial()); + // let newMat: MaterialBase = (mat = new UnLitMaterial()); + this.gltf.resources[materialKey] = newMat; + // newMat.doubleSided + newMat.name = md.name; + if (primitive.material) { + const { baseColorTexture, baseColorFactor, metallicFactor, roughnessFactor, doubleSided, metallicRoughnessTexture, normalTexture, occlusionTexture, emissiveTexture, emissiveFactor, enableBlend, alphaCutoff } = primitive.material; + + let physicMaterial = (newMat = this.applyMaterialExtensions(primitive.material, newMat) as PhysicMaterial); + if (`enableBlend` in primitive.material) { + if (primitive.material[`enableBlend`]) { + physicMaterial.blendMode = BlendMode.NORMAL; + } else { + physicMaterial.blendMode = BlendMode.NONE; + } + + if (primitive.material.defines) { + if (primitive.material.defines.indexOf(`ALPHA_BLEND`) != -1) { + physicMaterial.blendMode = BlendMode.ALPHA; + physicMaterial.transparent = true; + } + } + } + + if (`alphaCutoff` in primitive.material && alphaCutoff > 0) { + physicMaterial.alphaCutoff = alphaCutoff; + physicMaterial.blendMode = BlendMode.NORMAL; + physicMaterial.transparent = true; + } + + if (primitive.material.transformUV1) physicMaterial.uvTransform_1 = primitive.material.transformUV1; + if (primitive.material.transformUV2) physicMaterial.uvTransform_2 = primitive.material.transformUV2; + + physicMaterial.baseColor = new Color(baseColorFactor[0], baseColorFactor[1], baseColorFactor[2], baseColorFactor[3]); + + physicMaterial.roughness = roughnessFactor; + + physicMaterial.metallic = metallicFactor; + + physicMaterial.doubleSide = doubleSided; + + if (baseColorTexture) { + physicMaterial.baseMap = baseColorTexture; + } + + if (normalTexture) { + physicMaterial.normalMap = normalTexture; + } + + if (metallicRoughnessTexture) { + physicMaterial.maskMap = metallicRoughnessTexture; + } + + if (occlusionTexture && (metallicRoughnessTexture != occlusionTexture)) { + physicMaterial.aoMap = occlusionTexture; + } + + if (emissiveTexture) { + physicMaterial.emissiveMap = emissiveTexture; + } + + if (emissiveFactor && (emissiveFactor[0] > 0 || emissiveFactor[1] > 0 || emissiveFactor[2] > 0)) { + if (physicMaterial.emissiveMap) { + if (physicMaterial.emissiveMap == defaultRes.blackTexture) { + physicMaterial.emissiveMap = defaultRes.whiteTexture; + } + } + let emissiveFactorA = emissiveFactor[3] ? emissiveFactor[3] : 1.0; + physicMaterial.emissiveColor = new Color(emissiveFactor[0], emissiveFactor[1], emissiveFactor[2], emissiveFactorA); + physicMaterial.emissiveIntensity = 1; + } + + //todo add material debug + if (Engine3D.setting.material.materialDebug) { + physicMaterial.debug(); + } + } + } + + const { attribArrays, modelName, drawMode } = primitive; + let geometry: GeometryBase; + + //todo need add position draw mode support + if (!attribArrays[`indices`].data) { + let indices = []; + let count = attribArrays['position'].data.length / 3 / 3; + for (let i = 0; i < count; i++) { + let a = i * 3; + indices.push(a + 2); + indices.push(a + 0); + indices.push(a + 1); + } + attribArrays[`indices`] = { + data: new Uint8Array(indices), + normalize: false, + numComponents: 1, + }; + } + if (!attribArrays[`normal`]) { + let normal = []; + let count = attribArrays['position'].data.length / 3; + for (let i = 0; i < count; i++) { + normal.push(0); + normal.push(0); + normal.push(0); + } + attribArrays[`normal`] = { + data: new Float32Array(normal), + normalize: false, + numComponents: 3, + }; + } + if (attribArrays[`indices`].data && attribArrays[`indices`].data.length > 3) { + let meshName = primitive.meshName(); + if (this.gltf.resources[meshName]) { + geometry = this.gltf.resources[meshName]; + } else { + geometry ||= this.createGeometryBase(meshName, attribArrays, primitive); + this.gltf.resources[meshName] = geometry; + } + + const model: Object3D = new Object3D(); //new Model( primitive.attribArrays.mesh ); + model.name = modelName + i; + + if (this.gltf.animations && attribArrays[VertexAttributeName.joints0] != undefined) { + geometry ||= this.createGeometryBase(modelName, attribArrays, primitive); + this.gltf.resources[meshName] = geometry; + + let skeletonNode = this.gltf.nodes[nodeInfo.skin.skeleton]; + if (skeletonNode.dnode && skeletonNode.dnode['nodeObj']) { + let node = skeletonNode.dnode['nodeObj']; + let skeletonAnimation = node.addComponent(SkeletonAnimationComponent); + if (skeletonAnimation) { + skeletonAnimation.skeleton = this.subParser.parseSkeleton(nodeInfo.skin.skeleton); + for (let i = 0; i < this.gltf.animations.length; i++) { + let animation = this.gltf.animations[i]; + if (!animation.name) animation.name = i.toString(); + let animationClip = this.subParser.parseSkeletonAnimation(skeletonAnimation.skeleton, animation); + skeletonAnimation.addAnimationClip(animationClip); + } + } + } else { + skeletonNode.dnode['skeleton'] = nodeInfo.skin; + } + + let smr = model.addComponent(SkinnedMeshRenderer); + smr.castShadow = true; + smr.castGI = true; + smr.geometry = geometry; + smr.material = mat; + smr.skinJointsName = this.parseSkinJoints(nodeInfo.skin); + smr.skinInverseBindMatrices = nodeInfo.skin.inverseBindMatrices; + } else { + geometry ||= this.createGeometryBase(modelName, attribArrays, primitive); + this.gltf.resources[meshName] = geometry; + + if (geometry.hasAttribute(VertexAttributeName.joints0)) { + geometry.vertexAttributeMap.delete(VertexAttributeName.joints0) + } + + let mc = model.addComponent(MeshRenderer); + mc.castShadow = true; + mc.castGI = true; + mc.geometry = geometry; + mc.material = mat; + } + + const uniformobj = {}; + const skinDefines = (nodeInfo.skin && nodeInfo.skin.defines) || []; + // model.defines = primitive.defines.concat( skinDefines ); + // parse material + + // morph targets + // if (primitive.weights) + // uniformobj[GLTFParser.MORPH_WEIGHT_UNIFORM] = primitive.weights; + + // model.setUniformObj( uniformobj ); + + // if ( nodeInfo.primitives.length < 2 ) + // node.addChild( model ); + // else + node.addChild(model); + } + + // models.push( model ); + } + + // if ( node.transform.childrenCount > 0 ) + // node.gltfPrimitives = node.children; + + // if ( nodeInfo.skin ) + + // if ( skins.indexOf( nodeInfo.skin ) > - 1 ) + // nodeInfo.skin.models.push( ...models ); + // else { + + // node.skin = Object.assign( nodeInfo.skin, { models } ); + // skins.push( node.skin ); + + // } + // } + } + + private createGeometryBase(name: string, attribArrays: any, primitive: any): GeometryBase { + let geometry = new GeometryBase(); + geometry.name = name; + + // geometry.geometrySource = new SerializeGeometrySource().setGLTFGeometry(this.initUrl, name); + //morphTarget + geometry.morphTargetsRelative = primitive.morphTargetsRelative; + let targetNames = primitive.targetNames; + if (targetNames && targetNames.length > 0) { + let morphTargetDictionary = geometry.morphTargetDictionary = {} as any; + for (let i = 0; i < targetNames.length; i++) { + morphTargetDictionary[targetNames[i]] = i; + } + } + //vIndex + if (geometry.morphTargetDictionary) { + let vertexCount = attribArrays['position'].data.length / 3; + let vIndexArray = new Float32Array(vertexCount); + for (let i = 0; i < vertexCount; i++) { + vIndexArray[i] = i; + } + attribArrays[`vIndex`] = { + data: vIndexArray, + normalize: false, + numComponents: 1, + }; + } + + for (const attributeName in attribArrays) { + let attributeData = attribArrays[attributeName]; + geometry.setAttribute(attributeName, attributeData.data); + } + + let indicesAttribute = geometry.getAttribute(VertexAttributeName.indices); + geometry.addSubGeometry( + { + indexStart: 0, + indexCount: indicesAttribute.data.length, + vertexStart: 0, + index: 0, + } + ) + return geometry; + } + + private applyMaterialExtensions(dmaterial: any, mat: MaterialBase): MaterialBase { + KHR_materials_clearcoat.apply(this.gltf, dmaterial, mat); + KHR_materials_unlit.apply(this.gltf, dmaterial, mat); + KHR_materials_emissive_strength.apply(this.gltf, dmaterial, mat); + return mat; + } + + private parseSkinJoints(skin) { + let skinJointsName: Array = []; + for (let nodeId of skin.joints) { + let node = this.gltf.nodes[nodeId]; + skinJointsName.push(node.name); + } + return skinJointsName; + } +} diff --git a/src/engine/loader/parser/gltf/GLTFSubParserMaterial.ts b/src/engine/loader/parser/gltf/GLTFSubParserMaterial.ts new file mode 100644 index 00000000..266596dc --- /dev/null +++ b/src/engine/loader/parser/gltf/GLTFSubParserMaterial.ts @@ -0,0 +1,160 @@ +import { Vector4 } from "../../../math/Vector4"; +import { defaultRes } from "../../../textures/DefaultRes"; +import { GLTF_Info } from "./GLTFInfo"; +import { GLTFParser } from "./GLTFParser"; +import { GLTFSubParser } from "./GLTFSubParser"; + +/** + * @internal + */ +export class GLTFSubParserMaterial { + protected gltf: GLTF_Info; + protected subParser: GLTFSubParser; + + constructor(subParser: GLTFSubParser) { + this.gltf = subParser.gltf; + this.subParser = subParser; + } + + public async parse(materialId: number) { + let material; + if (materialId == undefined) { + material = GLTFParser.defaultMaterial; + } else { + material = this.gltf.materials[materialId]; + } + + if (!material) + return this.errorMiss('material', materialId); + + if (material.isParsed) + return material.dmaterial; + + let { name, pbrMetallicRoughness, normalTexture, occlusionTexture, emissiveTexture, emissiveFactor, alphaMode, alphaCutoff, doubleSided, extensions } = material; + const dmaterial = { + name, + defines: [], + doubleSided: !!doubleSided, + baseColorFactor: [1, 1, 1, 1], + emissiveFactor: null, + alphaCutoff: 0, + enableBlend: false, + baseColorTexture: null, + metallicRoughnessTexture: null, + normalTexture: null, + occlusionTexture: null, + emissiveTexture: null, + transformUV1: null, + transformUV2: null, + extensions: null, + }; + + if (pbrMetallicRoughness) { + const { baseColorFactor, metallicFactor, roughnessFactor, baseColorTexture, metallicRoughnessTexture } = pbrMetallicRoughness; + + Object.assign(dmaterial, { + baseColorFactor: baseColorFactor || [1, 1, 1, 1], + metallicFactor: metallicFactor === undefined ? 1.0 : metallicFactor, + roughnessFactor: roughnessFactor === undefined ? 0.15 : roughnessFactor, + }); + + if (baseColorTexture) { + //extensions:{KHR_texture_transform: {…}} + let ext = baseColorTexture.extensions; + if (ext) { + let KHR_texture_transform = ext.KHR_texture_transform; + if (KHR_texture_transform) { + dmaterial.transformUV1 = new Vector4( + KHR_texture_transform.offset ? KHR_texture_transform.offset[0] : 0.0, + KHR_texture_transform.offset ? KHR_texture_transform.offset[1] : 0.0, + KHR_texture_transform.scale ? KHR_texture_transform.scale[0] : 1.0, + KHR_texture_transform.scale ? KHR_texture_transform.scale[1] : 1.0, + ); + } + } + const texture = await this.parseTexture(baseColorTexture.index); + if (texture) { + dmaterial.baseColorTexture = texture; + } else { + dmaterial.baseColorTexture = defaultRes.redTexture; + } + } + + if (metallicRoughnessTexture) { + const texture = await this.parseTexture(metallicRoughnessTexture.index); + if (texture) { + dmaterial.metallicRoughnessTexture = texture; + } else { + dmaterial.metallicRoughnessTexture = defaultRes.blackTexture; + } + } + } else { + Object.assign(dmaterial, { + baseColorFactor: [1, 1, 1, 1], + metallicFactor: 0, + roughnessFactor: 0.5, + }); + } + + if (dmaterial.baseColorFactor && dmaterial.baseColorFactor[3] < 1.0) { + alphaMode = alphaMode === 'MASK' ? 'MASK' : 'BLEND'; + } + + if (alphaMode && alphaMode !== 'OPAQUE') { + if (alphaMode === 'MASK') { + dmaterial.defines.push(GLTFParser.getAlphaMaskDefine()); + dmaterial.alphaCutoff = alphaCutoff === undefined ? 0.5 : alphaCutoff; + } + + if (alphaMode === 'BLEND') { + dmaterial.defines.push(GLTFParser.getAlphaBlendDefine()); + dmaterial.enableBlend = true; + } + } + + if (normalTexture) { + const texture = await this.parseTexture(normalTexture.index); + if (texture) { + dmaterial.normalTexture = texture; + } else { + dmaterial.normalTexture = defaultRes.normalTexture; + } + } + + if (occlusionTexture) { + const texture = await this.parseTexture(occlusionTexture.index); + if (texture) { + dmaterial.occlusionTexture = texture; + } + } + + if (emissiveFactor) { + dmaterial.emissiveFactor = emissiveFactor; + } + + if (emissiveTexture) { + const texture = await this.parseTexture(emissiveTexture.index); + if (texture) { + dmaterial.emissiveTexture = texture; + } else { + dmaterial.emissiveTexture = defaultRes.blackTexture; + } + } + + if (extensions) { + dmaterial.extensions = extensions; + } + + material.isParsed = true; + material.dmaterial = dmaterial; + return dmaterial; + } + + private async parseTexture(index: number) { + return this.subParser.parseTexture(index); + } + + private errorMiss(e, info?) { + throw new Error(e + info); + } +} diff --git a/src/engine/loader/parser/gltf/GLTFSubParserMesh.ts b/src/engine/loader/parser/gltf/GLTFSubParserMesh.ts new file mode 100644 index 00000000..7c5c21b5 --- /dev/null +++ b/src/engine/loader/parser/gltf/GLTFSubParserMesh.ts @@ -0,0 +1,208 @@ +import { VertexAttributeName } from "../../../core/geometry/VertexAttributeName"; +import { GLTF_Info } from "./GLTFInfo"; +import { GLTFParser } from "./GLTFParser"; +import { GLTFSubParser } from "./GLTFSubParser"; +import { KHR_draco_mesh_compression } from "./extends/KHR_draco_mesh_compression"; + +/** + * @internal + */ +export class GLTFSubParserMesh { + protected gltf: GLTF_Info; + protected subParser: GLTFSubParser; + + constructor(subParser: GLTFSubParser) { + this.gltf = subParser.gltf; + this.subParser = subParser; + } + + public async parse(meshId: number) { + const mesh = this.gltf.meshes[meshId]; + + if (!mesh) + return this.errorMiss('mesh', meshId); + + if (mesh.isParsed) + return mesh.dprimitives; + + const primitives = mesh.primitives; + const extras = mesh.extras; + const dprimitives = []; + for (let i = 0; i < primitives.length; i++) { + const primitive = primitives[i]; + const { attributes, indices, material, mode, name, targets, morphTargetsRelative, extensions } = primitive; + + let tmpName = mesh.name; + for (let tn in attributes) { + tmpName += tn; + } + tmpName += `indices:${indices}`; + tmpName += `material:${material}`; + + const dprimitive = { + attribArrays: { indices: [] }, + weights: [], + defines: [], + material: null, + drawMode: null, + meshName: null, + modelName: null, + morphTargetsRelative: false, + targetNames: extras ? extras.targetNames : null, + }; + + let hasNormal = false; + let hasTangent = false; + let texCoordNum = 0; + let jointVec8 = false; + let vertexColor = 0; + + let overlayAccessors; + if (extensions && extensions.KHR_draco_mesh_compression) { + overlayAccessors = await KHR_draco_mesh_compression.apply(this.subParser, primitive); + } + + for (const attribute in attributes) { + const accessor = overlayAccessors ? overlayAccessors[attribute] : this.parseAccessor(attributes[attribute]); + + if (accessor) { + let attribName; + switch (attribute) { + case 'POSITION': + attribName = VertexAttributeName.position; + break; + + case 'NORMAL': + attribName = VertexAttributeName.normal; + hasNormal = true; + break; + + // case 'TANGENT': + // attribName = VertexAttributeName.tangent; + // hasTangent = true; + // break; + + case 'TEXCOORD_0': + attribName = VertexAttributeName.uv; + texCoordNum++; + break; + + // case 'TEXCOORD_1': + // attribName = VertexAttributeName.uv1; + // texCoordNum++; + // break; + + case 'JOINTS_0': + attribName = VertexAttributeName.joints0; + break; + + case 'JOINTS_1': + attribName = VertexAttributeName.joints1; + jointVec8 = true; + break; + + case 'WEIGHTS_0': + attribName = VertexAttributeName.weights0; + break; + + case 'WEIGHTS_1': + attribName = VertexAttributeName.weights1; + break; + + // case 'COLOR_0': + // attribName = VertexAttributeName.color; + // vertexColor = accessor.numComponents; + // break; + + default: + attribName = attribute; + } + + dprimitive.attribArrays[attribName] = accessor; + } + } + + if (hasNormal) dprimitive.defines.push(GLTFParser.getHasNormalDefine()); + if (hasTangent) dprimitive.defines.push(GLTFParser.getHasTangentDefine()); + if (texCoordNum) dprimitive.defines.push(GLTFParser.getTexCoordDefine(texCoordNum)); + if (jointVec8) dprimitive.defines.push(GLTFParser.getJointVec8Define()); + if (vertexColor) dprimitive.defines.push(GLTFParser.getVertexColorDefine(vertexColor)); + + if (indices !== undefined) { + const accessor = overlayAccessors ? overlayAccessors['indices'] : this.parseAccessor(indices); + if (accessor) dprimitive.attribArrays.indices = accessor; + } + + const dmaterial = await this.parseMaterial(material); + if (dmaterial) { + dprimitive.material = dmaterial; + dprimitive.defines = dprimitive.defines.concat(dmaterial.defines); + } + + dprimitive.drawMode = mode === undefined ? 4 : mode; + dprimitive.meshName = () => { + return tmpName; + }; //|| GLTFParser.getMeshNameCounter(); + dprimitive.modelName = mesh.name || GLTFParser.getModelNameCounter(); + + if (targets) { + dprimitive.defines.push(GLTFParser.getMorphTargetsDefine(targets.length)); + dprimitive.morphTargetsRelative = true; + let hasPositions = false; + let hasNormals = false; + let hasTangents = false; + for (let j = 0; j < targets.length; j++) { + const target = targets[j]; + Object.keys(target).forEach((attribute) => { + const accessor = this.parseAccessor(target[attribute]); + if (accessor) { + let attribName; + switch (attribute) { + case 'POSITION': + attribName = GLTFParser.MORPH_POSITION_PREFIX + j; + hasPositions = true; + break; + case 'NORMAL': + attribName = GLTFParser.MORPH_NORMAL_PREFIX + j; + hasNormals = true; + break; + case 'TANGENT': + attribName = GLTFParser.MORPH_TANGENT_PREFIX + j; + hasTangents = true; + break; + default: + attribName = false; + } + + if (!attribName) console.error(`glTF has unsupported morph target attribute ${attribute}`); + else dprimitive.attribArrays[attribName] = accessor; + } + }); + } + + if (hasPositions) dprimitive.defines.push(GLTFParser.getMorphtargetPositionDefine()); + if (hasNormals) dprimitive.defines.push(GLTFParser.getMorphtargetNormalDefine()); + if (hasTangents) dprimitive.defines.push(GLTFParser.getMorphtargetTangentDefine()); + dprimitive.weights = mesh.weights || new Array(targets.length).fill(0); + } + + dprimitives.push(dprimitive); + } + + mesh.dprimitives = dprimitives; + mesh.isParsed = true; + return mesh.dprimitives; + } + + private parseAccessor(accessorId) { + return this.subParser.parseAccessor(accessorId); + } + + private parseMaterial(material) { + return this.subParser.parseMaterial(material); + } + + private errorMiss(e, info?) { + throw new Error(e + info); + } +} diff --git a/src/engine/loader/parser/gltf/GLTFSubParserSkeleton.ts b/src/engine/loader/parser/gltf/GLTFSubParserSkeleton.ts new file mode 100644 index 00000000..e60eb3ac --- /dev/null +++ b/src/engine/loader/parser/gltf/GLTFSubParserSkeleton.ts @@ -0,0 +1,112 @@ +import { Joint } from "../../../components/anim/skeletonAnim/Joint"; +import { Skeleton } from "../../../components/anim/skeletonAnim/Skeleton"; +import { SkeletonAnimationClip } from "../../../components/anim/skeletonAnim/SkeletonAnimationClip"; +import { GLTF_Info } from "./GLTFInfo"; +import { GLTFSubParser } from "./GLTFSubParser"; + +export class GLTFSubParserSkeleton { + protected gltf: GLTF_Info; + protected subParser: GLTFSubParser; + + constructor(subParser: GLTFSubParser) { + this.gltf = subParser.gltf; + this.subParser = subParser; + } + + public parse(skeletonID: number): Skeleton { + let skeleton: Skeleton = new Skeleton(); + this.buildSkeleton(skeleton, undefined, skeletonID); + return skeleton; + } + + public parseSkeletonAnimation(skeleton: Skeleton, animation) { + let count = 0; + let numFrame: number = this.subParser.parseAccessor(animation.samplers[0].input).data.length; + let skeletonPoseLength: number = 12 * skeleton.numJoint; + let bufferData = new Float32Array(skeletonPoseLength * numFrame); + for (var index = 0; index < skeleton.numJoint; index++) { + for (var nFrame: number = 0; nFrame < numFrame; nFrame++) { + var dstOffset = skeletonPoseLength * nFrame + 12 * index; + bufferData[dstOffset + 0] = 1; + bufferData[dstOffset + 1] = 1; + bufferData[dstOffset + 2] = 1; + bufferData[dstOffset + 3] = 1; + } + } + + for (let channel of animation.channels) { + let sampler = animation.samplers[channel.sampler]; + const inputAccessor = this.subParser.parseAccessor(sampler.input); + const outputAccessor = this.subParser.parseAccessor(sampler.output); + let nodeId = channel.target.node; + let property = channel.target.path; + let node = this.gltf.nodes[nodeId]; + if (!node) { + continue; + } + count++; + let joint = skeleton.getJointByName(node.name); + switch (property) { + case 'scale': + for (var nFrame: number = 0; nFrame < numFrame; nFrame++) { + var srcOffset = nFrame * outputAccessor.numComponents; + var dstOffset = skeletonPoseLength * nFrame + 12 * joint.index; + bufferData[dstOffset + 0] = outputAccessor.data[srcOffset + 0]; // x + bufferData[dstOffset + 1] = outputAccessor.data[srcOffset + 1]; // y + bufferData[dstOffset + 2] = outputAccessor.data[srcOffset + 2]; // z + bufferData[dstOffset + 3] = 1; + } + break; + case 'rotation': + for (var nFrame: number = 0; nFrame < numFrame; nFrame++) { + var srcOffset = nFrame * outputAccessor.numComponents; + var dstOffset = skeletonPoseLength * nFrame + 12 * joint.index + 4; + bufferData[dstOffset + 0] = outputAccessor.data[srcOffset + 0]; // x + bufferData[dstOffset + 1] = outputAccessor.data[srcOffset + 1]; // y + bufferData[dstOffset + 2] = outputAccessor.data[srcOffset + 2]; // z + bufferData[dstOffset + 3] = outputAccessor.data[srcOffset + 3]; // w + } + break; + case 'translation': + for (var nFrame: number = 0; nFrame < numFrame; nFrame++) { + var srcOffset = nFrame * outputAccessor.numComponents; + var dstOffset = skeletonPoseLength * nFrame + 12 * joint.index + 8; + bufferData[dstOffset + 0] = outputAccessor.data[srcOffset + 0]; // x + bufferData[dstOffset + 1] = outputAccessor.data[srcOffset + 1]; // y + bufferData[dstOffset + 2] = outputAccessor.data[srcOffset + 2]; // z + bufferData[dstOffset + 3] = inputAccessor.data[nFrame * inputAccessor.numComponents]; + } + break; + } + } + + let animationClip = new SkeletonAnimationClip(animation.name, skeleton, numFrame, bufferData); + return animationClip; + } + + private buildSkeleton(skeleton: Skeleton, parent: Joint, nodeId: number, depth: number = 0) { + let node = this.gltf.nodes[nodeId]; + if (!node.name) { + node.name = 'Node_' + nodeId; + } + + let joint = new Joint(node.name); + joint.parent = parent; + if (node.scale) { + joint.scale.set(node.scale[0], node.scale[1], node.scale[2]); + } + if (node.rotation) { + joint.rotation.set(node.rotation[0], node.rotation[1], node.rotation[2], node.rotation[3]); + } + if (node.translation) { + joint.translation.set(node.translation[0], node.translation[1], node.translation[2]); + } + skeleton.addJoint(joint); + + if (node.children) { + for (let children of node.children) { + this.buildSkeleton(skeleton, joint, children, depth + 1); + } + } + } +} diff --git a/src/engine/loader/parser/gltf/GLTFSubParserSkin.ts b/src/engine/loader/parser/gltf/GLTFSubParserSkin.ts new file mode 100644 index 00000000..0a90e69c --- /dev/null +++ b/src/engine/loader/parser/gltf/GLTFSubParserSkin.ts @@ -0,0 +1,80 @@ +import { GLTF_Info } from "./GLTFInfo"; +import { GLTFParser } from "./GLTFParser"; +import { GLTFSubParser } from "./GLTFSubParser"; + +export class GLTFSubParserSkin { + protected gltf: GLTF_Info; + protected subParser: GLTFSubParser; + + constructor(subParser: GLTFSubParser) { + this.gltf = subParser.gltf; + this.subParser = subParser; + } + + public parse(skinId: number) { + const skin = this.gltf.skins[skinId]; + + if (!skin) + return this.errorMiss('skin', skinId); + + if (skin.isParsed) + return skin.dskin; + + const { name, joints, inverseBindMatrices, skeleton } = skin; + + if (!joints) + return this.errorMiss('skin.joints', skinId); + + skin.isParsed = true; + skin.dskin = false; + let dskin = { + name, + skeleton: null, + inverseBindMatrices: null, + joints, + defines: [GLTFParser.getJointsNumDefine(joints.length)], + }; + + if (skeleton) { + dskin.skeleton = skeleton; + } else { + var rootNodeId = -1; + for (let i = 0; i < this.gltf.nodes.length; i++) { + const n = this.gltf.nodes[i]; + if (n.name == 'root') { + rootNodeId = i; + break; + } + } + if (rootNodeId == -1) { + let scene = this.gltf.scenes[this.gltf.scene]; + rootNodeId = scene.nodes[scene.nodes.length - 1]; + } + dskin.skeleton = rootNodeId; + } + // dskin.skeleton = skeleton === undefined ? GLTFParser.SCENE_ROOT_SKELETON : skeleton; + dskin.inverseBindMatrices = GLTFParser.IDENTITY_INVERSE_BIND_MATRICES; + + if (inverseBindMatrices !== undefined) { + const accessor = this.parseAccessor(inverseBindMatrices); + if (accessor) { + const array = accessor.data; + const matrices = []; + for (let i = 0; i < array.length; i += 16) matrices.push(array.slice(i, i + 16)); + + dskin.inverseBindMatrices = matrices; + } else dskin = null; + } + + skin.dskin = dskin; + return skin.dskin; + } + + private parseAccessor(accessorId) { + return this.subParser.parseAccessor(accessorId); + } + + private errorMiss(e, info?) { + throw new Error(e + info); + } +} diff --git a/src/engine/loader/parser/gltf/TypeArray.ts b/src/engine/loader/parser/gltf/TypeArray.ts new file mode 100644 index 00000000..cec8e3c2 --- /dev/null +++ b/src/engine/loader/parser/gltf/TypeArray.ts @@ -0,0 +1,103 @@ +const isArrayBuffer = window.SharedArrayBuffer + ? function isArrayBufferOrSharedArrayBuffer(ary) { + return ary && ary.buffer && (ary.buffer instanceof ArrayBuffer || ary.buffer instanceof window.SharedArrayBuffer); + } + : function isArrayBuffer(ary) { + return ary && ary.buffer && ary.buffer instanceof ArrayBuffer; + }; + +const BYTE = 0x1400; +const UNSIGNED_BYTE = 0x1401; +const SHORT = 0x1402; +const UNSIGNED_SHORT = 0x1403; +const INT = 0x1404; +const UNSIGNED_INT = 0x1405; +const FLOAT = 0x1406; +const UNSIGNED_SHORT_4_4_4_4 = 0x8033; +const UNSIGNED_SHORT_5_5_5_1 = 0x8034; +const UNSIGNED_SHORT_5_6_5 = 0x8363; +const HALF_FLOAT = 0x140b; +const UNSIGNED_INT_2_10_10_10_REV = 0x8368; +const UNSIGNED_INT_10F_11F_11F_REV = 0x8c3b; +const UNSIGNED_INT_5_9_9_9_REV = 0x8c3e; +const FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8dad; +const UNSIGNED_INT_24_8 = 0x84fa; + +const glTypeToTypedArray = {}; +{ + const tt = glTypeToTypedArray; + tt[BYTE] = Int8Array; + tt[UNSIGNED_BYTE] = Uint8Array; + tt[SHORT] = Int16Array; + tt[UNSIGNED_SHORT] = Uint16Array; + tt[INT] = Int32Array; + tt[UNSIGNED_INT] = Uint32Array; + tt[FLOAT] = Float32Array; + tt[UNSIGNED_SHORT_4_4_4_4] = Uint16Array; + tt[UNSIGNED_SHORT_5_5_5_1] = Uint16Array; + tt[UNSIGNED_SHORT_5_6_5] = Uint16Array; + tt[HALF_FLOAT] = Uint16Array; + tt[UNSIGNED_INT_2_10_10_10_REV] = Uint32Array; + tt[UNSIGNED_INT_10F_11F_11F_REV] = Uint32Array; + tt[UNSIGNED_INT_5_9_9_9_REV] = Uint32Array; + tt[FLOAT_32_UNSIGNED_INT_24_8_REV] = Uint32Array; + tt[UNSIGNED_INT_24_8] = Uint32Array; +} + +/** + * @internal + */ +export function getGLTypeFromTypedArrayType(typedArrayType) { + switch (typedArrayType) { + case Int8Array: + return BYTE; + case Uint8Array: + return UNSIGNED_BYTE; + case Uint8ClampedArray: + return UNSIGNED_BYTE; + case Int16Array: + return SHORT; + case Uint16Array: + return UNSIGNED_SHORT; + case Int32Array: + return INT; + case Uint32Array: + return UNSIGNED_INT; + case Float32Array: + return FLOAT; + default: + throw new Error('unsupported typed array type'); + } +} + +/** + * @internal + */ +export function getGLTypeFromTypedArray(typedArray) { + if (typedArray instanceof Int8Array) return BYTE; + if (typedArray instanceof Uint8Array) return UNSIGNED_BYTE; + if (typedArray instanceof Uint8ClampedArray) return UNSIGNED_BYTE; + if (typedArray instanceof Int16Array) return SHORT; + if (typedArray instanceof Uint16Array) return UNSIGNED_SHORT; + if (typedArray instanceof Int32Array) return INT; + if (typedArray instanceof Uint32Array) return UNSIGNED_INT; + if (typedArray instanceof Float32Array) return FLOAT; + throw new Error('unsupported typed array type'); +} + +/** + * @internal + */ +export function getTypedArrayTypeFromGLType(type) { + const arrayType = glTypeToTypedArray[type]; + if (!arrayType) throw new Error('unkonw gl type'); + return arrayType; +} + +/** + * @internal + */ +export function getTypedArray(array, Type = Float32Array) { + if (isArrayBuffer(array)) return array; + return new Type(array); +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_draco_mesh_compression.ts b/src/engine/loader/parser/gltf/extends/KHR_draco_mesh_compression.ts new file mode 100644 index 00000000..e924d1a6 --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_draco_mesh_compression.ts @@ -0,0 +1,174 @@ +//https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_draco_mesh_compression + +import { GLTF_Primitives } from "../GLTFInfo"; +import { FileLoader } from "../../../FileLoader"; +import { GLTFSubParser } from "../GLTFSubParser"; + +/** + * @internal + * @group Loader + */ +export class KHR_draco_mesh_compression { + private static _workerCode: string; + private static _workers: Map = new Map() + public static async apply(parser: GLTFSubParser, primitive: GLTF_Primitives) { + if (!primitive.extensions) { + return; + } + + const extensionArgs = primitive.extensions['KHR_draco_mesh_compression']; + if (!extensionArgs) { + return; + } + + let worker = this._workers.get(parser.gltf) + if (!worker) { + worker = new Worker(await this.initDecoder()) + this._workers.set(parser.gltf, worker) + } + + worker.postMessage({ + type: 'init', + decoderConfig: { + // wasmBinary: dracoDecoderWasm + }, + }); + + let buffer = parser.parseBufferView(extensionArgs.bufferView); + if (!buffer.result) { + let result = await new Promise((resolve, reject) => { + worker.onmessage = e => { + const msg = e.data; + if (msg.type == 'decode') { + resolve(msg.result); + } else if (msg.type == 'error') { + reject(msg.error); + } + }; + worker.postMessage({ + type: 'decoder', + buffer: buffer, + attributes: extensionArgs.attributes + }, [buffer]); + }); + buffer.result = result; + } + return buffer.result; + } + public static unload(gltf: any) { + let worker = this._workers.get(gltf) + if (worker) { + worker.terminate() + this._workers.delete(gltf) + } + } + protected static async initDecoder() { + if (!this._workerCode) { + let dracoDecoderJs = await new FileLoader().loadTxt('https://cdn.orillusion.com/draco_decoder_gltf.js'); + // let dracoDecoderWasm = await new FileLoader().loadBinData('draco/draco_decoder_gltf.js'); + const blob = new Blob([dracoDecoderJs['data'], '', `(${dracoDecoderWoeker})()`], { type: 'application/javascript' }); + this._workerCode = URL.createObjectURL(blob); + } + return this._workerCode; + } +} + +function dracoDecoderWoeker() { + let decoderConfig; + let decoderPending; + onmessage = e => { + const msg = e.data; + switch (msg.type) { + case 'init': + decoderConfig = msg.decoderConfig; + decoderPending = new Promise((resolve, reject) => { + decoderConfig.onModuleLoaded = draco => { + resolve({ + draco: draco + }); + }; + // @ts-ignore + DracoDecoderModule(decoderConfig); + }); + break; + case 'decoder': + const buffer = msg.buffer; + const attributes = msg.attributes; + decoderPending.then(module => { + const draco = module.draco; + let decoder = new draco.Decoder(); + let decoderBuffer = new draco.DecoderBuffer(); + decoderBuffer.Init(new Int8Array(buffer), buffer.byteLength); + + let status, dracoGeometry; + + try { + const geometryType = decoder.GetEncodedGeometryType(decoderBuffer); + if (geometryType == draco.TRIANGULAR_MESH) { + dracoGeometry = new draco.Mesh(); + status = decoder.DecodeBufferToMesh(decoderBuffer, dracoGeometry); + } /*else if (geometryType == draco.POINT_CLOUD) { + dracoGeometry = new draco.PointCloud(); + status = decoder.DecodeBufferToPointCloud(decoderBuffer, dracoGeometry); + } */else { + self.postMessage(new Error('INVALID_GEOMETRY_TYPE:' + geometryType)); + } + + if (!status.ok()) { + self.postMessage(new Error('DracoDecode:' + status.error_msg())); + } + + let result = {}; + for (const attributeName in attributes) { + let attribute = decoder.GetAttributeByUniqueId(dracoGeometry, attributes[attributeName]); + const numComponents = attribute.num_components(); + const numPoints = dracoGeometry.num_points(); + const numValues = numPoints * numComponents; + const byteLength = numValues * Float32Array.BYTES_PER_ELEMENT; + const dataType = draco.DT_FLOAT32; // getDracoDataType(draco, Float32Array); + const ptr = draco._malloc(byteLength); + decoder.GetAttributeDataArrayForAllPoints(dracoGeometry, attribute, dataType, byteLength, ptr); + const array = new Float32Array(draco.HEAPF32.buffer, ptr, numValues).slice(); + draco._free(ptr); + + result[attributeName] = { + data: array, + numComponents, + normalize: false, + }; + } + + { + const numFaces = dracoGeometry.num_faces(); + const numIndices = numFaces * 3; + const byteLength = numIndices * 4; + const ptr = draco._malloc(byteLength); + decoder.GetTrianglesUInt32Array(dracoGeometry, byteLength, ptr); + const index = new Uint32Array(draco.HEAPF32.buffer, ptr, numIndices).slice(); + draco._free(ptr); + result['indices'] = { + data: index, + numComponents: 1, + normalize: false, + }; + } + + self.postMessage({ + type: 'decode', + result + }); + } catch (error) { + self.postMessage({ + type: 'error', + error: error.message + }); + } finally { + draco.destroy(dracoGeometry); + draco.destroy(decoder); + draco.destroy(decoderBuffer); + } + }); + break; + } + }; +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_lights_punctual.ts b/src/engine/loader/parser/gltf/extends/KHR_lights_punctual.ts new file mode 100644 index 00000000..77f2d376 --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_lights_punctual.ts @@ -0,0 +1,8 @@ +//https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_lights_punctual + +/** + * @internal + * @group Loader + */ +export class KHR_lights_punctual { +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_clearcoat.ts b/src/engine/loader/parser/gltf/extends/KHR_materials_clearcoat.ts new file mode 100644 index 00000000..2d875b47 --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_materials_clearcoat.ts @@ -0,0 +1,28 @@ +// https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_clearcoat + +import { MaterialBase } from '../../../../materials/MaterialBase'; +import { PhysicMaterial } from '../../../../materials/PhysicMaterial'; + +/** + * @internal + * @group Loader + */ +export class KHR_materials_clearcoat { + public static apply(gltf: any, dmaterial: any, tMaterial: any) { + let extensions = dmaterial.extensions; + if (extensions && extensions[`KHR_materials_clearcoat`]) { + (tMaterial as MaterialBase).setDefine('USE_CLEARCOAT', true); + + let KHR_materials_clearcoat = extensions[`KHR_materials_clearcoat`]; + if (`clearcoatFactor` in KHR_materials_clearcoat) { + dmaterial.clearcoatFactor = KHR_materials_clearcoat[`clearcoatFactor`]; + (tMaterial as PhysicMaterial).clearcoatFactor = dmaterial.clearcoatFactor; + } + + if (`clearcoatRoughnessFactor` in KHR_materials_clearcoat) { + dmaterial.clearcoatRoughnessFactor = KHR_materials_clearcoat[`clearcoatRoughnessFactor`]; + (tMaterial as PhysicMaterial).clearcoatRoughnessFactor = dmaterial.clearcoatRoughnessFactor; + } + } + } +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_emissive_strength.ts b/src/engine/loader/parser/gltf/extends/KHR_materials_emissive_strength.ts new file mode 100644 index 00000000..4964eb3e --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_materials_emissive_strength.ts @@ -0,0 +1,17 @@ +//https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_emissive_strength + +import { defaultRes } from "../../../../textures/DefaultRes"; + +export class KHR_materials_emissive_strength { + public static apply(gltf: any, dmaterial: any, tMaterial: any) { + let extensions = dmaterial.extensions; + if (extensions && extensions[`KHR_materials_emissive_strength`]) { + tMaterial.emissiveIntensity = extensions[`KHR_materials_emissive_strength`].emissiveStrength * 0.5; + if (tMaterial.emissiveMap == defaultRes.blackTexture) { + tMaterial.emissiveMap = defaultRes.whiteTexture; + } + } else { + tMaterial.emissiveIntensity = 1; + } + } +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_ior.ts b/src/engine/loader/parser/gltf/extends/KHR_materials_ior.ts new file mode 100644 index 00000000..ba894545 --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_materials_ior.ts @@ -0,0 +1,8 @@ +//https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_ior + +/** + * @internal + * @group Loader + */ +export class KHR_materials_ior { +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_sheen.ts b/src/engine/loader/parser/gltf/extends/KHR_materials_sheen.ts new file mode 100644 index 00000000..66b7ba38 --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_materials_sheen.ts @@ -0,0 +1,8 @@ +//https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_sheen + +/** + * @internal + * @group Loader + */ +export class KHR_materials_sheen { +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_specular.ts b/src/engine/loader/parser/gltf/extends/KHR_materials_specular.ts new file mode 100644 index 00000000..3170ba29 --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_materials_specular.ts @@ -0,0 +1,8 @@ +//https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_specular + +/** + * @internal + * @group Loader + */ +export class KHR_materials_specular { +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_transmission.ts b/src/engine/loader/parser/gltf/extends/KHR_materials_transmission.ts new file mode 100644 index 00000000..eab0b74b --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_materials_transmission.ts @@ -0,0 +1,8 @@ +//https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_transmission + +/** + * @internal + * @group Loader + */ +export class KHR_materials_transmission { +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_unlit.ts b/src/engine/loader/parser/gltf/extends/KHR_materials_unlit.ts new file mode 100644 index 00000000..c6452df2 --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_materials_unlit.ts @@ -0,0 +1,16 @@ +//https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_unlit + +/** + * @internal + * @group Loader + */ +export class KHR_materials_unlit { + public static apply(gltf: any, dmaterial: any, tMaterial: any) { + let extensions = dmaterial.extensions; + if (extensions && extensions[`KHR_materials_unlit`]) { + tMaterial.supportLight = true; + } else { + tMaterial.supportLight = false; + } + } +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_variants.ts b/src/engine/loader/parser/gltf/extends/KHR_materials_variants.ts new file mode 100644 index 00000000..b5563fd1 --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_materials_variants.ts @@ -0,0 +1,8 @@ +//https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_variants + +/** + * @internal + * @group Loader + */ +export class KHR_materials_variants { +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_volume.ts b/src/engine/loader/parser/gltf/extends/KHR_materials_volume.ts new file mode 100644 index 00000000..5ecb9f1d --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_materials_volume.ts @@ -0,0 +1,8 @@ +// https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_volume + +/** + * @internal + * @group Loader + */ +export class KHR_materials_volume { +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_mesh_quantization.ts b/src/engine/loader/parser/gltf/extends/KHR_mesh_quantization.ts new file mode 100644 index 00000000..9fc43e37 --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_mesh_quantization.ts @@ -0,0 +1,8 @@ +//https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_mesh_quantization + +/** + * @internal + * @group Loader + */ +export class KHR_mesh_quantization { +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_texture_basisu.ts b/src/engine/loader/parser/gltf/extends/KHR_texture_basisu.ts new file mode 100644 index 00000000..a9a79dd7 --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_texture_basisu.ts @@ -0,0 +1,8 @@ +//https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_basisu + +/** + * @internal + * @group Loader + */ +export class KHR_texture_basisu { +} diff --git a/src/engine/loader/parser/gltf/extends/KHR_texture_transform.ts b/src/engine/loader/parser/gltf/extends/KHR_texture_transform.ts new file mode 100644 index 00000000..4a0dfc87 --- /dev/null +++ b/src/engine/loader/parser/gltf/extends/KHR_texture_transform.ts @@ -0,0 +1,8 @@ +//https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform + +/** + * @internal + * @group Loader + */ +export class KHR_texture_transform { +} From cfe660bbed720eb082a1f6e1a5de847f63606194 Mon Sep 17 00:00:00 2001 From: hellmor Date: Mon, 24 Apr 2023 15:14:30 +0800 Subject: [PATCH 039/100] feat(propertyAnimation): Add property animation feature (#46) Add property animation feature --- .../curveAnim/curveAnim/AnimationMonitor.ts | 186 +++++++++++++++++ .../curveAnim/curveAnim/AttributeAnimCurve.ts | 23 +++ .../curveAnim/curveAnim/PropertyAnimClip.ts | 97 +++++++++ .../curveAnim/curveAnim/PropertyAnimation.ts | 193 ++++++++++++++++++ .../curveAnim/PropertyAnimationEvent.ts | 27 +++ .../anim/curveAnim/curveAnim/PropertyHelp.ts | 114 +++++++++++ 6 files changed, 640 insertions(+) create mode 100644 src/engine/components/anim/curveAnim/curveAnim/AnimationMonitor.ts create mode 100644 src/engine/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts create mode 100644 src/engine/components/anim/curveAnim/curveAnim/PropertyAnimClip.ts create mode 100644 src/engine/components/anim/curveAnim/curveAnim/PropertyAnimation.ts create mode 100644 src/engine/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts create mode 100644 src/engine/components/anim/curveAnim/curveAnim/PropertyHelp.ts diff --git a/src/engine/components/anim/curveAnim/curveAnim/AnimationMonitor.ts b/src/engine/components/anim/curveAnim/curveAnim/AnimationMonitor.ts new file mode 100644 index 00000000..8ebccc7c --- /dev/null +++ b/src/engine/components/anim/curveAnim/curveAnim/AnimationMonitor.ts @@ -0,0 +1,186 @@ +import { Object3D } from '../../../core/entities/Object3D'; +import { clamp, repeat } from '../../../math/MathUtil'; +import { Matrix4 } from '../../../math/Matrix4'; +import { PropertyAnimation } from './PropertyAnimation'; +import { PropertyAnimClip, WrapMode } from './PropertyAnimClip'; +import { PropertyHelp } from './PropertyHelp'; +/** + * @internal + * @group Animation + */ +export class AnimationMonitor { + public static readonly Complete: number = 0; + public static readonly Seek: number = 1; + + private _propertyAnimClip: { [animName: string]: PropertyAnimClip }; + private _target: Object3D; + private _animation: PropertyAnimation; + private _propertyCache: { + [path: string]: { [attribute: string]: { value: any; property: string } }; + }; + private _bindObjects: Object3D[] = []; + private _currentClip: PropertyAnimClip; + private _frame: number = 0; + private _time: number = 0; + private _isPlaying: boolean = true; + public speed: number = 1; + + constructor(animation: PropertyAnimation) { + this._target = animation.object3D; + this._animation = animation; + this._propertyAnimClip = {}; + this._propertyCache = {}; + } + + public get object3D() { + return this._target; + } + + public get time(): number { + return this._time; + } + + public get currentClip(): PropertyAnimClip { + return this._currentClip; + } + + public getClip(name: string): PropertyAnimClip { + return this._propertyAnimClip[name]; + } + + public addClip(clip: PropertyAnimClip): this { + this._propertyAnimClip[clip.name] = clip; + + for (const objPath in clip.objAnimClip) { + let objClip = clip.objAnimClip[objPath]; + let bind = this._target; + if (objPath == '') { + bind = this._target; + } else { + // let objNames = objPath.split('/'); + // let objName = objNames[objNames.length - 1]; + bind = this._target.getObjectByName(objPath) as Object3D; + } + + let curve = objClip.curve; + for (const attribute in curve) { + if (Object.prototype.hasOwnProperty.call(curve, attribute)) { + // const attributeAnim = curve[attribute]; + // let att = PropertyHelp.property[attribute]; + let atts = PropertyHelp.property[attribute].split('.'); + if (bind) { + if (this._bindObjects.indexOf(bind) == -1) { + this._bindObjects.push(bind); + } + if (this._propertyCache[objPath] == null) { + this._propertyCache[objPath] = {}; + + } + this._propertyCache[objPath][attribute] = { + value: bind[atts[0]], + property: atts[1], + }; + for (let i = 1; i < atts.length - 1; i++) { + this._propertyCache[objPath][attribute] = { + value: bind[atts[i]], + property: atts[i + 1], + }; + } + } + } + } + } + return this; + } + + public play(name: string, reset: boolean = true): PropertyAnimClip { + let clip = this._propertyAnimClip[name]; + if (!clip) return null; + + this._isPlaying = true; + + if (reset || !this._currentClip || this._currentClip.name != name) { + this._time = 0; + } + this._currentClip = clip; + return this._currentClip; + } + + public stop(): this { + this._isPlaying = false; + return this; + } + + public toggle(): this { + this._isPlaying = !this._isPlaying; + return this; + } + + public get isPlaying() { + return this._isPlaying; + } + + public update(time: number, delta: number) { + time = time * 0.001; + delta = delta * 0.001; + if (!this._currentClip || this._frame == time) return; + if (!this._isPlaying) return; + + this._frame = time; + let lastTime = this._time; + this._time = this.calcTime(lastTime + delta * this.speed); + this.validProperty(); + if (this._currentClip.wrapMode != WrapMode.Loop && this._currentClip.wrapMode != WrapMode.Default) { + let complete = this.speed > 0 ? this._time >= this._currentClip.totalTime : this._time <= 0; + if (complete) { + this._isPlaying = false; + this._animation['statusCall'](AnimationMonitor.Complete, lastTime, this._time); + } + } + this._animation['statusCall'](AnimationMonitor.Seek, lastTime, this._time); + } + + public seek(time: number): this { + this._time = this.calcTime(time); + this.validProperty(); + return this; + } + + private calcTime(time: number): number { + if (this._currentClip.wrapMode == WrapMode.Loop || this._currentClip.wrapMode == WrapMode.Default) { + time = repeat(time, this._currentClip.totalTime); + } else { + time = clamp(time, 0, this._currentClip.totalTime); + } + return time; + } + + private validProperty() { + if (this._target) { + for (const objName in this._currentClip.objAnimClip) { + let objClip = this._currentClip.objAnimClip[objName]; + let hasQuaternion = false; + let curve = objClip.curve; + for (const attribute in curve) { + if (Object.prototype.hasOwnProperty.call(curve, attribute)) { + const attributeAnim = curve[attribute]; + // this.target[PropertyHelp.property[key]] = attributeAnim.getValue(this._time); + let value = this._propertyCache[objName][attribute]; + let scale = PropertyHelp.property_scale[attribute]; + hasQuaternion = hasQuaternion || PropertyHelp.property_quaternion[attribute]; + let ret = attributeAnim.getValue(this._time) * scale + PropertyHelp.property_offset[attribute]; + value.value[value.property] = ret; + } + } + + if (hasQuaternion) { + let transform = this._target.transform; + Matrix4.getEuler(transform.localRotation, transform.localRotQuat, true, 'YXZ'); + } + } + } + for (let i of this._bindObjects) { + i.transform.notifyChange(); + } + } +} diff --git a/src/engine/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts b/src/engine/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts new file mode 100644 index 00000000..b3c42c97 --- /dev/null +++ b/src/engine/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts @@ -0,0 +1,23 @@ +import { AnimationCurve } from '../../../math/AnimationCurve'; +/** + * @internal + * @group Animation + */ +export class AttributeAnimCurve extends AnimationCurve { + public attribute: string = ''; + public propertyList: string[]; + public path: string; + + constructor() { + super(); + } + + public unSerialized(data: any): this { + let { attribute, path } = data; + this.attribute = attribute; + this.path = path; + this.propertyList = attribute.split('.'); + super.unSerialized(data.curve); + return this; + } +} diff --git a/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimClip.ts b/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimClip.ts new file mode 100644 index 00000000..97f84c5f --- /dev/null +++ b/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimClip.ts @@ -0,0 +1,97 @@ +import { AttributeAnimCurve } from './AttributeAnimCurve'; +/** + * @internal + * @group Animation + */ +export class ObjectAnimClip { + public curve: { [attribute: string]: AttributeAnimCurve } = {}; +} +/** + * @group Animation + */ +export enum WrapMode { + /** + * Read loop mode from animation clips. + */ + Default = 0, + /** + * When the time reaches the end of the animation clip, the clip will automatically stop playing and the time will be reset to the beginning of the clip. + */ + Clamp = 1, + /** + * Stop the animation when the time reaches the end. + */ + Once = 1, + /** + * When the time reaches the end, replay from the beginning. + */ + Loop = 2, + /** + * Play the animation. When it reaches the endpoint, it will continue to play the last frame and never stop playing. + */ + PingPong = 4, + /** + * Play the animation. When playing to the end, the animation is always in the sampling state of the last frame. + */ + ClampForever = 8, +} +/** + * All keyframe data for attribute animation + * @internal + * @group Animation + */ +export class PropertyAnimClip { + public name: string; + public objAnimClip: { [path: string]: ObjectAnimClip }; + + public totalTime: number = 0; + public time: number = 0; + // private _startTime: number = 0; + private _stopTime: number = 0; + private _loopTime: any; + private _wrapMode: WrapMode; + private _sampleRate: any; + + public get wrapMode(): WrapMode { + if (!this._wrapMode) this._wrapMode = WrapMode.Default; + return this._wrapMode; + } + + public set wrapMode(value: WrapMode) { + this._wrapMode = value; + } + + public parser(jsonData: any) { + this.objAnimClip = {}; + + let clip = jsonData['AnimationClip']; + + let { m_Name, m_AnimationClipSettings, m_WrapMode, m_SampleRate } = clip; + + this.name = m_Name; + this._wrapMode = m_WrapMode; + this._sampleRate = m_SampleRate; + this._loopTime = m_AnimationClipSettings.m_LoopTime; + // this._startTime = m_AnimationClipSettings.m_StartTime; + // this._stopTime = m_AnimationClipSettings.m_StopTime; + + // this.totalTime = this._stopTime - this._startTime; + + for (const key in clip.m_EditorCurves) { + if (Object.prototype.hasOwnProperty.call(clip.m_EditorCurves, key)) { + const curve = clip.m_EditorCurves[key]; + let attribute = curve.attribute; + + let attributeAnimCurve = new AttributeAnimCurve(); + attributeAnimCurve.unSerialized(curve); + this.totalTime = Math.max(this.totalTime, attributeAnimCurve.totalTime); + let objClip = this.objAnimClip[curve.path]; + if (!objClip) { + objClip = new ObjectAnimClip(); + this.objAnimClip[curve.path] = objClip; + } + objClip.curve[attribute] = attributeAnimCurve; + } + } + } +} diff --git a/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimation.ts b/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimation.ts new file mode 100644 index 00000000..3699124f --- /dev/null +++ b/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimation.ts @@ -0,0 +1,193 @@ +import { Object3D } from '../../../core/entities/Object3D'; +import { Time } from '../../../util/Time'; +import { ComponentBase } from '../../ComponentBase'; +import { AnimationMonitor } from './AnimationMonitor'; +import { AnimatorEventKeyframe, PropertyAnimationEvent } from './PropertyAnimationEvent'; +import { PropertyAnimClip } from './PropertyAnimClip'; +/** + * Attribute Animation Component + * @group Animation + */ +export class PropertyAnimation extends ComponentBase { + private _animator: AnimationMonitor; + private _clips: PropertyAnimClip[] = []; + /** + * name of default animation clip + */ + public defaultClip: string; + /** + * is it play auto + */ + public autoPlay: boolean; + + private _seekEvent: PropertyAnimationEvent; + private _completeEvent: PropertyAnimationEvent; + private _keyFrameList: { [key: string]: AnimatorEventKeyframe[] }; + + constructor() { + super(); + this._seekEvent = new PropertyAnimationEvent(this, PropertyAnimationEvent.SEEK); + this._completeEvent = new PropertyAnimationEvent(this, PropertyAnimationEvent.COMPLETE); + this._keyFrameList = {}; + } + + /** + * register a event to animator + * @param frame source AnimatorEventKeyframe + */ + public registerEventKeyFrame(frame: AnimatorEventKeyframe) { + let list = this._keyFrameList[frame.clipName]; + if (list == null) { + this._keyFrameList[frame.clipName] = list = []; + } + list.push(frame); + } + + /** + * @internal + */ + init() { + this._animator = new AnimationMonitor(this); + + } + /** + * @internal + */ + onUpdate() { + if (this.enable) { + this._animator && this._animator.update(Time.time, Time.delta); + } + } + + /** + * append a perperty animation clip + * @param clip source PropertyAnimClip + */ + public appendClip(clip: PropertyAnimClip) { + this._clips.push(clip); + this._animator.addClip(clip); + } + + private statusCall(tag: number, last: number, now: number): void { + if (tag == AnimationMonitor.Complete) { + this.eventDispatcher.dispatchEvent(this._completeEvent); + } else if (tag == AnimationMonitor.Seek) { + if (last != now) { + let frames = this._keyFrameList[this.currentClip.name]; + if (frames) { + for (let frame of frames) { + if (frame.time > last && frame.time <= now) { + this._seekEvent.data = this._seekEvent.frame = frame; + this.eventDispatcher.dispatchEvent(this._seekEvent); + } + } + } + } + } + } + + /** + * set playing speed + */ + public set speed(value: number) { + this._animator.speed = value; + } + + /** + * get playing speed + */ + public get speed(): number { + return this._animator.speed; + } + + /** + * stop playing + */ + public stop(): void { + this._animator && this._animator.stop(); + } + + /** + * stop or resume playing + */ + public toggle(): void { + this._animator && this._animator.toggle(); + } + + /** + * get animation clip by clip name + * @param clip name of PropertyAnimClip + * @returns + */ + public getClip(clip: string): PropertyAnimClip { + if (this._animator) { + return this._animator.getClip(clip); + } + return null; + } + + /** + * get animation clip which is playing now + */ + public get currentClip(): PropertyAnimClip { + if (this._animator) { + return this._animator.currentClip; + } + return null; + } + + /** + * get time of current animator + */ + public get time(): number { + return this._animator.time; + } + + /** + * seek the animation to assign time + * @param time assign time + */ + public seek(time: number) { + if (this._animator) { + this._animator.seek(time); + } + } + + /** + * play animation by given name + * @param clip animation name + * @param reset if true, play the animation from time 0 + * @returns + */ + public play(clip: string, reset: boolean = true): PropertyAnimClip { + if (this._animator) { + return this._animator.play(clip, reset); + } + return null; + } + + /** + * @internal + * + */ + public start() { + super.start(); + if (this.autoPlay) { + this.play(this.defaultClip); + } + } + + /** + * Create a new PropertyAnimation component, copy the properties of the current component, + * and add them to the target object. + * @param obj target object3D + */ + public cloneTo(obj: Object3D) { + let animator = obj.addComponent(PropertyAnimation); + animator.autoPlay = this.autoPlay; + animator.defaultClip = this.defaultClip; + for (let i: number = 0, count = this._clips.length; i < count; i++) { + animator.appendClip(this._clips[i]); + } + } +} diff --git a/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts b/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts new file mode 100644 index 00000000..672fb87a --- /dev/null +++ b/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts @@ -0,0 +1,27 @@ +import { CEvent } from '../../../event/CEvent'; +import { PropertyAnimation } from './PropertyAnimation'; +/** + * @internal + * @group Animation + */ +export class AnimatorEventKeyframe { + public clipName: string; + public data: any; + public time: number; +} +/** + * @internal + * @group Animation + */ +export class PropertyAnimationEvent extends CEvent { + public static SEEK: string = 'SEEK'; + public static COMPLETE: string = 'COMPLETE'; + + public animation: PropertyAnimation; + public frame: AnimatorEventKeyframe; + + constructor(animation: PropertyAnimation, name: string) { + super(name); + this.animation = animation; + } +} diff --git a/src/engine/components/anim/curveAnim/curveAnim/PropertyHelp.ts b/src/engine/components/anim/curveAnim/curveAnim/PropertyHelp.ts new file mode 100644 index 00000000..68ecc1ef --- /dev/null +++ b/src/engine/components/anim/curveAnim/curveAnim/PropertyHelp.ts @@ -0,0 +1,114 @@ +/** + * @internal + * @group Animation + */ +export class PropertyHelp { + static property: any = { + 'm_LocalPosition.x': 'localPosition.x', + 'm_LocalPosition.y': 'localPosition.y', + 'm_LocalPosition.z': 'localPosition.z', + + 'm_LocalRotation.x': 'localQuaternion.x', + 'm_LocalRotation.y': 'localQuaternion.y', + 'm_LocalRotation.z': 'localQuaternion.z', + 'm_LocalRotation.w': 'localQuaternion.w', + + 'localEulerAnglesRaw.x': 'localRotation.x', + 'localEulerAnglesRaw.y': 'localRotation.y', + 'localEulerAnglesRaw.z': 'localRotation.z', + + 'm_LocalEulerAngles.x': 'localRotation.x', + 'm_LocalEulerAngles.y': 'localRotation.y', + 'm_LocalEulerAngles.z': 'localRotation.z', + + 'm_LocalScale.x': 'localScale.x', + 'm_LocalScale.y': 'localScale.y', + 'm_LocalScale.z': 'localScale.z', + + 'm_Color.r': 'r', + 'm_Color.g': 'g', + 'm_Color.b': 'b', + 'm_Color.a': 'alpha', + + 'field of view': 'camera3D.fov', + + m_IsActive: 'visible', + m_Sprite: 'texture', + + m_FlipX: 'flipX', + m_FlipY: 'flipY', + }; + + static property_quaternion: any = { + 'm_LocalRotation.x': true, + 'm_LocalRotation.y': true, + 'm_LocalRotation.z': true, + 'm_LocalRotation.w': true, + }; + + static property_scale: any = { + 'm_LocalPosition.x': -1, + 'm_LocalPosition.y': 1, + 'm_LocalPosition.z': 1, + + 'localEulerAnglesRaw.x': -1, //Deg2Rad(1), + 'localEulerAnglesRaw.y': 1, //Deg2Rad(1), + 'localEulerAnglesRaw.z': 1, //Deg2Rad(1), + + 'm_LocalEulerAngles.x': -1, //Deg2Rad(1), + 'm_LocalEulerAngles.y': 1, //Deg2Rad(1), + 'm_LocalEulerAngles.z': 1, //Deg2Rad(1), + + 'm_LocalRotation.x': -1, //Rad2Deg(1), + 'm_LocalRotation.y': 1, //Rad2Deg(1), + 'm_LocalRotation.z': 1, //Rad2Deg(1), + 'm_LocalRotation.w': -1, //Rad2Deg(1), + + 'm_LocalScale.x': 1, + 'm_LocalScale.y': 1, + 'm_LocalScale.z': 1, + + 'm_Color.r': 1, + 'm_Color.g': 1, + 'm_Color.b': 1, + 'm_Color.a': 1, + + 'field of view': 1, + + m_IsActive: 1, + m_Sprite: 1, + }; + + static property_offset: any = { + 'm_LocalPosition.x': 0, + 'm_LocalPosition.y': 0, + 'm_LocalPosition.z': 0, + + 'localEulerAnglesRaw.x': 0, //Deg2Rad(0), + 'localEulerAnglesRaw.y': 0, //Deg2Rad(0), + 'localEulerAnglesRaw.z': 0, //Deg2Rad(0), + + 'm_LocalEulerAngles.x': 0, //Deg2Rad(0), + 'm_LocalEulerAngles.y': 0, //Deg2Rad(0), + 'm_LocalEulerAngles.z': 0, //Deg2Rad(0), + + 'm_LocalRotation.x': 0, + 'm_LocalRotation.y': 0, + 'm_LocalRotation.z': 0, + 'm_LocalRotation.w': 0, + + 'm_LocalScale.x': 0, + 'm_LocalScale.y': 0, + 'm_LocalScale.z': 0, + + 'field of view': 0, + + 'm_Color.r': 0, + 'm_Color.g': 0, + 'm_Color.b': 0, + 'm_Color.a': 0, + + m_IsActive: 0, + m_Sprite: 0, + }; +} From 3961fc9d5e863d9fd20fc140ffa3cd0c01a8308e Mon Sep 17 00:00:00 2001 From: hellmor Date: Mon, 24 Apr 2023 15:15:05 +0800 Subject: [PATCH 040/100] feats(morph): Add morph files (#33) Add morph animation feature into engine. --- src/engine/components/anim/OAnimationEvent.ts | 19 ++ .../anim/morphAnim/MorphTargetBlender.ts | 98 ++++++++ .../anim/morphAnim/MorphTargetData.ts | 226 ++++++++++++++++++ .../anim/morphAnim/MorphTargetFrame.ts | 64 +++++ .../anim/morphAnim/MorphTargetKey.ts | 54 +++++ .../anim/morphAnim/MorphTarget_shader.ts | 111 +++++++++ 6 files changed, 572 insertions(+) create mode 100644 src/engine/components/anim/OAnimationEvent.ts create mode 100644 src/engine/components/anim/morphAnim/MorphTargetBlender.ts create mode 100644 src/engine/components/anim/morphAnim/MorphTargetData.ts create mode 100644 src/engine/components/anim/morphAnim/MorphTargetFrame.ts create mode 100644 src/engine/components/anim/morphAnim/MorphTargetKey.ts create mode 100644 src/engine/components/anim/morphAnim/MorphTarget_shader.ts diff --git a/src/engine/components/anim/OAnimationEvent.ts b/src/engine/components/anim/OAnimationEvent.ts new file mode 100644 index 00000000..3b2108fe --- /dev/null +++ b/src/engine/components/anim/OAnimationEvent.ts @@ -0,0 +1,19 @@ +import { CEvent } from "../../event/CEvent"; +import { SkeletonAnimationComponent } from "../SkeletonAnimationComponent"; + +/** + * Skeleton animation event + * @group Animation + */ +export class OAnimationEvent extends CEvent { + /** + * owner skeleton animation component + */ + public skeletonAnimation: SkeletonAnimationComponent; + + constructor(name: string, time: number) { + super(); + this.type = name; + this.time = time; + } +} diff --git a/src/engine/components/anim/morphAnim/MorphTargetBlender.ts b/src/engine/components/anim/morphAnim/MorphTargetBlender.ts new file mode 100644 index 00000000..96d58a6d --- /dev/null +++ b/src/engine/components/anim/morphAnim/MorphTargetBlender.ts @@ -0,0 +1,98 @@ +import { MorphTargetMapper } from "./MorphTargetKey"; +import { Object3D } from "../../../core/entities/Object3D"; +import { RendererMask, RendererMaskUtil } from "../../../gfx/renderJob/passRenderer/state/RendererMask"; +import { Matrix4 } from "../../../math/Matrix4"; +import { Quaternion } from "../../../math/Quaternion"; +import { Vector3 } from "../../../math/Vector3"; +import { ComponentBase } from "../../ComponentBase"; +import { MorphTargetFrame } from "./MorphTargetFrame"; +import { MeshRenderer } from "../../renderer/MeshRenderer"; + +export class MorphTargetBlender extends ComponentBase { + private _targetRenderers: { [key: string]: MeshRenderer[] } = {}; + private _vec3 = new Vector3(); + private _matrix4: Matrix4 = new Matrix4(); + private _quaternion: Quaternion = new Quaternion(); + + protected init(param?: any): void { + let meshRenders: MeshRenderer[] = this.fetchMorphRenderers(this.object3D); + for (const renderer of meshRenders) { + let hasMorphTarget = RendererMaskUtil.hasMask(renderer.rendererMask, RendererMask.MorphTarget); + if (hasMorphTarget) { + renderer.selfCloneMaterials('MORPH_TARGET_UUID'); + } + for (const key in renderer.geometry.morphTargetDictionary) { + let renderList = this._targetRenderers[key] || []; + renderList.push(renderer); + this._targetRenderers[key] = renderList; + } + } + + } + + public getMorphRenderersByKey(key: string): MeshRenderer[] { + return this._targetRenderers[key]; + } + + public cloneMorphRenderers(): { [key: string]: MeshRenderer[] } { + let dst = {} as any; + for (let key in this._targetRenderers) { + dst[key] = this._targetRenderers[key]; + } + return dst; + } + + + /** + * Inject arkit data into the model and let all meshRender below the node accept morph animation + * @param frame: BlendShape data output from ARKit. + * @param keyMapper: Table mapping the relationship between the model's modelKey and ARKit's output arkitKey: {modelKey: arkitKey}. + * @param multiplier: Scaling factor for movement data. + * @returns + */ + public applyBlendShape(frame: MorphTargetFrame, keyMapper: MorphTargetMapper, multiplier: number = 1): void { + if (!frame) { + console.warn('blendShape is null'); + return; + } + //transform + this._vec3.setFromArray(frame.transform.transform[3]); + this._vec3.multiplyScalar(multiplier); + this.object3D.transform.localPosition = this._vec3; + //rotation + this._vec3.setFromArray(frame.transform.transform[2]); + this._matrix4.copyColFrom(2, this._vec3); + this._vec3.setFromArray(frame.transform.transform[1]); + this._matrix4.copyColFrom(1, this._vec3); + this._vec3.setFromArray(frame.transform.transform[0]); + this._matrix4.copyColFrom(0, this._vec3); + + this._matrix4.transpose(); + this._quaternion.fromMatrix(this._matrix4); + this.object3D.localQuaternion = this._quaternion; + //morph + for (let keyInModel in keyMapper) { + let renderList = this._targetRenderers[keyInModel]; + let stdKey = keyMapper[keyInModel]; + let influence = frame.texture[stdKey]; + this.applyMorphTargetInfluence(keyInModel, influence, renderList); + } + } + + private applyMorphTargetInfluence(key: string, influence: number, rendererList: MeshRenderer[]): void { + for (let renderer of rendererList) { + renderer.setMorphInfluence(key, influence); + } + } + + private fetchMorphRenderers(obj: Object3D): MeshRenderer[] { + let sourceRenders: MeshRenderer[] = obj.getComponentsInChild(MeshRenderer); + let result: MeshRenderer[] = []; + for (let renderer of sourceRenders) { + if (renderer.hasMask(RendererMask.MorphTarget)) { + result.push(renderer); + } + } + return result; + } +} \ No newline at end of file diff --git a/src/engine/components/anim/morphAnim/MorphTargetData.ts b/src/engine/components/anim/morphAnim/MorphTargetData.ts new file mode 100644 index 00000000..afc0521d --- /dev/null +++ b/src/engine/components/anim/morphAnim/MorphTargetData.ts @@ -0,0 +1,226 @@ +import { StorageGPUBuffer } from '../../../gfx/graphics/webGpu/core/buffer/StorageGPUBuffer'; +import { UniformGPUBuffer } from '../../../gfx/graphics/webGpu/core/buffer/UniformGPUBuffer'; +import { MorphTarget_shader } from '../../../components/anim/morphAnim/MorphTarget_shader'; +import { ComputeShader } from '../../../gfx/graphics/webGpu/shader/ComputeShader'; +import { GPUContext } from '../../../gfx/renderJob/GPUContext'; +import { RenderShader } from '../../../gfx/graphics/webGpu/shader/RenderShader'; +import { VertexAttributeData, GeometryBase } from '../../../..'; + +type MorphTargetCollectData = { + mtCount: number; + vCount: number; + mergedPos: Float32Array; + mergedNormal: Float32Array; +} + +class MorphAttrDataGroup { + source: Float32Array; + input: StorageGPUBuffer; + output: StorageGPUBuffer; + + reset(value: Float32Array): void { + this.input && this.input.destroy(); + this.output && this.output.destroy(); + this.input = this.output = null; + this.source = value; + } + + public apply(vertexCount: number): void { + if (this.source) { + if (!this.input) { + let usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST; + this.input = new StorageGPUBuffer(this.source.length, usage, this.source); + this.input.apply(); + } + + if (!this.output) { + let usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC; + this.output = new StorageGPUBuffer(vertexCount * 3, usage); + this.output.apply(); + } + } + + } +} + +export class MorphTargetData { + public enable: boolean; + public morphTargetsRelative: boolean; + public readonly MaxMorphTargetCount: number = 64; + + protected _computeConfigArray: Float32Array; + protected _computeConfigBuffer: UniformGPUBuffer; + protected _morphInfluenceArray: Float32Array; + protected _morphInfluenceBuffer: StorageGPUBuffer; + protected _positionAttrDataGroup: MorphAttrDataGroup; + protected _normalAttrDataGroup: MorphAttrDataGroup; + + private _isInfluenceDirty: boolean; + + protected _morphTargetCount: number; + protected _totalVertexCount: number; + + protected _computeShader: ComputeShader; + protected _computeShaders: ComputeShader[]; + protected _computeWorkGroupXY: number = 1; + + protected _collectMorphTargetData: MorphTargetCollectData; + + constructor() { + this._isInfluenceDirty = true; + this.generateGPUBuffer(); + this._positionAttrDataGroup = new MorphAttrDataGroup(); + this._normalAttrDataGroup = new MorphAttrDataGroup(); + } + + public initMorphTarget(geometry: GeometryBase): void { + this._collectMorphTargetData = this.collectMorphTargetList(geometry); + + this._computeShader && this._computeShader.destroy(); + let code = MorphTarget_shader.CsMain; + this._computeShader = new ComputeShader(code); + if (this._collectMorphTargetData.mergedNormal) { + this._computeShader.setDefine('USE_MORPHNORMALS', true); + } else { + this._computeShader.deleteDefine('USE_MORPHNORMALS'); + } + this._computeShaders = [this._computeShader]; + + this._isInfluenceDirty = true; + this._morphTargetCount = this._collectMorphTargetData.mtCount; + this._totalVertexCount = this._collectMorphTargetData.vCount; + this._morphInfluenceArray.fill(0); + this._computeWorkGroupXY = this.calcWorkGroup(this._totalVertexCount); + // + this._positionAttrDataGroup.reset(this._collectMorphTargetData.mergedPos); + this._normalAttrDataGroup.reset(this._collectMorphTargetData.mergedNormal); + } + + public applyRenderShader(renderShader: RenderShader) { + this.uploadMorphTargetBuffer(); + this.uploadConfigGBuffer(); + // + renderShader.setUniformBuffer('morphTargetConfig', this._computeConfigBuffer); + renderShader.setStorageBuffer('morphTargetOpPositions', this._positionAttrDataGroup.output); + + if (this._collectMorphTargetData.mergedNormal) { + renderShader.setStorageBuffer('morphTargetOpNormals', this._normalAttrDataGroup.output); + } + } + + public computeMorphTarget(command: GPUCommandEncoder): void { + this.uploadConfigGBuffer(); + this.uploadMorphTargetBuffer(); + + this._computeShader.setUniformBuffer('morphTargetConfig', this._computeConfigBuffer); + this._computeShader.setStorageBuffer('morphTargetInfluence', this._morphInfluenceBuffer); + this._computeShader.setStorageBuffer('morphTargetPositions', this._positionAttrDataGroup.input); + this._computeShader.setStorageBuffer('morphTargetOpPositions', this._positionAttrDataGroup.output); + if (this._collectMorphTargetData.mergedNormal) { + this._computeShader.setStorageBuffer('morphTargetNormals', this._normalAttrDataGroup.input); + this._computeShader.setStorageBuffer('morphTargetOpNormals', this._normalAttrDataGroup.output); + } + this._computeShader.workerSizeX = this._computeWorkGroupXY; + this._computeShader.workerSizeY = this._computeWorkGroupXY; + this._computeShader.workerSizeZ = 1; + + GPUContext.computeCommand(command, this._computeShaders); + } + + public updateInfluence(index: number, value: number) { + this._isInfluenceDirty = true; + this._morphInfluenceArray[index] = value; + } + + private collectMorphTargetList(geometry: GeometryBase): MorphTargetCollectData { + let posAttrList = this.collectAttribute('a_morphPositions_', geometry); + let morphTargetCount = posAttrList.length; + let vertexCount: number = posAttrList[0].data.length / 3; + + //position + let posArray: Float32Array = new Float32Array(vertexCount * morphTargetCount * 3); + { + let offset: number = 0; + for (let i = 0; i < morphTargetCount; i++) { + let item = posAttrList[i]; + posArray.set(item.data, offset); + offset += item.data.length; + } + } + + //normal + let normalAttrList = this.collectAttribute('a_morphNormals_', geometry); + let normalArray: Float32Array; + if (normalAttrList && normalAttrList.length > 0) { + let offset: number = 0; + normalArray = new Float32Array(vertexCount * morphTargetCount * 3); + for (let i = 0; i < morphTargetCount; i++) { + let item = normalAttrList[i]; + normalArray.set(item.data, offset); + offset += item.data.length; + } + } + + return { mtCount: morphTargetCount, vCount: vertexCount, mergedPos: posArray, mergedNormal: normalArray }; + } + + private collectAttribute(attrKey: string, geometry: GeometryBase): VertexAttributeData[] { + let list = []; + for (let i = 0; i < this.MaxMorphTargetCount; i++) { + let morphKey = attrKey + i; + let item = geometry.getAttribute(morphKey); + if (!item) break; + else list[i] = item; + + } + return list; + } + + private uploadConfigGBuffer(): void { + if (this._isInfluenceDirty) { + let sumInfluence = 0; + for (let i = 0; i < this._morphTargetCount; i++) { + sumInfluence += this._morphInfluenceArray[i]; + } + this._morphInfluenceBuffer.setFloat32Array('data', this._morphInfluenceArray); + this._morphInfluenceBuffer.apply(); + // sumInfluence = Math.max(sumInfluence, 0); + // sumInfluence = Math.min(sumInfluence, 1); + this._computeConfigArray[0] = this.morphTargetsRelative ? 1 : 1 - sumInfluence; + this._computeConfigArray[1] = this._morphTargetCount; + this._computeConfigArray[2] = this._totalVertexCount; + this._computeConfigArray[3] = this._computeWorkGroupXY; + this._computeConfigBuffer.setFloat32Array('data', this._computeConfigArray); + this._computeConfigBuffer.apply(); + this._isInfluenceDirty = false; + } + } + + private calcWorkGroup(count: number): number { + let groupXY = Math.ceil(Math.sqrt(count)); + let log2 = Math.ceil(Math.log2(groupXY)); + groupXY = Math.pow(2, log2); + return groupXY; + } + + + protected uploadMorphTargetBuffer(): void { + if (!this._positionAttrDataGroup.output) { + this._positionAttrDataGroup.apply(this._totalVertexCount); + } + if (!this._normalAttrDataGroup.output) { + this._normalAttrDataGroup.apply(this._totalVertexCount); + } + } + + protected generateGPUBuffer() { + //config + this._computeConfigArray = new Float32Array(4); + this._computeConfigBuffer = new UniformGPUBuffer(4); + + //influence array + this._morphInfluenceArray = new Float32Array(this.MaxMorphTargetCount); + let usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST; + this._morphInfluenceBuffer = new StorageGPUBuffer(this.MaxMorphTargetCount, usage); + } +} diff --git a/src/engine/components/anim/morphAnim/MorphTargetFrame.ts b/src/engine/components/anim/morphAnim/MorphTargetFrame.ts new file mode 100644 index 00000000..09701297 --- /dev/null +++ b/src/engine/components/anim/morphAnim/MorphTargetFrame.ts @@ -0,0 +1,64 @@ +class texture { + mouthRollLower: number; + browOuterUp_L: number; + mouthSmile_L: number; + jawRight: number; + eyeLookOut_L: number; + mouthFunnel: number; + mouthUpperUp_R: number; + browDown_L: number; + jawLeft: number; + mouthLowerDown_L: number; + noseSneer_R: number; + jawForward: number; + mouthLowerDown_R: number; + browInnerUp: number; + mouthRollUpper: number; + mouthStretch_R: number; + mouthPucker: number; + eyeBlink_L: number; + mouthUpperUp_L: number; + mouthShrugUpper: number; + eyeLookIn_R: number; + noseSneer_L: number; + mouthFrown_L: number; + cheekSquint_L: number; + eyeLookDown_L: number; + mouthDimple_L: number; + mouthFrown_R: number; + eyeLookIn_L: number; + eyeLookOut_R: number; + mouthLeft: number; + mouthStretch_L: number; + mouthPress_L: number; + mouthDimple_R: number; + eyeWide_R: number; + browDown_R: number; + eyeLookUp_R: number; + eyeBlink_R: number; + cheekSquint_R: number; + mouthRight: number; + eyeLookDown_R: number; + eyeLookUp_L: number; + eyeSquint_L: number; + jawOpen: number; + browOuterUp_R: number; + mouthClose: number; + mouthShrugLower: number; + eyeWide_L: number; + tongueOut: number; + eyeSquint_R: number; + cheekPuff: number; + mouthPress_R: number; + mouthSmile_R: number; +} + +type float3 = [number, number, number]; +type float4 = [number, number, number, number]; +type float4x4 = [float4, float4, float4, float4]; +type transform = { leftEyeTransform: float4x4, lookAtPoint: float3, rightEyeTransform: float4x4, transform: float4x4 }; + +export class MorphTargetFrame { + texture: texture; + transform: transform; +} diff --git a/src/engine/components/anim/morphAnim/MorphTargetKey.ts b/src/engine/components/anim/morphAnim/MorphTargetKey.ts new file mode 100644 index 00000000..25807687 --- /dev/null +++ b/src/engine/components/anim/morphAnim/MorphTargetKey.ts @@ -0,0 +1,54 @@ +export type MorphTargetMapper = { [key: string]: MorphTargetStandardKey }; +export type MorphTargetStandardKey = + 'mouthRollLower' | + 'browOuterUp_L' | + 'mouthSmile_L' | + 'jawRight' | + 'eyeLookOut_L' | + 'mouthFunnel' | + 'mouthUpperUp_R' | + 'browDown_L' | + 'jawLeft' | + 'mouthLowerDown_L' | + 'noseSneer_R' | + 'jawForward' | + 'mouthLowerDown_R' | + 'browInnerUp' | + 'mouthRollUpper' | + 'mouthStretch_R' | + 'mouthPucker' | + 'eyeBlink_L' | + 'mouthUpperUp_L' | + 'mouthShrugUpper' | + 'eyeLookIn_R' | + 'noseSneer_L' | + 'mouthFrown_L' | + 'cheekSquint_L' | + 'eyeLookDown_L' | + 'mouthDimple_L' | + 'mouthFrown_R' | + 'eyeLookIn_L' | + 'eyeLookOut_R' | + 'mouthLeft' | + 'mouthStretch_L' | + 'mouthPress_L' | + 'mouthDimple_R' | + 'eyeWide_R' | + 'browDown_R' | + 'eyeLookUp_R' | + 'eyeBlink_R' | + 'cheekSquint_R' | + 'mouthRight' | + 'eyeLookDown_R' | + 'eyeLookUp_L' | + 'eyeSquint_L' | + 'jawOpen' | + 'browOuterUp_R' | + 'mouthClose' | + 'mouthShrugLower' | + 'eyeWide_L' | + 'tongueOut' | + 'eyeSquint_R' | + 'cheekPuff' | + 'mouthPress_R' | + 'mouthSmile_R'; diff --git a/src/engine/components/anim/morphAnim/MorphTarget_shader.ts b/src/engine/components/anim/morphAnim/MorphTarget_shader.ts new file mode 100644 index 00000000..dc020156 --- /dev/null +++ b/src/engine/components/anim/morphAnim/MorphTarget_shader.ts @@ -0,0 +1,111 @@ +export class MorphTarget_shader { + public static getMorphTargetShaderBinding(group: number, beginBinding: number): string { + return /* wgsl */ ` + fn blendMorphTargetPosition(vertexID:i32, posIn:vec3) -> vec3{ + let offset:i32 = vertexID * 3; + var pos = posIn * morphTargetConfig.morphBaseInfluence; + pos += vec3(morphTargetOpPositions[offset], morphTargetOpPositions[offset + 1], morphTargetOpPositions[offset + 2]); + return pos; + } + + #if USE_MORPHNORMALS + fn blendMorphTargetNormal(vertexID:i32, normalIn:vec3) -> vec3{ + let offset:i32 = vertexID * 3; + var normal = normalIn * morphTargetConfig.morphBaseInfluence; + normal += vec3(morphTargetOpNormals[offset], morphTargetOpNormals[offset + 1], morphTargetOpNormals[offset + 2]); + return normal; + } + #endif + + struct MorphTargetConfigData { + morphBaseInfluence:f32, + morphTargetCount:f32, + totalVertexCount:f32, + computeWorkGroupXY:f32, + }; + + @group(${group}) @binding(${beginBinding}) + var morphTargetConfig: MorphTargetConfigData; + + @group(${group}) @binding(${beginBinding + 1}) + var morphTargetOpPositions: array; + + #if USE_MORPHNORMALS + @group(${group}) @binding(${beginBinding + 2}) + var morphTargetOpNormals: array; + #endif +`; + } + + public static getMorphTargetAttr(beginLocation: number): string { + let value = `@location(${beginLocation}) vIndex: f32,`; + return value; + } + + public static getMorphTargetCalcVertex(): string { + return /* wgsl */ ` + vertexPosition = blendMorphTargetPosition(i32(vertex.vIndex), vertexPosition); + + #if USE_MORPHNORMALS + vertexNormal = blendMorphTargetNormal(i32(vertex.vIndex), vertexNormal); + #endif + `; + } + + public static CsMain: string = /* wgsl */ ` + struct MorphTargetConfigData { + morphBaseInfluence:f32, + morphTargetCount:f32, + totalVertexCount:f32, + computeWorkGroupXY:f32, + }; + + @group(0) @binding(0) var morphTargetConfig: MorphTargetConfigData; + @group(0) @binding(1) var morphTargetInfluence : array; + @group(0) @binding(2) var morphTargetPositions : array; + @group(0) @binding(3) var morphTargetOpPositions : array; + + #if USE_MORPHNORMALS + @group(0) @binding(4) var morphTargetNormals : array; + @group(0) @binding(5) var morphTargetOpNormals : array; + #endif + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain(@builtin(global_invocation_id) globalInvocation_id : vec3) + { + let vertexIndex:i32 = i32(globalInvocation_id.y) * i32(morphTargetConfig.computeWorkGroupXY) + i32(globalInvocation_id.x); + + let morphTargetCount:i32 = i32(morphTargetConfig.morphTargetCount); + let totalVertexCount:i32 = i32(morphTargetConfig.totalVertexCount); + var vertexPosition:vec3 = vec3(0.0); + var vertexNormal:vec3 = vec3(0.0); + if(vertexIndex < totalVertexCount) + { + for(var i:i32 = 0; i < morphTargetCount; i ++){ + let offset:i32 = (i * totalVertexCount + vertexIndex) * 3; + let morphPosition = vec3(morphTargetPositions[offset], morphTargetPositions[offset + 1], morphTargetPositions[offset + 2]); + vertexPosition += morphTargetInfluence[i] * morphPosition; + } + + var writeOffset = vertexIndex * 3; + //op position + morphTargetOpPositions[writeOffset] = vertexPosition.x; + morphTargetOpPositions[writeOffset + 1] = vertexPosition.y; + morphTargetOpPositions[writeOffset + 2] = vertexPosition.z; + + #if USE_MORPHNORMALS + for(var i:i32 = 0; i < morphTargetCount; i ++){ + let offset:i32 = (i * totalVertexCount + vertexIndex) * 3; + let morphNormal = vec3(morphTargetNormals[offset], morphTargetNormals[offset + 1], morphTargetNormals[offset + 2]); + vertexNormal += morphTargetInfluence[i] * morphNormal; + } + + //op normal + morphTargetOpNormals[writeOffset] = vertexNormal.x; + morphTargetOpNormals[writeOffset + 1] = vertexNormal.y; + morphTargetOpNormals[writeOffset + 2] = vertexNormal.z; + #endif + } + } +`; +} From 72c73408d97dc4600472f62147974f4ffbc655bf Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Mon, 24 Apr 2023 15:15:39 +0800 Subject: [PATCH 041/100] feat(GPUBuffer): add GPU Buffer (#54) add UniformGPUBuffer add StructStorageGPUBuffer add StorageGPUBuffer add MaterialDataUniformGPUBuffer --- src/engine/core/geometry/GeometryBase.ts | 180 ++++++++++++++++ .../core/geometry/GeometryIndicesBuffer.ts | 50 +++++ .../core/geometry/GeometryVertexBuffer.ts | 193 ++++++++++++++++++ .../core/geometry/GeometryVertexType.ts | 5 + src/engine/core/geometry/VertexAttribute.ts | 17 ++ .../core/geometry/VertexAttributeData.ts | 6 + .../core/geometry/VertexAttributeName.ts | 19 ++ .../core/geometry/VertexAttributeSize.ts | 15 ++ .../core/geometry/VertexAttributeStride.ts | 17 ++ src/engine/core/geometry/VertexFormat.ts | 5 + .../buffer/MaterialDataUniformGPUBuffer.ts | 72 +++++++ .../webGpu/core/buffer/StorageGPUBuffer.ts | 14 ++ .../core/buffer/StructStorageGPUBuffer.ts | 14 ++ .../webGpu/core/buffer/UniformGPUBuffer.ts | 16 ++ 14 files changed, 623 insertions(+) create mode 100644 src/engine/core/geometry/GeometryBase.ts create mode 100644 src/engine/core/geometry/GeometryIndicesBuffer.ts create mode 100644 src/engine/core/geometry/GeometryVertexBuffer.ts create mode 100644 src/engine/core/geometry/GeometryVertexType.ts create mode 100644 src/engine/core/geometry/VertexAttribute.ts create mode 100644 src/engine/core/geometry/VertexAttributeData.ts create mode 100644 src/engine/core/geometry/VertexAttributeName.ts create mode 100644 src/engine/core/geometry/VertexAttributeSize.ts create mode 100644 src/engine/core/geometry/VertexAttributeStride.ts create mode 100644 src/engine/core/geometry/VertexFormat.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/buffer/StorageGPUBuffer.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/buffer/UniformGPUBuffer.ts diff --git a/src/engine/core/geometry/GeometryBase.ts b/src/engine/core/geometry/GeometryBase.ts new file mode 100644 index 00000000..4c629a81 --- /dev/null +++ b/src/engine/core/geometry/GeometryBase.ts @@ -0,0 +1,180 @@ +import { ArrayBufferData } from "../../gfx/graphics/webGpu/core/buffer/GPUBufferBase"; +import { ShaderReflection } from "../../gfx/graphics/webGpu/shader/value/ShaderReflectionInfo"; +import { Vector3 } from "../../math/Vector3"; +import { UUID } from "../../util/Global"; +import { BoundingBox } from "../bound/BoundingBox"; +import { VertexAttributeName } from "./VertexAttributeName"; +import { GeometryVertexBuffer } from "./GeometryVertexBuffer"; +import { GeometryIndicesBuffer } from "./GeometryIndicesBuffer"; +import { VertexAttributeData } from "../../.."; +import { GeometryVertexType } from "./GeometryVertexType"; + +export type LodLevel = { + indexStart: number; + indexCount: number; + vertexStart: number; + index: number; +} + + +/** + * geometry split more subGeometry descriptor + * @group Geometry + */ +export class SubGeometry { + public lodLevels: LodLevel[]; +} + + +/** + * @group Geometry + */ +export class GeometryBase { + public uuid: string; + public name: string; + public subGeometries: SubGeometry[] = []; + public morphTargetsRelative: boolean; + public morphTargetDictionary: { value: string; key: number }; + public bounds: BoundingBox; + private _attributeMap: Map; + private _attributes: string[]; + private _indicesBuffer: GeometryIndicesBuffer; + private _vertexBuffer: GeometryVertexBuffer; + constructor() { + this.uuid = UUID(); + + this._attributeMap = new Map(); + this._attributes = []; + + this.bounds = new BoundingBox(new Vector3(), new Vector3(1, 1, 1)); + this.bounds.min.x = Number.MAX_VALUE; + this.bounds.min.y = Number.MAX_VALUE; + this.bounds.min.z = Number.MAX_VALUE; + + this.bounds.max.x = -Number.MAX_VALUE; + this.bounds.max.y = -Number.MAX_VALUE; + this.bounds.max.z = -Number.MAX_VALUE; + + this._vertexBuffer = new GeometryVertexBuffer(); + } + + public get indicesBuffer(): GeometryIndicesBuffer { + return this._indicesBuffer; + } + + public get vertexBuffer(): GeometryVertexBuffer { + return this._vertexBuffer; + } + + public get vertexAttributes(): string[] { + return this._attributes; + } + + public get vertexAttributeMap(): Map { + return this._attributeMap; + } + + public get geometryType(): GeometryVertexType { + return this._vertexBuffer.geometryType; + } + public set geometryType(value: GeometryVertexType) { + this._vertexBuffer.geometryType = value; + } + + /** + */ + public updateBounds(min: Vector3, max: Vector3) { + this.bounds.setFromMinMax(min, max); + } + + /** + * add subGeometry form lod level + * @param lodLevels @see LodLevel + */ + public addSubGeometry(...lodLevels: LodLevel[]) { + let sub = new SubGeometry(); + sub.lodLevels = lodLevels; + this.subGeometries.push(sub); + } + + /** + * create geometry by shaderReflection + * @param shaderReflection ShaderReflection + */ + generate(shaderReflection: ShaderReflection) { + this._indicesBuffer.upload(this.getAttribute(VertexAttributeName.indices).data); + this._vertexBuffer.createVertexBuffer(this._attributeMap, shaderReflection); + this._vertexBuffer.updateAttributes(this._attributeMap); + } + + public setIndices(data: ArrayBufferData) { + if (!this._attributeMap.has(VertexAttributeName.indices)) { + let vertexInfo: VertexAttributeData = { + attribute: VertexAttributeName.indices, + data: data, + } + this._attributeMap.set(VertexAttributeName.indices, vertexInfo); + this._indicesBuffer = new GeometryIndicesBuffer(); + this._indicesBuffer.createIndicesBuffer(vertexInfo); + } + } + + public setAttribute(attribute: string, data: ArrayBufferData) { + if (attribute == VertexAttributeName.indices) { + this.setIndices(data); + } else { + let vertexInfo: VertexAttributeData = { + attribute: attribute, + data: data, + } + this._attributeMap.set(attribute, vertexInfo); + this._attributes.push(attribute); + } + } + + public getAttribute(attribute: string): VertexAttributeData { + return this._attributeMap.get(attribute) as VertexAttributeData; + } + + public hasAttribute(attribute: string): boolean { + return this._attributeMap.has(attribute); + } + + public genWireframe(): Vector3[] { + let positionAttribute = this.getAttribute(`position`); + let indexAttribute = this.getAttribute(`indices`); + if (indexAttribute && positionAttribute && indexAttribute.data.length > 0) { + let vertexData = positionAttribute.data; + let lines = []; + for (let i = 0; i < indexAttribute.data.length / 3; i++) { + const i1 = indexAttribute.data[i * 3 + 0]; + const i2 = indexAttribute.data[i * 3 + 1]; + const i3 = indexAttribute.data[i * 3 + 2]; + + let p1 = new Vector3(vertexData[i1 * 3 + 0], vertexData[i1 * 3 + 1], vertexData[i1 * 3 + 2]); + let p2 = new Vector3(vertexData[i2 * 3 + 0], vertexData[i2 * 3 + 1], vertexData[i2 * 3 + 2]); + let p3 = new Vector3(vertexData[i3 * 3 + 0], vertexData[i3 * 3 + 1], vertexData[i3 * 3 + 2]); + + lines.push(p1, p2); + lines.push(p2, p3); + lines.push(p3, p1); + } + return lines; + } + return null; + } + + public compute() { + if (this._indicesBuffer) { + this._indicesBuffer.compute(); + } + + if (this._vertexBuffer) { + this._vertexBuffer.compute(); + } + } + + public isPrimitive(): boolean { + return false;// this.geometrySource != null && this.geometrySource.type != 'none'; + } +} diff --git a/src/engine/core/geometry/GeometryIndicesBuffer.ts b/src/engine/core/geometry/GeometryIndicesBuffer.ts new file mode 100644 index 00000000..50429331 --- /dev/null +++ b/src/engine/core/geometry/GeometryIndicesBuffer.ts @@ -0,0 +1,50 @@ +import { ArrayBufferData } from "../../gfx/graphics/webGpu/core/buffer/GPUBufferBase"; +import { IndicesGPUBuffer } from "../../gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer"; +import { VertexAttributeData } from "./VertexAttributeData"; + + +export class GeometryIndicesBuffer { + public uuid: string = ''; + public name: string; + public indicesGPUBuffer: IndicesGPUBuffer; + public indicesFormat: GPUIndexFormat = `uint16`; + public indicesCount: number = 0; + constructor() { + } + + public createIndicesBuffer(indicesData: VertexAttributeData) { + if (indicesData.data instanceof Uint16Array) { + this.indicesFormat = `uint16`; + } else if (indicesData.data instanceof Uint32Array) { + this.indicesFormat = `uint32`; + } + this.indicesCount = indicesData.data.length; + this.indicesGPUBuffer = new IndicesGPUBuffer(indicesData.data); + } + + public upload(data: ArrayBufferData) { + this.indicesGPUBuffer.indicesNode.setArrayBuffer(0, data as ArrayBuffer); + this.indicesGPUBuffer.apply(); + } + + public compute() { + + } + + /** + * Get indices form geometry data + * Get position attribute form geometry data + * Get normal attribute form geometry data + * Get tangent attribute form geometry data + * Get uv0 attribute form geometry data + * Get uv1 attribute form geometry data + * Get uv2 attribute form geometry data + * + * Change position data to GPUBuffer and apply + * Change normal data to GPUBuffer and apply + * Change tangent data to GPUBuffer and apply + * Change uv0 data to GPUBuffer and apply + * Change uv1 data to GPUBuffer and apply + * Change uv2 data to GPUBuffer and apply + */ +} \ No newline at end of file diff --git a/src/engine/core/geometry/GeometryVertexBuffer.ts b/src/engine/core/geometry/GeometryVertexBuffer.ts new file mode 100644 index 00000000..762514fe --- /dev/null +++ b/src/engine/core/geometry/GeometryVertexBuffer.ts @@ -0,0 +1,193 @@ +import { VertexGPUBuffer } from "../../gfx/graphics/webGpu/core/buffer/VertexGPUBuffer"; +import { ShaderReflection } from "../../gfx/graphics/webGpu/shader/value/ShaderReflectionInfo"; +import { VertexAttributeData } from "./VertexAttributeData"; +import { GeometryVertexType } from "./GeometryVertexType"; +import { VertexBufferLayout, VertexAttribute } from "./VertexAttribute"; +import { VertexAttributeSize } from "./VertexAttributeSize"; + + +export class GeometryVertexBuffer { + public vertexCount: number = 0; + public vertexGPUBuffer: VertexGPUBuffer; + public geometryType: GeometryVertexType = GeometryVertexType.compose; + private _vertexBufferLayouts: VertexBufferLayout[]; + private _attributeSlotLayouts: VertexAttribute[][]; + private _attributeLocation: { [attribute: string]: number }; + + constructor() { + this._vertexBufferLayouts = []; + this._attributeLocation = {}; + this._attributeSlotLayouts = []; + } + + public get vertexBufferLayouts() { + return this._vertexBufferLayouts; + } + + public createVertexBuffer(vertexDataInfos: Map, shaderReflection: ShaderReflection) { + switch (this.geometryType) { + case GeometryVertexType.split: + this.createSplitVertexBuffer(vertexDataInfos, shaderReflection); + break; + case GeometryVertexType.compose: + this.createComposeVertexBuffer(vertexDataInfos, shaderReflection); + break; + } + } + + private createSplitVertexBuffer(vertexDataInfos: Map, shaderReflection: ShaderReflection) { + let vertexOffset = 0; + for (let i = 0; i < shaderReflection.attributes.length; i++) { + const attributeInfo = shaderReflection.attributes[i]; + + if (attributeInfo.name == `index`) continue; + this._attributeLocation[attributeInfo.name] = attributeInfo.location; + + let attributeLayout: VertexAttribute = { + name: attributeInfo.name, + format: attributeInfo.format, + offset: 0, + shaderLocation: attributeInfo.location, + stride: VertexAttributeSize[attributeInfo.format] + } + + this._attributeSlotLayouts[attributeInfo.location] = [attributeLayout]; + + let vertexInfo = vertexDataInfos.get(attributeInfo.name); + if (!vertexInfo) { + vertexInfo = { + attribute: attributeInfo.name, + data: new Float32Array(attributeInfo.size * this.vertexCount) + } + vertexDataInfos.set(attributeInfo.name, vertexInfo); + } + let len = vertexInfo.data.length / attributeLayout.stride; + if (this.vertexCount != 0 && this.vertexCount != len) { + console.error(" vertex count not match attribute count"); + } + this.vertexCount = len; + + + this._vertexBufferLayouts[attributeInfo.location] = { + name: attributeInfo.name, + arrayStride: attributeInfo.size * 4, + stepMode: `vertex`, + attributes: this._attributeSlotLayouts[attributeInfo.location], + offset: vertexOffset * 4, + size: this.vertexCount * attributeInfo.size * 4 + } + + vertexOffset += this.vertexCount * attributeInfo.size; + } + + this.vertexGPUBuffer = new VertexGPUBuffer(vertexOffset); + } + + private createComposeVertexBuffer(vertexDataInfos: Map, shaderReflection: ShaderReflection) { + this._attributeSlotLayouts[0] = []; + + let attributeOffset = 0; + for (let i = 0; i < shaderReflection.attributes.length; i++) { + const attributeInfo = shaderReflection.attributes[i]; + if (attributeInfo.name == `index`) continue; + this._attributeLocation[attributeInfo.name] = attributeInfo.location; + + let attributeLayout: VertexAttribute = { + name: attributeInfo.name, + format: attributeInfo.format, + offset: attributeOffset * 4, + shaderLocation: attributeInfo.location, + stride: VertexAttributeSize[attributeInfo.format] + } + this._attributeSlotLayouts[0][attributeInfo.location] = attributeLayout; + + let vertexInfo = vertexDataInfos.get(attributeInfo.name); + if (!vertexInfo) { + vertexInfo = { + attribute: attributeInfo.name, + data: new Float32Array(attributeInfo.size * this.vertexCount) + } + vertexDataInfos.set(attributeInfo.name, vertexInfo); + } + let len = vertexInfo.data.length / attributeLayout.stride; + if (this.vertexCount != 0 && this.vertexCount != len) { + console.error(" vertex count not match attribute count"); + } + this.vertexCount = len; + + attributeOffset += attributeInfo.size; + } + + this._vertexBufferLayouts[0] = { + name: `composeStruct`, + arrayStride: attributeOffset * 4, + stepMode: `vertex`, + attributes: this._attributeSlotLayouts[0], + offset: 0, + size: this.vertexCount * attributeOffset * 4 + } + + this.vertexGPUBuffer = new VertexGPUBuffer(this.vertexCount * attributeOffset); + } + + public upload(attribute: string, vertexDataInfo: VertexAttributeData) { + switch (this.geometryType) { + case GeometryVertexType.split: + { + let location = this._attributeLocation[attribute]; + let vertexBufferLayout = this._vertexBufferLayouts[location]; + this.vertexGPUBuffer.node.setFloat32Array(vertexBufferLayout.offset / 4, vertexDataInfo.data as Float32Array); + } + break; + case GeometryVertexType.compose: + { + for (let i = 0; i < this.vertexCount; i++) { + const attributeLayout = this._attributeSlotLayouts[0][this._attributeLocation[attribute]]; + for (let k = 0; k < attributeLayout.stride; k++) { + let atData = vertexDataInfo.data[i * attributeLayout.stride + k]; + let index = i * (this._vertexBufferLayouts[0].arrayStride / 4) + (attributeLayout.offset / 4) + k; + this.vertexGPUBuffer.node.setFloat(atData, index); + } + } + } + break; + } + this.vertexGPUBuffer.apply(); + } + + public updateAttributes(vertexDataInfos: Map) { + switch (this.geometryType) { + case GeometryVertexType.split: + { + for (let i = 0; i < this._vertexBufferLayouts.length; i++) { + const vertexBufferLayout = this._vertexBufferLayouts[i]; + let attributeData = vertexDataInfos.get(vertexBufferLayout.name); + this.vertexGPUBuffer.node.setFloat32Array(vertexBufferLayout.offset / 4, attributeData.data as Float32Array); + } + } + break; + case GeometryVertexType.compose: + { + for (let i = 0; i < this.vertexCount; i++) { + this._attributeSlotLayouts.forEach((v) => { + for (let j = 0; j < v.length; j++) { + const attributeLayout = v[j]; + let attributeData = vertexDataInfos.get(attributeLayout.name); + for (let k = 0; k < attributeLayout.stride; k++) { + let atData = attributeData.data[i * attributeLayout.stride + k]; + let index = i * (this._vertexBufferLayouts[0].arrayStride / 4) + (attributeLayout.offset / 4) + k; + this.vertexGPUBuffer.node.setFloat(atData, index); + } + } + }); + } + } + break; + } + this.vertexGPUBuffer.apply(); + } + + public compute() { + + } +} \ No newline at end of file diff --git a/src/engine/core/geometry/GeometryVertexType.ts b/src/engine/core/geometry/GeometryVertexType.ts new file mode 100644 index 00000000..618c36a8 --- /dev/null +++ b/src/engine/core/geometry/GeometryVertexType.ts @@ -0,0 +1,5 @@ + +export enum GeometryVertexType { + split, + compose, +} \ No newline at end of file diff --git a/src/engine/core/geometry/VertexAttribute.ts b/src/engine/core/geometry/VertexAttribute.ts new file mode 100644 index 00000000..36a8e5ab --- /dev/null +++ b/src/engine/core/geometry/VertexAttribute.ts @@ -0,0 +1,17 @@ + +export class VertexBufferLayout implements GPUVertexBufferLayout { + name: string; + offset: number; + size: number; + arrayStride: number; + stepMode?: GPUVertexStepMode; + attributes: Iterable; +} + +export class VertexAttribute implements GPUVertexAttribute { + name: string; + format: GPUVertexFormat; + offset: number; + shaderLocation: number; + stride: number; +} \ No newline at end of file diff --git a/src/engine/core/geometry/VertexAttributeData.ts b/src/engine/core/geometry/VertexAttributeData.ts new file mode 100644 index 00000000..915fe22c --- /dev/null +++ b/src/engine/core/geometry/VertexAttributeData.ts @@ -0,0 +1,6 @@ +import { ArrayBufferData } from "../../.."; + +export type VertexAttributeData = { + attribute: string, + data: ArrayBufferData, +} \ No newline at end of file diff --git a/src/engine/core/geometry/VertexAttributeName.ts b/src/engine/core/geometry/VertexAttributeName.ts new file mode 100644 index 00000000..c4decd61 --- /dev/null +++ b/src/engine/core/geometry/VertexAttributeName.ts @@ -0,0 +1,19 @@ +/** + * @internal + */ +export enum VertexAttributeName { + position = 'position', + normal = 'normal', + uv = 'uv', + TANGENT = 'TANGENT', + TEXCOORD_1 = 'TEXCOORD_1', + TEXCOORD_2 = 'TEXCOORD_2', + color = 'color', + joints0 = 'joints0', + joints1 = 'joints1', + weights0 = 'weights0', + weights1 = 'weights1', + indices = `indices`, + vIndex = 'vIndex', + a_morphPositions_0 = 'a_morphPositions_0', +} diff --git a/src/engine/core/geometry/VertexAttributeSize.ts b/src/engine/core/geometry/VertexAttributeSize.ts new file mode 100644 index 00000000..3a5e90a9 --- /dev/null +++ b/src/engine/core/geometry/VertexAttributeSize.ts @@ -0,0 +1,15 @@ +/** + * @internal + */ +export enum VertexAttributeSize { + 'u32' = 1, + 'f32' = 1, + 'vec2' = 2, + 'vec3' = 3, + 'vec4' = 4, + + 'float32' = 1, + 'float32x2' = 2, + 'float32x3' = 3, + 'float32x4' = 4, +} diff --git a/src/engine/core/geometry/VertexAttributeStride.ts b/src/engine/core/geometry/VertexAttributeStride.ts new file mode 100644 index 00000000..4c01520c --- /dev/null +++ b/src/engine/core/geometry/VertexAttributeStride.ts @@ -0,0 +1,17 @@ +/** + * @internal + */ +export enum VertexAttributeStride { + position = 3, + normal = 3, + TANGENT = 4, + uv = 2, + TEXCOORD_1 = 2, + color = 4, + joints0 = 4, + weights0 = 4, + joints1 = 4, + weights1 = 4, + vIndex = 1, + a_morphPositions_0 = 3, +} diff --git a/src/engine/core/geometry/VertexFormat.ts b/src/engine/core/geometry/VertexFormat.ts new file mode 100644 index 00000000..088e9d01 --- /dev/null +++ b/src/engine/core/geometry/VertexFormat.ts @@ -0,0 +1,5 @@ +import { GPUVertexFormat } from '../../gfx/graphics/webGpu/WebGPUConst'; +/** + * @internal + */ +export let VertexFormat = [null, GPUVertexFormat.float32, GPUVertexFormat.float32x2, GPUVertexFormat.float32x3, GPUVertexFormat.float32x4]; diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts b/src/engine/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts new file mode 100644 index 00000000..216a3b87 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts @@ -0,0 +1,72 @@ +import { ShaderReflectionStructInfo } from '../../../../../..'; +import { MemoryDO } from '../../../../../core/pool/memory/MemoryDO'; +import { webGPUContext } from '../../Context3D'; +import { UniformNode } from '../uniforms/UniformNode'; +import { GPUBufferBase } from './GPUBufferBase'; +/** + * Real time Uniform GPUBuffer used by shaders + * @group GFX + */ +export class MaterialDataUniformGPUBuffer extends GPUBufferBase { + public uniformNodes: UniformNode[] = []; + private _onChange: boolean = true; + constructor() { + super(); + } + + /** + * Initialize bound shader base variables + * The array of variables is automatically mapped through the parameters of the shader reflection + * @param uniformNodes + * @see UniformNode + */ + initDataUniform(uniformNodes: UniformNode[]) { + this.uniformNodes = uniformNodes; + let len = 0; + for (const key in uniformNodes) { + const node = uniformNodes[key]; + if (!node) { + console.error(key, "is empty") + }; + len += node.size * 4; + } + len = Math.floor(len / 256 + 1) * 256; + + this.createBuffer(GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, len / 4); + for (const key in uniformNodes) { + const node = uniformNodes[key]; + if (!node) console.error(key, "is empty"); + + let memoryInfo = this.memory.allocation_node(node.size * 4); + node.memoryInfo = memoryInfo; + node.bindOnChange = () => this.onChange(); + } + } + + private onChange() { + this._onChange = true; + } + + /** + * Reapply and write to buffer + * @returns + */ + public apply() { + if (this.uniformNodes.length == 0) return; + // if (this.uniformNodes.length > 0 && this.uniformNodes[0].type == "IrradianceVolumeData") { + // if (this.uniformNodes[0].data["isVolumeFrameChange"]) { + // this._onChange = true; + // } + // } + if (!this._onChange) return; + + for (const key in this.uniformNodes) { + const node = this.uniformNodes[key]; + node.update(); + } + + super.apply(); + this._onChange = false; + } + +} diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/StorageGPUBuffer.ts b/src/engine/gfx/graphics/webGpu/core/buffer/StorageGPUBuffer.ts new file mode 100644 index 00000000..36b09e42 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/buffer/StorageGPUBuffer.ts @@ -0,0 +1,14 @@ +import { ArrayBufferData, GPUBufferBase } from './GPUBufferBase'; +/** + * The buffer of the storage class + * written in the computer shader or CPU Coder + * usage GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST + * @group GFX + */ +export class StorageGPUBuffer extends GPUBufferBase { + constructor(size: number, usage: number = 0, data?: ArrayBufferData) { + super(); + this.createBuffer(GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | usage, size, data); + // this.createBuffer(GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST, size, data); + } +} diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer.ts b/src/engine/gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer.ts new file mode 100644 index 00000000..b3cff78a --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer.ts @@ -0,0 +1,14 @@ +import { Struct } from '../../../../../util/struct/Struct'; +import { GPUBufferBase } from './GPUBufferBase'; +/** + * Structure storage class buffer, convenient for initializing gpubuffers of structure types + * written in the computer shader or CPU Coder + * usage GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST {@link GPUBufferUsage} + * @group GFX + */ +export class StructStorageGPUBuffer extends GPUBufferBase { + constructor(struct: { new(): T }, count: number, usage: number = 0) { + super(); + this.createBufferByStruct(GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | usage, struct, count); + } +} diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/UniformGPUBuffer.ts b/src/engine/gfx/graphics/webGpu/core/buffer/UniformGPUBuffer.ts new file mode 100644 index 00000000..d2b34fa8 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/buffer/UniformGPUBuffer.ts @@ -0,0 +1,16 @@ +import { GPUBufferBase } from './GPUBufferBase'; +/** + * CPU write, GPU read-only transmission buffer + * Can only be copied and written in the cpu coder + * usage GPUBufferUsage.UNIFORM & GPUBufferUsage.COPY_DST & GPUBufferUsage.COPY_SRC {@link GPUBufferUsage} + * @group GFX + */ +export class UniformGPUBuffer extends GPUBufferBase { + constructor(size: number, data?: Float32Array) { + super(); + this.createBuffer(GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, size, data); + } + + public genUniformNodes() { + } +} From 3f46e1b20ba08b5fd5666ab55eaacc63a4daefc7 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Mon, 24 Apr 2023 15:16:03 +0800 Subject: [PATCH 042/100] feat(geometry): add geometry (#53) add geometry buffer , transform to gpu buffer add geometry used at renderer From 0fdc1e92f334682cb2305861e703754527c23d14 Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Mon, 24 Apr 2023 15:16:30 +0800 Subject: [PATCH 043/100] feat(Graphic3D): add wireframe graphics to draw (#42) add Graphic3D add Graphics3DShape add Graphic3DBatchRenderer add Graphic3DFillRenderer add Graphic3DLineBatchRenderer --- .../graphic/Graphic3DBatchRenderer.ts | 118 +++++ .../graphic/Graphic3DFillRenderer.ts | 11 + .../graphic/Graphic3DFixedRenderPipeline.ts | 203 ++++++++ .../graphic/Graphic3DLineBatchRenderer.ts | 11 + .../passRenderer/graphic/Graphic3DRender.ts | 476 ++++++++++++++++++ .../passRenderer/graphic/GraphicConfig.ts | 3 + .../passRenderer/graphic/Graphics3DShape.ts | 139 +++++ 7 files changed, 961 insertions(+) create mode 100644 src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts create mode 100644 src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts create mode 100644 src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts create mode 100644 src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts create mode 100644 src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DRender.ts create mode 100644 src/engine/gfx/renderJob/passRenderer/graphic/GraphicConfig.ts create mode 100644 src/engine/gfx/renderJob/passRenderer/graphic/Graphics3DShape.ts diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts new file mode 100644 index 00000000..ace71f0c --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts @@ -0,0 +1,118 @@ +import { RenderNode } from "../../../../components/renderer/RenderNode"; +import { BoundingBox } from "../../../../core/bound/BoundingBox"; +import { View3D } from "../../../../core/View3D"; +import { Color } from "../../../../math/Color"; +import { Vector3 } from "../../../../math/Vector3"; +import { ClusterLightingRender } from "../cluster/ClusterLightingRender"; +import { RendererMask } from "../state/RendererMask"; +import { RendererPassState } from "../state/RendererPassState"; +import { RendererType } from "../state/RendererType"; +import { Graphic3DFixedRenderPipeline } from "./Graphic3DFixedRenderPipeline"; +import { GraphicConfig } from "./GraphicConfig"; +import { Graphics3DShape } from "./Graphics3DShape"; + +/** +* @internal +*/ +export class Graphic3DBatchRenderer extends RenderNode { + public shapes: Map; + protected mDirtyData: boolean = false; + protected mMinIndexCount: number; + protected mGPUPrimitiveTopology: GPUPrimitiveTopology; + protected mRenderPipeline: Graphic3DFixedRenderPipeline; + + constructor(minIndexCount: number, topology: GPUPrimitiveTopology) { + super(); + this.alwaysRender = true; + this.mMinIndexCount = minIndexCount; + this.mGPUPrimitiveTopology = topology; + this.shapes = new Map(); + this.addRendererMask(RendererMask.Particle); + } + + public fillShapData(uuid: string, type: string, color: Color, points: Vector3[]) { + this.mDirtyData = true; + var data: Graphics3DShape; + + if (this.shapes.has(uuid)) { + data = this.shapes.get(uuid); + if (data.shapeData.length < GraphicConfig.ShapeVertexSize * points.length) { + data.shapeData = new Float32Array(GraphicConfig.ShapeVertexSize * points.length); + } + } else { + data = new Graphics3DShape(this.transform._worldMatrix.index); + data.type = type; + data.color = color; + data.shapeData = new Float32Array(GraphicConfig.ShapeVertexSize * points.length); + } + + const shapeData = data.shapeData; + const transformIndex = this.transform._worldMatrix.index; + for (let i = 0, index = 0; i < points.length; ++i) { + const point = points[i]; + shapeData[index++] = point.x; + shapeData[index++] = point.y; + shapeData[index++] = point.z; + shapeData[index++] = transformIndex; + shapeData[index++] = color.r; + shapeData[index++] = color.g; + shapeData[index++] = color.b; + shapeData[index++] = color.a; + } + this.shapes.set(uuid, data); + } + + protected init() { + super.init(); + this.castGI = false; + this.castShadow = false; + this.mRenderPipeline = new Graphic3DFixedRenderPipeline(this.mMinIndexCount, this.mGPUPrimitiveTopology); + } + + public removeShape(uuid: string) { + if (this.shapes.has(uuid)) { + this.mDirtyData = true; + this.shapes.delete(uuid); + } + } + + protected initPipeline() { + this.object3D.bound = new BoundingBox(Vector3.ZERO, Vector3.MAX); + this._readyPipeline = true; + } + + public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingRender?: ClusterLightingRender) { + // if(!this.enable || passType != RendererType.COLOR ) return ; + if (this.mDirtyData) { + this.mRenderPipeline.reset(); + this.shapes.forEach((shape, uuid) => { + this.mRenderPipeline.addShapeData(shape); + }); + this.mDirtyData = false; + } + return; + } + + public renderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingRender: ClusterLightingRender, encoder: GPURenderPassEncoder, useBundle: boolean = false) { + // if(!this.enable || passType != RendererType.COLOR ) return ; + this.mRenderPipeline.render(rendererPassState, encoder); + } + + public allocGraphics3DShape(uuid: string, transformIndex: number) { + let shape: Graphics3DShape; + + if (this.shapes.has(uuid)) { + shape = this.shapes.get(uuid); + shape.reset(); + } else { + shape = new Graphics3DShape(transformIndex); + shape.uuid = uuid; + shape.type = 'line'; + shape.color = Color.COLOR_WHITE; + this.shapes.set(shape.uuid, shape); + } + + this.mDirtyData = true; + return shape; + } +} \ No newline at end of file diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts new file mode 100644 index 00000000..6f61a330 --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts @@ -0,0 +1,11 @@ +import { GPUPrimitiveTopology } from "../../../../.."; +import { Graphic3DBatchRenderer } from "./Graphic3DBatchRenderer"; + +/** + * @internal + */ +export class Graphic3DFillRenderer extends Graphic3DBatchRenderer { + constructor() { + super(3, GPUPrimitiveTopology.triangle_list); + } +} diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts new file mode 100644 index 00000000..fbbbb448 --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts @@ -0,0 +1,203 @@ +import { GPUContext, Preprocessor } from "../../../../.."; +import { BlendFactor, BlendMode } from "../../../../materials/BlendMode"; +import { GlobalBindGroupLayout } from "../../../graphics/webGpu/core/bindGroups/GlobalBindGroupLayout"; +import { GPUCullMode, GPUCompareFunction } from "../../../graphics/webGpu/WebGPUConst"; +import { webGPUContext } from "../../../graphics/webGpu/Context3D"; +import { RendererPassState } from "../state/RendererPassState"; +import { Graphics3DShape } from "./Graphics3DShape"; +import Graphic3DShader_vs from "../../../../assets/shader/graphic/Graphic3DShader_vs.wgsl?raw" +import Graphic3DShader_fs from "../../../../assets/shader/graphic/Graphic3DShader_fs.wgsl?raw" + +/** + * @internal + */ +export class Graphic3DFixedRenderPipeline { + + protected mCount: number; + protected mBatchSize: number; + protected mBatchCount: number; + protected mMinIndexCount: number; + protected mOffset: number; + protected mIndexBuffer: GPUBuffer; + protected mDataBuffer: Float32Array; + protected mBatchBuffers: GPUBuffer[]; + protected mVertexShader: GPUShaderModule; + protected mFragmentShader: GPUShaderModule; + protected mRenderPipeline: GPURenderPipeline; + protected mRenderPipelineLayout: GPUPipelineLayout; + protected mVertexBufferLayout: GPUVertexBufferLayout; + protected mGPUPrimitiveTopology: GPUPrimitiveTopology; + + constructor(minIndexCount: number, topology: GPUPrimitiveTopology) { + this.mMinIndexCount = minIndexCount; + this.mGPUPrimitiveTopology = topology; + this.mBatchSize = Math.trunc(65536 / this.mMinIndexCount); + this.init(); + } + + public reset() { + this.mCount = 0; + this.mOffset = 0; + this.mBatchCount = 0; + } + + public addShapeData(shape: Graphics3DShape) { + let data = shape.shapeData; + while (data.length > 0) { + if (this.mOffset >= this.mDataBuffer.length) { + this.flush(); + } + + if (this.mOffset + data.length <= this.mDataBuffer.length) { + this.mDataBuffer.set(data, this.mOffset); + this.mOffset += data.length; + break; + } + + let remainLength = this.mDataBuffer.length - this.mOffset; + this.mDataBuffer.set(data.slice(0, remainLength), this.mOffset); + this.mOffset += remainLength; + data = data.slice(remainLength); + } + } + + protected flush() { + if (this.mOffset > 0) { + let vertexBuffer: GPUBuffer; + if (this.mBatchCount < this.mBatchBuffers.length) { + vertexBuffer = this.mBatchBuffers[this.mBatchCount]; + } else { + vertexBuffer = webGPUContext.device.createBuffer({ + size: this.mDataBuffer.byteLength, + usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, + }) + this.mBatchBuffers.push(vertexBuffer); + } + // console.log(`writeBuffer(${this.mBatchCount}, ${this.mOffset})`); + webGPUContext.device.queue.writeBuffer(vertexBuffer, 0, this.mDataBuffer, 0, this.mOffset); + this.mCount += this.mOffset / 8; + this.mBatchCount++; + this.mOffset = 0; + } + } + + public render(rendererPassState: RendererPassState, encoder: GPURenderPassEncoder) { + const device = webGPUContext.device; + + if (!this.mRenderPipeline) { + let targets = rendererPassState.outAttachments; + if (rendererPassState.outColor != -1) { + let target = targets[rendererPassState.outColor]; + target.blend = BlendFactor.getBlend(BlendMode.NONE); + } + + this.mRenderPipelineLayout = device.createPipelineLayout({ + bindGroupLayouts: [GlobalBindGroupLayout.getGlobalDataBindGroupLayout()], + }); + + let descriptor: GPURenderPipelineDescriptor = { + label: 'Graphic3DFixedRenderPipeline', + layout: this.mRenderPipelineLayout, + vertex: { + module: this.mVertexShader, + entryPoint: 'main', + buffers: [this.mVertexBufferLayout], + }, + fragment: { + module: this.mFragmentShader, + entryPoint: 'main', + targets: targets, + }, + primitive: { + topology: this.mGPUPrimitiveTopology, + cullMode: GPUCullMode.back, + frontFace: 'ccw', + }, + }; + + if (rendererPassState.depthTexture) { + descriptor.depthStencil = { + depthWriteEnabled: true, + depthCompare: GPUCompareFunction.less_equal, + format: rendererPassState.depthTexture.format, + }; + } + + this.mRenderPipeline = GPUContext.createPipeline(descriptor); + } + + this.flush(); + if (this.mBatchCount > 0) { + // console.log(`[${this.mCount} / ${this.mBatchBuffers.length}]`); + encoder.setPipeline(this.mRenderPipeline); + encoder.setIndexBuffer(this.mIndexBuffer, `uint16`); + + let count = this.mCount / this.mMinIndexCount; + for (let i = Math.trunc(count / this.mBatchSize) - 1; i >= 0; i--) { + encoder.setVertexBuffer(0, this.mBatchBuffers[i]); + encoder.drawIndexed(this.mMinIndexCount * this.mBatchSize, 1, 0, 0, 0); + } + + count = count % this.mBatchSize; + if (count != 0) { + encoder.setVertexBuffer(0, this.mBatchBuffers[this.mBatchCount - 1]); + encoder.drawIndexed(this.mMinIndexCount * count, 1, 0, 0, 0); + } + } + } + + protected init() { + const device = webGPUContext.device; + + let indexData = new Uint16Array((Math.trunc(this.mMinIndexCount * this.mBatchSize / 4) + 1) * 4); + for (let i = 0; i < indexData.length; i++) { + indexData[i] = i; + } + this.mIndexBuffer = device.createBuffer({ + size: indexData.byteLength, + usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST, + }); + device.queue.writeBuffer(this.mIndexBuffer, 0, indexData); + + this.mVertexBufferLayout = { + arrayStride: (4 + 4) * 4, + stepMode: 'vertex', + attributes: [ + { shaderLocation: 0, offset: 0, format: 'float32x4' }, + { shaderLocation: 1, offset: 16, format: 'float32x4' }, + ], + }; + + this.mBatchBuffers = []; + this.mDataBuffer = new Float32Array((4 + 4) * indexData.length); + this.mBatchBuffers.push(device.createBuffer({ + size: this.mDataBuffer.byteLength, + usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, + })); + + this.mVertexShader = this.createShaderModule( + 'Graphic3DFixedRenderPipeline.vs', + Preprocessor.parse(Graphic3DShader_vs, {}) + ); + this.mFragmentShader = this.createShaderModule( + 'Graphic3DFixedRenderPipeline.fs', + Preprocessor.parse(Graphic3DShader_fs, {}) + ); + + this.reset(); + } + + protected createShaderModule(label: string, code: string): GPUShaderModule { + let shaderModule = webGPUContext.device.createShaderModule({ + label: label, + code: code, + }); + shaderModule.getCompilationInfo().then((e) => { + if (e.messages.length > 0) { + console.log(code); + console.log(e); + } + }); + return shaderModule; + } +} diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts new file mode 100644 index 00000000..5b9ccc5e --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts @@ -0,0 +1,11 @@ +import { GPUPrimitiveTopology } from "../../../../.."; +import { Graphic3DBatchRenderer } from "./Graphic3DBatchRenderer"; + +/** + * @internal + */ +export class Graphic3DLineBatchRenderer extends Graphic3DBatchRenderer { + constructor() { + super(2, GPUPrimitiveTopology.line_list); + } +} diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DRender.ts b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DRender.ts new file mode 100644 index 00000000..d1751647 --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DRender.ts @@ -0,0 +1,476 @@ +import { GeometryBase } from "../../../../core/geometry/GeometryBase"; +import { Color } from "../../../../math/Color"; +import { Vector3 } from "../../../../math/Vector3"; +import { DEGREES_TO_RADIANS } from "../../../../math/MathUtil"; +import { Transform } from "../../../../components/Transform"; +import { BoundingBox } from "../../../../core/bound/BoundingBox"; +import { Camera3D } from "../../../../core/Camera3D"; +import { CameraType } from "../../../../core/CameraType"; +import { Object3D } from "../../../../core/entities/Object3D"; +import { Object3DUtil } from "../../../../util/Object3DUtil"; +import { Graphics3DShape } from "./Graphics3DShape"; +import { GraphicConfig } from "./GraphicConfig"; +import { Graphic3DFillRenderer } from "./Graphic3DFillRenderer"; +import { Graphic3DLineBatchRenderer } from "./Graphic3DLineBatchRenderer"; + +export class Graphic3D extends Object3D { + + protected mLineRender: Graphic3DLineBatchRenderer; + protected mFillRender: Graphic3DFillRenderer; + + constructor() { + super(); + this.serializeTag = "dont-serialize"; + this.mLineRender = this.addComponent(Graphic3DLineBatchRenderer); + this.mFillRender = this.addComponent(Graphic3DFillRenderer); + } + + /** + * Draw the 3 - dimensional axes + * @param uuid Graphic identification ID + * @param origin original point + * @param size Length of axis + */ + public drawAxis(uuid: string, origin: Vector3 = new Vector3(0, 0, 0), size: number = 10) { + this.createCustomShape(uuid).buildAxis( + origin, size + ); + } + + /** + * Draw a line + * @param uuid Graphic identification ID + * @param points Line path point + * @param color Color + */ + public drawLines(uuid: string, points: Vector3[], colors: Color | Color[] = Color.COLOR_WHITE) { + this.createCustomShape(uuid).buildLines( + points, colors + ); + } + + /** + * drawing curve + * @param uuid Graphic identification ID + * @param points Curve position point + * @param samples Number of Samples + * @param tension Strength of curve + * @param color Color of curve + */ + public drawCurve(uuid: string, points: Vector3[], samples: number = 10, tension: number = 0.5, color: Color = Color.COLOR_WHITE) { + var result: Vector3[] = []; + let u = new Vector3(), v = new Vector3(); + for (let i = 0; i < points.length - 1; ++i) { + result.push(points[i]); + + const p0 = points[Math.max(i - 1, 0)]; + const p1 = points[i]; + const p2 = points[i + 1]; + const p3 = points[Math.min(i + 2, points.length - 1)]; + + // let u = (p2 - p0) * (tension / 3.0) + p1; + p2.subtract(p0, u).multiplyScalar(tension / 3.0).add(p1, u); + // let v = (p1 - p3) * (tension / 3.0) + p2; + p1.subtract(p3, v).multiplyScalar(tension / 3.0).add(p2, v); + + result.push(...this.calculateBezierCurve(p1, u, v, p2, samples)); + } + result.push(points[points.length - 1]); + this.drawLines(uuid, result, color); + } + + protected calculateBezierCurve(p0: Vector3, p1: Vector3, p2: Vector3, p3: Vector3, samples: number): Vector3[] { + var result = new Array(samples); + for (let i = 0; i < samples; ++i) { + let t = (i + 1) / (samples + 1.0); + let _1t = 1 - t; + let v0 = p0.mul(_1t * _1t * _1t); + let v1 = p1.mul(3 * t * _1t * _1t); + let v2 = p2.mul(3 * t * t * _1t); + let v3 = p3.mul(t * t * t); + result[i] = v0.add(v1).add(v2).add(v3); + } + return result; + } + + /** + * Draw a rectangle + * @param uuid Graphic identification ID + * @param origin original point + * @param width Width of rectangle + * @param height Height of rectangle + * @param color The color of the rectangle + */ + public drawRect(uuid: string, origin: Vector3, width: number, height: number, color: Color = Color.COLOR_WHITE) { + this.drawLines(uuid, [ + origin, + new Vector3(origin.x + width, origin.y, origin.z), + new Vector3(origin.x + width, origin.y + height, origin.z), + new Vector3(origin.x, origin.y + height, origin.z), + origin, + ], color); + } + + /** + * Draw a circle + * @param uuid Graphic identification ID + * @param center centre point + * @param radius radius + * @param segments Number of line segments + * @param up Direction of plane + * @param color The color of the circle + */ + public drawCircle(uuid: string, center: Vector3, radius: number, segments: number = 32, up: Vector3 = Vector3.Y_AXIS, color: Color = Color.COLOR_WHITE) { + this.createCustomShape(uuid).buildCircle( + center, radius, segments, up, color + ); + } + + /** + * Draw a Sector + * @param uuid Graphic identification ID + * @param center centre point + * @param radius radius + * @param startAngle Angle of onset + * @param endAngle Angle of end + * @param segments number of segments + * @param up Direction of plane + * @param color The color of the sector + */ + public drawSector(uuid: string, center: Vector3, radius: number, startAngle: number, endAngle: number, segments: number = 16, up: Vector3 = Vector3.Y_AXIS, color: Color = Color.COLOR_WHITE) { + const totalAngle = (endAngle - startAngle) * DEGREES_TO_RADIANS; + startAngle *= DEGREES_TO_RADIANS + var points: Vector3[] = []; + points.push(center); + for (let i = 0; i <= segments; ++i) { + if (i > 0) { + points.push(points[points.length - 1]); + } + var verAngle: number = totalAngle * (i / segments) + startAngle; + var x: number = radius * Math.cos(verAngle); + var y: number = radius * Math.sin(verAngle); + switch (up) { + case Vector3.X_AXIS: + points.push(center.add(new Vector3(0, x, y))); + break; + case Vector3.Y_AXIS: + points.push(center.add(new Vector3(x, 0, y))); + break; + case Vector3.Z_AXIS: + points.push(center.add(new Vector3(x, y, 0))); + break; + default: + points.push(center.add(new Vector3(x, y, 0))); + break; + } + } + points.push(points[points.length - 1]); + points.push(center); + this.mLineRender.fillShapData(uuid, 'line', color, points); + } + + /** + * Draw a ArcLine + * @param uuid Graphic identification ID + * @param center centre point + * @param radius radius + * @param startAngle Angle of onset + * @param endAngle Angle of end + * @param segments number of segments + * @param up Direction of plane + * @param color The color of the sector + */ + public drawArcLine(uuid: string, center: Vector3, radius: number, startAngle: number, endAngle: number, segments: number = 16, up: Vector3 = Vector3.Y_AXIS, color: Color = Color.COLOR_WHITE) { + this.mLineRender.allocGraphics3DShape(uuid, this.transform._worldMatrix.index).buildArcLine( + center, radius, startAngle, endAngle, segments, up, color + ); + } + + /** + * Creates a custom line segment graph and returns a Shape with the same uuid from the pool if it already exists. + * @param uuid Graphic identification ID + * @param parentTransform Parent node Transform + * @returns Graphics3DShape + */ + public createCustomShape(uuid: string, parentTransform: Transform = this.transform): Graphics3DShape { + return this.mLineRender.allocGraphics3DShape(uuid, parentTransform._worldMatrix.index); + } + + /** + * Draw the box + * @param uuid Graphic identification ID + * @param minPoint Point of minimum + * @param maxPoint Point of maximum + * @param color The color of the box + */ + public drawBox(uuid: string, minPoint: Vector3, maxPoint: Vector3, color: Color = Color.COLOR_WHITE) { + var points: Vector3[] = []; + + points.push(minPoint); + points.push(new Vector3(maxPoint.x, minPoint.y, minPoint.z)); + points.push(points[points.length - 1]); + points.push(new Vector3(maxPoint.x, maxPoint.y, minPoint.z)); + points.push(points[points.length - 1]); + points.push(new Vector3(minPoint.x, maxPoint.y, minPoint.z)); + points.push(points[points.length - 1]); + points.push(minPoint); + + points.push(points[points.length - 1]); + points.push(new Vector3(minPoint.x, minPoint.y, maxPoint.z)); + points.push(points[points.length - 1]); + points.push(new Vector3(maxPoint.x, minPoint.y, maxPoint.z)); + points.push(points[points.length - 1]); + points.push(new Vector3(maxPoint.x, maxPoint.y, maxPoint.z)); + points.push(points[points.length - 1]); + points.push(new Vector3(minPoint.x, maxPoint.y, maxPoint.z)); + points.push(points[points.length - 1]); + points.push(new Vector3(minPoint.x, minPoint.y, maxPoint.z)); + + points.push(new Vector3(minPoint.x, maxPoint.y, minPoint.z)); + points.push(new Vector3(minPoint.x, maxPoint.y, maxPoint.z)); + + points.push(new Vector3(maxPoint.x, maxPoint.y, minPoint.z)); + points.push(new Vector3(maxPoint.x, maxPoint.y, maxPoint.z)); + + points.push(new Vector3(maxPoint.x, minPoint.y, minPoint.z)); + points.push(new Vector3(maxPoint.x, minPoint.y, maxPoint.z)); + + this.mLineRender.fillShapData(uuid, 'line', color, points); + } + + /** + * Draw the fill rectangle + * @param uuid Graphic identification ID + * @param minPoint Point of minimum + * @param maxPoint Point of maximum + * @param color The color of the fill rectangle + */ + public drawFillRect(uuid: string, origin: Vector3, width: number, height: number, color: Color = Color.COLOR_WHITE) { + this.mFillRender.fillShapData(uuid, 'fill', color, [ + origin, + new Vector3(origin.x + width, origin.y, origin.z), + new Vector3(origin.x + width, origin.y + height, origin.z), + new Vector3(origin.x + width, origin.y + height, origin.z), + new Vector3(origin.x, origin.y + height, origin.z), + origin + ]); + } + + /** + * Draw the fill circle + * @param uuid Graphic identification ID + * @param center centre point + * @param radius radius + * @param segments number of segments + * @param up Direction of plane + * @param color The color of the fill circle + */ + public drawFillCircle(uuid: string, center: Vector3, radius: number, segments: number = 32, up: Vector3 = Vector3.Y_AXIS, color: Color = Color.COLOR_WHITE) { + var points: Vector3[] = []; + points.push(center); + for (let i = 0; i <= segments; ++i) { + if (i >= 2) { + points.push(center); + points.push(points[points.length - 2]); + } + var verAngle: number = (2 * Math.PI * i) / segments; + var x: number = radius * Math.cos(verAngle); + var y: number = radius * Math.sin(verAngle); + switch (up) { + case Vector3.X_AXIS: + points.push(center.add(new Vector3(0, x, y))); + break; + case Vector3.Y_AXIS: + points.push(center.add(new Vector3(x, 0, y))); + break; + case Vector3.Z_AXIS: + points.push(center.add(new Vector3(x, y, 0))); + break; + default: + points.push(center.add(new Vector3(x, y, 0))); + break; + } + } + this.mFillRender.fillShapData(uuid, 'fill', color, points); + } + + /** + * Draw wire frame for geometry + * @param uuid Graphic identification ID + * @param geometry Geometric object + * @param transform The Transform that needs to be bound + * @param color The color of the wire frame + */ + public drawMeshWireframe(uuid: string, geometry: GeometryBase, transform: Transform, color: Color = Color.COLOR_WHITE) { + if (geometry) this.createCustomShape(uuid, transform ? transform : this.transform).fillShapeData( + geometry.genWireframe(), + color + ); + } + + /** + * Draw the fill sector + * @param uuid Graphic identification ID + * @param center centre point + * @param radius radius + * @param startAngle Angle of onset + * @param endAngle Angle of end + * @param segments number of segments + * @param up Direction of plane + * @param color The color of the fill sector + */ + public drawFillSector(uuid: string, center: Vector3, radius: number, startAngle: number, endAngle: number, segments: number = 16, up: Vector3 = Vector3.Y_AXIS, color: Color = Color.COLOR_WHITE) { + const totalAngle = (endAngle - startAngle) * DEGREES_TO_RADIANS; + startAngle *= DEGREES_TO_RADIANS + var points: Vector3[] = []; + points.push(center); + for (let i = 0; i <= segments; ++i) { + if (i >= 2) { + points.push(center); + points.push(points[points.length - 2]); + } + var verAngle: number = totalAngle * (i / segments) + startAngle; + var x: number = radius * Math.cos(verAngle); + var y: number = radius * Math.sin(verAngle); + switch (up) { + case Vector3.X_AXIS: + points.push(center.add(new Vector3(0, x, y))); + break; + case Vector3.Y_AXIS: + points.push(center.add(new Vector3(x, 0, y))); + break; + case Vector3.Z_AXIS: + points.push(center.add(new Vector3(x, y, 0))); + break; + default: + points.push(center.add(new Vector3(x, y, 0))); + break; + } + } + this.mFillRender.fillShapData(uuid, 'fill', color, points); + } + + /** + * Draw bounding box + * @param uuid Graphic identification ID + * @param boundingBox Bounding box object + * @param color The color of the bounding box + */ + public drawBoundingBox(uuid: string, boundingBox: BoundingBox, color: Color = Color.COLOR_WHITE) { + this.drawBox(uuid, boundingBox.min, boundingBox.max, color); + } + + /** + * Draw the camera cone + * @param camera The camera to display the cone + * @param color The color of the camera cone + */ + public drawCameraFrustum(camera: Camera3D, color: Color = Color.COLOR_WHITE) { + if (camera.type == CameraType.perspective) { + let y = Math.tan(camera.fov / 2 * DEGREES_TO_RADIANS); + let x = y * camera.aspect; + let worldMatrix = camera.transform._worldMatrix; + + let f0 = worldMatrix.transformVector(new Vector3(-x, -y, 1)); + let f1 = worldMatrix.transformVector(new Vector3(-x, y, 1)); + let f2 = worldMatrix.transformVector(new Vector3(x, -y, 1)); + let f3 = worldMatrix.transformVector(new Vector3(x, y, 1)); + + let far = camera.far; + let near = camera.near; + let pos = camera.transform.worldPosition; + + let farLB = new Vector3().copyFrom(f0).multiplyScalar(far).add(pos); + let farLT = new Vector3().copyFrom(f1).multiplyScalar(far).add(pos); + let farRB = new Vector3().copyFrom(f2).multiplyScalar(far).add(pos); + let farRT = new Vector3().copyFrom(f3).multiplyScalar(far).add(pos); + + let nearLB = new Vector3().copyFrom(f0).multiplyScalar(near).add(pos); + let nearLT = new Vector3().copyFrom(f1).multiplyScalar(near).add(pos); + let nearRB = new Vector3().copyFrom(f2).multiplyScalar(near).add(pos); + let nearRT = new Vector3().copyFrom(f3).multiplyScalar(near).add(pos); + + let custom = this.createCustomShape(`CameraFrustum_${camera.object3D.uuid}`); + custom.buildLines([nearLT, farLT], color); + custom.buildLines([nearLB, farLB], color); + custom.buildLines([nearRT, farRT], color); + custom.buildLines([nearRB, farRB], color); + custom.buildLines([farLT, farRT, farRB, farLB, farLT], color); + custom.buildLines([nearLT, nearRT, nearRB, nearLB, nearLT], color); + } else if (camera.type == CameraType.ortho) { + camera.viewPort; + camera.viewPort.height; + let worldMatrix = camera.transform.worldMatrix; + let farLT = worldMatrix.transformVector(new Vector3(camera.viewPort.width * -0.5, camera.viewPort.height * 0.5, camera.far)); + let farLB = worldMatrix.transformVector(new Vector3(camera.viewPort.width * -0.5, camera.viewPort.height * -0.5, camera.far)); + let farRT = worldMatrix.transformVector(new Vector3(camera.viewPort.width * 0.5, camera.viewPort.height * 0.5, camera.far)); + let farRB = worldMatrix.transformVector(new Vector3(camera.viewPort.width * 0.5, camera.viewPort.height * -0.5, camera.far)); + + let nearLT = worldMatrix.transformVector(new Vector3(camera.viewPort.width * -0.5, camera.viewPort.height * 0.5, camera.near)); + let nearLB = worldMatrix.transformVector(new Vector3(camera.viewPort.width * -0.5, camera.viewPort.height * -0.5, camera.near)); + let nearRT = worldMatrix.transformVector(new Vector3(camera.viewPort.width * 0.5, camera.viewPort.height * 0.5, camera.near)); + let nearRB = worldMatrix.transformVector(new Vector3(camera.viewPort.width * 0.5, camera.viewPort.height * -0.5, camera.near)); + + let custom = this.createCustomShape(`CameraFrustum_${camera.object3D.uuid}`); + custom.buildLines([nearLT, farLT], color); + custom.buildLines([nearLB, farLB], color); + custom.buildLines([nearRT, farRT], color); + custom.buildLines([nearRB, farRB], color); + custom.buildLines([farLT, farRT, farRB, farLB, farLT], color); + custom.buildLines([nearLT, nearRT, nearRB, nearLB, nearLT], color); + } + } + + /** + * Draws the bounding box of the object + * @param obj The object to display the bounding box + * @param color The color of the bounding box + */ + public drawObjectBoundingBox(obj: Object3D, color: Color = Color.COLOR_WHITE) { + let boundingBox = Object3DUtil.genMeshBounds(obj); + this.drawBox(`Bounds_${obj.uuid}`, boundingBox.min, boundingBox.max, color); + } + + /** + * Erases the specified graph + * @param uuid Graphic identification ID + */ + public Clear(uuid: string) { + if (this.mLineRender.shapes.has(uuid)) { + this.mLineRender.removeShape(uuid); + } else if (this.mFillRender.shapes.has(uuid)) { + this.mFillRender.removeShape(uuid); + } + } + + /** + * Erase all drawn graphics + */ + public ClearAll() { + this.mLineRender.shapes.clear(); + this.mFillRender.shapes.clear(); + } + + /** + * Changes the specified graphics color + * @param uuid Graphic identification ID + * @param color New color value + */ + public ChangeColor(uuid: string, color: Color) { + var shape: Graphics3DShape; + + if (this.mLineRender.shapes.has(uuid)) { + shape = this.mLineRender.shapes.get(uuid); + } else if (this.mFillRender.shapes.has(uuid)) { + shape = this.mFillRender.shapes.get(uuid); + } else return + + const shapeData = shape.shapeData; + for (let i = 0; i < shapeData.length; i += GraphicConfig.ShapeVertexSize) { + shapeData[i + 4] = color.r; + shapeData[i + 5] = color.g; + shapeData[i + 6] = color.b; + shapeData[i + 7] = color.a; + } + } +} diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/GraphicConfig.ts b/src/engine/gfx/renderJob/passRenderer/graphic/GraphicConfig.ts new file mode 100644 index 00000000..3c8695e3 --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/graphic/GraphicConfig.ts @@ -0,0 +1,3 @@ +export class GraphicConfig { + public static ShapeVertexSize = 8; +} diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphics3DShape.ts b/src/engine/gfx/renderJob/passRenderer/graphic/Graphics3DShape.ts new file mode 100644 index 00000000..49e6497f --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/graphic/Graphics3DShape.ts @@ -0,0 +1,139 @@ +import { Color } from "../../../../math/Color"; +import { DEGREES_TO_RADIANS } from "../../../../math/MathUtil"; +import { Vector3 } from "../../../../math/Vector3"; +import { GraphicConfig } from "./GraphicConfig"; + +/** + * @internal + */ +export class Graphics3DShape { + public uuid: string; + public type: string; + public color: Color; + public count: number = 0; + public shapeData: Float32Array; + public dirtyData: boolean = false; + public memoryDataIndex: number = -1; + protected transformIndex: number; + + constructor(transformIndex: number) { + this.transformIndex = transformIndex; + } + + public buildAxis(origin: Vector3 = new Vector3(0, 0, 0), size: number = 10) { + this.buildLines([origin, new Vector3(origin.x + size, origin.y, origin.z)], Color.hexRGBColor(Color.RED)); + this.buildLines([origin, new Vector3(origin.x, origin.y + size, origin.z)], Color.hexRGBColor(Color.GREEN)); + this.buildLines([origin, new Vector3(origin.x, origin.y, origin.z + size)], Color.hexRGBColor(Color.BLUE)); + } + + public buildLines(points: Vector3[], colors: Color | Color[] = Color.COLOR_WHITE) { + if (points.length < 2) { + return; + } + + if (points.length == 2) { + this.fillShapeData(points, colors); + return; + } + + var linePoints = new Array(points.length + points.length - 2); + for (let i = 1, index = 0; i < points.length; ++i) { + linePoints[index++] = points[i - 1]; + linePoints[index++] = points[i]; + } + this.fillShapeData(linePoints, colors); + } + + public buildArcLine(center: Vector3, radius: number, startAngle: number, endAngle: number, segments: number = 16, up: Vector3 = Vector3.Y_AXIS, color: Color = Color.COLOR_WHITE) { + const totalAngle = (endAngle - startAngle) * DEGREES_TO_RADIANS; + startAngle *= DEGREES_TO_RADIANS + var points: Vector3[] = []; + for (let i = 0; i <= segments; ++i) { + if (i > 1) { + points.push(points[points.length - 1]); + } + var verAngle: number = totalAngle * (i / segments) + startAngle; + var x: number = radius * Math.cos(verAngle); + var y: number = radius * Math.sin(verAngle); + switch (up) { + case Vector3.X_AXIS: + points.push(center.add(new Vector3(0, x, y))); + break; + case Vector3.Y_AXIS: + points.push(center.add(new Vector3(x, 0, y))); + break; + case Vector3.Z_AXIS: + points.push(center.add(new Vector3(x, y, 0))); + break; + default: + points.push(center.add(new Vector3(x, y, 0))); + break; + } + } + this.fillShapeData(points, color); + } + + public buildCircle(center: Vector3, radius: number, segments: number = 32, up: Vector3 = Vector3.Y_AXIS, color: Color = Color.COLOR_WHITE) { + var points: Vector3[] = []; + for (let i = 0; i <= segments; ++i) { + var verAngle: number = (2 * Math.PI * i) / segments; + var x: number = radius * Math.cos(verAngle); + var y: number = radius * Math.sin(verAngle); + switch (up) { + case Vector3.X_AXIS: + points.push(center.add(new Vector3(0, x, y))); + break; + case Vector3.Y_AXIS: + points.push(center.add(new Vector3(x, 0, y))); + break; + case Vector3.Z_AXIS: + points.push(center.add(new Vector3(x, y, 0))); + break; + default: + points.push(center.add(new Vector3(x, y, 0))); + break; + } + if (i > 0) points.push(points[points.length - 1]); + } + points.push(points[0]); + this.fillShapeData(points, color); + } + + public fillShapeData(points: Vector3[], colors: Color | Color[]) { + if (!this.shapeData) { + this.shapeData = new Float32Array(GraphicConfig.ShapeVertexSize * points.length); + } else if (this.count + GraphicConfig.ShapeVertexSize * points.length >= this.shapeData.length) { + let tmp = new Float32Array(this.shapeData.length + GraphicConfig.ShapeVertexSize * points.length); + tmp.set(this.shapeData); + this.shapeData = tmp; + } + + const shapeData = this.shapeData; + for (let i = 0; i < points.length; ++i) { + const point = points[i]; + shapeData[this.count++] = point.x; + shapeData[this.count++] = point.y; + shapeData[this.count++] = point.z; + shapeData[this.count++] = this.transformIndex; + + if (colors instanceof Color) { + shapeData[this.count++] = colors.r; + shapeData[this.count++] = colors.g; + shapeData[this.count++] = colors.b; + shapeData[this.count++] = colors.a; + } else { + const color = colors[i]; + shapeData[this.count++] = color.r; + shapeData[this.count++] = color.g; + shapeData[this.count++] = color.b; + shapeData[this.count++] = color.a; + } + } + + this.dirtyData = true; + } + + public reset() { + this.count = 0; + } +} From 934bbb2e5f3cb3dd3907a7c5694e0262b9148192 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Mon, 24 Apr 2023 15:39:31 +0800 Subject: [PATCH 044/100] feat(audio): add audio components (#59) StaticAudio PositionAudio AudioListener --- src/engine/components/audio/AudioListener.ts | 54 ++++++ src/engine/components/audio/PositionAudio.ts | 181 +++++++++++++++++++ src/engine/components/audio/StaticAudio.ts | 114 ++++++++++++ 3 files changed, 349 insertions(+) create mode 100644 src/engine/components/audio/AudioListener.ts create mode 100644 src/engine/components/audio/PositionAudio.ts create mode 100644 src/engine/components/audio/StaticAudio.ts diff --git a/src/engine/components/audio/AudioListener.ts b/src/engine/components/audio/AudioListener.ts new file mode 100644 index 00000000..ef73fe67 --- /dev/null +++ b/src/engine/components/audio/AudioListener.ts @@ -0,0 +1,54 @@ +import { ComponentBase } from '../ComponentBase'; + +/** + * Audio Listener + * Used in conjunction {@link PositionAudio} or {@link StaticAudio} + * @internal + * @group Audio + */ +export class AudioListener extends ComponentBase { + public readonly context: AudioContext; + public readonly gain: GainNode; + constructor() { + super(); + this.context = new AudioContext(); + this.gain = this.context.createGain(); + this.gain.connect(this.context.destination); + } + protected start() { + + } + protected update() { + if (!this.context) { + return; + } + const listener = this.context.listener; + const _position = this.object3D.transform.worldPosition; + const _orientation = this.object3D.transform.forward; + const up = this.object3D.transform.up; + if (isNaN(_orientation.x)) { + return; + } + if (listener.positionX) { + const endTime = this.context.currentTime; + listener.positionX.linearRampToValueAtTime(_position.x, endTime); + listener.positionY.linearRampToValueAtTime(_position.y, endTime); + listener.positionZ.linearRampToValueAtTime(_position.z, endTime); + listener.forwardX.linearRampToValueAtTime(_orientation.x, endTime); + listener.forwardY.linearRampToValueAtTime(_orientation.y, endTime); + listener.forwardZ.linearRampToValueAtTime(_orientation.z, endTime); + listener.upX.linearRampToValueAtTime(up.x, endTime); + listener.upY.linearRampToValueAtTime(up.y, endTime); + listener.upZ.linearRampToValueAtTime(up.z, endTime); + } else { + listener.setPosition(_position.x, _position.y, _position.z); + listener.setOrientation(_orientation.x, _orientation.y, _orientation.z, up.x, up.y, up.z); + } + } + + destroy() { + this.gain.disconnect(); + this.context.close(); + super.destroy(); + } +} diff --git a/src/engine/components/audio/PositionAudio.ts b/src/engine/components/audio/PositionAudio.ts new file mode 100644 index 00000000..73439adb --- /dev/null +++ b/src/engine/components/audio/PositionAudio.ts @@ -0,0 +1,181 @@ +import { Object3D } from '../../core/entities/Object3D'; +import { UnLitMaterial } from '../../materials/UnLitMaterial'; +import { Color } from '../../math/Color'; +import { Vector3 } from '../../math/Vector3'; +import { BoxGeometry } from '../../shape/BoxGeometry'; +import { MeshRenderer } from '../renderer/MeshRenderer'; +import { AudioListener } from './AudioListener'; +import { StaticAudio } from './StaticAudio'; +/** + * Dynamic audio component, with volume varying based on the relative position of the monitor + * @internal + * @group Audio + */ +export class PositionAudio extends StaticAudio { + public panner: PannerNode; + private _helper: boolean = false; + private _thickness: number = 0.1; + private _step: number = 16; + private _lines: Object3D[] = []; + constructor() { + super(); + } + public setLister(listener: AudioListener): this { + super.setLister(listener); + this.panner = this.context?.createPanner() as PannerNode; + this.panner.panningModel = 'HRTF'; + this.panner.connect(this.gainNode as GainNode); + return this; + } + public showHelper(thickness?: number, step?: number) { + this._helper = true + if (thickness) { + this._thickness = thickness; + } + if (step) { + this._step = step; + } + const innerAngle = this.panner.coneInnerAngle; + const outerAngle = this.panner.coneOuterAngle; + const diffAngle = (outerAngle - innerAngle) / 2; + let refLength = this.panner.refDistance; + let maxLength = this.panner.maxDistance; + let box = new BoxGeometry(1, 1, 1); + + let m1 = new UnLitMaterial(); + m1.baseColor = new Color(1, 0, 0); + let m2 = new UnLitMaterial(); + m2.baseColor = new Color(0, 0, 1); + let m3 = new UnLitMaterial(); + m3.baseColor = new Color(0, 1, 0); + let m4 = new UnLitMaterial(); + m4.baseColor = new Color(1, 1, 0); + for (let i = 0; i < this._step; i++) { + let group = new Object3D(); + let angle = (i * outerAngle) / (this._step - 1); + let isOuterAngle = angle < diffAngle || angle > innerAngle + diffAngle; + { + let line = new Object3D(); + let mr = line.addComponent(MeshRenderer); + mr.geometry = box; + mr.material = isOuterAngle ? m2 : m1; + mr.castShadow = false; + mr.castGI = false; + line.localScale = new Vector3(refLength, this._thickness, this._thickness); + line.x = refLength / 2; + group.addChild(line); + } + { + let line = new Object3D(); + let mr = line.addComponent(MeshRenderer); + mr.geometry = box; + mr.material = isOuterAngle ? m4 : m3; + mr.castShadow = false; + mr.castGI = false; + line.localScale = new Vector3(maxLength, this._thickness / 2, this._thickness / 2); + line.x = maxLength / 2; + group.addChild(line); + } + group.rotationY = -90 + outerAngle / 2 - angle; + this.object3D.addChild(group); + this._lines.push(group); + } + } + public hideHelper() { + this._helper = false; + for (let l of this._lines) { + l.removeAllChild(); + l.removeFromParent(); + l.dispose(); + } + this._lines.length = 0; + } + public toggleHelper() { + if (this._helper) { + this.hideHelper(); + } + else { + this.showHelper(); + } + } + public updateHeler() { + this.hideHelper(); + this.showHelper(); + } + public get refDistance() { + return this.panner.refDistance; + } + public set refDistance(value: number) { + this.panner.refDistance = value; + if (this._helper) { + this.updateHeler(); + } + } + public get rolloffFactor() { + return this.panner.rolloffFactor; + } + public set rolloffFactor(value: number) { + this.panner.rolloffFactor = value; + } + public get distanceModel() { + return this.panner.distanceModel; + } + public set distanceModel(value: DistanceModelType) { + this.panner.distanceModel = value; + } + public get maxDistance() { + return this.panner.maxDistance; + } + public set maxDistance(value: number) { + this.panner.maxDistance = value; + if (this._helper) { + this.updateHeler(); + } + } + + public setDirectionalCone(coneInnerAngle: number, coneOuterAngle: number, coneOuterGain: number) { + this.panner.coneInnerAngle = coneInnerAngle; + this.panner.coneOuterAngle = coneOuterAngle; + this.panner.coneOuterGain = coneOuterGain; + if (this._helper) { + this.updateHeler(); + } + return this; + } + protected connect() { + this.source?.connect(this.panner); + } + public start() { + } + public stop(): this { + return super.stop(); + } + protected onUpdate() { + if (!this.playing) { + return; + } + const panner = this.panner; + const _position = this.object3D.transform.worldPosition; + const _orientation = this.object3D.transform.forward; + if (isNaN(_orientation.x)) { + return; + } + if (panner.positionX && this.context) { + const endTime = this.context.currentTime; + panner.positionX.linearRampToValueAtTime(_position.x, endTime); + panner.positionY.linearRampToValueAtTime(_position.y, endTime); + panner.positionZ.linearRampToValueAtTime(_position.z, endTime); + panner.orientationX.linearRampToValueAtTime(_orientation.x, endTime); + panner.orientationY.linearRampToValueAtTime(_orientation.y, endTime); + panner.orientationZ.linearRampToValueAtTime(_orientation.z, endTime); + } else { + panner.setPosition(_position.x, _position.y, _position.z); + panner.setOrientation(_orientation.x, _orientation.y, _orientation.z); + } + } + public destroy() { + this.panner.disconnect(); + this.hideHelper(); + super.destroy(); + } +} diff --git a/src/engine/components/audio/StaticAudio.ts b/src/engine/components/audio/StaticAudio.ts new file mode 100644 index 00000000..448b9c0a --- /dev/null +++ b/src/engine/components/audio/StaticAudio.ts @@ -0,0 +1,114 @@ +import { ComponentBase } from '../ComponentBase'; +import { AudioListener } from './AudioListener'; +/** + * Static audio component, volume level does not vary depending on the position of the monitor + * @internal + * @group Audio + */ +export class StaticAudio extends ComponentBase { + private listener: AudioListener | null = null; + public context: AudioContext | null = null; + public gainNode: GainNode | null = null; + public source: AudioBufferSourceNode | null = null + private _options = { + loop: true, + volume: 1, + }; + public playing = false; + private _currentTime: number = 0; + private _buffer: AudioBuffer | null = null + constructor() { + super(); + } + public setLister(listener: AudioListener): this { + this.listener = listener; + this.context = listener.context as AudioContext; + this.gainNode = this.context.createGain(); + this.gainNode.connect(this.listener.gain); + + this.context.addEventListener('statechange', () => { + if (this.context?.state === 'closed') { + console.warn('AudioListener removed'); + this.stop(); + this.gainNode?.disconnect(); + this.listener = null; + this.context = null; + this.gainNode = null; + } + }) + return this; + } + async load(url: string, options: {} = {}) { + Object.assign(this._options, options); + let req = await fetch(url); + let buffer = await req.arrayBuffer(); + this._buffer = await this.context?.decodeAudioData(buffer) as AudioBuffer; + } + async loadBuffer(buffer: ArrayBuffer, options: {} = {}) { + Object.assign(this._options, options); + this._buffer = await this.context?.decodeAudioData(buffer) as AudioBuffer; + } + // loadAudio(mediaElement: HTMLAudioElement) { + // this.element = mediaElement; + // this.source = this.context.createMediaElementSource(mediaElement); + // this.connect(); + // } + public play(): this { + if (!this.context) { + console.warn('no audio source yet'); + return this; + } + if (this.playing) { + console.warn('Audio is alredy playing'); + return this; + } + if (!this._buffer) { + console.warn('Audio is not ready'); + return this; + } + const source = this.context.createBufferSource(); + source.buffer = this._buffer; + source.loop = this._options.loop; + this.source = source; + this.connect(); + this.source.start(0, this._currentTime); + this.setVolume(this._options.volume); + this.playing = true; + return this; + } + public pause(): this { + if (!this.playing) { + console.warn('Audio is not playing'); + return this; + } + this._currentTime = this.context?.currentTime || 0; + this.source?.stop(); + this.source?.disconnect(); + this.playing = false; + return this; + } + public stop(): this { + this.pause(); + this._currentTime = 0; + return this; + } + public setVolume(value: number): this { + if (!this.context) { + console.warn('no audio source yet'); + return this; + } + this.gainNode?.gain.setTargetAtTime(value, this.context ? this.context.currentTime : 0, 0.01); + return this; + } + protected connect() { + this.source?.connect(this.gainNode as GainNode); + } + protected onUpdate() { + super.onUpdate(); + } + public destroy() { + this.stop(); + this.gainNode?.disconnect(); + super.destroy(); + } +} From b790f83e6bd19f3dab43a4b705bcaef3373d86a7 Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Mon, 24 Apr 2023 16:08:29 +0800 Subject: [PATCH 045/100] feat(SkeletonAnimation): add skeleton animation component (#55) add SkeletonAnimationComponent add SkeletonAnimationClip add SkeletonAnimationClipState --- .../components/SkeletonAnimationComponent.ts | 373 ++++++++++++++++++ .../components/anim/skeletonAnim/Joint.ts | 48 +++ .../components/anim/skeletonAnim/JointPose.ts | 10 + .../components/anim/skeletonAnim/Skeleton.ts | 44 +++ .../skeletonAnim/SkeletonAnimationClip.ts | 136 +++++++ .../SkeletonAnimationClipState.ts | 116 ++++++ .../skeletonAnim/SkeletonAnimationCompute.ts | 38 ++ .../anim/skeletonAnim/SkeletonPose.ts | 118 ++++++ .../buffer/SkeletonBlendComputeArgs.ts | 115 ++++++ .../buffer/SkeletonTransformComputeArgs.ts | 96 +++++ .../shader/compute_skeleton_blend.ts | 40 ++ .../shader/compute_skeleton_transform.ts | 44 +++ 12 files changed, 1178 insertions(+) create mode 100644 src/engine/components/SkeletonAnimationComponent.ts create mode 100644 src/engine/components/anim/skeletonAnim/Joint.ts create mode 100644 src/engine/components/anim/skeletonAnim/JointPose.ts create mode 100644 src/engine/components/anim/skeletonAnim/Skeleton.ts create mode 100644 src/engine/components/anim/skeletonAnim/SkeletonAnimationClip.ts create mode 100644 src/engine/components/anim/skeletonAnim/SkeletonAnimationClipState.ts create mode 100644 src/engine/components/anim/skeletonAnim/SkeletonAnimationCompute.ts create mode 100644 src/engine/components/anim/skeletonAnim/SkeletonPose.ts create mode 100644 src/engine/components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs.ts create mode 100644 src/engine/components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs.ts create mode 100644 src/engine/components/anim/skeletonAnim/shader/compute_skeleton_blend.ts create mode 100644 src/engine/components/anim/skeletonAnim/shader/compute_skeleton_transform.ts diff --git a/src/engine/components/SkeletonAnimationComponent.ts b/src/engine/components/SkeletonAnimationComponent.ts new file mode 100644 index 00000000..e5403baa --- /dev/null +++ b/src/engine/components/SkeletonAnimationComponent.ts @@ -0,0 +1,373 @@ +import { Object3D } from "../core/entities/Object3D"; +import { StorageGPUBuffer } from "../gfx/graphics/webGpu/core/buffer/StorageGPUBuffer"; +import { Time } from "../util/Time"; +import { ComponentBase } from "./ComponentBase"; +import { Skeleton } from "./anim/skeletonAnim/Skeleton"; +import { SkeletonAnimationClip } from "./anim/skeletonAnim/SkeletonAnimationClip"; +import { SkeletonAnimationClipState } from "./anim/skeletonAnim/SkeletonAnimationClipState"; +import { SkeletonPose } from "./anim/skeletonAnim/SkeletonPose"; + +/** + * skeleton animation + * @group Animation + */ +export class SkeletonAnimationComponent extends ComponentBase { + /** + * Whether it is playing + */ + public isPlaying: boolean = true; + + /** + * Global animation time scaling + */ + public timeScale: number = 1.0; + + protected _skeleton: Skeleton; + protected _clips: SkeletonAnimationClip[] = []; + protected _clipStates: Map = new Map(); + protected _mixSkeletonPose: SkeletonPose; + protected _mixTempSkeletonPose: SkeletonPose; + protected _currentClipState: SkeletonAnimationClipState; + protected _bindList: Array = []; + protected _jointMatrixIndexTableBuffer: StorageGPUBuffer; + protected _crossFadeState: SkeletonAnimationCrossFadeState; + + constructor() { + super(); + } + + protected start() { + + } + + /** + * The name of the currently playing animation + */ + public get currName(): string { + if (this._currentClipState) { + return this._currentClipState.name; + } + return ''; + } + + /** + * Skeleton data + */ + public set skeleton(value: Skeleton) { + this._skeleton = value; + this._mixSkeletonPose = new SkeletonPose(this._skeleton, true); + this._mixTempSkeletonPose = new SkeletonPose(this._skeleton); + const jointMatrixIndexTable = new Float32Array(this._mixSkeletonPose.jointMatrixIndexTable); + this._jointMatrixIndexTableBuffer = new StorageGPUBuffer(this._skeleton.numJoint * 4, 0, jointMatrixIndexTable); + this._jointMatrixIndexTableBuffer.visibility = GPUShaderStage.VERTEX | GPUShaderStage.COMPUTE; + } + + /** + * Skeleton data + */ + public get skeleton(): Skeleton { + return this._skeleton; + } + + /** + * Current final skeleton posture data + */ + public get finalSkeletonPose(): SkeletonPose { + return this._mixSkeletonPose; + } + + /** + * Bone matrix index table data + */ + public get jointMatrixIndexTableBuffer(): StorageGPUBuffer { + return this._jointMatrixIndexTableBuffer; + } + + /** + * Get the bone index information by the bone name + * @param skinJointsName bone name + * @returns bone index + */ + public getJointIndexTable(skinJointsName: Array): Array { + let result = new Array(); + for (let i = 0; i < skinJointsName.length; i++) { + const name = skinJointsName[i]; + let joint = this._skeleton.getJointByName(name); + result[i] = joint ? joint.index : -1; + } + return result; + } + + /** + * Add a skeleton animation clip + * @param clip Skeletal animation clip + */ + public addAnimationClip(clip: SkeletonAnimationClip) { + if (!this._clipStates.has(clip.name)) { + this._clips.push(clip); + let clipState = new SkeletonAnimationClipState(clip); + clipState.animation = this; + this._clipStates.set(clip.name, clipState); + if (!this._currentClipState) { + this.setCurrentClipState(clipState) + } + } + } + + /** + * Gets the animation clip data object with the specified name + * @param name Name of animation + * @returns Animation clip data object + */ + public getAnimationClip(name: string): SkeletonAnimationClip { + var clipState = this.getAnimationClipState(name); + if (clipState) { + return clipState.clip; + } + return null + } + + /** + * Gets all animation clip data objects + * @returns Animation clip data object + */ + public getAnimationClips(): SkeletonAnimationClip[] { + return this._clips; + } + + /** + * Gets the animation clip state object with the specified name + * @param name Name of animation + * @returns Animation clip state object + */ + public getAnimationClipState(name: string): SkeletonAnimationClipState { + if (this._clipStates.has(name)) { + return this._clipStates.get(name); + } + return null + } + + /** + * Gets all animation clip state objects + * @returns Animation clip state object + */ + public getAnimationClipStates(): Map { + return this._clipStates; + } + + /** + * stop playing + */ + public pause() { + this.isPlaying = false; + } + + /** + * Resume playback + */ + public resume() { + this.isPlaying = true; + } + + /** + * Play the specified animation + * @param animName The data set name for the animation + * @param speed Animation playback speed, default value is 1.0 + * @param reset When true, each play starts with the first frame + * @returns + */ + public play(animName: string, speed: number = 1, reset: boolean = false): boolean { + if (this._currentClipState && this._currentClipState.name == animName) { + if (reset) { + this._currentClipState.reset(); + } + return false; + } + + let clipState = this.getAnimationClipState(animName); + if (!clipState) { + return false; + } + + clipState.speed = speed; + clipState.reset(); + + this._clipStates.forEach((clipState, name) => { + clipState.weight = 0; + }) + + this.setCurrentClipState(clipState) + return true; + } + + /** + * Fades the current animation and fades into another animation state for a specified time. + * @param animName The name of the animation to fade in. + * @param crossTime The time of transition, in seconds. + * @returns + */ + public crossFade(animName: string, crossTime: number) { + if (crossTime < 0.01) { + this.play(animName); + return; + } + + if (this._currentClipState.name == animName) { + return; + } + + let clipState = this.getAnimationClipState(animName); + if (!clipState) { + return; + } + clipState.reset(); + + if (this._crossFadeState) { + if (this._crossFadeState.inClip) { + this._crossFadeState.inClip.weight = 0 + } + if (this._crossFadeState.outClip) { + this._crossFadeState.outClip.weight = 0 + } + this._crossFadeState.reset(clipState, this._currentClipState, crossTime); + } else { + this._crossFadeState = new SkeletonAnimationCrossFadeState( + clipState, + this._currentClipState, + crossTime + ); + } + + this._currentClipState = clipState; + } + + /** + * Set the animation loop + * @param animName The data set name for the animation + * @param isLoop If true, loop the animation + */ + public setAnimIsLoop(animName: string, isLoop: boolean) { + if (this._clipStates.has(animName)) { + this._clipStates.get(animName).loop = isLoop; + } + } + + /** + * Add joint bindings to the object + * @param jointName Name of joint + * @param obj Object of binding + */ + public addJointBind(jointName: string, obj: Object3D) { + this._bindList.push({ + jointName: jointName, + obj: obj, + }); + } + + /** + * Removes the joint binding of the specified object + * @param jointName Name of joint + * @param obj Object of binding + */ + public removeJointBind(obj: Object3D) { + for (let index = 0; index < this._bindList.length; index++) { + let item = this._bindList[index]; + if (item.obj == obj) { + this._bindList.splice(index, 1); + break; + } + } + } + + /** + * @internal + */ + public onUpdate() { + if (!this.isPlaying) { + return; + } + + let delta = (Time.delta * 0.001) * this.timeScale; + + if (this._crossFadeState) { + this._crossFadeState.update(delta); + } + + var totalWeight = 0; + var mixClipState: SkeletonAnimationClipState[] = []; + this._clipStates.forEach((clipState, name) => { + if (clipState.weight > 0) { + clipState.update(delta); + totalWeight += clipState.weight; + mixClipState.push(clipState); + } + }) + + if (mixClipState.length > 0) { + this._mixSkeletonPose.copyFrom(mixClipState[0].currSkeletonPose); + for (var i = 1; i < mixClipState.length; ++i) { + const clipState = mixClipState[i]; + this._mixTempSkeletonPose.lerp(this._mixSkeletonPose, clipState.currSkeletonPose, clipState.weight / totalWeight); + this._mixSkeletonPose.copyFrom(this._mixTempSkeletonPose); + } + } + } + + /** + * Clones the current component to the specified object + * @param obj target object + */ + public cloneTo(obj: Object3D) { + let animator = obj.addComponent(SkeletonAnimationComponent); + animator.skeleton = this.skeleton; + for (var i = 0; i < this._clips.length; ++i) { + animator.addAnimationClip(this._clips[i]) + } + } + + protected setCurrentClipState(clipState: SkeletonAnimationClipState) { + if (this._currentClipState == clipState) { + return + } + + this._currentClipState = clipState; + this._currentClipState.weight = 1.0; + } +} + +/** + * @internal + * @group Animation + */ +class SkeletonAnimationCrossFadeState { + public inClip: SkeletonAnimationClipState; + public outClip: SkeletonAnimationClipState; + public currentTime: number; + public crossFadeTime: number; + + constructor(inClip: SkeletonAnimationClipState, outClip: SkeletonAnimationClipState, time: number) { + this.reset(inClip, outClip, time); + } + + public reset(inClip: SkeletonAnimationClipState, outClip: SkeletonAnimationClipState, time: number) { + this.inClip = inClip; + this.outClip = outClip; + this.currentTime = 0; + this.crossFadeTime = time; + } + + public update(delta: number) { + if (!this.inClip || !this.outClip) { + return; + } + this.currentTime += delta; + this.inClip.weight = Math.min(Math.abs(this.currentTime % this.crossFadeTime) / this.crossFadeTime, 1.0); + this.outClip.weight = 1.0 - this.inClip.weight; + if (Math.abs(this.currentTime) >= this.crossFadeTime) { + this.inClip.weight = 1.0; + this.outClip.weight = 0.0; + this.inClip = null; + this.outClip = null; + } + } +} diff --git a/src/engine/components/anim/skeletonAnim/Joint.ts b/src/engine/components/anim/skeletonAnim/Joint.ts new file mode 100644 index 00000000..4a08a0af --- /dev/null +++ b/src/engine/components/anim/skeletonAnim/Joint.ts @@ -0,0 +1,48 @@ +import { Quaternion } from '../../../math/Quaternion'; +import { Vector3 } from '../../../math/Vector3'; + +/** + * Bone and joint data + * @internal + * @group Animation + */ +export class Joint { + /** + * Name of bone joint + */ + public name: string = ''; + + /** + * Bone joint index + */ + public index: number = 0; + + /** + * The parent of a bone joint + */ + public parent: Joint = null; + + /** + * Bone joint child object + */ + public children: Array = []; + + /** + * The scaling value of the bone joint + */ + public scale: Vector3 = new Vector3(); + + /** + * The rotation Angle of the bone and joint + */ + public rotation: Quaternion = new Quaternion(); + + /** + * The position of the bone joint + */ + public translation: Vector3 = new Vector3(); + + constructor(name: string = '') { + this.name = name; + } +} diff --git a/src/engine/components/anim/skeletonAnim/JointPose.ts b/src/engine/components/anim/skeletonAnim/JointPose.ts new file mode 100644 index 00000000..e6ccd711 --- /dev/null +++ b/src/engine/components/anim/skeletonAnim/JointPose.ts @@ -0,0 +1,10 @@ +import { Matrix4 } from '../../../math/Matrix4'; + +export class JointPose { + public index: number; + public worldMatrix: Matrix4; + constructor(index: number, useGlobalMatrix: boolean = false) { + this.index = index; + this.worldMatrix = new Matrix4(!useGlobalMatrix); + } +} diff --git a/src/engine/components/anim/skeletonAnim/Skeleton.ts b/src/engine/components/anim/skeletonAnim/Skeleton.ts new file mode 100644 index 00000000..78963ace --- /dev/null +++ b/src/engine/components/anim/skeletonAnim/Skeleton.ts @@ -0,0 +1,44 @@ +import { webGPUContext } from '../../../gfx/graphics/webGpu/Context3D'; +import { Joint } from './Joint'; + +/** + * Skeleton data + * @internal + * @group Animation + */ +export class Skeleton { + /** + * Link information for all joints + */ + public joints: Array; + + constructor(joints: Array = []) { + this.joints = joints; + } + + public get numJoint(): number { + return this.joints.length; + } + + public addJoint(joint: Joint) { + joint.index = this.joints.push(joint) - 1; + } + + public getJointName(jointIndex: number): string { + return this.joints[jointIndex].name; + } + + public getJointParentIndex(jointIndex: number): number { + let joint = this.joints[jointIndex]; + return joint.parent ? joint.parent.index : -1; + } + + public getJointByName(name: string): Joint { + for (let joint of this.joints) { + if (joint.name == name) { + return joint; + } + } + return null; + } +} diff --git a/src/engine/components/anim/skeletonAnim/SkeletonAnimationClip.ts b/src/engine/components/anim/skeletonAnim/SkeletonAnimationClip.ts new file mode 100644 index 00000000..b1480b5a --- /dev/null +++ b/src/engine/components/anim/skeletonAnim/SkeletonAnimationClip.ts @@ -0,0 +1,136 @@ +import { Skeleton } from './Skeleton'; +import { SkeletonPose } from './SkeletonPose'; +import { OAnimationEvent } from '../OAnimationEvent'; + +/** + * + * SkeletonAnimationClip contains all keyframe data of one skeleton animation + * @internal + * @group Animation + */ +export class SkeletonAnimationClip { + public name: string = ''; + protected _skeleton: Skeleton; + protected _skeletonPoses: Array; + protected _animationClipData: Float32Array; + protected _events: Array; + + constructor(name: string, skeleton: Skeleton, numFrame: number, bufferData: Float32Array) { + this.name = name; + this._skeleton = skeleton; + this._animationClipData = bufferData; + if (numFrame > 0 && bufferData) { + this._skeletonPoses = new Array(numFrame); + let skeletonPoseLength: number = 12 * skeleton.numJoint; + for (let nFrame: number = 0; nFrame < numFrame; nFrame++) { + let byteOffset: number = skeletonPoseLength * nFrame * 4; + let poseData = new Float32Array(bufferData.buffer, byteOffset, skeletonPoseLength); + let skeletonPose = new SkeletonPose(skeleton); + skeletonPose.buildSkeletonPose(poseData); + this._skeletonPoses[nFrame] = skeletonPose; + } + } + } + + /* + * Animation total time in seconds + */ + public get totalTime(): number { + return this._skeletonPoses[this._skeletonPoses.length - 1].time; + } + + /* + * Frame rate at which keyframes are sampled. + */ + public get frameRate(): number { + return this.totalTime / this._skeletonPoses.length; + } + + /* + * Returns owner skeleton + */ + public get skeleton(): Skeleton { + return this._skeleton; + } + + /* + * Returns key frame count + */ + public get numFrame(): number { + return this._skeletonPoses.length - 1; + } + + /* + * Returns float32 array of this animation clip + */ + public get animationClipData(): Float32Array { + return this._animationClipData; + } + + /* + * Returns skeletonPose at target frame + */ + public getSkeletonPose(frame: number): SkeletonPose { + return this._skeletonPoses[frame]; + } + + /** + * Returns lerped skeletonPose between currFrame and nextFrame + * @param currFrame selected frame No.1 + * @param nextFrame selected frame No.2 + * @param weight number + * @param dst result SkeletonPose + */ + public getLerpSkeletonPose(currFrame: number, nextFrame: number, weight: number, dst: SkeletonPose): SkeletonPose { + let skeletonPoseA = this.getSkeletonPose(currFrame); + let skeletonPoseB = this.getSkeletonPose(nextFrame); + dst.lerp(skeletonPoseA, skeletonPoseB, weight); + return dst; + } + + /** + * create one skeletonAnimationClip from startTime to endTime + * @param name the name of new animation clip + * @param startTime set time of animation clip start from + * @param endTime set time of animation clip end of + */ + public createSubClip(name: string, startTime: number, endTime: number): SkeletonAnimationClip { + var result = new SkeletonAnimationClip(name, this._skeleton, 0, null); + const startFrame = Math.max(Math.floor(startTime / this.frameRate), 0); + const endFrame = Math.min(Math.floor(endTime / this.frameRate), this._skeletonPoses.length - 1); + result._skeletonPoses = this._skeletonPoses.slice(startFrame, endFrame); + const skeletonPoseByteLength = 12 * this._skeleton.numJoint * 4; + this._animationClipData = new Float32Array(this._animationClipData, startFrame * skeletonPoseByteLength, (endFrame - startFrame) * skeletonPoseByteLength); + return result; + } + + /** + * register a event in this animation clip. + * @param eventName event name + * @param startTime number + */ + public addEvent(eventName: string, triggerTime: number) { + if (!this._events) { + this._events = new Array(); + } + this._events.push(new OAnimationEvent(eventName, triggerTime)); + } + + /** + * remove a event in this animation clip + * @param eventName event name + */ + public removeEvent(eventName: string) { + if (this._events) { + this._events = this._events.filter(items => items.type != eventName); + } + } + + /** + * Returns all AnimationEvent of this animationClip + * @param eventName event name + */ + public getEvents(): Array { + return this._events; + } +} diff --git a/src/engine/components/anim/skeletonAnim/SkeletonAnimationClipState.ts b/src/engine/components/anim/skeletonAnim/SkeletonAnimationClipState.ts new file mode 100644 index 00000000..14cce854 --- /dev/null +++ b/src/engine/components/anim/skeletonAnim/SkeletonAnimationClipState.ts @@ -0,0 +1,116 @@ +import { CEventDispatcher } from '../../../event/CEventDispatcher'; +import { Time } from '../../../util/Time'; +import { SkeletonAnimationClip } from './SkeletonAnimationClip'; +import { SkeletonPose } from './SkeletonPose'; + +/** + * Skeletal data at specific time points, skeletal animation interpolation operations + * @internal + * @group Animation + */ +export class SkeletonAnimationClipState { + public loop: boolean = true; + public speed: number = 1.0; + public t: number = 0.0; + public time: number = 0.0; + public weight: number = 0; + public currFrame: number = 0; + public lastFrame: number = -1; + public nextFrame: number = 0; + public clip: SkeletonAnimationClip; + public animation: any; + protected _isEnd: boolean = false; + protected _currSkeletonPose: SkeletonPose; + + constructor(clip: SkeletonAnimationClip) { + this.clip = clip; + this._currSkeletonPose = new SkeletonPose(this.clip.skeleton); + } + + public reset() { + this.time = 0; + this.weight = 0; + this._isEnd = false; + } + + /** + * Returns animation clip's name. + */ + public get name(): string { + return this.clip.name; + } + + /** + * Returns current skeleton pose. + */ + public get currSkeletonPose(): SkeletonPose { + return this._currSkeletonPose; + } + + /** + * update animation clip, it will change key frame to sample animation clip. + * @param delta time from last frame to now + */ + public update(delta: number) { + this.time = (this.time + delta * this.speed) % this.clip.totalTime; + let frameTime = (this.time / this.clip.frameRate); + this.currFrame = Math.trunc(frameTime); + this.t = frameTime - this.currFrame; + + if (this.currFrame < 0) { + this.currFrame = this.clip.numFrame + this.currFrame; + } + + if (this.time >= 0) { + this.nextFrame = (this.currFrame + 1) % this.clip.numFrame; + } else { + + this.nextFrame = this.currFrame - 1; + if (this.nextFrame < 0) { + this.nextFrame = this.clip.numFrame + this.nextFrame; + } + + this.t = 1 - this.t; + } + + if (this._isEnd) { + this.currFrame = this.nextFrame = this.speed < 0 ? 0 : this.clip.numFrame - 1; + } else if (this.currFrame != this.lastFrame) { + let endFrame: number = this.speed < 0 ? 0 : this.clip.numFrame; + if (this.currFrame == endFrame) { + if (this.loop) { + this.currFrame = 0; + this.nextFrame = 1; + this.time = this.t = 0; + } else { + this.currFrame = this.nextFrame = this.speed < 0 ? 0 : this.clip.numFrame - 1; + this._isEnd = true; + } + } + + var events = this.clip.getEvents(); + if (events) { + for (let event of events) { + var triggerFrame = Math.floor(event.time / this.clip.frameRate); + triggerFrame = Math.min(triggerFrame, this.clip.numFrame); + triggerFrame = Math.max(triggerFrame, 0); + if (triggerFrame == this.currFrame) { + event.skeletonAnimation = this.animation; + this.animation.events.dispatchEvent(event); + break; + } + } + } + + this.lastFrame = this.currFrame; + } + + // if (EngineSetting.AnimationSetting.useGPUComputeSkeltonAnimation) { + // let skeletonPoseA = this.clip.getSkeletonPose(this.currFrame); + // let skeletonPoseB = this.clip.getSkeletonPose(this.nextFrame); + // // SkeletonAnimationCompute.addLerpSkeletonPoseJob(skeletonPoseA, skeletonPoseB, this.t, this.mCurrSkeletonPose); + // } else { + this.clip.getLerpSkeletonPose(this.currFrame, this.nextFrame, this.t, this._currSkeletonPose); + // } + } +} diff --git a/src/engine/components/anim/skeletonAnim/SkeletonAnimationCompute.ts b/src/engine/components/anim/skeletonAnim/SkeletonAnimationCompute.ts new file mode 100644 index 00000000..5a466699 --- /dev/null +++ b/src/engine/components/anim/skeletonAnim/SkeletonAnimationCompute.ts @@ -0,0 +1,38 @@ +import { webGPUContext } from '../../../gfx/graphics/webGpu/Context3D'; + +/** + * Skeletal animation + * @internal + * @group Animation + */ +export class SkeletonAnimationCompute { + private _computePipeline: GPUComputePipeline; + private _computeBindGroup: GPUBindGroup; + + constructor(computeShader: string, entries: GPUBindGroupEntry[]) { + let device = webGPUContext.device; + this._computePipeline = device.createComputePipeline({ + layout: `auto`, + compute: { + module: device.createShaderModule({ + code: computeShader, + }), + entryPoint: 'CsMain', + }, + }); + + this._computeBindGroup = device.createBindGroup({ + layout: this._computePipeline.getBindGroupLayout(0), + entries: entries, + }); + } + + public compute(command: GPUCommandEncoder, workgroupCountX: GPUSize32, workgroupCountY?: GPUSize32, workgroupCountZ?: GPUSize32): this { + let computePass = command.beginComputePass(); + computePass.setPipeline(this._computePipeline); + computePass.setBindGroup(0, this._computeBindGroup); + computePass.dispatchWorkgroups(workgroupCountX, workgroupCountY, workgroupCountZ); + computePass.end(); + return this; + } +} diff --git a/src/engine/components/anim/skeletonAnim/SkeletonPose.ts b/src/engine/components/anim/skeletonAnim/SkeletonPose.ts new file mode 100644 index 00000000..a2b7cb8c --- /dev/null +++ b/src/engine/components/anim/skeletonAnim/SkeletonPose.ts @@ -0,0 +1,118 @@ +import { makeMatrix44, Matrix4, multiplyMatrices4x4REF } from '../../../..'; +import { Quaternion } from '../../../math/Quaternion'; +import { Vector3 } from '../../../math/Vector3'; +import { JointPose } from './JointPose'; +import { Skeleton } from './Skeleton'; + +/** + * Skeleton animation consists of many skeleton pose, + * and each pose describes the transformation information of all bone + * @group SkeletonPose + */ +export class SkeletonPose { + /** + * time of this pose in owner animation clip + */ + public time: number; + protected _skeleton: Skeleton; + protected _jointsPose: Array; + protected mJointMatrixIndexTable: Array; + + constructor(skeleton: Skeleton, useGlobalMatrix: boolean = false) { + this._skeleton = skeleton; + this._jointsPose = new Array(skeleton.numJoint); + this.mJointMatrixIndexTable = new Array(skeleton.numJoint); + for (let index = 0; index < skeleton.numJoint; index++) { + let joint = new JointPose(index, useGlobalMatrix); + this._jointsPose[index] = joint; + this.mJointMatrixIndexTable[index] = joint.worldMatrix.index; + } + } + + /** + * build this pose from float32 array data + */ + public buildSkeletonPose(poseData: Float32Array) { + let scale = new Vector3(); + let rotation = new Quaternion(); + let translation = new Vector3(); + let jointLocalMatrix = new Array(this._skeleton.numJoint); + this.time = poseData[11] > 0 ? poseData[11] : poseData[24]; + for (let jointIndex = 0; jointIndex < this._skeleton.numJoint; jointIndex++) { + let byteOffset = 12 * jointIndex * 4; + let jointData = new Float32Array(poseData.buffer, poseData.byteOffset + byteOffset, 12); + + let localMatrix = new Matrix4(); + scale.set(jointData[0], jointData[1], jointData[2]); + rotation.set(jointData[4], jointData[5], jointData[6], jointData[7]); + translation.set(jointData[8], jointData[9], jointData[10]); + makeMatrix44(rotation.getEulerAngles(), translation, scale, localMatrix); + jointLocalMatrix[jointIndex] = localMatrix; + + let joint = new JointPose(jointIndex); + const nParentIndex = this._skeleton.getJointParentIndex(jointIndex); + if (nParentIndex < 0) { + joint.worldMatrix.copyFrom(localMatrix); + } else { + let parentJoint = this._jointsPose[nParentIndex]; + multiplyMatrices4x4REF(parentJoint.worldMatrix, localMatrix, joint.worldMatrix); + } + this._jointsPose[jointIndex] = joint; + } + } + + /** + * Returns joints count of owner skeleton + */ + public get numJoint(): number { + return this._skeleton.numJoint; + } + + /** + * Returns all joint pose + */ + public get joints(): Array { + return this._jointsPose; + } + + /** + * Returns list of matrix's index + */ + public get jointMatrixIndexTable(): Array { + return this.mJointMatrixIndexTable; + } + + /** + * Returns lerped skeletonPose from pose a to pose b + * @param a selected pose No.1 + * @param b selected pose No.2 + * @param weight number + */ + public lerp(a: SkeletonPose, b: SkeletonPose, weight: number) { + for (let index = 0; index < this._jointsPose.length; index++) { + let jointA = a._jointsPose[index]; + let jointB = b._jointsPose[index]; + let jointDst = this._jointsPose[index]; + jointDst.worldMatrix.lerp(jointA.worldMatrix, jointB.worldMatrix, weight); + } + } + + /** + * Copy skeleton pose from other skeleton pose + * @param other source skeleton pose + */ + public copyFrom(other: SkeletonPose) { + for (let index = 0; index < this._jointsPose.length; index++) { + this._jointsPose[index].worldMatrix.copyFrom(other._jointsPose[index].worldMatrix) + } + } + + /** + * Reset this skeleton pose + */ + public reset() { + for (let index = 0; index < this._jointsPose.length; index++) { + this._jointsPose[index].worldMatrix.identity(); + } + } +} diff --git a/src/engine/components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs.ts b/src/engine/components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs.ts new file mode 100644 index 00000000..ca9d6f00 --- /dev/null +++ b/src/engine/components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs.ts @@ -0,0 +1,115 @@ +import { MemoryDO } from '../../../../core/pool/memory/MemoryDO'; +import { MemoryInfo } from '../../../../core/pool/memory/MemoryInfo'; +import { webGPUContext } from '../../../../gfx/graphics/webGpu/Context3D'; +/** + * @internal + * @group Animation + */ +export class SkeletonBlendComputeArgs extends MemoryDO { + public numJoint: MemoryInfo; + public numState: MemoryInfo; + public time: MemoryInfo; + public weight: MemoryInfo; + public argumentsData: { [name: string]: MemoryInfo }; + protected _isDirty: boolean = false; + protected _argumentsBuffer: GPUBuffer; + protected _argumentsBufferEntries: GPUBindGroupEntry; + + constructor() { + super(); + this.allocationMemorySet([ + { name: `numJoint`, data: [0] }, + { name: `numState`, data: [0] }, + { name: `retain1`, data: [0] }, + { name: `retain2`, data: [0] }, + { name: `time`, data: [0, 0] }, + { name: `weight`, data: [0, 0] }, + ]); + this.generateGPUBuffer(); + } + + public getGPUBuffer(): GPUBuffer { + return this._argumentsBuffer; + } + + public getGPUBindGroupEntry(): GPUBindGroupEntry { + return this._argumentsBufferEntries; + } + + // public setNumJoint(value: number) { + // if (this.numJoint.bytes[0] != value) { + // this.numJoint.bytes[0] = value; + // this.isDirty = true; + // } + // } + + // public setNumState(value: number) { + // if (this.numState.bytes[0] != value) { + // this.numState.bytes[0] = value; + // this.isDirty = true; + // } + // } + + // public setTime(index: number, value: number) { + // if (this.time.bytes[index] != value) { + // this.time.bytes[index] = value; + // this.isDirty = true; + // } + // } + + // public setWeight(index: number, value: number) { + // if (this.weight.bytes[index] != value) { + // this.weight.bytes[index] = value; + // this.isDirty = true; + // } + // } + + public updateGPUBuffer(): this { + if (this._isDirty) { + this._isDirty = false; + webGPUContext.device.queue.writeBuffer(this._argumentsBuffer, 0, this.shareDataBuffer); + } + return this; + } + + protected allocationMemorySet(dataDic: { name: string; data: number[] }[]): void { + this.argumentsData = {}; + + let count = 0; + for (let i = 0; i < dataDic.length; i++) { + const element = dataDic[i]; + count += element.data.length; + } + + this.allocation(count * 4); + + let self = this; + for (let i = 0; i < dataDic.length; i++) { + const element = dataDic[i]; + const key = element.name; + this.argumentsData[key] = this.allocation_node(element.data.length * 4); + // if (key in self) { + self[key] = this.argumentsData[key]; + // } + } + } + + protected generateGPUBuffer() { + let device = webGPUContext.device; + + this._argumentsBuffer = device.createBuffer({ + size: this.shareDataBuffer.byteLength, + usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, + mappedAtCreation: false, + }); + + this._argumentsBufferEntries = { + binding: 0, + resource: { + buffer: this._argumentsBuffer, + offset: 0, + size: this.shareDataBuffer.byteLength, + }, + }; + } +} diff --git a/src/engine/components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs.ts b/src/engine/components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs.ts new file mode 100644 index 00000000..775b7320 --- /dev/null +++ b/src/engine/components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs.ts @@ -0,0 +1,96 @@ +import { MemoryDO } from '../../../../core/pool/memory/MemoryDO'; +import { MemoryInfo } from '../../../../core/pool/memory/MemoryInfo'; +import { webGPUContext } from '../../../../gfx/graphics/webGpu/Context3D'; +/** + * @internal + * @group Animation + */ +export class SkeletonTransformComputeArgs extends MemoryDO { + public numJoint: MemoryInfo; + public numFrame: MemoryInfo; + public retain0: MemoryInfo; + public retain1: MemoryInfo; + public argumentsData: { [name: string]: MemoryInfo }; + protected _isDirty: boolean = false; + protected _argumentsBuffer: GPUBuffer; + protected _argumentsBufferEntries: GPUBindGroupEntry; + + constructor() { + super(); + this.allocationMemorySet([ + { name: `numJoint`, data: [0] }, + { name: `numFrame`, data: [0] }, + { name: `retain0`, data: [0] }, + { name: `retain1`, data: [0] }, + ]); + this.generateGPUBuffer(); + } + + public getGPUBuffer(): GPUBuffer { + return this._argumentsBuffer; + } + + public getGPUBindGroupEntry(): GPUBindGroupEntry { + return this._argumentsBufferEntries; + } + + // public setNumJoint(value: number) { + // if (this.numJoint.bytes[0] != value) { + // this.numJoint.bytes[0] = value; + // this.isDirty = true; + // } + // } + + // public setNumFrame(value: number) { + // if (this.numFrame.bytes[0] != value) { + // this.numFrame.bytes[0] = value; + // this.isDirty = true; + // } + // } + + public updateGPUBuffer() { + if (this._isDirty) { + this._isDirty = false; + webGPUContext.device.queue.writeBuffer(this._argumentsBuffer, 0, this.shareDataBuffer); + } + } + + protected allocationMemorySet(dataDic: { name: string; data: number[] }[]): void { + this.argumentsData = {}; + + let count = 0; + for (let i = 0; i < dataDic.length; i++) { + const element = dataDic[i]; + count += element.data.length; + } + + this.allocation(count * 4); + + let self = this; + for (let i = 0; i < dataDic.length; i++) { + const element = dataDic[i]; + const key = element.name; + this.argumentsData[key] = this.allocation_node(element.data.length * 4); + self[key] = this.argumentsData[key]; + } + } + + protected generateGPUBuffer() { + let device = webGPUContext.device; + + this._argumentsBuffer = device.createBuffer({ + size: this.shareDataBuffer.byteLength, + usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, + mappedAtCreation: false, + }); + + this._argumentsBufferEntries = { + binding: 0, + resource: { + buffer: this._argumentsBuffer, + offset: 0, + size: this.shareDataBuffer.byteLength, + }, + }; + } +} diff --git a/src/engine/components/anim/skeletonAnim/shader/compute_skeleton_blend.ts b/src/engine/components/anim/skeletonAnim/shader/compute_skeleton_blend.ts new file mode 100644 index 00000000..eea87c88 --- /dev/null +++ b/src/engine/components/anim/skeletonAnim/shader/compute_skeleton_blend.ts @@ -0,0 +1,40 @@ +import { MathShader } from "../../../../assets/shader/math/MathShader"; + +/** + * @internal + */ +export let compute_skeleton_blend = /* wgsl */ ` + ${MathShader} + + struct Arguments { + numJoint: f32, + numState: f32, + retain1: f32, + retain2: f32, + time: vec2, + weight: vec2, + }; + + struct JointData { + scale: vec4, + rotation: vec4, + translation: vec4, + }; + + @group(0) @binding(0) var args: Arguments; + @group(0) @binding(1) var jointsFinalMatrix: array>; + @group(0) @binding(2) var jointsWorldMatrix: array>; + + @compute @workgroup_size(1) + fn CsMain(@builtin(workgroup_id) workgroup_id: vec3, @builtin(local_invocation_index) local_index: u32) { + let numJoint = i32(args.numJoint); + let numState = i32(args.numState); + let nJointIndex = i32(workgroup_id.x); + + jointsFinalMatrix[nJointIndex] = mixMatrix4x4(jointsWorldMatrix[0 * numJoint + nJointIndex], jointsWorldMatrix[1 * numJoint + nJointIndex], args.time[0]) * args.weight[0]; + + for (var i = 1; i < numState; i++) { + jointsFinalMatrix[nJointIndex] += mixMatrix4x4(jointsWorldMatrix[(i * 2 + 0) * numJoint + nJointIndex], jointsWorldMatrix[(i * 2 + 1) * numJoint + nJointIndex], args.time[i]) * args.weight[i]; + } + } +`; diff --git a/src/engine/components/anim/skeletonAnim/shader/compute_skeleton_transform.ts b/src/engine/components/anim/skeletonAnim/shader/compute_skeleton_transform.ts new file mode 100644 index 00000000..bf84002c --- /dev/null +++ b/src/engine/components/anim/skeletonAnim/shader/compute_skeleton_transform.ts @@ -0,0 +1,44 @@ +import { MathShader } from "../../../../assets/shader/math/MathShader"; + +/** + * @internal + */ +export let compute_skeleton_transform = /* wgsl */ ` + ${MathShader} + + struct Arguments { + numJoint: f32, + numFrame: f32, + retain0: f32, + retain1: f32, + }; + + struct JointData { + scale: vec4, + rotation: vec4, + translation: vec4, + }; + + @group(0) @binding(0) var args: Arguments; + @group(0) @binding(1) var jointsKeyframe: array; + @group(0) @binding(2) var jointsWorldMatrix: array>; + @group(0) @binding(3) var jointsParentIndex: array; + + @compute @workgroup_size(1) + fn CsMain(@builtin(workgroup_id) workgroup_id: vec3, @builtin(local_invocation_index) local_index: u32) { + let numJoint = i32(args.numJoint); + let nFrameIndex = i32(workgroup_id.x); + for (var nJointIndex = 0; nJointIndex < numJoint; nJointIndex++) { + let dataIndex = nFrameIndex * numJoint + nJointIndex; + let joint = jointsKeyframe[dataIndex]; + let jointLocalMatrix = MakeMatrix4x4(joint.scale.xyz, joint.rotation, joint.translation.xyz); + + let nParentIndex = i32(jointsParentIndex[nJointIndex]); + if (nParentIndex < 0) { + jointsWorldMatrix[dataIndex] = jointLocalMatrix; + } else { + jointsWorldMatrix[dataIndex] = jointsWorldMatrix[nFrameIndex * numJoint + nParentIndex] * jointLocalMatrix; + } + } + } +`; From 5a6fc22232ef86c29d6d3abeba5dd4d08c250dd8 Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Mon, 24 Apr 2023 16:09:06 +0800 Subject: [PATCH 046/100] feat(Camera): add camera controller (#58) add CameraControllerBase add FirstPersonCameraController add FlyCameraController add HoverCameraController add ThirdPersonCameraController --- .../controller/CameraControllerBase.ts | 89 ++++++ .../controller/FirstPersonCameraController.ts | 70 +++++ .../controller/FlyCameraController.ts | 277 ++++++++++++++++++ .../controller/HoverCameraController.ts | 264 +++++++++++++++++ .../controller/ThirdPersonCameraController.ts | 66 +++++ 5 files changed, 766 insertions(+) create mode 100644 src/engine/components/controller/CameraControllerBase.ts create mode 100644 src/engine/components/controller/FirstPersonCameraController.ts create mode 100644 src/engine/components/controller/FlyCameraController.ts create mode 100644 src/engine/components/controller/HoverCameraController.ts create mode 100644 src/engine/components/controller/ThirdPersonCameraController.ts diff --git a/src/engine/components/controller/CameraControllerBase.ts b/src/engine/components/controller/CameraControllerBase.ts new file mode 100644 index 00000000..00201a89 --- /dev/null +++ b/src/engine/components/controller/CameraControllerBase.ts @@ -0,0 +1,89 @@ +import { Object3D } from '../../core/entities/Object3D'; +import { Vector3 } from '../../math/Vector3'; + +/** + * The base class of camera controllers + * @internal + * @group CameraController + */ +export class CameraControllerBase { + protected _autoUpdate: boolean = true; + protected _target: Object3D | null; + protected _lookAtObject: Object3D | null; + protected _origin: Vector3 = new Vector3(0.0, 0.0, 0.0); + protected _speed: number = 300; + + /** + * + * @constructor + * @param targetObject control object3D + * @param lookAtObject observational object3D + */ + constructor(targetObject: Object3D | null = null, lookAtObject: Object3D | null = null) { + this._target = targetObject; + this._lookAtObject = lookAtObject; + } + + /** + * + * Get the control object3D + * @returns Object3D + */ + public get target(): Object3D | null { + return this._target; + } + + /** + * + * Set the control object3D + * @param val Object3D + */ + public set target(val: Object3D | null) { + if (this._target == val) return; + this._target = val; + } + + /** + * + * Get observational object3D + * @returns Object3D + */ + public get lookAtObject(): Object3D | null { + return this._lookAtObject; + } + + /** + * + * Set observational object3D + * @param val Object3D + */ + public set lookAtObject(val: Object3D | null) { + if (this._lookAtObject == val) return; + this._lookAtObject = val; + } + + /** + * + * Get moving speed + * @returns number + * @version FlyEngine + */ + public get speed(): number { + return this._speed; + } + + /** + * + * Set moving speed + * @returns number + * @version FlyEngine + */ + public set speed(val: number) { + this._speed = val; + } + + /** + * update(tick) + */ + public update() { } +} diff --git a/src/engine/components/controller/FirstPersonCameraController.ts b/src/engine/components/controller/FirstPersonCameraController.ts new file mode 100644 index 00000000..b74d3930 --- /dev/null +++ b/src/engine/components/controller/FirstPersonCameraController.ts @@ -0,0 +1,70 @@ +import { Camera3D, ComponentBase, Engine3D, Object3D, PointerEvent3D, Vector3 } from '../../..'; + +/** + * @internal + * @group CameraController + */ +export class FirstPersonCameraController extends ComponentBase { + public focus: Object3D; + + public distance: number = 5; + + private _camera: Camera3D; + + constructor() { + super(); + this.serializeTag = 'dont-serialize'; + } + + protected start() { + this._camera = this.object3D.getOrAddComponent(Camera3D); + if (!this._camera) { + console.error('FirstPersonCameraController need camera'); + return; + } + + if (!this.focus) { + console.error('FirstPersonCameraController need target'); + return; + } + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_WHEEL, this.mouseWheel, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_UP, this.mouseUp, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_DOWN, this.mouseDown, this); + } + + private mouseDown(e: PointerEvent3D) { + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_MOVE, this.mouseMove, this); + } + + private mouseUp(e: PointerEvent3D) { + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_MOVE, this.mouseMove, this); + } + + private mouseMove(e: PointerEvent3D) { + // this.rotation.y += e.movementX * 0.01; + // this.rotation.x += e.movementY * 0.01; + let temp = this.transform.localRotation; + temp.y += e.movementX * 0.01; + temp.x += e.movementY * 0.01; + this.transform.localRotation = temp; + } + + private mouseWheel(e: PointerEvent3D) { + this.distance += Engine3D.inputSystem.wheelDelta * 0.1; + } + + public onUpdate() { + let vec = new Vector3(); + this._camera.transform.forward.scaleToRef(this.distance, vec); + var focusPoint = this.focus.transform.worldPosition; + // this._camera.transform.localPosition = focusPoint.subtract(vec); + this._camera.transform.localPosition = focusPoint; + } + + public destroy(): void { + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_WHEEL, this.mouseWheel, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_UP, this.mouseUp, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_DOWN, this.mouseDown, this); + super.destroy(); + } +} diff --git a/src/engine/components/controller/FlyCameraController.ts b/src/engine/components/controller/FlyCameraController.ts new file mode 100644 index 00000000..de8a9c72 --- /dev/null +++ b/src/engine/components/controller/FlyCameraController.ts @@ -0,0 +1,277 @@ +import { clamp, ComponentBase, Engine3D, KeyCode, KeyEvent, lerp, PointerEvent3D, Time, Vector3 } from "../../.."; + +/** + * Free camera controller. + * Move forward, backward, left, and right in the direction of W A S D. + * Control the camera's movement direction by holding down the left mouse button + * @group CameraController + */ +export class FlyCameraController extends ComponentBase { + /** + * Camera movement speed + */ + public moveSpeed: number = 2; + /** + * + * Coordinates of specific objects + */ + public targetPos: Vector3 = new Vector3(0, 0, 10); + /** + * + * Camera orientation coordinates + */ + public lookAtPos: Vector3 = new Vector3(0, 0, 0); + + /** + * @internal + */ + public config: { shiftMoveScale: number } = { shiftMoveScale: 20.0 }; + + private _moveScale: number = 1; + private _dir: Vector3; + private _mouseFactory: number = 25; + private _factory: number = 1.5; + private _mouseDown: boolean = false; + private _lastPos: Vector3; + + private _keyState: { + front: boolean; + back: boolean; + left: boolean; + right: boolean; + q: boolean; + e: boolean; + }; + + + constructor() { + super(); + this.serializeTag = 'dont-serialize'; + this._lastPos = new Vector3(); + this._keyState = { + front: false, + back: false, + left: false, + right: false, + q: false, + e: false, + }; + this.setCamera(new Vector3(0, 0, 100), new Vector3(0, 0, 0)); + } + + /** + * + * Initialize camera data + * @param cameraPos source position + * @param lookAt target position + */ + public setCamera(cameraPos: Vector3, lookAt: Vector3) { + this.targetPos.copyFrom(cameraPos); + this.lookAtPos.copyFrom(lookAt); + this.Reset(); + } + + /** + * @internal + */ + protected start(): void { + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_WHEEL, this.mouseWheel, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_UP, this.mouseUp, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_DOWN, this.mouseDown, this); + + Engine3D.inputSystem.addEventListener(KeyEvent.KEY_UP, this.keyUp, this); + Engine3D.inputSystem.addEventListener(KeyEvent.KEY_DOWN, this.keyDown, this); + + this.transform.lookAt(this.targetPos, this.lookAtPos); + + + } + + private mouseWheel(e: PointerEvent3D) { } + + private keyUp(e: KeyEvent) { + switch (e.keyCode) { + case KeyCode.Key_W: + this._keyState.front = false; + break; + case KeyCode.Key_S: + this._keyState.back = false; + break; + case KeyCode.Key_A: + this._keyState.left = false; + break; + case KeyCode.Key_D: + this._keyState.right = false; + break; + case KeyCode.Key_Shift_L: + this._moveScale = 1.0; + break; + case KeyCode.Key_Q: + this._keyState.q = false; + break; + case KeyCode.Key_E: + this._keyState.e = false; + break; + + case KeyCode.Key_F: + this.transform.lookAt(this.targetPos, this.lookAtPos); + break; + default: + break; + } + } + + private keyDown(e: KeyEvent) { + switch (e.keyCode) { + case KeyCode.Key_W: + this._keyState.front = true; + break; + case KeyCode.Key_S: + this._keyState.back = true; + break; + case KeyCode.Key_A: + this._keyState.left = true; + break; + case KeyCode.Key_D: + this._keyState.right = true; + break; + case KeyCode.Key_Q: + this._keyState.q = true; + break; + case KeyCode.Key_E: + this._keyState.e = true; + break; + case KeyCode.Key_Shift_L: + this._moveScale = this.config.shiftMoveScale; + default: + break; + } + } + + private Reset() { + this._lastPos.x = Engine3D.inputSystem.mouseLastX; + this._lastPos.y = Engine3D.inputSystem.mouseLastY; + } + + private mouseDown(e: PointerEvent3D) { + this.Reset(); + this._mouseDown = true; + } + + private mouseUp(e: PointerEvent3D) { + this.Reset(); + this._mouseDown = false; + } + + /** + * + * Get the smoothness of the camera by keyboard control + */ + public get factory(): number { + return this._factory; + } + + /** + * + * Set the smoothness of the camera by keyboard control + */ + public set factory(value: number) { + this._factory = value; + } + + /** + * + * Get the smoothness of the camera by mouse control + */ + public get mouseFactory(): number { + return this._mouseFactory; + } + + /** + * + * Set the smoothness of the camera by mouse control + */ + public set mouseFactory(value: number) { + this._mouseFactory = value; + } + + /** + * @internal + * @param target + * @param current + * @param t + * @returns + */ + private internal(target: number, current: number, t: number) { + return (current - target) * t; + } + + public onUpdate(): void { + this.transform.updateWorldMatrix(); + let transform = this.transform; + let dt = clamp(Time.delta, 0.0, 0.016); + + if (this._mouseDown) { + // let rX = Lerp(transform.rotationY, transform.rotationY + (inputSystem.mouseLastX - this._lastPos.x) * 0.25, Time.detail * this._mouseFactory); + // let rY = Lerp(transform.rotationX, transform.rotationX + (inputSystem.mouseLastY - this._lastPos.y) * 0.25, Time.detail * this._mouseFactory); + transform.rotationY -= this.internal(transform.rotationY + (Engine3D.inputSystem.mouseLastX - this._lastPos.x) * 0.25, transform.rotationY, dt * this._mouseFactory); + transform.rotationX -= this.internal(transform.rotationX + (Engine3D.inputSystem.mouseLastY - this._lastPos.y) * 0.25, transform.rotationX, dt * this._mouseFactory); + this.Reset(); + } + + if (this._keyState.front) { + let forward = transform.forward; + transform.x -= this.internal(transform.x + forward.x * this.moveSpeed * this._moveScale, transform.x, dt * this._factory); + transform.y -= this.internal(transform.y + forward.y * this.moveSpeed * this._moveScale, transform.y, dt * this._factory); + transform.z -= this.internal(transform.z + forward.z * this.moveSpeed * this._moveScale, transform.z, dt * this._factory); + } + + if (this._keyState.back) { + let forward = transform.forward; + transform.x += this.internal(transform.x + forward.x * this.moveSpeed * this._moveScale, transform.x, dt * this._factory); + transform.y += this.internal(transform.y + forward.y * this.moveSpeed * this._moveScale, transform.y, dt * this._factory); + transform.z += this.internal(transform.z + forward.z * this.moveSpeed * this._moveScale, transform.z, dt * this._factory); + } + + if (this._keyState.left) { + let right = transform.left; + transform.x += this.internal(transform.x + right.x * this.moveSpeed * this._moveScale, transform.x, dt * this._factory); + transform.y += this.internal(transform.y + right.y * this.moveSpeed * this._moveScale, transform.y, dt * this._factory); + transform.z += this.internal(transform.z + right.z * this.moveSpeed * this._moveScale, transform.z, dt * this._factory); + } + + if (this._keyState.right) { + let right = transform.left; + transform.x -= this.internal(transform.x + right.x * this.moveSpeed * this._moveScale, transform.x, dt * this._factory); + transform.y -= this.internal(transform.y + right.y * this.moveSpeed * this._moveScale, transform.y, dt * this._factory); + transform.z -= this.internal(transform.z + right.z * this.moveSpeed * this._moveScale, transform.z, dt * this._factory); + } + + if (this._keyState.q) { + transform.y = lerp(transform.y, transform.y - this.moveSpeed * this._moveScale, dt * this._factory); + } + + if (this._keyState.e) { + transform.y = lerp(transform.y, transform.y + this.moveSpeed * this._moveScale, dt * this._factory); + // transform.y -= this.moveSpeed * this._moveScale * Time.detail ; + } + + // if (Input.GetKey(KeyCode.E)) + // transform.position += transform.up * speed * Time.deltaTime; + // if (Input.GetKey(KeyCode.Q)) + // transform.position -= transform.up * speed * Time.deltaTime; + } + + /** + * @internal + */ + public destroy(): void { + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_WHEEL, this.mouseWheel, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_UP, this.mouseUp, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_DOWN, this.mouseDown, this); + + Engine3D.inputSystem.removeEventListener(KeyEvent.KEY_UP, this.keyUp, this); + Engine3D.inputSystem.removeEventListener(KeyEvent.KEY_DOWN, this.keyDown, this); + super.destroy(); + } +} diff --git a/src/engine/components/controller/HoverCameraController.ts b/src/engine/components/controller/HoverCameraController.ts new file mode 100644 index 00000000..5a8834e3 --- /dev/null +++ b/src/engine/components/controller/HoverCameraController.ts @@ -0,0 +1,264 @@ +import { Camera3D, clamp, ComponentBase, Engine3D, Object3D, PointerEvent3D, Quaternion, Time, Vector3, Vector3Ex } from "../../.."; +import { Object3DUtil } from "../../util/Object3DUtil"; + +/** + * Hovering camera controller + * @group CameraController + */ +export class HoverCameraController extends ComponentBase { + /** + * camera controlling + */ + public camera: Camera3D; + + /** + * The closest distance that the mouse wheel can operate + */ + public minDistance: number = 0.1; + + /** + * The farthest distance that the mouse wheel can operate + */ + public maxDistance: number = 500; + + /** + * Smoothing coefficient of rolling angle + */ + public rollSmooth: number = 15.0; + + /** + * Smoothing coefficient of dragging + */ + public dragSmooth: number = 20; + + /** + * Smoothing coefficient of rolling + */ + public wheelSmooth: number = 10; + + /** + * Mouse scrolling step coefficient + */ + public wheelStep: number = 0.002; + + /** + * Right mouse movement coefficient + */ + public mouseRightFactor: number = 0.5; + + /** + * Left mouse movement coefficient + */ + public mouseLeftFactor: number = 20; + + /** + * Whether to enable smooth mode + */ + public smooth: boolean = true; + + /** + * @internal + */ + private _wheelStep: number = 0.002; + + private _distance: number = 0; + + /** + * Distance between camera and target + */ + public distance: number = 10; + private _roll: number = 0; + + /** + * Roll angle around y-axis + */ + public roll: number = 0; + private _pitch: number = 0; + + /** + * Pitch angle around x-axis + */ + public pitch: number = 0; + + private _currentPos: Object3D; + + /** + * @internal + */ + private _targetPos: Object3D; + + private _mouseLeftDown: boolean = false; + private _mouseRightDown: boolean = false; + private _bottomClamp: number = 89.99; + private _topClamp: number = -89.99; + private _tempDir = new Vector3(); + private _tempPos = new Vector3(); + + /** + * @constructor + */ + constructor() { + super(); + this.serializeTag = 'dont-serialize'; + this._currentPos = new Object3D(); + this._targetPos = new Object3D(); + } + + /** + * @internal + */ + protected start(): void { + this.camera = this.object3D.getOrAddComponent(Camera3D); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_DOWN, this.onMouseDown, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_MOVE, this.onMouseMove, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_UP, this.onMouseUp, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_WHEEL, this.onMouseWheel, this); + + } + + /** + * Initialize Camera + * @param roll Roll angle around y-axis + * @param pitch Pitch angle around x-axis + * @param distance max distance to target + * @param target coordinates of the target + */ + public setCamera(roll: number, pitch: number, distance: number, target?: Vector3) { + this.roll = roll; + this.pitch = pitch; + this.distance = distance; + this.maxDistance = distance * 1.2; + if (target) { + this._targetPos.transform.localPosition.copy(target); + } + } + + public focusByBounds(obj: Object3D) { + let bounds = Object3DUtil.genMeshBounds(obj); + this.target = bounds.center; + console.log(bounds.size); + console.log(bounds.center); + } + + /** + * Set target position + */ + public set target(target: Vector3) { + this._targetPos.transform.localPosition.copy(target); + } + + /** + * Get target position + * @return {Vector3} + */ + public get target(): Vector3 { + return this._targetPos.transform.localPosition; + } + + private onMouseWheel(e: PointerEvent3D) { + if (!this.enable) return; + this._wheelStep = (this.wheelStep * Vector3Ex.distance(this._currentPos.transform.worldPosition, this.camera.transform.worldPosition)) / 10; + this.distance -= Engine3D.inputSystem.wheelDelta * this._wheelStep; + this.distance = clamp(this.distance, this.minDistance, this.maxDistance); + } + + private onMouseDown(e: PointerEvent3D) { + if (!this.enable) return; + switch (e.mouseCode) { + case 0: + this._mouseLeftDown = true; + break; + case 1: + break; + case 2: + this._mouseRightDown = true; + break; + default: + break; + } + } + + private onMouseUp(e: PointerEvent3D) { + // if (!this._enable) return; + this._mouseLeftDown = false; + this._mouseRightDown = false; + // console.log("mouseup"); + } + + /** + * @internal + */ + private onMouseMove(e: PointerEvent3D) { + // return; + if (!this.enable) return; + if (this._mouseRightDown) { + let p = 0.25; //this.distance / (this.camera.far - this.camera.near); + let f = this.camera.transform.forward; + Vector3Ex.mulScale(f, e.movementY * p * this.camera.aspect, Vector3.HELP_1); + this._targetPos.x += Vector3.HELP_1.x * this.mouseRightFactor; + // this._targetPos.y -= Vector3.HELP_1.y; + this._targetPos.z += Vector3.HELP_1.z * this.mouseRightFactor; + + let f2 = this.camera.transform.right; + Vector3Ex.mulScale(f2, -e.movementX * p, Vector3.HELP_1); + this._targetPos.x -= Vector3.HELP_1.x * this.mouseRightFactor; + // this._targetPos.y -= Vector3.HELP_1.y; + this._targetPos.z -= Vector3.HELP_1.z * this.mouseRightFactor; + } + + if (this._mouseLeftDown) { + this.roll -= e.movementX * Time.delta * 0.001 * this.mouseLeftFactor; + this.pitch -= e.movementY * Time.delta * 0.001 * this.mouseLeftFactor; + this.pitch = clamp(this.pitch, this._topClamp, this._bottomClamp); + } + } + + public onUpdate(): void { + if (!this.enable) return; + + let dt = clamp(Time.delta, 0.0, 0.016); + if (this.smooth) { + this._currentPos.x += (this._targetPos.x - this._currentPos.x) * dt * this.dragSmooth; + this._currentPos.y += (this._targetPos.y - this._currentPos.y) * dt * this.dragSmooth; + this._currentPos.z += (this._targetPos.z - this._currentPos.z) * dt * this.dragSmooth; + + this._distance += (this.distance - this._distance) * dt * this.wheelSmooth; + + this._roll += (this.roll - this._roll) * dt * this.rollSmooth; + this._pitch += (this.pitch - this._pitch) * dt * this.rollSmooth; + } else { + this._currentPos.x = this._targetPos.x; + this._currentPos.y = this._targetPos.y; + this._currentPos.z = this._targetPos.z; + + this._distance = this.distance; + + this._roll = this.roll; + this._pitch = this.pitch; + } + + this._tempDir.set(0, 0, 1); + + let q = Quaternion.HELP_0; + q.fromEulerAngles(this._pitch, this._roll, 0.0); + this._tempDir.applyQuaternion(q); + + this._tempPos = Vector3Ex.mulScale(this._tempDir, this._distance, this._tempPos); + this._tempPos.add(this._currentPos.transform.localPosition, this._tempPos); + + this.transform.lookAt(this._tempPos, this._currentPos.transform.localPosition, Vector3.UP); + this.camera.lookTarget.copy(this._currentPos.transform.localPosition); + } + + /** + * @internal + */ + public destroy() { + this.camera = null; + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_DOWN, this.onMouseDown, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_MOVE, this.onMouseMove, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_UP, this.onMouseUp, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_WHEEL, this.onMouseWheel, this); + super.destroy(); + } +} diff --git a/src/engine/components/controller/ThirdPersonCameraController.ts b/src/engine/components/controller/ThirdPersonCameraController.ts new file mode 100644 index 00000000..921fd0ec --- /dev/null +++ b/src/engine/components/controller/ThirdPersonCameraController.ts @@ -0,0 +1,66 @@ +import { Camera3D, ComponentBase, Engine3D, Object3D, PointerEvent3D, Vector3 } from "../../.."; + +/** + * @internal + * @group CameraController + */ +export class ThirdPersonCameraController extends ComponentBase { + public focus: Object3D; + private _rotation: Vector3 = new Vector3(45, 0, 0); + + public distance: number = 5; + + private _camera: Camera3D; + + constructor() { + super(); + this.serializeTag = 'dont-serialize'; + } + + protected start() { + this._camera = this.object3D.getOrAddComponent(Camera3D); + if (!this._camera) { + console.error('ThirdPersonCameraController need camera'); + return; + } + + if (!this.focus) { + console.error('ThirdPersonCameraController need target'); + return; + } + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_WHEEL, this.mouseWheel, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_UP, this.mouseUp, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_DOWN, this.mouseDown, this); + } + + private mouseDown(e: PointerEvent3D) { + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_MOVE, this.mouseMove, this); + } + + private mouseUp(e: PointerEvent3D) { + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_MOVE, this.mouseMove, this); + } + + private mouseMove(e: PointerEvent3D) { + this._rotation.y += e.movementX * 0.01; + this._rotation.x += e.movementY * 0.01; + } + + private mouseWheel(e: PointerEvent3D) { + this.distance += Engine3D.inputSystem.wheelDelta * 0.1; + } + + public onUpdate() { + let vec = new Vector3(); + this._camera.transform.forward.scaleToRef(this.distance, vec); + var focusPoint = this.focus.transform.worldPosition; + this._camera.transform.localPosition = focusPoint.subtract(vec); + } + + public destroy(): void { + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_WHEEL, this.mouseWheel, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_UP, this.mouseUp, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_DOWN, this.mouseDown, this); + super.destroy(); + } +} From d5b850a43f8c7268c1cd937851101e6c946c2b79 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Mon, 24 Apr 2023 16:23:19 +0800 Subject: [PATCH 047/100] feat(render): add render framework (#57) add engine render frame work --- .../gfx/graphics/webGpu/core/Camera3D.ts | 520 ++++++++++++++++++ .../gfx/graphics/webGpu/core/CameraType.ts | 5 + .../gfx/graphics/webGpu/core/CubeCamera.ts | 73 +++ .../webGpu/core/PointShadowCubeCamera.ts | 89 +++ .../gfx/graphics/webGpu/core/ViewQuad.ts | 87 +++ .../gfx/renderJob/collect/CollectInfo.ts | 16 + .../renderJob/collect/EntityBatchCollect.ts | 34 ++ .../gfx/renderJob/collect/EntityCollect.ts | 245 +++++++++ .../gfx/renderJob/collect/RenderGroup.ts | 11 + .../renderJob/collect/ShadowLightsCollect.ts | 165 ++++++ .../gfx/renderJob/color/ColorPassRenderer.ts | 123 +++++ .../gfx/renderJob/config/RTResourceConfig.ts | 9 + .../gfx/renderJob/config/RenderLayer.ts | 30 + .../gfx/renderJob/frame/GBufferFrame.ts | 85 +++ .../gfx/renderJob/frame/ProbeGBufferFrame.ts | 46 ++ src/engine/gfx/renderJob/frame/RTFrame.ts | 47 ++ .../gfx/renderJob/frame/RTResourceMap.ts | 99 ++++ .../gfx/renderJob/jobs/ForwardRenderJob.ts | 75 +++ src/engine/gfx/renderJob/jobs/RenderMap.ts | 42 ++ src/engine/gfx/renderJob/jobs/RendererJob.ts | 303 ++++++++++ .../renderJob/occlusion/OcclusionSystem.ts | 101 ++++ .../renderJob/passRenderer/RenderContext.ts | 80 +++ .../renderJob/passRenderer/RendererBase.ts | 231 ++++++++ .../preDepth/PreDepthPassRenderer.ts | 105 ++++ .../gfx/renderJob/preDepth/ZCullingCompute.ts | 42 ++ .../gfx/renderJob/state/RendererMask.ts | 34 ++ .../gfx/renderJob/state/RendererPassState.ts | 40 ++ .../gfx/renderJob/state/RendererType.ts | 17 + src/engine/setting/EngineSetting.ts | 51 ++ 29 files changed, 2805 insertions(+) create mode 100644 src/engine/gfx/graphics/webGpu/core/Camera3D.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/CameraType.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/CubeCamera.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/PointShadowCubeCamera.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/ViewQuad.ts create mode 100644 src/engine/gfx/renderJob/collect/CollectInfo.ts create mode 100644 src/engine/gfx/renderJob/collect/EntityBatchCollect.ts create mode 100644 src/engine/gfx/renderJob/collect/EntityCollect.ts create mode 100644 src/engine/gfx/renderJob/collect/RenderGroup.ts create mode 100644 src/engine/gfx/renderJob/collect/ShadowLightsCollect.ts create mode 100644 src/engine/gfx/renderJob/color/ColorPassRenderer.ts create mode 100644 src/engine/gfx/renderJob/config/RTResourceConfig.ts create mode 100644 src/engine/gfx/renderJob/config/RenderLayer.ts create mode 100644 src/engine/gfx/renderJob/frame/GBufferFrame.ts create mode 100644 src/engine/gfx/renderJob/frame/ProbeGBufferFrame.ts create mode 100644 src/engine/gfx/renderJob/frame/RTFrame.ts create mode 100644 src/engine/gfx/renderJob/frame/RTResourceMap.ts create mode 100644 src/engine/gfx/renderJob/jobs/ForwardRenderJob.ts create mode 100644 src/engine/gfx/renderJob/jobs/RenderMap.ts create mode 100644 src/engine/gfx/renderJob/jobs/RendererJob.ts create mode 100644 src/engine/gfx/renderJob/occlusion/OcclusionSystem.ts create mode 100644 src/engine/gfx/renderJob/passRenderer/RenderContext.ts create mode 100644 src/engine/gfx/renderJob/passRenderer/RendererBase.ts create mode 100644 src/engine/gfx/renderJob/preDepth/PreDepthPassRenderer.ts create mode 100644 src/engine/gfx/renderJob/preDepth/ZCullingCompute.ts create mode 100644 src/engine/gfx/renderJob/state/RendererMask.ts create mode 100644 src/engine/gfx/renderJob/state/RendererPassState.ts create mode 100644 src/engine/gfx/renderJob/state/RendererType.ts create mode 100644 src/engine/setting/EngineSetting.ts diff --git a/src/engine/gfx/graphics/webGpu/core/Camera3D.ts b/src/engine/gfx/graphics/webGpu/core/Camera3D.ts new file mode 100644 index 00000000..e12c0877 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/Camera3D.ts @@ -0,0 +1,520 @@ +import { ComponentBase } from '../components/ComponentBase'; +import { Engine3D } from '../Engine3D'; +import { HaltonSeq } from '../math/HaltonSeq'; +import { MathUtil } from '../math/MathUtil'; +import { Matrix4, matrixMultiply } from '../math/Matrix4'; +import { Ray } from '../math/Ray'; +import { Rect } from '../math/Rect'; +import { Vector2 } from '../math/Vector2'; +import { Vector3 } from '../math/Vector3'; +import { CameraUtil } from '../util/CameraUtil'; +import { Frustum } from './bound/Frustum'; +import { CameraType } from './CameraType'; +import { CubeCamera } from './CubeCamera'; +import { ComponentType } from "../util/SerializeDefine"; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; + +/** + * Camera components + * @group Components + */ +export class Camera3D extends ComponentBase { + /** + * camera Perspective + */ + public fov: number = 1; + + /** + * camera use name + */ + public name: string; + + /** + * Viewport width and height Scale + */ + public aspect: number = 1; + + /** + * camera near plane + */ + public near: number = 1; + + /** + * camera far plane + */ + public far: number = 5000; + + /** + * camera view port size + */ + public viewPort: Rect = new Rect(); + + /** + * camera frustum + */ + public frustum: Frustum; + + /** + * this camera is shadow camera + */ + public isShadowCamera: boolean = false; + + /** + * @internal + */ + public _projectionMatrixInv: Matrix4 = new Matrix4(); + private _projectionMatrix: Matrix4 = new Matrix4(); + private _viewMatrix: Matrix4 = new Matrix4(); + private _unprojection: Matrix4 = new Matrix4(); + private _pvMatrixInv: Matrix4 = new Matrix4(); + private _pvMatrix: Matrix4 = new Matrix4(); + private _halfw: number; + private _halfh: number; + private _ray: Ray; + + /** + * @internal + */ + public get projectionMatrix() { + return this._projectionMatrix; + } + + + /** + * camera look at from where point + */ + public lookTarget: Vector3; + + /** + * camera type + */ + public type: CameraType = CameraType.perspective; + + /** + * @internal + */ + public cubeShadowCameras: CubeCamera[] = []; + + + constructor() { + super(); + this.componentType = ComponentType.camera3D; + } + + protected init() { + super.init(); + this._ray = new Ray(); + this.frustum = new Frustum(); + + this.viewPort.x = 0; + this.viewPort.y = 0; + this.viewPort.w = webGPUContext.presentationSize[0]; + this.viewPort.h = webGPUContext.presentationSize[1]; + this.lookTarget = new Vector3(0, 0, 0); + } + + /** + * @internal + */ + protected start() { } + + /** + * Create a perspective camera + * @param fov + * @param aspect + * @param near + * @param far + */ + public perspective(fov: number, aspect: number, near: number, far: number) { + this.fov = fov; + this.aspect = aspect; + this.near = near; + this.far = far; + this._projectionMatrix.perspective(fov, aspect, near, far); + this.type = CameraType.perspective; + } + + /** + * Create an orthographic camera + * @param width screen width + * @param height screen height + * @param znear camera near plane + * @param zfar camera far plane + */ + public ortho(width: number, height: number, znear: number, zfar: number) { + this.near = Math.max(znear, 0.1); + this.far = zfar; + this._projectionMatrix.ortho(width, height, znear, zfar); + this.type = CameraType.ortho; + } + + /** + * + * Create an orthographic camera + * @param l + * @param r + * @param b + * @param t + * @param zn camera near plane + * @param zf camera far plane + */ + public orthoOffCenter(l: number, r: number, b: number, t: number, zn: number, zf: number) { + this.near = Math.max(zn, 0.01); + this.far = zf; + this._projectionMatrix.orthoOffCenter(l, r, b, t, zn, zf); + this.type = CameraType.ortho; + } + + public orthoZo(l: number, r: number, b: number, t: number, zn: number, zf: number) { + this.near = Math.max(zn, 0.01); + this.far = zf; + this._projectionMatrix.orthoZO(l, r, b, t, zn, zf); + this.type = CameraType.ortho; + } + + /** + * + * view invert matrix + */ + public get viewMatrix(): Matrix4 { + this._viewMatrix.copyFrom(this.transform.worldMatrix); + this._viewMatrix.invert(); + return this._viewMatrix; + } + + /** + * + * shadow camera view invert matrix + */ + public get shadowViewMatrix(): Matrix4 { + this._viewMatrix.copyFrom(this.transform.worldMatrix); + this._viewMatrix.appendScale(1, 1.0, 1.0); + this._viewMatrix.invert(); + return this._viewMatrix; + } + + /** + * world space object to screen + * @param n world space + * @param target Creating an orthogonal camera with 2D screen coordinates that default to null will return a new object + */ + public object3DToScreenRay(n: Vector3, target: Vector3 = null): Vector3 { + if (!target) { + target = new Vector3(0, 0, 0, 1); + } + this._halfw = this.viewPort.width * 0.5; + this._halfh = this.viewPort.height * 0.5; + + MathUtil.transformVector(this.viewMatrix, n, target); + this.project(target, target); + + target.x = this._halfw + target.x * this._halfw; + target.y = this.viewPort.height - (this._halfh - target.y * this._halfh); + return target; + } + + /** + * Convert 2D screen coordinates to 3D coordinates as world space + * @param n 2D screen coordinates + * @param target 3D coordinates as world space + */ + public screenRayToObject3D(n: Vector3, target: Vector3 = null): Vector3 { + if (!target) { + target = new Vector3(); + } + this._halfw = this.viewPort.width * 0.5; + this._halfh = this.viewPort.height * 0.5; + + let fScreenPtX = n.x; + let fScreenPtY = n.y; + let m_fRadius = 1; + target.x = fScreenPtX / this.viewPort.width - 0.25; + target.y = fScreenPtY / this.viewPort.height - 0.25; + + this.unProject(target.x, target.y, n.z, target); + // this.transform.localMatrix.transformVector4(target, target); + + return target; + } + + /** + * get project * view matrix + */ + public get pvMatrix(): Matrix4 { + matrixMultiply(this._projectionMatrix, this.viewMatrix, this._pvMatrix); + return this._pvMatrix; + } + + public get pvMatrix2(): Matrix4 { + matrixMultiply(this._projectionMatrix, this.transform.worldMatrix, this._pvMatrix); + return this._pvMatrix; + } + + /** + * get (project * view) invert matrix + */ + public get pvMatrixInv(): Matrix4 { + let pvMatrixInv = this._pvMatrixInv.copyFrom(this.pvMatrix); + pvMatrixInv.invert(); + return pvMatrixInv; + } + + /** + * get project invert matrix + */ + public get projectionMatrixInv(): Matrix4 { + this._projectionMatrixInv.copyFrom(this._projectionMatrix); + this._projectionMatrixInv.invert(); + return this._projectionMatrixInv; + } + + /** + * Enter a 3D coordinate point to obtain the projected coordinate point + * @param nX 3D x + * @param nY 3D y + * @param sZ 3D z + * @param target The projected coordinate point can be empty + * @returns Coordinates after projection + */ + public unProject(nX: number, nY: number, sZ: number, target?: Vector3): Vector3 { + if (!target) target = new Vector3(); + target.x = nX; + target.y = -nY; + target.z = sZ; + target.w = 1.0; + + target.x *= sZ; + target.y *= sZ; + + this._unprojection.copyFrom(this._projectionMatrix); + this._unprojection.invert(); + + MathUtil.transformVector(this._unprojection, target, target); + target.z = sZ; + + return target; + } + + /** + * Enter the projected coordinate points to obtain a 3D coordinate point. + * @param n Coordinate points after photography + * @param target 3D coordinate points + * @returns 3D coordinate points + */ + private project(n: Vector3, target: Vector3): Vector3 { + this._projectionMatrix.perspectiveMultiplyPoint3(n, target); + target.x = target.x / target.w; + target.y = -target.y / target.w; + target.z = n.z; + return target; + } + + /** + * Enter the 2D coordinates of the screen to obtain a ray that starts from the camera position and passes through the corresponding 3D position of the screen. + * @param viewPortPosX Screen x coordinate + * @param viewPortPosY Screen y coordinate + * @returns ray + */ + public screenPointToRay(viewPortPosX: number, viewPortPosY: number): Ray { + let ray: Ray = this._ray; + + let start = CameraUtil.UnProjection(viewPortPosX, viewPortPosY, 0.01, this); + let end = CameraUtil.UnProjection(viewPortPosX, viewPortPosY, 1.0, this); + end = end.subtract(start).normalize(); + + ray.origin.copyFrom(start); + // ray.dir.copyFrom(end); + ray.direction = end; + + return ray; + } + + /** + * Convert screen coordinates to world coordinates + * @param viewPortPosX Screen x coordinate + * @param viewPortPosY Screen y coordinate + * @param z Screen z coordinate + * @returns World coordinates + */ + public screenPointToWorld(viewPortPosX: number, viewPortPosY: number, z: number): Vector3 { + let pos = CameraUtil.UnProjection(viewPortPosX, viewPortPosY, z, this); + return pos; + } + + /** + * Convert world coordinates to screen coordinates + * @param viewPortPosX Screen x coordinate + * @param viewPortPosY Screen y coordinate + * @param z Screen z coordinate + * @returns World coordinates + */ + public worldToScreenPoint(point: Vector3, target?: Vector3): Vector3 { + let pos = CameraUtil.Projection(point, this, target); + return pos; + } + + /** + * Current object's gaze position (global) (modified by its own global transformation) + * @param pos Own position (global) + * @param target Location of the target (global) + * @param up Upward direction + */ + public lookAt(pos: Vector3, target: Vector3, up: Vector3 = Vector3.Y_AXIS) { + this.transform.lookAt(pos, target, up); + if (target) this.lookTarget.copyFrom(target); + } + + /** + * @internal + */ + public resetProjectMatrix() { + this.perspective(this.fov, this.aspect, this.near, this.far); + } + + /** + * @internal + */ + public onUpdate() { + if (this.type == CameraType.perspective) { + this.aspect = webGPUContext.aspect; + this.resetProjectMatrix(); + } + if (this._useJitterProjection) { + this.getJitteredProjectionMatrix(); + } + this.frustum.update(this.pvMatrix); + } + + private _haltonSeq: HaltonSeq; + private _jitterOffsetList: Vector2[]; + private _useJitterProjection: boolean = false; + private _jitterFrameIndex: number = 0; + private _sampleIndex: number = 0; + private _jitterX: number = 0; + private _jitterY: number = 0; + + public get jitterFrameIndex() { + return this._jitterFrameIndex; + } + + public get jitterX(): number { + return this._jitterX; + } + + public get jitterY(): number { + return this._jitterY; + } + + public enableJitterProjection(value: boolean) { + this._jitterFrameIndex = 0; + this._useJitterProjection = value; + this._haltonSeq ||= new HaltonSeq(); + this._jitterOffsetList = []; + for (let i = 0; i < 8; i++) { + let offset = this.generateRandomOffset(); + this._jitterOffsetList.push(offset); + } + this._jitterOffsetList.reverse(); + } + + private generateRandomOffset(): Vector2 { + let offset = new Vector2(HaltonSeq.get((this._sampleIndex & 1023) + 1, 2) - 0.5, HaltonSeq.get((this._sampleIndex & 1023) + 1, 3) - 0.5); + const k_SampleCount = 8; + if (++this._sampleIndex >= k_SampleCount) this._sampleIndex = 0; + + return offset; + } + + private getJitteredProjectionMatrix() { + let setting = Engine3D.setting.render.postProcessing.taa; + let mat = this._projectionMatrix; + let temporalJitterScale: number = setting.temporalJitterScale; + let offsetIndex = this._jitterFrameIndex % setting.jitterSeedCount; + let num1 = this._jitterOffsetList[offsetIndex].x * temporalJitterScale; + let num2 = this._jitterOffsetList[offsetIndex].y * temporalJitterScale; + + let jitX = mat.get(0, 2); + let jitY = mat.get(1, 2); + + this._jitterX = num1 / this.viewPort.width; + this._jitterY = num2 / this.viewPort.height; + jitX += this._jitterX; + jitY += this._jitterY; + mat.set(0, 2, jitX); + mat.set(1, 2, jitY); + + this._jitterFrameIndex++; + } + + /** + * + * @param shadowCamera + * @param lightDir + */ + public getCastShadowLightSpaceMatrix(shadowCamera: Camera3D, lightDir: Vector3) { + let frustum: Frustum = this.frustum; + + let proMat = this.projectionMatrixInv; + let wMat = this.transform.worldMatrix; + Matrix4.helpMatrix.copyFrom(proMat); + Matrix4.helpMatrix.multiply(wMat); + + frustum.setFrustumCorners(Matrix4.helpMatrix); + + let corners = frustum.corners; + let center = Vector3.HELP_6; + center.set(0, 0, 0); + + for (const iterator of corners) { + center.add(iterator, center); + } + + center.div(corners.length, center); + + let lookTarget = Vector3.HELP_5; + lookTarget.copyFrom(center); + Vector3.HELP_0.copyFrom(lightDir); + lookTarget.add(Vector3.HELP_0, lookTarget); + shadowCamera.lookAt(lookTarget, center, Vector3.UP); + + let minX = Number.MAX_VALUE; + let maxX = -Number.MAX_VALUE; + let minY = Number.MAX_VALUE; + let maxY = -Number.MAX_VALUE; + let minZ = Number.MAX_VALUE; + let maxZ = -Number.MAX_VALUE; + + for (const iterator of corners) { + minX = Math.min(minX, iterator.x); + maxX = Math.max(maxX, iterator.x); + minY = Math.min(minY, iterator.y); + maxY = Math.max(maxY, iterator.y); + minZ = Math.min(minZ, iterator.z); + maxZ = Math.max(maxZ, iterator.z); + } + + // Tune this parameter according to the scene + let zMult = Engine3D.setting.shadow.shadowQuality; + + if (minZ < 0) { + minZ *= zMult; + } else { + minZ /= zMult; + } + if (maxZ < 0) { + maxZ /= zMult; + } else { + maxZ *= zMult; + } + + shadowCamera.orthoOffCenter(minX, maxX, minY, maxY, minZ, maxZ); + } + + public getWorldDirection(target?: Vector3) { + target ||= new Vector3(); + this.transform.updateWorldMatrix(); + const e = this.transform._worldMatrix.rawData; + return target.set(-e[8], -e[9], -e[10]).normalize(); + } + +} diff --git a/src/engine/gfx/graphics/webGpu/core/CameraType.ts b/src/engine/gfx/graphics/webGpu/core/CameraType.ts new file mode 100644 index 00000000..8ada4e45 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/CameraType.ts @@ -0,0 +1,5 @@ +export enum CameraType { + ortho, + perspective, + shadow, +} \ No newline at end of file diff --git a/src/engine/gfx/graphics/webGpu/core/CubeCamera.ts b/src/engine/gfx/graphics/webGpu/core/CubeCamera.ts new file mode 100644 index 00000000..0a287425 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/CubeCamera.ts @@ -0,0 +1,73 @@ +import { CameraType } from '../..'; +import { Vector3 } from '../math/Vector3'; +import { CameraUtil } from '../util/CameraUtil'; +import { Camera3D } from './Camera3D'; +import { Object3D } from './entities/Object3D'; + +/** + * A cube camera containing 6 perspective cameras. + * @internal + * @group Entity + */ +export class CubeCamera extends Object3D { + public up_camera: Camera3D; + public down_camera: Camera3D; + public left_camera: Camera3D; + public right_camera: Camera3D; + public front_camera: Camera3D; + public back_camera: Camera3D; + + /** + * + * Construct a cube camera with 6 perspective cameras, + * @param near near plane + * @param far far plane + */ + constructor(near: number = 0.001, far: number = 10000, fov: number = 90, isShadow: boolean = false) { + super(); + this.initCubeCamera(near, far, fov, isShadow); + } + + initCubeCamera(near: number, far: number, fov: number = 90, isShadow: boolean = false) { + this.up_camera = CameraUtil.createCamera3DObject(this, 'up'); + this.down_camera = CameraUtil.createCamera3DObject(this, 'down'); + this.left_camera = CameraUtil.createCamera3DObject(this, 'left'); + this.right_camera = CameraUtil.createCamera3DObject(this, 'right'); + this.front_camera = CameraUtil.createCamera3DObject(this, 'front'); + this.back_camera = CameraUtil.createCamera3DObject(this, 'back'); + + this.up_camera.isShadowCamera = isShadow; + this.down_camera.isShadowCamera = isShadow; + this.left_camera.isShadowCamera = isShadow; + this.right_camera.isShadowCamera = isShadow; + this.front_camera.isShadowCamera = isShadow; + this.back_camera.isShadowCamera = isShadow; + + let aspect = 1.0; // webGPUContext.aspect; + this.up_camera.perspective(fov, aspect, near, far); + this.up_camera.lookAt(Vector3.ZERO, Vector3.UP, Vector3.DOWN); + + this.down_camera.perspective(fov, aspect, near, far); + this.down_camera.lookAt(Vector3.ZERO, Vector3.DOWN, Vector3.DOWN); + + this.left_camera.perspective(fov, aspect, near, far); + this.left_camera.lookAt(Vector3.ZERO, Vector3.LEFT); + + this.right_camera.perspective(fov, aspect, near, far); + this.right_camera.lookAt(Vector3.ZERO, Vector3.RIGHT); + + this.front_camera.perspective(fov, aspect, near, far); + this.front_camera.lookAt(Vector3.ZERO, Vector3.FORWARD); + + this.back_camera.perspective(fov, aspect, near, far); + this.back_camera.lookAt(Vector3.ZERO, Vector3.BACK); + + this.up_camera.type = CameraType.shadow; + this.down_camera.type = CameraType.shadow; + this.left_camera.type = CameraType.shadow; + this.right_camera.type = CameraType.shadow; + this.front_camera.type = CameraType.shadow; + this.back_camera.type = CameraType.shadow; + } + +} diff --git a/src/engine/gfx/graphics/webGpu/core/PointShadowCubeCamera.ts b/src/engine/gfx/graphics/webGpu/core/PointShadowCubeCamera.ts new file mode 100644 index 00000000..877266d1 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/PointShadowCubeCamera.ts @@ -0,0 +1,89 @@ +import { Vector3 } from '../math/Vector3'; +import { CameraUtil } from '../util/CameraUtil'; +import { Camera3D } from './Camera3D'; +import { CameraType } from './CameraType'; +import { Object3D } from './entities/Object3D'; + +/** + * A cubic camera containing 6 perspective cameras. + * @internal + * @group Entity + */ +export class PointShadowCubeCamera extends Object3D { + public up_camera: Camera3D; + public down_camera: Camera3D; + public left_camera: Camera3D; + public right_camera: Camera3D; + public front_camera: Camera3D; + public back_camera: Camera3D; + public set label(v: string) { + this.up_camera.name = v + 'up'; + this.down_camera.name = v + 'down'; + this.left_camera.name = v + 'left'; + this.right_camera.name = v + 'right'; + this.front_camera.name = v + 'front'; + this.back_camera.name = v + 'back'; + } + /** + * + * @constructor + * @param near distance from origin to near plane of frustum + * @param far distance from origin to far plane of frustum + */ + constructor(near: number = 0.001, far: number = 10000, fov: number = 90, isShadow: boolean = false) { + super(); + this.initCubeCamera(near, far, fov, isShadow); + } + + initCubeCamera(near: number, far: number, fov: number = 90, isShadow: boolean = false) { + this.up_camera = CameraUtil.createCamera3DObject(this, 'up'); + this.down_camera = CameraUtil.createCamera3DObject(this, 'down'); + this.left_camera = CameraUtil.createCamera3DObject(this, 'left'); + this.right_camera = CameraUtil.createCamera3DObject(this, 'right'); + this.front_camera = CameraUtil.createCamera3DObject(this, 'front'); + this.back_camera = CameraUtil.createCamera3DObject(this, 'back'); + + this.up_camera.isShadowCamera = isShadow; + this.down_camera.isShadowCamera = isShadow; + this.left_camera.isShadowCamera = isShadow; + this.right_camera.isShadowCamera = isShadow; + this.front_camera.isShadowCamera = isShadow; + this.back_camera.isShadowCamera = isShadow; + + let aspect = 1.0; // webGPUContext.aspect; + this.up_camera.perspective(fov, aspect, near, far); + this.up_camera.lookAt(Vector3.ZERO, Vector3.UP, Vector3.DOWN); + this.up_camera.object3D.scaleX = -1; + this.up_camera.object3D.rotationY = 180; + + this.down_camera.perspective(fov, aspect, near, far); + this.down_camera.lookAt(Vector3.ZERO, Vector3.DOWN, Vector3.DOWN); + this.down_camera.object3D.scaleX = -1; + this.down_camera.object3D.rotationY = 180; + + this.left_camera.perspective(fov, aspect, near, far); + this.left_camera.lookAt(Vector3.ZERO, Vector3.LEFT); + this.left_camera.object3D.scaleX = -1; + + this.right_camera.perspective(fov, aspect, near, far); + this.right_camera.lookAt(Vector3.ZERO, Vector3.RIGHT); + this.right_camera.object3D.scaleX = -1; + + this.front_camera.perspective(fov, aspect, near, far); + this.front_camera.lookAt(Vector3.ZERO, Vector3.FORWARD); + this.front_camera.object3D.scaleX = -1; + + this.back_camera.perspective(fov, aspect, near, far); + this.back_camera.lookAt(Vector3.ZERO, Vector3.BACK); + this.back_camera.object3D.scaleX = -1; + + this.up_camera.type = CameraType.shadow; + this.down_camera.type = CameraType.shadow; + this.left_camera.type = CameraType.shadow; + this.right_camera.type = CameraType.shadow; + this.front_camera.type = CameraType.shadow; + this.back_camera.type = CameraType.shadow; + + } + +} diff --git a/src/engine/gfx/graphics/webGpu/core/ViewQuad.ts b/src/engine/gfx/graphics/webGpu/core/ViewQuad.ts new file mode 100644 index 00000000..93655478 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/ViewQuad.ts @@ -0,0 +1,87 @@ +import { QuadGlsl_fs, QuadGlsl_vs } from '../assets/shader/glsl/Quad_glsl'; +import { ShaderLib } from '../assets/shader/ShaderLib'; +import { MeshRenderer } from '../components/renderer/MeshRenderer'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { UniformNode } from '../gfx/graphics/webGpu/core/uniforms/UniformNode'; +import { WebGPUDescriptorCreator } from '../gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator'; +import { GPUCompareFunction } from '../gfx/graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +import { RTFrame } from '../gfx/renderJob/frame/RTFrame'; +import { RendererPassState } from '../gfx/renderJob/passRenderer/state/RendererPassState'; +import { BlendMode } from '../materials/BlendMode'; +import { MaterialBase } from '../materials/MaterialBase'; +import { Color } from '../math/Color'; +import { PlaneGeometry } from '../shape/PlaneGeometry'; +import { defaultRes } from '../textures/DefaultRes'; +import { VirtualTexture } from '../textures/VirtualTexture'; +import { Object3D } from './entities/Object3D'; +/** + * @internal + * @group Entity + */ +export class ViewQuad extends Object3D { + width: number = 128; + height: number = 128; + quadRenderer: MeshRenderer; + material: MaterialBase; + uniforms: { [key: string]: UniformNode }; + rendererPassState: RendererPassState; + + constructor(vs: string = 'QuadGlsl_vs', fs: string = 'QuadGlsl_fs', rtFrame: RTFrame, shaderUniforms?: { [uniName: string]: UniformNode }, multisample: number = 0, f: boolean = false) { + super(); + + let renderTexture = rtFrame ? rtFrame.attachments : []; + + ShaderLib.register("QuadGlsl_vs", QuadGlsl_vs); + ShaderLib.register("QuadGlsl_fs", QuadGlsl_fs); + + this.material = new MaterialBase(); + this.material.setShader(vs, fs); + let shader = this.material.getShader(); + this.material.blendMode = BlendMode.NONE; + let shaderState = shader.shaderState; + shaderState.frontFace = `cw`; + // shaderState.cullMode = `back`; + shaderState.depthWriteEnabled = false; + shaderState.depthCompare = GPUCompareFunction.always; + shaderState.multisample = multisample; + this.uniforms = shader.uniforms = shaderUniforms ? shaderUniforms : { color: new UniformNode(new Color()) }; + + this.quadRenderer = this.addComponent(MeshRenderer); + this.quadRenderer.material = this.material; + this.quadRenderer.castGI = false; + this.quadRenderer.castShadow = false; + this.quadRenderer.drawType = f ? 2 : 0; + // this.quadRenderer.renderOrder = 99999; + this.quadRenderer.geometry = new PlaneGeometry(100, 100, 1, 1); + this.quadRenderer[`__start`](); + this.quadRenderer[`_enable`] = true; + this.quadRenderer[`onEnable`](); + this.colorTexture = defaultRes.blackTexture; + + shader.setUniformFloat(`x`, 0); + shader.setUniformFloat(`y`, 0); + shader.setUniformFloat(`width`, 100); + shader.setUniformFloat(`height`, 100); + + // this.createRendererPassState(renderTargets, depth); + // this.rendererPassState = WebGPUDescriptorPool.createRendererPassState(renderTargets, shaderState.multisample>0 ? false : true); + this.rendererPassState = WebGPUDescriptorCreator.createRendererPassState(rtFrame, `load`); + if (shaderState.multisample > 0) { + this.rendererPassState.multisample = shaderState.multisample; + this.rendererPassState.multiTexture = webGPUContext.device.createTexture({ + size: { + width: webGPUContext.presentationSize[0], + height: webGPUContext.presentationSize[1], + }, + sampleCount: shaderState.multisample, + format: renderTexture.length > 0 ? renderTexture[0].format : webGPUContext.presentationFormat, + usage: GPUTextureUsage.RENDER_ATTACHMENT, + }) + } + } + + public set colorTexture(tex: Texture) { + this.material.baseMap = tex; + } +} diff --git a/src/engine/gfx/renderJob/collect/CollectInfo.ts b/src/engine/gfx/renderJob/collect/CollectInfo.ts new file mode 100644 index 00000000..a1f2c154 --- /dev/null +++ b/src/engine/gfx/renderJob/collect/CollectInfo.ts @@ -0,0 +1,16 @@ +import { RenderNode } from '../../../components/renderer/RenderNode'; +/** + * @internal + * @group Post + */ +export class CollectInfo { + public opaqueList: RenderNode[] = []; + public transparentList: RenderNode[] = []; + public offset: number = 0; + public sky: RenderNode; + public clean() { + this.opaqueList.length = 0; + this.transparentList.length = 0; + this.offset = 0; + } +} diff --git a/src/engine/gfx/renderJob/collect/EntityBatchCollect.ts b/src/engine/gfx/renderJob/collect/EntityBatchCollect.ts new file mode 100644 index 00000000..e13790ff --- /dev/null +++ b/src/engine/gfx/renderJob/collect/EntityBatchCollect.ts @@ -0,0 +1,34 @@ +import { RenderNode } from '../../../components/renderer/RenderNode'; +import { RendererType } from '../passRenderer/state/RendererType'; +import { RenderGroup } from './RenderGroup'; +/** + * @internal + * @group Post + */ +export class EntityBatchCollect { + public renderGroup: Map; + + constructor() { + this.renderGroup = new Map(); + } + + public collect_add(node: RenderNode) { + let g_key = ''; + let s_key = ''; + g_key += node.geometry.uuid; + for (let i = 0; i < node.materials.length; i++) { + const mat = node.materials[i]; + s_key += mat.renderShader.shaderVariant; + } + let key = g_key + s_key; + if (!this.renderGroup.has(key)) { + this.renderGroup.set(key, { + bundleMap: new Map(), + key: key, + renderNodes: [], + }); + } + if (this.renderGroup.get(key).renderNodes.indexOf(node) == -1) + this.renderGroup.get(key).renderNodes.push(node); + } +} diff --git a/src/engine/gfx/renderJob/collect/EntityCollect.ts b/src/engine/gfx/renderJob/collect/EntityCollect.ts new file mode 100644 index 00000000..d2f2d090 --- /dev/null +++ b/src/engine/gfx/renderJob/collect/EntityCollect.ts @@ -0,0 +1,245 @@ +import { Graphic3DBatchRenderer, Graphic3DFillRenderer, Graphic3DLineBatchRenderer, ReflectionProbeComponent, RendererMaskUtil, RenderLayer, RenderLayerUtil } from '../../../..'; +import { LightBase } from '../../../components/lights/LightBase'; +import { RenderNode } from '../../../components/renderer/RenderNode'; +import { SkyRenderer } from '../../../components/renderer/SkyRenderer'; +import { Scene3D } from '../../../core/Scene3D'; +import { Probe } from '../passRenderer/ddgi/Probe'; +import { CollectInfo } from './CollectInfo'; +import { EntityBatchCollect } from './EntityBatchCollect'; +import { RenderGroup } from './RenderGroup'; +/** + * @internal + * @group Post + */ +export class EntityCollect { + // private static _sceneRenderList: Map; + private _sceneLights: Map; + private _sceneGIProbes: Map; + private _sceneReflectionProbes: Map; + + private _source_opaqueRenderNodes: Map; + private _source_transparentRenderNodes: Map; + + private _graphics: Graphic3DBatchRenderer[]; + + private _op_renderGroup: Map; + private _tr_renderGroup: Map; + + public state: { + /** + * gi effect lighting change + */ + giLightingChange: boolean + } = { + giLightingChange: true + } + + public sky: SkyRenderer; + + private _collectInfo: CollectInfo; + + private static _instance: EntityCollect; + public static get instance() { + if (!this._instance) { + this._instance = new EntityCollect(); + } + return this._instance; + } + + constructor() { + // this._sceneRenderList = new Map(); + this._sceneLights = new Map(); + this._sceneGIProbes = new Map(); + this._sceneReflectionProbes = new Map(); + + this._source_opaqueRenderNodes = new Map(); + this._source_transparentRenderNodes = new Map(); + + this._graphics = []; + + this._op_renderGroup = new Map(); + this._tr_renderGroup = new Map(); + + this._collectInfo = new CollectInfo(); + } + + private getPashList(root: Scene3D, renderNode: RenderNode) { + if (renderNode[`renderOrder`] < 3000) { + return this._source_opaqueRenderNodes.get(root); + } else if (renderNode[`renderOrder`] >= 3000) { + return this._source_transparentRenderNodes.get(root); + } + } + + private sortRenderNode(list: RenderNode[], renderNode: RenderNode) { + for (let i = list.length - 1; i > 0; i--) { + const element = list[i]; + if (element[`renderOrder`] < renderNode[`renderOrder`]) { + list.push(renderNode); + return; + } + } + list.push(renderNode); + } + + public addRenderNode(root: Scene3D, renderNode: RenderNode) { + if (!root) return; + if (renderNode instanceof SkyRenderer) { + this.sky = renderNode; + } else if (renderNode instanceof Graphic3DBatchRenderer) { + if (this._graphics.indexOf(renderNode) == -1) { + this._graphics.push(renderNode); + } + } else if (!RenderLayerUtil.hasMask(renderNode.object3D.renderLayer, RenderLayer.None)) { + this.removeRenderNode(root, renderNode); + if (renderNode[`renderOrder`] < 3000) { + if (!this._op_renderGroup.has(root)) { + this._op_renderGroup.set(root, new EntityBatchCollect()); + } + this._op_renderGroup.get(root).collect_add(renderNode); + } else if (renderNode[`renderOrder`] >= 3000) { + if (!this._tr_renderGroup.has(root)) { + this._tr_renderGroup.set(root, new EntityBatchCollect()); + } + this._tr_renderGroup.get(root).collect_add(renderNode); + } + } else { + this.removeRenderNode(root, renderNode); + if (renderNode[`renderOrder`] < 3000) { + if (!this._source_opaqueRenderNodes.has(root)) { + this._source_opaqueRenderNodes.set(root, []); + } + this._source_opaqueRenderNodes.get(root).push(renderNode); + } else if (renderNode[`renderOrder`] >= 3000) { + if (!this._source_transparentRenderNodes.has(root)) { + this._source_transparentRenderNodes.set(root, []); + } + this._source_transparentRenderNodes.get(root).push(renderNode); + } + + let list = this.getPashList(root, renderNode); + let index = list.indexOf(renderNode); + if (index == -1) { + this.sortRenderNode(list, renderNode); + } + } + renderNode.object3D.renderNode = renderNode; + } + + public removeRenderNode(root: Scene3D, renderNode: RenderNode) { + if (renderNode instanceof SkyRenderer) { + this.sky = null; + } else if (!RenderLayerUtil.hasMask(renderNode.object3D.renderLayer, RenderLayer.None)) { + + } else { + let list = this.getPashList(root, renderNode); + if (list) { + let index = list.indexOf(renderNode); + if (index != -1) { + list.splice(index, 1); + } + } + } + } + + public addLight(root: Scene3D, light: LightBase) { + if (!this._sceneLights.has(root)) { + this._sceneLights.set(root, [light]); + } else { + let hasLight = this._sceneLights.get(root).indexOf(light) != -1; + if (!hasLight) + this._sceneLights.get(root).push(light); + } + } + + public removeLight(root: Scene3D, light: LightBase) { + if (this._sceneLights.has(root)) { + let list = this._sceneLights.get(root); + let index = list.indexOf(light); + if (index != -1) { + list.splice(index, 1); + } + } + } + + public addGIProbe(root: Scene3D, probe: Probe) { + if (!this._sceneGIProbes.has(root)) { + this._sceneGIProbes.set(root, [probe]); + } else { + this._sceneGIProbes.get(root).push(probe); + } + } + + public removeGIProbe(root: Scene3D, probe: Probe) { + if (this._sceneGIProbes.has(root)) { + let list = this._sceneGIProbes.get(root); + let index = list.indexOf(probe); + if (index != -1) { + list.splice(index, 1); + } + } + } + + + public addReflectionProbe(root: Scene3D, probe: ReflectionProbeComponent) { + if (!this._sceneReflectionProbes.has(root)) { + this._sceneReflectionProbes.set(root, [probe]); + } else { + this._sceneReflectionProbes.get(root).push(probe); + } + } + + public removeReflectionProbe(root: Scene3D, probe: ReflectionProbeComponent) { + if (this._sceneReflectionProbes.has(root)) { + let list = this._sceneReflectionProbes.get(root); + let index = list.indexOf(probe); + if (index != -1) { + list.splice(index, 1); + } + } + } + + public getLights(root: Scene3D): LightBase[] { + let list = this._sceneLights.get(root); + return list ? list : []; + } + + public getProbes(root: Scene3D) { + let list = this._sceneGIProbes.get(root); + return list ? list : []; + } + + public getReflectionProbes(root: Scene3D) { + let list = this._sceneReflectionProbes.get(root); + return list ? list : []; + } + + + public getRenderNodes(scene: Scene3D): CollectInfo { + this._collectInfo.clean(); + this._collectInfo.sky = this.sky; + + let list2 = this._source_opaqueRenderNodes.get(scene); + if (list2) { + this._collectInfo.opaqueList = list2.concat(); + this._collectInfo.offset = list2.length; + } + let list5 = this._source_transparentRenderNodes.get(scene); + if (list5) { + this._collectInfo.transparentList = list5.concat(); + } + return this._collectInfo; + } + + public getOpRenderGroup(scene: Scene3D): EntityBatchCollect { + return this._op_renderGroup.get(scene); + } + + public getTrRenderGroup(scene: Scene3D): EntityBatchCollect { + return this._tr_renderGroup.get(scene); + } + + public getGraphicList(): Graphic3DBatchRenderer[] { + return this._graphics; + } +} diff --git a/src/engine/gfx/renderJob/collect/RenderGroup.ts b/src/engine/gfx/renderJob/collect/RenderGroup.ts new file mode 100644 index 00000000..33ec5b1b --- /dev/null +++ b/src/engine/gfx/renderJob/collect/RenderGroup.ts @@ -0,0 +1,11 @@ +import { RenderNode } from '../../../components/renderer/RenderNode'; +import { RendererType } from '../passRenderer/state/RendererType'; +/** + * @internal + * @group Post + */ +export type RenderGroup = { + key: string; + bundleMap: Map; + renderNodes: RenderNode[]; +}; diff --git a/src/engine/gfx/renderJob/collect/ShadowLightsCollect.ts b/src/engine/gfx/renderJob/collect/ShadowLightsCollect.ts new file mode 100644 index 00000000..6b8d40a0 --- /dev/null +++ b/src/engine/gfx/renderJob/collect/ShadowLightsCollect.ts @@ -0,0 +1,165 @@ +import { CameraUtil, Engine3D, UUID } from '../../../..'; +import { DirectLight } from '../../../components/lights/DirectLight'; +import { LightBase } from '../../../components/lights/LightBase'; +import { LightType } from '../../../components/lights/LightData'; +import { Scene3D } from '../../../core/Scene3D'; +import { View3D } from '../../../core/View3D'; +/** + * @internal + * @group Lights + */ +export class ShadowLightsCollect { + + public static directionLightList: Map; + public static pointLightList: Map; + + public static init() { + this.directionLightList = new Map(); + this.pointLightList = new Map(); + } + + static getShadowLightList(light: LightBase) { + if (!light.transform.view3D) return null; + if (light.lightData.lightType == LightType.DirectionLight) { + let list = this.directionLightList.get(light.transform.view3D.scene); + if (!list) { + list = []; + this.directionLightList.set(light.transform.view3D.scene, list); + } + return list; + } else if (light.lightData.lightType == LightType.PointLight) { + let list = this.pointLightList.get(light.transform.view3D.scene); + if (!list) { + list = []; + this.pointLightList.set(light.transform.view3D.scene, list); + } + return list; + } else if (light.lightData.lightType == LightType.SpotLight) { + let list = this.pointLightList.get(light.transform.view3D.scene); + if (!list) { + list = []; + this.pointLightList.set(light.transform.view3D.scene, list); + } + return list; + } + } + + static getShadowLightWhichScene(scene: Scene3D, type: LightType) { + if (type == LightType.DirectionLight) { + let list = this.directionLightList.get(scene); + if (!list) { + list = []; + this.directionLightList.set(scene, list); + } + return list; + } else if (type == LightType.PointLight) { + let list = this.pointLightList.get(scene); + if (!list) { + list = []; + this.pointLightList.set(scene, list); + } + return list; + } + } + + static getDirectShadowLightWhichScene(scene: Scene3D) { + let list = this.directionLightList.get(scene); + if (!list) { + list = []; + this.directionLightList.set(scene, list); + } + return list; + } + + static getPointShadowLightWhichScene(scene: Scene3D) { + let list = this.pointLightList.get(scene); + if (!list) { + list = []; + this.pointLightList.set(scene, list); + } + return list; + } + + static addShadowLight(light: LightBase) { + if (!light.transform.view3D) return null; + if (light.lightData.lightType == LightType.DirectionLight) { + let list = this.directionLightList.get(light.transform.view3D.scene); + if (!list) { + list = []; + this.directionLightList.set(light.transform.view3D.scene, list); + } + if (light instanceof DirectLight && !light.shadowCamera) { + light.shadowCamera = CameraUtil.createCamera3DObject(null, 'shadowCamera'); + light.shadowCamera.name = UUID(); + light.shadowCamera.isShadowCamera = true; + light.shadowCamera.orthoOffCenter( + Engine3D.setting.shadow.shadowBound, + -Engine3D.setting.shadow.shadowBound, + Engine3D.setting.shadow.shadowBound, + -Engine3D.setting.shadow.shadowBound, + 1, + 50000, + ); + } + let has = list.indexOf(light as DirectLight) == -1; + if (has) { + if (list.length < 8) { + light.lightData.castShadowIndex = list.length; + } + list.push(light as DirectLight); + } + return list; + } else if (light.lightData.lightType == LightType.PointLight) { + let list = this.pointLightList.get(light.transform.view3D.scene); + if (!list) { + list = []; + this.pointLightList.set(light.transform.view3D.scene, list); + } + let has = list.indexOf(light) == -1; + if (has) { + if (list.length < 8) { + light.lightData.castShadowIndex = list.length; + } + list.push(light); + } + return list; + } else if (light.lightData.lightType == LightType.SpotLight) { + let list = this.pointLightList.get(light.transform.view3D.scene); + if (!list) { + list = []; + this.pointLightList.set(light.transform.view3D.scene, list); + } + let has = list.indexOf(light) == -1; + if (has) { + if (list.length < 8) { + light.lightData.castShadowIndex = list.length; + } + list.push(light); + } + return list; + } + } + + public static removeShadowLight(light: LightBase) { + if (!light.transform.view3D) return null; + if (light.lightData.lightType == LightType.DirectionLight) { + let list = this.directionLightList.get(light.transform.view3D.scene); + if (list) { + let index = list.indexOf(light as DirectLight); + if (index != -1) { + list.splice(index, 1); + } + } + return list; + } else if (light.lightData.lightType == LightType.PointLight) { + let list = this.pointLightList.get(light.transform.view3D.scene); + if (list) { + let index = list.indexOf(light); + if (index != -1) { + list.splice(index, 1); + } + } + return list; + } + } +} diff --git a/src/engine/gfx/renderJob/color/ColorPassRenderer.ts b/src/engine/gfx/renderJob/color/ColorPassRenderer.ts new file mode 100644 index 00000000..2bc130ec --- /dev/null +++ b/src/engine/gfx/renderJob/color/ColorPassRenderer.ts @@ -0,0 +1,123 @@ +import { Engine3D } from '../../../../Engine3D'; +import { RendererBase } from '../RendererBase'; +import { RendererType } from '../state/RendererType'; +import { OcclusionSystem } from '../../occlusion/OcclusionSystem'; +import { EntityCollect, GPUContext, RenderContext, RenderNode, RTResourceMap, View3D } from '../../../../..'; +import { ProfilerUtil } from '../../../../util/ProfilerUtil'; + +/** + * @internal + * Base Color Renderer + * @author sirxu + * @group Post + */ +export class ColorPassRenderer extends RendererBase { + constructor() { + super(); + this.passType = RendererType.COLOR; + } + + public render(view: View3D, occlusionSystem: OcclusionSystem, maskTr: boolean = false) { + // return ; + this.renderContext.clean(); + + let scene = view.scene; + let camera = view.camera; + + this.rendererPassState.camera3D = camera; + let collectInfo = EntityCollect.instance.getRenderNodes(scene); + + let op_bundleList = this.renderBundleOp(view, collectInfo, occlusionSystem); + let tr_bundleList = maskTr ? [] : this.renderBundleTr(view, collectInfo, occlusionSystem); + ProfilerUtil.start("colorPass Renderer"); + + { + ProfilerUtil.start("ColorPass Draw Opaque"); + + this.renderContext.beginRenderPass(); + + let command = this.renderContext.command; + let renderPassEncoder = this.renderContext.encoder; + + // renderPassEncoder.setViewport(camera.viewPort.x, camera.viewPort.y, camera.viewPort.width, camera.viewPort.height, 0.0, 1.0); + // renderPassEncoder.setScissorRect(camera.viewPort.x, camera.viewPort.y, camera.viewPort.width, camera.viewPort.height); + + // renderPassEncoder.setViewport(view.viewPort.x, view.viewPort.y, view.viewPort.width, view.viewPort.height, 0.0, 1.0); + // renderPassEncoder.setScissorRect(view.viewPort.x, view.viewPort.y, view.viewPort.width, view.viewPort.height); + + GPUContext.bindCamera(renderPassEncoder, camera); + + if (op_bundleList.length > 0) { + // GPUContext.bindCamera(renderPassEncoder,camera); + let entityBatchCollect = EntityCollect.instance.getOpRenderGroup(scene); + entityBatchCollect.renderGroup.forEach((group) => { + for (let i = 0; i < group.renderNodes.length; i++) { + const node = group.renderNodes[i]; + node.transform.updateWorldMatrix(); + } + }); + + renderPassEncoder.executeBundles(op_bundleList); + } + + if (!maskTr && EntityCollect.instance.sky) { + GPUContext.bindCamera(renderPassEncoder, camera); + EntityCollect.instance.sky.renderPass2(view, this._rendererType, this.rendererPassState, this.clusterLightingRender, renderPassEncoder); + } + + GPUContext.bindCamera(renderPassEncoder, camera); + this.drawNodes(view, this.renderContext, collectInfo.opaqueList, occlusionSystem); + this.renderContext.endRenderPass(); + ProfilerUtil.end("ColorPass Draw Opaque"); + } + + { + ProfilerUtil.start("ColorPass Draw Transparent"); + + this.renderContext.beginRenderPass(); + + let command = this.renderContext.command; + let renderPassEncoder = this.renderContext.encoder; + + if (tr_bundleList.length > 0) { + renderPassEncoder.executeBundles(tr_bundleList); + } + + if (!maskTr) { + GPUContext.bindCamera(renderPassEncoder, camera); + this.drawNodes(view, this.renderContext, collectInfo.transparentList, occlusionSystem); + } + + let graphicsList = EntityCollect.instance.getGraphicList(); + for (let i = 0; i < graphicsList.length; i++) { + const graphic3DRenderNode = graphicsList[i]; + let matrixIndex = graphic3DRenderNode.transform.worldMatrix.index; + graphic3DRenderNode.nodeUpdate(view, this._rendererType, this.splitRendererPassState, this.clusterLightingRender); + graphic3DRenderNode.renderPass2(view, this._rendererType, this.splitRendererPassState, this.clusterLightingRender, renderPassEncoder); + } + + this.renderContext.endRenderPass(); + ProfilerUtil.end("ColorPass Draw Transparent"); + } + + ProfilerUtil.end("colorPass Renderer"); + } + + public drawNodes(view: View3D, renderContext: RenderContext, nodes: RenderNode[], occlusionSystem: OcclusionSystem) { + { + for (let i = Engine3D.setting.render.drawOpMin; i < Math.min(nodes.length, Engine3D.setting.render.drawOpMax); ++i) { + let renderNode = nodes[i]; + + if (!renderNode.transform.enable) continue; + if (!renderNode.enable) continue; + renderNode.nodeUpdate(view, this._rendererType, this.rendererPassState, this.clusterLightingRender); + renderNode.renderPass(view, this.passType, this.renderContext); + } + } + } + + + protected occlusionRenderNodeTest(i: number, id: number, occlusionSystem: OcclusionSystem): boolean { + return occlusionSystem.zDepthRenderNodeTest(id) > 0; + } +} diff --git a/src/engine/gfx/renderJob/config/RTResourceConfig.ts b/src/engine/gfx/renderJob/config/RTResourceConfig.ts new file mode 100644 index 00000000..687e12ca --- /dev/null +++ b/src/engine/gfx/renderJob/config/RTResourceConfig.ts @@ -0,0 +1,9 @@ +export class RTResourceConfig { + public static colorBufferTex_NAME: string = 'colorBufferTex'; + public static positionBufferTex_NAME: string = 'positionBufferTex'; + public static normalBufferTex_NAME: string = 'normalBufferTex'; + public static materialBufferTex_NAME: string = 'materialBufferTex'; + public static zBufferTexture_NAME: string = 'zBufferTexture'; + public static zPreDepthTexture_NAME: string = 'zPreDepthTexture'; + public static outTex_NAME: string = 'outTex'; +} diff --git a/src/engine/gfx/renderJob/config/RenderLayer.ts b/src/engine/gfx/renderJob/config/RenderLayer.ts new file mode 100644 index 00000000..5340db92 --- /dev/null +++ b/src/engine/gfx/renderJob/config/RenderLayer.ts @@ -0,0 +1,30 @@ +/** + * render layer enum + * @internal + * @group Post + */ +export enum RenderLayer { + None = 1 << 1, + StaticBatch = 1 << 2, + DynamicBatch = 1 << 3, +} + +/** + * @internal + * @group GFX + */ +export class RenderLayerUtil { + public static addMask(src: RenderLayer, tag: RenderLayer): RenderLayer { + let value = src | tag; + return value; + } + + public static removeMask(src: RenderLayer, tag: RenderLayer): RenderLayer { + let value = src & (~tag); + return value; + } + + public static hasMask(m1: RenderLayer, m2: RenderLayer): boolean { + return (m1 & m2) != 0; + } +} diff --git a/src/engine/gfx/renderJob/frame/GBufferFrame.ts b/src/engine/gfx/renderJob/frame/GBufferFrame.ts new file mode 100644 index 00000000..80e8b8cc --- /dev/null +++ b/src/engine/gfx/renderJob/frame/GBufferFrame.ts @@ -0,0 +1,85 @@ +import { VirtualTexture } from "../../../textures/VirtualTexture"; +import { webGPUContext } from "../../graphics/webGpu/Context3D"; +import { GPUTextureFormat } from "../../graphics/webGpu/WebGPUConst"; +import { RTDescriptor } from "../../graphics/webGpu/descriptor/RTDescriptor"; +import { RTResourceConfig } from "../config/RTResourceConfig"; +import { RTFrame } from "./RTFrame"; +import { RTResourceMap } from "./RTResourceMap"; + +export class GBufferFrame extends RTFrame { + public static gBufferMap: Map = new Map(); + + constructor() { + super([], []); + } + + crateGBuffer(key: string, rtWidth: number, rtHeight: number) { + let attachments = this.attachments; + let reDescriptors = this.rtDescriptors; + // GPUTextureFormat.rgba16float, GPUTextureFormat.rgba8unorm, GPUTextureFormat.rgba8unorm + let colorBufferTex = RTResourceMap.createRTTexture(key + RTResourceConfig.colorBufferTex_NAME, rtWidth, rtHeight, GPUTextureFormat.rgba16float, false); + let positionBufferTex = RTResourceMap.createRTTexture(key + RTResourceConfig.positionBufferTex_NAME, rtWidth, rtHeight, GPUTextureFormat.rgba16float, false); + let normalBufferTex = RTResourceMap.createRTTexture(key + RTResourceConfig.normalBufferTex_NAME, rtWidth, rtHeight, GPUTextureFormat.rgba8unorm, false); + let materialBufferTex = RTResourceMap.createRTTexture(key + RTResourceConfig.materialBufferTex_NAME, rtWidth, rtHeight, GPUTextureFormat.rgba8unorm, false); + + attachments.push(colorBufferTex); + attachments.push(positionBufferTex); + attachments.push(normalBufferTex); + attachments.push(materialBufferTex); + + let colorRTDes = new RTDescriptor(); + colorRTDes.loadOp = `clear`; + // colorRTDes.clearValue = [1,0,0,1]; + + //depth24plus-stencil8 + // let depthTexture = new VirtualTexture(rtWidth, rtHeight, GPUTextureFormat.depth32float, false); + let depthTexture = new VirtualTexture(rtWidth, rtHeight, `depth24plus`, false); + depthTexture.name = `depthTexture`; + let depthDec = new RTDescriptor(); + depthDec.loadOp = `load`; + this.depthTexture = depthTexture; + + reDescriptors.push(colorRTDes); + reDescriptors.push(new RTDescriptor()); + reDescriptors.push(new RTDescriptor()); + reDescriptors.push(new RTDescriptor()); + } + + public getColorMap() { + return this.attachments[0]; + } + + public getPositionMap() { + return this.attachments[1]; + } + + public getNormalMap() { + return this.attachments[2]; + } + + public getMaterialMap() { + return this.attachments[3]; + } + + /** + * @internal + */ + public static getGBufferFrame(key: string): GBufferFrame { + let gBuffer: GBufferFrame; + if (!GBufferFrame.gBufferMap.has(key)) { + gBuffer = new GBufferFrame(); + let size = webGPUContext.presentationSize; + gBuffer.crateGBuffer(key, size[0], size[1]); + GBufferFrame.gBufferMap.set(key, gBuffer); + } else { + gBuffer = GBufferFrame.gBufferMap.get(key); + } + return gBuffer; + } + + public clone() { + let gBufferFrame = new GBufferFrame(); + this.clone2Frame(gBufferFrame); + return gBufferFrame; + } +} \ No newline at end of file diff --git a/src/engine/gfx/renderJob/frame/ProbeGBufferFrame.ts b/src/engine/gfx/renderJob/frame/ProbeGBufferFrame.ts new file mode 100644 index 00000000..5b635823 --- /dev/null +++ b/src/engine/gfx/renderJob/frame/ProbeGBufferFrame.ts @@ -0,0 +1,46 @@ +import { RTDescriptor, RTFrame, VirtualTexture } from "../../../.."; +import { GPUTextureFormat } from "../../graphics/webGpu/WebGPUConst"; +import { RTResourceConfig } from "../config/RTResourceConfig"; +import { RTResourceMap } from "./RTResourceMap"; + +export class ProbeGBufferFrame extends RTFrame { + + constructor(rtWidth: number, rtHeight: number) { + super([], []); + this.crateGBuffer(rtWidth, rtHeight); + } + + crateGBuffer(rtWidth: number, rtHeight: number) { + let attachments = this.attachments; + let rtDescripts = this.rtDescriptors; + let positionMap = new VirtualTexture(rtWidth, rtHeight, GPUTextureFormat.rgba16float, false); + positionMap.name = `positionMap`; + let posDec = new RTDescriptor(); + posDec.loadOp = `load`; + + let normalMap = new VirtualTexture(rtWidth, rtHeight, GPUTextureFormat.rgba16float, false); + normalMap.name = `normalMap`; + let normalDec = new RTDescriptor(); + normalDec.loadOp = `load`; + + let colorMap = new VirtualTexture(rtWidth, rtHeight, GPUTextureFormat.rgba16float, false); + colorMap.name = `colorMap`; + let colorDec = new RTDescriptor(); + colorDec.loadOp = `load`; + + let depthTexture = new VirtualTexture(rtWidth, rtHeight, GPUTextureFormat.depth24plus, false); + depthTexture.name = `depthTexture`; + let depthDec = new RTDescriptor(); + depthDec.loadOp = `load`; + + attachments.push(positionMap); + attachments.push(normalMap); + attachments.push(colorMap); + + rtDescripts.push(posDec); + rtDescripts.push(normalDec); + rtDescripts.push(colorDec); + + this.depthTexture = depthTexture; + } +} \ No newline at end of file diff --git a/src/engine/gfx/renderJob/frame/RTFrame.ts b/src/engine/gfx/renderJob/frame/RTFrame.ts new file mode 100644 index 00000000..b0093e02 --- /dev/null +++ b/src/engine/gfx/renderJob/frame/RTFrame.ts @@ -0,0 +1,47 @@ +import { VirtualTexture } from "../../../textures/VirtualTexture"; +import { Texture } from "../../graphics/webGpu/core/texture/Texture"; +import { RTDescriptor } from "../../graphics/webGpu/descriptor/RTDescriptor"; + +export class RTFrame { + public label: string; + public customSize: boolean = false; + public attachments: VirtualTexture[]; + public rtDescriptors: RTDescriptor[]; + + public zPreTexture: VirtualTexture; + public depthTexture: VirtualTexture; + + public depthViewIndex: number = 0; + public depthCleanValue: number = 1; + public depthLoadOp: GPULoadOp = `clear`; + public isOutTarget: boolean = true; + + constructor(attachments: VirtualTexture[], rtDescriptors: RTDescriptor[], depthTexture?: VirtualTexture, zPreTexture?: VirtualTexture, isOutTarget: boolean = true) { + this.attachments = attachments; + this.rtDescriptors = rtDescriptors; + this.depthTexture = depthTexture; + this.zPreTexture = zPreTexture; + this.isOutTarget = isOutTarget; + } + + public clone2Frame(rtFrame: RTFrame) { + rtFrame.attachments.push(...this.attachments.concat()); + for (let i = 0; i < this.rtDescriptors.length; i++) { + const des = this.rtDescriptors[i]; + let rtDes = new RTDescriptor(); + rtDes.loadOp = des.loadOp; + rtDes.storeOp = des.storeOp; + rtDes.clearValue = des.clearValue; + rtFrame.rtDescriptors.push(rtDes); + } + rtFrame.depthTexture = this.depthTexture; + rtFrame.zPreTexture = this.zPreTexture; + rtFrame.customSize = this.customSize; + } + + public clone() { + let rtFrame = new RTFrame([], []); + this.clone2Frame(rtFrame); + return rtFrame; + } +} \ No newline at end of file diff --git a/src/engine/gfx/renderJob/frame/RTResourceMap.ts b/src/engine/gfx/renderJob/frame/RTResourceMap.ts new file mode 100644 index 00000000..b2a0eed9 --- /dev/null +++ b/src/engine/gfx/renderJob/frame/RTResourceMap.ts @@ -0,0 +1,99 @@ +import { ViewQuad } from '../../../core/ViewQuad'; +import { defaultRes } from '../../../textures/DefaultRes'; +import { Uint16Texture } from '../../../textures/Uint16Texture'; +import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { UniformNode } from '../../graphics/webGpu/core/uniforms/UniformNode'; +import { RTDescriptor } from '../../graphics/webGpu/descriptor/RTDescriptor'; +import { GPUTextureFormat } from '../../graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../../graphics/webGpu/Context3D'; +import { GPUContext } from '../GPUContext'; +import { GBufferFrame } from './GBufferFrame'; +import { RTFrame } from './RTFrame'; +import { RTResourceConfig } from '../config/RTResourceConfig'; +/** + * @internal + * @group Post + */ +export class RTResourceMap { + + public static rtTextureMap: Map; + public static rtViewQuad: Map; + + public static init() { + this.rtTextureMap = new Map(); + this.rtViewQuad = new Map(); + } + + public static createRTTexture(name: string, rtWidth: number, rtHeight: number, format: GPUTextureFormat, useMipmap: boolean = false, sampleCount: number = 0) { + let rt: VirtualTexture = this.rtTextureMap.get(name); + if (!rt) { + if (name == RTResourceConfig.colorBufferTex_NAME) { + rt = new VirtualTexture(rtWidth, rtHeight, format, useMipmap, undefined, 1, sampleCount, false); + } else { + rt = new VirtualTexture(rtWidth, rtHeight, format, useMipmap, undefined, 1, sampleCount, true); + } + rt.name = name; + RTResourceMap.rtTextureMap.set(name, rt); + } + return rt; + } + + public static createRTTextureArray(name: string, rtWidth: number, rtHeight: number, format: GPUTextureFormat, length: number = 1, useMipmap: boolean = false, sampleCount: number = 0) { + let rt: VirtualTexture = this.rtTextureMap.get(name); + if (!rt) { + rt = new VirtualTexture(rtWidth, rtHeight, format, useMipmap, undefined, length, sampleCount); + rt.name = name; + RTResourceMap.rtTextureMap.set(name, rt); + } + return rt; + } + + public static createViewQuad(name: string, shaderVS: string, shaderFS: string, outRtTexture: VirtualTexture, shaderUniforms?: { [uniName: string]: UniformNode }, multisample: number = 0) { + let rtFrame = new RTFrame([ + outRtTexture + ], + [ + new RTDescriptor() + ]); + let viewQuad = new ViewQuad(shaderVS, shaderFS, rtFrame, shaderUniforms, multisample); + RTResourceMap.rtViewQuad.set(name, viewQuad); + return viewQuad; + } + + public static getTexture(name: string) { + return this.rtTextureMap.get(name); + } + + public static CreateSplitTexture(id: string) { + let colorTex = this.getTexture(RTResourceConfig.colorBufferTex_NAME); + let tex = this.getTexture(id + "_split"); + if (!tex) { + tex = this.createRTTexture(id + "_split", colorTex.width, colorTex.height, colorTex.format, false); + } + return tex; + } + + public static WriteSplitColorTexture(id: string) { + let colorTex = this.getTexture(RTResourceConfig.colorBufferTex_NAME); + let tex = this.getTexture(id + "_split"); + const commandEncoder = GPUContext.beginCommandEncoder(); + commandEncoder.copyTextureToTexture( + { + texture: colorTex.getGPUTexture(), + mipLevel: 0, + origin: { x: 0, y: 0, z: 0 }, + }, + { + texture: tex.getGPUTexture(), + mipLevel: 0, + origin: { x: 0, y: 0, z: 0 }, + }, + { + width: tex.width, + height: tex.height, + depthOrArrayLayers: 1, + }, + ); + GPUContext.endCommandEncoder(commandEncoder); + } +} diff --git a/src/engine/gfx/renderJob/jobs/ForwardRenderJob.ts b/src/engine/gfx/renderJob/jobs/ForwardRenderJob.ts new file mode 100644 index 00000000..9766cb40 --- /dev/null +++ b/src/engine/gfx/renderJob/jobs/ForwardRenderJob.ts @@ -0,0 +1,75 @@ +import { defaultRes, GBufferFrame, View3D } from '../../../..'; +import { Scene3D } from '../../../core/Scene3D'; +import { Engine3D } from '../../../Engine3D'; +import { GlobalBindGroup } from '../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { ColorPassRenderer } from '../passRenderer/color/ColorPassRenderer'; +import { DDGIProbeRenderer } from '../passRenderer/ddgi/DDGIProbeRenderer'; +import { RendererJob } from './RendererJob'; +/** + * Forward+ + * Every time a forward rendering is performed, + * the entity of the object is rendered, and + * the color and depth buffer values are calculated. + * The depth buffer will determine whether a tile is visible. + * If visible, the values in the color buffer will be updated. + * @group engine3D + */ +export class ForwardRenderJob extends RendererJob { + constructor(view: View3D) { + super(view); + } + + public start(): void { + super.start(); + let rtFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer"); + { + let debugTextures = []; + let colorPassRenderer = new ColorPassRenderer(); + + if (Engine3D.setting.render.zPrePass) { + rtFrame.zPreTexture = this.depthPassRenderer.rendererPassState.depthTexture; + } + + colorPassRenderer.setRenderStates(rtFrame); + + if (Engine3D.setting.gi.enable) { + this.ddgiProbeRenderer = new DDGIProbeRenderer(GlobalBindGroup.getLightEntries(this.view.scene).irradianceVolume); + this.ddgiProbeRenderer.clusterLightingRender = this.clusterLightingRender; + this.ddgiProbeRenderer.setInputTexture([ + this.shadowMapPassRenderer.depth2DTextureArray, + this.pointLightShadowRenderer.cubeTextureArray + ]); + + colorPassRenderer.setIrradiance(this.ddgiProbeRenderer.irradianceColorMap, this.ddgiProbeRenderer.irradianceDepthMap); + + this.rendererMap.addRenderer(this.ddgiProbeRenderer); + + debugTextures.push( + this.ddgiProbeRenderer.positionMap, + this.ddgiProbeRenderer.normalMap, + this.ddgiProbeRenderer.colorMap, + this.ddgiProbeRenderer.lightingPass.lightingTexture, + this.ddgiProbeRenderer.irradianceColorMap, + this.ddgiProbeRenderer.irradianceDepthMap, + ); + } + + if (this.postRenderer) { + this.postRenderer.setDebugTexture(debugTextures); + } + + this.rendererMap.addRenderer(colorPassRenderer); + } + + if (Engine3D.setting.render.debug) { + this.debug(); + } + } + + /** + * @internal + */ + public debug() { + } + +} diff --git a/src/engine/gfx/renderJob/jobs/RenderMap.ts b/src/engine/gfx/renderJob/jobs/RenderMap.ts new file mode 100644 index 00000000..44a04ea0 --- /dev/null +++ b/src/engine/gfx/renderJob/jobs/RenderMap.ts @@ -0,0 +1,42 @@ +import { Camera3D } from "../../../core/Camera3D"; +import { Scene3D } from "../../../core/Scene3D"; +import { RendererBase } from "../passRenderer/RendererBase"; +import { RendererType } from "../passRenderer/state/RendererType"; + +export class RendererMap { + + private map: Map; + private passRendererList: RendererBase[]; + + constructor() { + this.map = new Map(); + this.passRendererList = []; + } + + public addRenderer(renderer: RendererBase) { + if (!this.map.has(renderer.passType)) { + this.map.set(renderer.passType, renderer); + if (renderer.passType <= (1 << 3)) { + this.addPassRenderer(renderer); + } + } else { + console.error("same renderer pass repeat!"); + } + } + + public getRenderer(passType: RendererType): RendererBase { + return this.map.get(passType); + } + + private addPassRenderer(renderer: RendererBase) { + this.passRendererList.push(renderer); + } + + public getAllRenderer(): Map { + return this.map; + } + + public getAllPassRenderer(): RendererBase[] { + return this.passRendererList; + } +} \ No newline at end of file diff --git a/src/engine/gfx/renderJob/jobs/RendererJob.ts b/src/engine/gfx/renderJob/jobs/RendererJob.ts new file mode 100644 index 00000000..bb032e4e --- /dev/null +++ b/src/engine/gfx/renderJob/jobs/RendererJob.ts @@ -0,0 +1,303 @@ +import { ComponentBase } from '../../../components/ComponentBase'; +import { Camera3D } from '../../../core/Camera3D'; +import { Scene3D } from '../../../core/Scene3D'; +import { Engine3D } from '../../../Engine3D'; +import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { GlobalBindGroup } from '../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { EntityCollect } from '../collect/EntityCollect'; +import { GPUContext } from '../GPUContext'; +import { OcclusionSystem } from '../occlusion/OcclusionSystem'; +import { ClusterLightingRender } from '../passRenderer/cluster/ClusterLightingRender'; +import { RendererBase } from '../passRenderer/RendererBase'; +import { PostRenderer } from '../passRenderer/post/PostRenderer'; +import { DDGIProbeRenderer } from '../passRenderer/ddgi/DDGIProbeRenderer'; +import { ShadowMapPassRenderer } from '../passRenderer/shadow/ShadowMapPassRenderer'; +import { PreDepthPassRenderer } from '../passRenderer/preDepth/PreDepthPassRenderer'; +import { PostBase } from '../post/PostBase'; +import { PointLightShadowRenderer } from '../passRenderer/shadow/PointLightShadowRenderer'; +import { UICanvas } from '../../../components/gui/core/UICanvas'; +import { View3D } from '../../../core/View3D'; +import { PickFire } from '../../../io/PickFire'; +import { ShadowLightsCollect } from '../collect/ShadowLightsCollect'; +import { GBufferFrame } from '../frame/GBufferFrame'; +import { RendererMap } from './RenderMap'; +import { ColorPassRenderer } from '../passRenderer/color/ColorPassRenderer'; +import { Graphic3D } from '../passRenderer/graphic/Graphic3DRender'; +import { ReflectionProbeRenderer } from '../passRenderer/probe/ReflectionProbeRenderer'; + +/** + * render jobs + * @internal + * @group Post + */ +export class RendererJob { + + private _canvas: UICanvas; + + /** + * @internal + */ + public rendererMap: RendererMap; + + /** + * @internal + */ + public shadowMapPassRenderer: ShadowMapPassRenderer; + + /** + * @internal + */ + public pointLightShadowRenderer: PointLightShadowRenderer; + + /** + * @internal + */ + public ddgiProbeRenderer: DDGIProbeRenderer; + + /** + * @internal + */ + public postRenderer: PostRenderer; + + /** + * @internal + */ + public clusterLightingRender: ClusterLightingRender; + + /** + * @internal + */ + public occlusionSystem: OcclusionSystem; + + /** + * @internal + */ + public depthPassRenderer: PreDepthPassRenderer; + + /** + * @internal + */ + public colorPassRenderer: ColorPassRenderer; + + /** + * @internal + */ + public reflectionProbeRenderer: ReflectionProbeRenderer; + + /** + * @internal + */ + public pauseRender: boolean = false; + public pickFire: PickFire; + + /** + * Graphics renderers (lines, rectangles, etc.) + */ + public graphic3D: Graphic3D; + + protected _view: View3D; + + /** + * Create a renderer task class + * @param scene Scene3D {@link Scene3D} + */ + constructor(view: View3D) { + this._view = view; + + ShadowLightsCollect.init(); + + this.rendererMap = new RendererMap(); + + this.occlusionSystem = new OcclusionSystem(); + + this.clusterLightingRender = new ClusterLightingRender(view); + this.rendererMap.addRenderer(this.clusterLightingRender); + + this.graphic3D = new Graphic3D(); + if (view && this.graphic3D) + view.scene.addChild(this.graphic3D); + + if (Engine3D.setting.render.zPrePass) { + this.depthPassRenderer = new PreDepthPassRenderer(); + this.rendererMap.addRenderer(this.depthPassRenderer); + } + + + this.shadowMapPassRenderer = new ShadowMapPassRenderer(); + this.pointLightShadowRenderer = new PointLightShadowRenderer(); + this.reflectionProbeRenderer = new ReflectionProbeRenderer(); + this.reflectionProbeRenderer.clusterLightingRender = this.clusterLightingRender; + } + + + /** + * @internal + */ + public get view(): View3D { + return this._view; + } + + public set view(view: View3D) { + this._view = view; + } + + /** + * start render task + */ + public start() { + } + + // public get guiCanvas(): UICanvas { + // return this._canvas; + // } + + /** + * stop render task + */ + public stop() { } + + /** + * pause render task + */ + public pause() { + this.pauseRender = true; + } + + /** + * back render task + */ + public resume() { + this.pauseRender = false; + } + + /** + * @internal + */ + public enablePost(gbufferFrame: GBufferFrame) { + this.postRenderer = new PostRenderer(); + this.postRenderer.setRenderStates(gbufferFrame); + this.rendererMap.addRenderer(this.postRenderer); + } + + /** + * Add a post processing special effects task + * @param post + */ + public addPost(post: PostBase): PostBase | PostBase[] { + if (!this.postRenderer) this.enablePost(GBufferFrame.getGBufferFrame('ColorPassGBuffer')); + + if (post instanceof PostBase) { + this.postRenderer.attachPost(this.view, post); + } + return post; + } + + /** + * Remove specified post-processing effects + * @param post + */ + public removePost(post: PostBase | PostBase[]) { + if (post instanceof PostBase) { + this.postRenderer.detachPost(this.view, post); + } else { + for (let i = 0; i < post.length; i++) { + this.postRenderer.detachPost(this.view, post[i]); + } + } + } + + /** + * @internal + */ + public render(renderLoop: Function) { + let view = this._view; + // let camera = this._view.camera; + // let scene = this._view.scene; + + this.view.scene.waitUpdate(); + + /****** + * auto update component list + *****/ + ComponentBase.componentsBeforeUpdateList.forEach((v, k) => { + if (k.enable) v(); + }); + + GlobalBindGroup.getLightEntries(view.scene).update(view); + + let globalMatrixBindGroup = GlobalBindGroup.modelMatrixBindGroup; + globalMatrixBindGroup.writeBuffer(); + + if (renderLoop) { + renderLoop(); + } + + ComponentBase.componentsUpdateList.forEach((v, k) => { + if (k.enable) v(); + }); + + let command = GPUContext.beginCommandEncoder(); + ComponentBase.componentsComputeList.forEach((v, k) => { + if (k.enable) v(view, command); + }); + GPUContext.endCommandEncoder(command); + + this.occlusionSystem.update(view.camera, view.scene); + this.renderFrame(view); + if (this.postRenderer && this.postRenderer.postList.length > 0) { + this.postRenderer.render(view); + } + + view.scene.envMapChange = false; + + ComponentBase.componentsLateUpdateList.forEach((v, k) => { + if (k.enable) v(); + }); + + } + + /** + * To render a frame of the scene + */ + protected renderFrame(view: View3D) { + this.clusterLightingRender.render(view, this.occlusionSystem); + if (this.shadowMapPassRenderer && Engine3D.setting.shadow.enable) { + this.shadowMapPassRenderer.render(view, this.occlusionSystem); + } + + if (this.pointLightShadowRenderer) { + this.pointLightShadowRenderer.render(view, this.occlusionSystem); + } + + if (this.depthPassRenderer) { + this.depthPassRenderer.beforeCompute(view, this.occlusionSystem); + this.depthPassRenderer.render(view, this.occlusionSystem); + this.depthPassRenderer.lateCompute(view, this.occlusionSystem); + } + + if (Engine3D.setting.gi.enable && this.ddgiProbeRenderer) { + this.ddgiProbeRenderer.beforeCompute(view, this.occlusionSystem); + this.ddgiProbeRenderer.render(view, this.occlusionSystem); + this.ddgiProbeRenderer.lateCompute(view, this.occlusionSystem); + } + + if (this.reflectionProbeRenderer) { + this.reflectionProbeRenderer.beforeCompute(view, this.occlusionSystem); + this.reflectionProbeRenderer.render(view, this.occlusionSystem); + this.reflectionProbeRenderer.lateCompute(view, this.occlusionSystem); + } + + let passList = this.rendererMap.getAllPassRenderer(); + for (let i = 0; i < passList.length; i++) { + const renderer = passList[i]; + renderer.clusterLightingRender = this.clusterLightingRender; + renderer.beforeCompute(view, this.occlusionSystem); + renderer.render(view, this.occlusionSystem); + renderer.lateCompute(view, this.occlusionSystem); + } + } + + public debug() { + + } +} diff --git a/src/engine/gfx/renderJob/occlusion/OcclusionSystem.ts b/src/engine/gfx/renderJob/occlusion/OcclusionSystem.ts new file mode 100644 index 00000000..45b8ee97 --- /dev/null +++ b/src/engine/gfx/renderJob/occlusion/OcclusionSystem.ts @@ -0,0 +1,101 @@ +import { RenderNode } from '../../../components/renderer/RenderNode'; +import { Camera3D } from '../../../core/Camera3D'; +import { Scene3D } from '../../../core/Scene3D'; +import { Engine3D } from '../../../Engine3D'; +import { EntityCollect } from '../collect/EntityCollect'; +/** + * @internal + * @group Post + */ +export class OcclusionSystem { + public frustumCullingList: Float32Array; + public zVisibleList: Float32Array; + + private _renderList: Map> + + constructor() { + this._renderList = new Map>(); + } + + /** + * Get GPU Test Occlusion test + * @param index + * @returns + */ + public occlusionRenderNodeTest(index: number): number { + if (!Engine3D.setting.occlusionQuery.enable) return 1; + if (this.frustumCullingList) { + return this.frustumCullingList[index]; + } else { + return 0; + } + } + + /** + * Get GPU Pixel depth visible Test + * @param index + * @returns + */ + public zDepthRenderNodeTest(index: number): number { + if (this.zVisibleList) { + return this.zVisibleList[index]; + } else { + return 0; + } + } + + public update(camera: Camera3D, scene: Scene3D) { + let cameraViewRenderList = this._renderList.get(camera); + if (!cameraViewRenderList) { + cameraViewRenderList = new Map(); + this._renderList.set(camera, cameraViewRenderList); + } + cameraViewRenderList.clear(); + + let nodes = EntityCollect.instance.getRenderNodes(scene); + // for (let i = 0; i < nodes.opaqueList.length; i++) { + // const node = nodes.opaqueList[i]; + // if(node.object3D.transform[`_localChange`]) + // node.object3D.transform.updateWorldMatrix(); + // } + // for (let i = 0; i < nodes.transparentList.length; i++) { + // const node = nodes.transparentList[i]; + // if(node.object3D.transform[`_localChange`]) + // node.object3D.transform.updateWorldMatrix(); + // } + + for (let i = 0; i < nodes.opaqueList.length; i++) { + const node = nodes.opaqueList[i]; + let inRender = 0; + + if (node.enable && node.transform.enable && node.object3D.bound) { + inRender = node.object3D.bound.containsFrustum(node.object3D, camera.frustum); + } + + if (inRender) { + cameraViewRenderList.set(node, inRender); + } + } + + for (let i = 0; i < nodes.transparentList.length; i++) { + const node = nodes.transparentList[i]; + let inRender = 0; + if (node.enable && node.transform.enable && node.object3D.bound) { + inRender = node.object3D.bound.containsFrustum(node.object3D, camera.frustum); + } + + if (inRender) { + cameraViewRenderList.set(node, inRender); + } + } + } + + renderCommitTesting(camera: Camera3D, renderNode: RenderNode): boolean { + let cameraRenderList = this._renderList.get(camera); + if (cameraRenderList) { + return this._renderList.get(camera).get(renderNode) > 0; + } else { + return false; + } + } +} diff --git a/src/engine/gfx/renderJob/passRenderer/RenderContext.ts b/src/engine/gfx/renderJob/passRenderer/RenderContext.ts new file mode 100644 index 00000000..875e8763 --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/RenderContext.ts @@ -0,0 +1,80 @@ +import { WebGPUDescriptorCreator } from "../../graphics/webGpu/descriptor/WebGPUDescriptorCreator"; +import { GPUContext } from "../GPUContext"; +import { RTFrame } from "../frame/RTFrame"; +import { RendererPassState } from "./state/RendererPassState"; + +export class RenderContext { + public command: GPUCommandEncoder; + public encoder: GPURenderPassEncoder; + private rendererPassStates: RendererPassState[]; + private rtFrame: RTFrame; + + constructor(rtFrame: RTFrame) { + this.rtFrame = rtFrame; + + this.rendererPassStates = []; + } + + public clean() { + this.rendererPassStates.length = 0; + GPUContext.cleanCache(); + } + + /** + * continue renderer pass state + * @returns + */ + public beginContinueRendererPassState() { + if (this.rendererPassStates.length > 0) { + let splitRtFrame = this.rtFrame.clone(); + for (const iterator of splitRtFrame.rtDescriptors) { + iterator.loadOp = `load`; + // iterator.storeOp = `discard`; + } + splitRtFrame.depthLoadOp = "load"; + let splitRendererPassState = WebGPUDescriptorCreator.createRendererPassState(splitRtFrame); + this.rendererPassStates.push(splitRendererPassState); + return splitRendererPassState; + } else { + let splitRendererPassState = WebGPUDescriptorCreator.createRendererPassState(this.rtFrame); + this.rendererPassStates.push(splitRendererPassState); + return splitRendererPassState; + } + } + + public get rendererPassState() { + return this.rendererPassStates[this.rendererPassStates.length - 1]; + } + + public beginRenderPass() { + this.beginContinueRendererPassState(); + this.begineNewCommand(); + this.beginNewEncoder(); + } + + public endRenderPass() { + this.endEncoder(); + this.endCommand(); + } + + public begineNewCommand(): GPUCommandEncoder { + this.command = GPUContext.beginCommandEncoder(); + return this.command; + } + + public endCommand() { + GPUContext.endCommandEncoder(this.command); + this.command = null; + } + + public beginNewEncoder() { + this.encoder = GPUContext.beginRenderPass(this.command, this.rendererPassState); + return this.encoder; + } + + public endEncoder() { + GPUContext.endPass(this.encoder); + this.encoder = null; + } + +} \ No newline at end of file diff --git a/src/engine/gfx/renderJob/passRenderer/RendererBase.ts b/src/engine/gfx/renderJob/passRenderer/RendererBase.ts new file mode 100644 index 00000000..63a16781 --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/RendererBase.ts @@ -0,0 +1,231 @@ +import { RenderNode } from '../../../components/renderer/RenderNode'; +import { Camera3D } from '../../../core/Camera3D'; +import { Scene3D } from '../../../core/Scene3D'; +import { ViewQuad } from '../../../core/ViewQuad'; +import { Engine3D } from '../../../Engine3D'; +import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { Texture } from '../../graphics/webGpu/core/texture/Texture'; +import { WebGPUDescriptorCreator } from '../../graphics/webGpu/descriptor/WebGPUDescriptorCreator'; +import { CollectInfo } from '../collect/CollectInfo'; +import { EntityCollect } from '../collect/EntityCollect'; +import { GPUContext } from '../GPUContext'; +import { OcclusionSystem } from '../occlusion/OcclusionSystem'; +import { ClusterLightingRender } from './cluster/ClusterLightingRender'; +import { RendererType } from './state/RendererType'; +import { RendererPassState } from './state/RendererPassState'; +import { RTFrame } from '../frame/RTFrame'; +import { CEventDispatcher, GPUTextureFormat, View3D } from '../../../..'; +import { RenderContext } from './RenderContext'; + +/** + * @internal + * @group Post + */ +export class RendererBase extends CEventDispatcher { + public rendererPassState: RendererPassState; + public splitRendererPassState: RendererPassState; + public useRenderBundle: boolean = false; + public clusterLightingRender: ClusterLightingRender; + public debugViewQuads: ViewQuad[]; + public debugTextures: Texture[]; + + protected renderContext: RenderContext; + + protected _rendererType: RendererType; + protected _rtFrame: RTFrame; + + public get passType(): RendererType { + return this._rendererType; + } + + public set passType(value: RendererType) { + this._rendererType = value; + } + + constructor() { + super(); + this.debugTextures = []; + this.debugViewQuads = []; + } + + public setRenderStates(rtFrame: RTFrame) { + this._rtFrame = rtFrame; + if (rtFrame) { + this.rendererPassState = WebGPUDescriptorCreator.createRendererPassState(rtFrame); + let splitRtFrame = rtFrame.clone(); + splitRtFrame.depthLoadOp = "load"; + for (const iterator of splitRtFrame.rtDescriptors) { + iterator.loadOp = `load`; + } + this.splitRendererPassState = WebGPUDescriptorCreator.createRendererPassState(splitRtFrame); + } + + this.renderContext = new RenderContext(rtFrame); + } + + public setIrradiance(probeIrradianceMap: VirtualTexture, probeDepthMap: VirtualTexture) { + this.rendererPassState.irradianceBuffer = [probeIrradianceMap, probeDepthMap]; + } + + + + public beforeCompute(view: View3D, occlusionSystem: OcclusionSystem) { } + public lateCompute(view: View3D, occlusionSystem: OcclusionSystem) { } + + public render(view: View3D, occlusionSystem: OcclusionSystem, maskTr: boolean = false) { + GPUContext.cleanCache(); + + let camera = view.camera; + let scene = view.scene; + + this.rendererPassState.camera3D = camera; + let collectInfo = EntityCollect.instance.getRenderNodes(scene); + // this.compute(collectInfo, scene, occlusionSystem); + + let op_bundleList = this.renderBundleOp(view, collectInfo, occlusionSystem); + let tr_bundleList = maskTr ? [] : this.renderBundleTr(view, collectInfo, occlusionSystem); + + { + let command = GPUContext.beginCommandEncoder(); + let renderPassEncoder = GPUContext.beginRenderPass(command, this.rendererPassState); + + if (op_bundleList.length > 0) { + renderPassEncoder.executeBundles(op_bundleList); + } + + if (!maskTr && EntityCollect.instance.sky) { + GPUContext.bindCamera(renderPassEncoder, camera); + EntityCollect.instance.sky.renderPass2(view, this._rendererType, this.rendererPassState, this.clusterLightingRender, renderPassEncoder); + } + + this.drawRenderNodes(view, renderPassEncoder, command, collectInfo.opaqueList, occlusionSystem); + + GPUContext.endPass(renderPassEncoder); + GPUContext.endCommandEncoder(command); + } + + { + let command = GPUContext.beginCommandEncoder(); + let renderPassEncoder = GPUContext.beginRenderPass(command, this.rendererPassState); + + if (tr_bundleList.length > 0) { + renderPassEncoder.executeBundles(tr_bundleList); + } + + if (!maskTr) { + GPUContext.bindCamera(renderPassEncoder, camera); + this.drawRenderNodes(view, renderPassEncoder, command, collectInfo.transparentList, occlusionSystem); + } + + GPUContext.endPass(renderPassEncoder); + GPUContext.endCommandEncoder(command); + } + } + + protected nodeUpload(collectInfo: CollectInfo, scene: Scene3D, occlusionSystem?: OcclusionSystem) { } + + protected occlusionRenderNodeTest(i: number, id: number, occlusionSystem: OcclusionSystem): boolean { + return occlusionSystem ? occlusionSystem.occlusionRenderNodeTest(i) > 0 : true; + } + + protected renderOp(encoder: GPURenderPassEncoder, command: GPUCommandEncoder, collectInfo: CollectInfo, scene: Scene3D, occlusionSystem: OcclusionSystem) { } + + protected renderTr(encoder: GPURenderPassEncoder, command: GPUCommandEncoder, collectInfo: CollectInfo, scene: Scene3D, occlusionSystem: OcclusionSystem) { } + + protected renderBundleOp(view: View3D, collectInfo: CollectInfo, occlusionSystem: OcclusionSystem) { + let entityBatchCollect = EntityCollect.instance.getOpRenderGroup(view.scene); + if (entityBatchCollect) { + let bundlerList = []; + entityBatchCollect.renderGroup.forEach((v) => { + if (v.bundleMap.has(this._rendererType)) { + bundlerList.push(v.bundleMap.get(this._rendererType)); + } else { + let renderBundleEncoder = GPUContext.recordBundleEncoder(this.rendererPassState.renderBundleEncoderDescriptor); + this.recordRenderBundleNode(view, renderBundleEncoder, v.renderNodes); + let newBundle = renderBundleEncoder.finish(); + v.bundleMap.set(this._rendererType, newBundle); + bundlerList.push(newBundle); + } + }); + return bundlerList; + } + return []; + } + + protected renderBundleTr(view: View3D, collectInfo: CollectInfo, occlusionSystem: OcclusionSystem) { + let entityBatchCollect = EntityCollect.instance.getTrRenderGroup(view.scene); + if (entityBatchCollect) { + let bundlerList = []; + entityBatchCollect.renderGroup.forEach((v) => { + if (v.bundleMap.has(this._rendererType)) { + bundlerList.push(v.bundleMap.get(this._rendererType)); + } else { + let renderBundleEncoder = GPUContext.recordBundleEncoder(this.rendererPassState.renderBundleEncoderDescriptor); + this.recordRenderBundleNode(view, renderBundleEncoder, v.renderNodes); + let newBundle = renderBundleEncoder.finish(); + v.bundleMap.set(this._rendererType, newBundle); + bundlerList.push(newBundle); + } + }); + return bundlerList; + } + return []; + } + + protected recordRenderBundleNode(view: View3D, encoder, nodes: RenderNode[]) { + GPUContext.bindCamera(encoder, view.camera); + GPUContext.bindGeometryBuffer(encoder, nodes[0].geometry); + for (let i = 0; i < nodes.length; ++i) { + let renderNode = nodes[i]; + let matrixIndex = renderNode.transform.worldMatrix.index; + if (!renderNode.transform.enable) + continue; + renderNode.recordRenderPass2(view, this._rendererType, this.rendererPassState, this.clusterLightingRender, encoder); + } + } + + protected drawRenderNodes(view: View3D, encoder: GPURenderPassEncoder, command: GPUCommandEncoder, nodes: RenderNode[], occlusionSystem: OcclusionSystem) { + GPUContext.bindCamera(encoder, view.camera); + for (let i = Engine3D.setting.render.drawOpMin; i < Math.min(nodes.length, Engine3D.setting.render.drawOpMax); ++i) { + let renderNode = nodes[i]; + if (!occlusionSystem.renderCommitTesting(view.camera, renderNode)) + continue; + if (!renderNode.transform.enable) + continue; + if (!renderNode.enable) + continue; + renderNode.renderPass2(view, this._rendererType, this.rendererPassState, this.clusterLightingRender, encoder); + } + } + + public setDebugTexture(textures: Texture[]) { + for (let i = 0; i < textures.length; i++) { + let tex = textures[i]; + let vs = "Quad_vert_wgsl"; + let fs = "Quad_frag_wgsl"; + switch (tex.format) { + case GPUTextureFormat.rgba8sint: + case GPUTextureFormat.rgba8uint: + case GPUTextureFormat.rgba8unorm: + case GPUTextureFormat.rgba16float: + case GPUTextureFormat.rgba32float: + fs = `Quad_frag_wgsl`; + break; + + case GPUTextureFormat.depth24plus: + case GPUTextureFormat.depth32float: + fs = `Quad_depth2d_frag_wgsl`; + if (tex.textureBindingLayout.viewDimension == `cube`) { + fs = `Quad_depthCube_frag_wgsl`; + } + break; + } + let viewQuad = new ViewQuad(vs, fs, new RTFrame([], [])); + this.debugTextures.push(textures[i]); + this.debugViewQuads.push(viewQuad); + } + } + + + +} diff --git a/src/engine/gfx/renderJob/preDepth/PreDepthPassRenderer.ts b/src/engine/gfx/renderJob/preDepth/PreDepthPassRenderer.ts new file mode 100644 index 00000000..58caa91b --- /dev/null +++ b/src/engine/gfx/renderJob/preDepth/PreDepthPassRenderer.ts @@ -0,0 +1,105 @@ +import { RenderNode } from '../../../../components/renderer/RenderNode'; +import { Camera3D } from '../../../../core/Camera3D'; +import { Scene3D } from '../../../../core/Scene3D'; +import { Engine3D } from '../../../../Engine3D'; +import { VirtualTexture } from '../../../../textures/VirtualTexture'; +import { ProfilerUtil } from '../../../../util/ProfilerUtil'; +import { GlobalBindGroup } from '../../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { StorageGPUBuffer } from '../../../graphics/webGpu/core/buffer/StorageGPUBuffer'; +import { RTDescriptor } from '../../../graphics/webGpu/descriptor/RTDescriptor'; +import { GPUTextureFormat } from '../../../graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../../../graphics/webGpu/Context3D'; +import { CollectInfo } from '../../collect/CollectInfo'; +import { EntityCollect } from '../../collect/EntityCollect'; +import { GPUContext } from '../../GPUContext'; +import { RTFrame } from '../../frame/RTFrame'; +import { RTResourceConfig } from '../../config/RTResourceConfig'; +import { RTResourceMap } from '../../frame/RTResourceMap'; +import { OcclusionSystem } from '../../occlusion/OcclusionSystem'; +import { RendererBase } from '../RendererBase'; +import { RendererType } from '../state/RendererType'; +import { ZCullingCompute } from './ZCullingCompute'; +import { View3D } from '../../../../core/View3D'; +/** + * @internal + * @group Post + */ +export class PreDepthPassRenderer extends RendererBase { + public zBufferTexture: VirtualTexture; + public useRenderBundle: boolean = false; + shadowPassCount: number; + zCullingCompute: ZCullingCompute; + constructor() { + super(); + this.passType = RendererType.DEPTH; + + let size = webGPUContext.presentationSize; + let scale = 1; + this.zBufferTexture = RTResourceMap.createRTTexture(RTResourceConfig.zBufferTexture_NAME, Math.floor(size[0] * scale), Math.floor(size[1] * scale), GPUTextureFormat.rgba16float, false); + let rtDec = new RTDescriptor() + rtDec.clearValue = [0, 0, 0, 0]; + rtDec.loadOp = `clear`; + let rtFrame = new RTFrame([ + this.zBufferTexture + ], [ + new RTDescriptor() + ], + RTResourceMap.createRTTexture(RTResourceConfig.zPreDepthTexture_NAME, Math.floor(size[0]), Math.floor(size[1]), GPUTextureFormat.depth32float, false), + null, + true + ); + this.setRenderStates(rtFrame); + } + + public lateCompute(view: View3D, occlusionSystem: OcclusionSystem) { + // this.zCullingCompute.compute(scene, occlusionSystem); + } + + render(view: View3D, occlusionSystem: OcclusionSystem) { + return; + let camera = view.camera; + let scene = view.scene; + GPUContext.cleanCache(); + + ProfilerUtil.start("DepthPass Renderer"); + + let scene3D = scene; + + this.rendererPassState.camera3D = camera; + let collectInfo = EntityCollect.instance.getRenderNodes(scene3D); + // this.compute(collectInfo, scene, occlusionSystem); + + // let op_bundleList = this.renderBundleOp(camera, collectInfo, scene, occlusionSystem); + // let tr_bundleList = true ? [] : this.renderBundleTr(camera, collectInfo, scene, occlusionSystem); + + let command = GPUContext.beginCommandEncoder(); + let encoder = GPUContext.beginRenderPass(command, this.rendererPassState); + + // if (op_bundleList.length > 0) { + // encoder.executeBundles(op_bundleList); + // } + + // if(!true&&EntityCollect.instance.sky){ + // GPUContext.bindCamera( encoder , camera); + // EntityCollect.instance.sky.renderPass2(this._rendererType,this.rendererPassState,scene,this.clusterLightingRender, encoder ); + // } + + // this.drawRenderNodes(camera, scene, encoder, command, collectInfo.opaqueList, occlusionSystem); + + // if (tr_bundleList.length > 0) { + // encoder.executeBundles(tr_bundleList); + // } + + // if (false) { + // this.drawRenderNodes(camera, scene, encoder, command, collectInfo.transparentList, occlusionSystem); + // } + + GPUContext.endPass(encoder); + GPUContext.endCommandEncoder(command); + + ProfilerUtil.end("DepthPass Renderer"); + // ProfilerUtil.print( "DepthPass Renderer" ); + } + + +} diff --git a/src/engine/gfx/renderJob/preDepth/ZCullingCompute.ts b/src/engine/gfx/renderJob/preDepth/ZCullingCompute.ts new file mode 100644 index 00000000..e2d147da --- /dev/null +++ b/src/engine/gfx/renderJob/preDepth/ZCullingCompute.ts @@ -0,0 +1,42 @@ +import { Scene3D } from '../../../../core/Scene3D'; +import { ComputeGPUBuffer } from '../../../graphics/webGpu/core/buffer/ComputeGPUBuffer'; +import { ComputeShader } from '../../../graphics/webGpu/shader/ComputeShader'; +import { GPUContext } from '../../GPUContext'; +import { RTResourceMap } from '../../frame/RTResourceMap'; +import { OcclusionSystem } from '../../occlusion/OcclusionSystem'; +import { Texture } from '../../../graphics/webGpu/core/texture/Texture'; +import { RTResourceConfig } from '../../config/RTResourceConfig'; +import ZPassShader_cs from '../../../../assets/shader/core/pass/ZPassShader_cs.wgsl?raw'; + +/** + * @internal + * @group Post + */ +export class ZCullingCompute { + computeShader: ComputeShader; + visibleBuffer: ComputeGPUBuffer; + texture: Texture; + constructor() { + this.computeShader = new ComputeShader(ZPassShader_cs); + + this.visibleBuffer = new ComputeGPUBuffer(8192 * 2); + this.computeShader.setStorageBuffer(`visibleBuffer`, this.visibleBuffer); + + this.texture = RTResourceMap.getTexture(RTResourceConfig.zBufferTexture_NAME); + this.computeShader.setSamplerTexture(`zBufferTexture`, this.texture); + this.computeShader.workerSizeX = Math.ceil(this.texture.width / 8); + this.computeShader.workerSizeY = Math.ceil(this.texture.height / 8); + this.computeShader.workerSizeZ = 1; + } + + compute(scene: Scene3D, occlusionSystem: OcclusionSystem) { + this.visibleBuffer.reset(true, 0); + this.visibleBuffer.apply(); + + let command = GPUContext.beginCommandEncoder(); + GPUContext.computeCommand(command, [this.computeShader]); + // GPUContext.submitCommandEncoder(command); + this.visibleBuffer.readBuffer(); + occlusionSystem.zVisibleList = this.visibleBuffer.outFloat32Array; + } +} diff --git a/src/engine/gfx/renderJob/state/RendererMask.ts b/src/engine/gfx/renderJob/state/RendererMask.ts new file mode 100644 index 00000000..cfb50d30 --- /dev/null +++ b/src/engine/gfx/renderJob/state/RendererMask.ts @@ -0,0 +1,34 @@ +/** + * RenderMask + * @group GFX + */ +export enum RendererMask { + Default = 1 << 0, + IgnoreDepthPass = 1 << 1, + Sky = IgnoreDepthPass | 1 << 2, + Particle = IgnoreDepthPass | 1 << 3, + SkinnedMesh = 1 << 4, + MorphTarget = 1 << 5, + Terrain = 1 << 6, + UI = 1 << 7, +} + +/** + * @internal + * @group GFX + */ +export class RendererMaskUtil { + public static addMask(src: RendererMask, tag: RendererMask): RendererMask { + let value = src | tag; + return value; + } + + public static removeMask(src: RendererMask, tag: RendererMask): RendererMask { + let value = src & (~tag); + return value; + } + + public static hasMask(m1: RendererMask, m2: RendererMask): boolean { + return (m1 & m2) != 0; + } +} diff --git a/src/engine/gfx/renderJob/state/RendererPassState.ts b/src/engine/gfx/renderJob/state/RendererPassState.ts new file mode 100644 index 00000000..f252f8de --- /dev/null +++ b/src/engine/gfx/renderJob/state/RendererPassState.ts @@ -0,0 +1,40 @@ +import { defaultRes, RTDescriptor, RTFrame, VirtualTexture } from '../../../../..'; +import { Camera3D } from '../../../../core/Camera3D'; +import { Texture } from '../../../graphics/webGpu/core/texture/Texture'; +/** + * @internal + */ +export class RendererPassState { + + public label: string = ""; + public customSize: boolean = false; + public zPreTexture: VirtualTexture = null; + public depthTexture: VirtualTexture = null; + public outAttachments: GPUColorTargetState[]; + public outColor: number = -1; + public renderTargets: Texture[]; + public rtTextureDescripts: RTDescriptor[]; + // public depthFormat: GPUTextureFormat = 'depth24plus'; + // public depthFormat: GPUTextureFormat = 'depth32float'; + // public depthTexture: GPUTexture; + public irradianceBuffer: Texture[]; + public multisample: number = 0; + public multiTexture: GPUTexture; + public depthViewIndex: number = 0; + public depthCleanValue: number = 0; + public isOutTarget: boolean = true; + public camera3D: Camera3D; + public rtFrame: RTFrame; + public renderPassDescriptor: GPURenderPassDescriptor; + public renderBundleEncoderDescriptor: GPURenderBundleEncoderDescriptor; + public depthLoadOp: GPULoadOp; + + + getLastRenderTexture() { + if (this.renderTargets) { + return this.renderTargets.length > 0 ? this.renderTargets[0] : defaultRes.redTexture; + } else { + return defaultRes.redTexture + } + } +} diff --git a/src/engine/gfx/renderJob/state/RendererType.ts b/src/engine/gfx/renderJob/state/RendererType.ts new file mode 100644 index 00000000..09bb584a --- /dev/null +++ b/src/engine/gfx/renderJob/state/RendererType.ts @@ -0,0 +1,17 @@ +/** + * @internal + */ +export enum RendererType { + COLOR = 1 << 0, + NORMAL = 1 << 1, + POSITION = 1 << 2, + GRAPHIC = 1 << 3, + + GI = 1 << 4, + Cluster = 1 << 5, + SHADOW = 1 << 6, + POINT_SHADOW = 1 << 7, + POST = 1 << 8, + DEPTH = 1 << 9, + REFLECTION = 1 << 10 +} diff --git a/src/engine/setting/EngineSetting.ts b/src/engine/setting/EngineSetting.ts new file mode 100644 index 00000000..24a578bd --- /dev/null +++ b/src/engine/setting/EngineSetting.ts @@ -0,0 +1,51 @@ +import { GlobalIlluminationSetting } from "./GlobalIlluminationSetting"; +import { LightSetting } from "./LightSetting"; +import { MaterialSetting } from "./MaterialSetting"; +import { OcclusionQuerySetting } from "./OcclusionQuerySetting"; +import { PickSetting } from "./PickSetting"; +import { RenderSetting } from "./RenderSetting"; +import { ShadowSetting } from "./ShadowSetting"; +import { SkySetting } from "./SkySetting"; + +export type EngineSetting = { + + /** + * @internal + */ + occlusionQuery: OcclusionQuerySetting; + + /** + * pick mode setting + */ + pick: PickSetting; + + /** + * render setting + */ + render: RenderSetting; + + /** + * sky setting + */ + sky: SkySetting; + + /** + * shadow setting + */ + shadow: ShadowSetting; + + /** + * global illumination setting + */ + gi: GlobalIlluminationSetting; + + /** + * light setting + */ + light: LightSetting; + + /** + * @internal + */ + material: MaterialSetting; +} \ No newline at end of file From 6e91c173c74eaee422559cff8430bb20f2d4782d Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Mon, 24 Apr 2023 16:36:42 +0800 Subject: [PATCH 048/100] feat(bound): add bound (#61) add ibound add frustum add boundBox add boundSphere --- .../gfx/graphics/webGpu/core/Camera3D.ts | 2 +- .../graphics/webGpu/core/bound/BoundingBox.ts | 388 ++++++++++++++++++ .../webGpu/core/bound/BoundingSphere.ts | 118 ++++++ .../gfx/graphics/webGpu/core/bound/Frustum.ts | 200 +++++++++ .../gfx/graphics/webGpu/core/bound/IBound.ts | 24 ++ 5 files changed, 731 insertions(+), 1 deletion(-) create mode 100644 src/engine/gfx/graphics/webGpu/core/bound/BoundingBox.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/bound/BoundingSphere.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/bound/Frustum.ts create mode 100644 src/engine/gfx/graphics/webGpu/core/bound/IBound.ts diff --git a/src/engine/gfx/graphics/webGpu/core/Camera3D.ts b/src/engine/gfx/graphics/webGpu/core/Camera3D.ts index e12c0877..2f060101 100644 --- a/src/engine/gfx/graphics/webGpu/core/Camera3D.ts +++ b/src/engine/gfx/graphics/webGpu/core/Camera3D.ts @@ -62,7 +62,7 @@ export class Camera3D extends ComponentBase { /** * @internal */ - public _projectionMatrixInv: Matrix4 = new Matrix4(); + private _projectionMatrixInv: Matrix4 = new Matrix4(); private _projectionMatrix: Matrix4 = new Matrix4(); private _viewMatrix: Matrix4 = new Matrix4(); private _unprojection: Matrix4 = new Matrix4(); diff --git a/src/engine/gfx/graphics/webGpu/core/bound/BoundingBox.ts b/src/engine/gfx/graphics/webGpu/core/bound/BoundingBox.ts new file mode 100644 index 00000000..4a6def06 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/bound/BoundingBox.ts @@ -0,0 +1,388 @@ +import { Frustum } from '../../..'; +import { Ray } from '../../math/Ray'; +import { Vector3 } from '../../math/Vector3'; +import { Object3D } from '../entities/Object3D'; +import { IBound } from './IBound'; + +/** + * BoundingBox + * @internal + * @group Core + */ +export class BoundingBox implements IBound { + /** + * The center of the bounding box. + */ + public center: Vector3; + /** + * + * The range of the bounding box. This is always half the size of these Bounds. + */ + public extents: Vector3; + /** + * + * The maximum point of the box body. This always equals center+extensions. + */ + public max: Vector3; + /** + * + * The minimum point of the box body. This always equals center extensions. + */ + public min: Vector3; + /** + * + * The total size of the box. This is always twice as much as extensions. + */ + public size: Vector3; + /** + * + * Create a new Bounds. + * @param center the center of the box. + * @param size The size of the box. + */ + constructor(center: Vector3, size: Vector3) { + this.center = center; + this.extents = new Vector3(size.x / 2, size.y / 2, size.z / 2); + this.size = size; + this.max = this.center.add(this.extents); + this.min = this.center.subtract(this.extents); + } + + public setFromMinMax(min: Vector3, max: Vector3) { + this.size = max.subtract(min); + this.center = this.size.div(2.0).add(min); + this.extents = new Vector3(this.size.x / 2, this.size.y / 2, this.size.z / 2); + this.min = min; + this.max = max; + } + + public setFromCenterAndSize(center: Vector3, size: Vector3) { + this.size = size; + this.center = center; + this.extents = new Vector3(this.size.x / 2, this.size.y / 2, this.size.z / 2); + this.min = new Vector3(this.center.x + -this.extents.x, this.center.y + -this.extents.y, this.center.z + -this.extents.z); + this.max = new Vector3(this.center.x + this.extents.x, this.center.y + this.extents.y, this.center.z + this.extents.z); + } + + public containsFrustum(obj: Object3D, frustum: Frustum) { + return frustum.containsBox(obj); + } + + + public merge(bound: BoundingBox) { + if (bound.min.x < this.min.x) this.min.x = bound.min.x; + if (bound.min.y < this.min.y) this.min.y = bound.min.y; + if (bound.min.z < this.min.z) this.min.z = bound.min.z; + + if (bound.max.x > this.max.x) this.max.x = bound.max.x; + if (bound.max.y > this.max.y) this.max.y = bound.max.y; + if (bound.max.z > this.max.z) this.max.z = bound.max.z; + + this.size.x = bound.max.x - bound.min.x; + this.size.y = bound.max.y - bound.min.y; + this.size.z = bound.max.z - bound.min.z; + + this.extents.x = this.size.x * 0.5; + this.extents.y = this.size.y * 0.5; + this.extents.z = this.size.z * 0.5; + + this.center.x = this.extents.x + bound.min.x; + this.center.y = this.extents.y + bound.min.y; + this.center.z = this.extents.z + bound.min.z; + } + + public intersects(bounds: IBound): boolean { + return this.min.x <= bounds.max.x && this.max.x >= bounds.min.x && this.min.y <= bounds.max.y && this.max.y >= bounds.min.y && this.min.z <= bounds.max.z && this.max.z >= bounds.min.z; + } + + public intersectsSphere(sphere: IBound): boolean { + return this.min.x <= sphere.max.x && this.max.x >= sphere.min.x && this.min.y <= sphere.max.y && this.max.y >= sphere.min.y && this.min.z <= sphere.max.z && this.max.z >= sphere.min.z; + } + + /** + * + * Does the target bounding box intersect with the bounding box + * @param box + * @returns + */ + public intersectsBox(box: IBound): boolean { + return this.min.x <= box.max.x && this.max.x >= box.min.x && this.min.y <= box.max.y && this.max.y >= box.min.y && this.min.z <= box.max.z && this.max.z >= box.min.z; + } + + /** + * + * Does the ray collide with the bounding box + * @param ray + * @param bounds + * @returns + */ + public static intersectRay(ray: Ray, bounds: IBound): boolean { + let tmin: number = 0; + let tmax: number = Number.MAX_VALUE; + let invdirx: number = 1 / ray.direction.x; + let invdiry: number = 1 / ray.direction.y; + let invdirz: number = 1 / ray.direction.z; + let origin: Vector3 = ray.origin; + let dirx: number = ray.direction.x; + let diry: number = ray.direction.y; + let dirz: number = ray.direction.z; + let min: Vector3 = bounds.min; + let max: Vector3 = bounds.max; + let t1: number; + let t2: number; + if (dirx >= 0) { + t1 = (min.x - origin.x) * invdirx; + t2 = (max.x - origin.x) * invdirx; + } else { + t1 = (max.x - origin.x) * invdirx; + t2 = (min.x - origin.x) * invdirx; + } + if (t1 > tmin) { + tmin = t1; + } + if (t2 < tmax) { + tmax = t2; + } + if (diry >= 0) { + t1 = (min.y - origin.y) * invdiry; + t2 = (max.y - origin.y) * invdiry; + } else { + t1 = (max.y - origin.y) * invdiry; + t2 = (min.y - origin.y) * invdiry; + } + if (t1 > tmin) { + tmin = t1; + } + if (t2 < tmax) { + tmax = t2; + } + if (dirz >= 0) { + t1 = (min.z - origin.z) * invdirz; + t2 = (max.z - origin.z) * invdirz; + } else { + t1 = (max.z - origin.z) * invdirz; + t2 = (min.z - origin.z) * invdirz; + } + if (t1 > tmin) { + tmin = t1; + } + if (t2 < tmax) { + tmax = t2; + } + return tmax >= tmin; + } + + public equals(bounds: IBound): boolean { + return this.center.equals(bounds.center) && this.extents.equals(bounds.extents); + } + + public expandByPoint(point: Vector3): void { + if (point.x < this.min.x) { + this.min.x = point.x; + } + if (point.x > this.max.x) { + this.max.x = point.x; + } + + if (point.y < this.min.y) { + this.min.y = point.y; + } + if (point.y > this.max.y) { + this.max.y = point.y; + } + if (point.z < this.min.z) { + this.min.z = point.z; + } + if (point.z > this.max.z) { + this.max.z = point.z; + } + } + + public static fromPoints(points: Vector3[]): BoundingBox { + var bounds: BoundingBox = new BoundingBox(new Vector3(), new Vector3()); + for (var i: number = 0; i < points.length; i++) { + bounds.expandByPoint(points[i]); + } + return bounds; + } + + public calculateTransform(obj: Object3D): void { + + } + + public clone(): IBound { + var bound: BoundingBox = new BoundingBox(this.center.clone(), this.size.clone()); + return bound; + } + + public intersectsRay(ray: Ray, point: Vector3): boolean { + throw new Error('Method not implemented.'); + } + + public containsPoint(point: Vector3): boolean { + return this.min.x <= point.x && this.max.x >= point.x && this.min.y <= point.y && this.max.y >= point.y && this.min.z <= point.z && this.max.z >= point.z; + } + + public getBoundVertex() { + let p0 = new Vector3(this.min.x, this.min.y, this.min.z); + let p1 = new Vector3(this.max.x, this.min.y, this.min.z); + let p2 = new Vector3(this.max.x, this.min.y, this.max.z); + let p3 = new Vector3(this.min.x, this.min.y, this.max.z); + + let p4 = new Vector3(this.min.x, this.max.y, this.min.z); + let p5 = new Vector3(this.max.x, this.max.y, this.min.z); + let p6 = new Vector3(this.max.x, this.max.y, this.max.z); + let p7 = new Vector3(this.min.x, this.max.y, this.max.z); + return [ + p2.x, + p2.y, + p2.z, + 1.0, + p3.x, + p3.y, + p3.z, + 1.0, + p0.x, + p0.y, + p0.z, + 1.0, + p1.x, + p1.y, + p1.z, + 1.0, + p2.x, + p2.y, + p2.z, + 1.0, + p0.x, + p0.y, + p0.z, + 1.0, + + p6.x, + p6.y, + p6.z, + 1.0, + p2.x, + p2.y, + p2.z, + 1.0, + p1.x, + p1.y, + p1.z, + 1.0, + p5.x, + p5.y, + p5.z, + 1.0, + p6.x, + p6.y, + p6.z, + 1.0, + p1.x, + p1.y, + p1.z, + 1.0, + + p7.x, + p7.y, + p7.z, + 1.0, + p6.x, + p6.y, + p6.z, + 1.0, + p5.x, + p5.y, + p5.z, + 1.0, + p4.x, + p4.y, + p4.z, + 1.0, + p7.x, + p7.y, + p7.z, + 1.0, + p5.x, + p5.y, + p5.z, + 1.0, + + p3.x, + p3.y, + p3.z, + 1.0, + p7.x, + p7.y, + p7.z, + 1.0, + p4.x, + p4.y, + p4.z, + 1.0, + p0.x, + p0.y, + p0.z, + 1.0, + p3.x, + p3.y, + p3.z, + 1.0, + p4.x, + p4.y, + p4.z, + 1.0, + + p6.x, + p6.y, + p6.z, + 1.0, + p7.x, + p7.y, + p7.z, + 1.0, + p3.x, + p3.y, + p3.z, + 1.0, + p3.x, + p3.y, + p3.z, + 1.0, + p2.x, + p2.y, + p2.z, + 1.0, + p6.x, + p6.y, + p6.z, + 1.0, + + p1.x, + p1.y, + p1.z, + 1.0, + p0.x, + p0.y, + p0.z, + 1.0, + p4.x, + p4.y, + p4.z, + 1.0, + p5.x, + p5.y, + p5.z, + 1.0, + p1.x, + p1.y, + p1.z, + 1.0, + p4.x, + p4.y, + p4.z, + 1.0, + ]; + } +} diff --git a/src/engine/gfx/graphics/webGpu/core/bound/BoundingSphere.ts b/src/engine/gfx/graphics/webGpu/core/bound/BoundingSphere.ts new file mode 100644 index 00000000..d452c40d --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/bound/BoundingSphere.ts @@ -0,0 +1,118 @@ +import { Ray } from '../../math/Ray'; +import { Vector3 } from '../../math/Vector3'; +import { Object3D } from '../entities/Object3D'; +import { Frustum } from './Frustum'; +import { IBound } from './IBound'; +/** + * BoundingSphere + * @internal + * @group Core + */ +export class BoundingSphere implements IBound { + + public center = new Vector3(); + public extents!: Vector3; //= new Vector3(); + public max!: Vector3; //= new Vector3(); + public min!: Vector3; // = new Vector3(); + public size!: Vector3; //= new Vector3(); + + public tmpVecA = new Vector3(); + public tmpVecB = new Vector3(); + public tmpVecC = new Vector3(); + public tmpVecD = new Vector3(); + + public radius: number = 0; + public diffBetweenPoints = new Vector3(); + public owner: any; + public forward: Vector3 = new Vector3(0, 0, 1); + + /** + * @internal + */ + private _center = new Vector3(); + constructor(center?: Vector3, radius?: number) { + this.center = center || new Vector3(0, 0, 0); + this.radius = radius === undefined ? 0.5 : radius; + } + + public containsPoint(point: Vector3) { + var lenSq = this.tmpVecA.subtract(point, this.center).lengthSquared; + var r = this.radius; + return lenSq < r * r; + } + + /** + * @function + * @name pc.BoundingSphere#intersectsRay + * @description Test if a ray intersects with the sphere. + * @param {pc.Ray} ray Ray to test against (direction must be normalized). + * @param {pc.Vec3} [point] If there is an intersection, the intersection point will be copied into here. + * @returns {Boolean} True if there is an intersection. + */ + public intersectsRay(ray: Ray, point: Vector3) { + var m = this.tmpVecA.copyFrom(ray.origin).subtract(this.center); + var b = m.dotProduct(this.tmpVecB.copyFrom(ray.direction).normalize()); + var c = m.dotProduct(m) - this.radius * this.radius; + + // exit if ray's origin outside of sphere (c > 0) and ray pointing away from s (b > 0) + if (c > 0 && b > 0) return null; + + var discr = b * b - c; + // a negative discriminant corresponds to ray missing sphere + if (discr < 0) return false; + + // ray intersects sphere, compute smallest t value of intersection + var t = Math.abs(-b - Math.sqrt(discr)); + + // if t is negative, ray started inside sphere so clamp t to zero + if (point) point.copyFrom(ray.direction).scaleBy(t).add(ray.origin); + + return true; + } + + /** + * @function + * @name pc.BoundingSphere#intersectsBoundingSphere + * @description Test if a Bounding Sphere is overlapping, enveloping, or inside this Bounding Sphere. + * @param {pc.BoundingSphere} sphere Bounding Sphere to test. + * @returns {Boolean} true if the Bounding Sphere is overlapping, enveloping, or inside this Bounding Sphere and false otherwise. + */ + public intersectsBoundingSphere(sphere: BoundingSphere) { + this.tmpVecA.subtract(sphere.center, this.center); + var totalRadius = sphere.radius + this.radius; + if (this.tmpVecA.lengthSquared <= totalRadius * totalRadius) { + return true; + } + return false; + } + + public calculateTransform(obj: Object3D) { + this.update(obj); + } + + + public containsFrustum(obj: Object3D, frustum: Frustum) { + return frustum.containsSphere(obj); + } + + public clone(): IBound { + return new BoundingSphere(this.center.clone(), this.radius); + } + + public update(obj: Object3D) { + this.owner = obj; + this._center.add(obj.transform.worldMatrix.position, this.center); + this.forward = obj.transform.forward; + } + /** + * @internal + */ + public merge(bound: IBound) { + throw new Error('BoundingSphere merge is not ready!'); + } + + public setFromCenterAndSize(center: Vector3, size: number) { + this.center.copy(center); + this.radius = size; + } +} diff --git a/src/engine/gfx/graphics/webGpu/core/bound/Frustum.ts b/src/engine/gfx/graphics/webGpu/core/bound/Frustum.ts new file mode 100644 index 00000000..b641a0cc --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/bound/Frustum.ts @@ -0,0 +1,200 @@ +import { Matrix4 } from "../../math/Matrix4"; +import { Vector3 } from "../../math/Vector3"; +import { Camera3D } from "../Camera3D"; +import { Object3D } from "../entities/Object3D"; +import { BoundingBox } from "./BoundingBox"; +import { BoundingSphere } from "./BoundingSphere"; + +/** + * @internal + * @group Core + */ +export class Frustum { + public viewProj = new Matrix4(); + public planes: Vector3[]; + public corners: Vector3[]; + + private _centerSize: Vector3; + constructor() { + this._centerSize = new Vector3(); + this.planes = []; + this.corners = []; + for (var i = 0; i < 6; i++) this.planes[i] = new Vector3(); + for (var i = 0; i < 2 * 2 * 2; i++) this.corners[i] = new Vector3(); + } + + genBox(pvInv: Matrix4) { + let i = 0; + let minX = 9999999; + let minY = 9999999; + let minZ = 9999999; + + let maxX = -9999999; + let maxY = -9999999; + let maxZ = -9999999; + for (let x = 0; x < 2; ++x) { + for (let y = 0; y < 2; ++y) { + for (let z = 0; z < 2; ++z) { + let pt = this.corners[i]; + pt.set(2.0 * x - 1.0, 2.0 * y - 1.0, z, 1.0); + pvInv.transformVector4(pt, pt); + pt.div(pt.w, pt); + i++; + minX = Math.min(pt.x, minX); + minY = Math.min(pt.y, minY); + minZ = Math.min(pt.z, minZ); + + maxX = Math.max(pt.x, maxX); + maxY = Math.max(pt.y, maxY); + maxZ = Math.max(pt.z, maxZ); + } + } + } + + this._centerSize.x = maxX - minX; + this._centerSize.y = maxY - minY; + this._centerSize.x = maxZ - minZ; + + return { + minX, minY, minZ, + maxX, maxY, maxZ + }; + } + + setFrustumCorners(pvInv: Matrix4) { + let i = 0; + for (let x = 0; x < 2; ++x) { + for (let y = 0; y < 2; ++y) { + for (let z = 0; z < 2; ++z) { + let pt = this.corners[i]; + pt.set(2.0 * x - 1.0, 2.0 * y - 1.0, z, 1.0); + pvInv.transformVector4(pt, pt); + pt.div(pt.w, pt); + i++; + } + } + } + } + + public update(vpMatrix: Matrix4) { + var vpm = vpMatrix.rawData; + + this.planes[0].x = vpm[3] - vpm[0]; + this.planes[0].y = vpm[7] - vpm[4]; + this.planes[0].z = vpm[11] - vpm[8]; + this.planes[0].w = vpm[15] - vpm[12]; + var t = Math.sqrt(this.planes[0].x * this.planes[0].x + this.planes[0].y * this.planes[0].y + this.planes[0].z * this.planes[0].z); + this.planes[0].x /= t; + this.planes[0].y /= t; + this.planes[0].z /= t; + this.planes[0].w /= t; + + this.planes[1].x = vpm[3] + vpm[0]; + this.planes[1].y = vpm[7] + vpm[4]; + this.planes[1].z = vpm[11] + vpm[8]; + this.planes[1].w = vpm[15] + vpm[12]; + t = Math.sqrt(this.planes[1].x * this.planes[1].x + this.planes[1].y * this.planes[1].y + this.planes[1].z * this.planes[1].z); + this.planes[1].x /= t; + this.planes[1].y /= t; + this.planes[1].z /= t; + this.planes[1].w /= t; + + this.planes[2].x = vpm[3] + vpm[1]; + this.planes[2].y = vpm[7] + vpm[5]; + this.planes[2].z = vpm[11] + vpm[9]; + this.planes[2].w = vpm[15] + vpm[13]; + t = Math.sqrt(this.planes[2].x * this.planes[2].x + this.planes[2].y * this.planes[2].y + this.planes[2].z * this.planes[2].z); + this.planes[2].x /= t; + this.planes[2].y /= t; + this.planes[2].z /= t; + this.planes[2].w /= t; + + this.planes[3].x = vpm[3] - vpm[1]; + this.planes[3].y = vpm[7] - vpm[5]; + this.planes[3].z = vpm[11] - vpm[9]; + this.planes[3].w = vpm[15] - vpm[13]; + t = Math.sqrt(this.planes[3].x * this.planes[3].x + this.planes[3].y * this.planes[3].y + this.planes[3].z * this.planes[3].z); + this.planes[3].x /= t; + this.planes[3].y /= t; + this.planes[3].z /= t; + this.planes[3].w /= t; + + this.planes[4].x = vpm[3] - vpm[2]; + this.planes[4].y = vpm[7] - vpm[6]; + this.planes[4].z = vpm[11] - vpm[10]; + this.planes[4].w = vpm[15] - vpm[14]; + t = Math.sqrt(this.planes[4].x * this.planes[4].x + this.planes[4].y * this.planes[4].y + this.planes[4].z * this.planes[4].z); + this.planes[4].x /= t; + this.planes[4].y /= t; + this.planes[4].z /= t; + this.planes[4].w /= t; + + this.planes[5].x = vpm[3] + vpm[2]; + this.planes[5].y = vpm[7] + vpm[6]; + this.planes[5].z = vpm[11] + vpm[10]; + this.planes[5].w = vpm[15] + vpm[14]; + t = Math.sqrt(this.planes[5].x * this.planes[5].x + this.planes[5].y * this.planes[5].y + this.planes[5].z * this.planes[5].z); + this.planes[5].x /= t; + this.planes[5].y /= t; + this.planes[5].z /= t; + this.planes[5].w /= t; + } + + public containsPoint(point: Vector3) { + for (var p = 0; p < 6; p++) { + if (this.planes[p].x * point.x + this.planes[p].y * point.y + this.planes[p].z * point.z + this.planes[p].w <= 0) return false; + } + return true; + } + + public containsSphere(object3D: Object3D) { + let sphere: BoundingSphere = object3D.bound as BoundingSphere; + let c: number = 0; + let d: number; + let p: number; + + let worldPos = object3D.transform.worldPosition; + + let sr = sphere.radius; + let scx = sphere.center.x + worldPos.x; + let scy = sphere.center.y + worldPos.y; + let scz = sphere.center.z + worldPos.z; + let planes = this.planes; + let plane: Vector3; + + for (p = 0; p < 6; p++) { + plane = planes[p]; + d = plane.x * scx + plane.y * scy + plane.z * scz + plane.w; + if (d <= -sr) return 0; + if (d > sr) c++; + } + + return c === 6 ? 2 : 1; + } + + public containsBox(obj: Object3D) { + let box = obj.bound; + let c = 0; + let d; + let p; + + let worldPos = obj.transform.worldPosition; + + let r = Math.max(box.size.x * obj.transform.scaleX, box.size.y * obj.transform.scaleY, box.size.z * obj.transform.scaleZ); + let sr = r; + let scx = box.center.x + worldPos.x; + let scy = box.center.y + worldPos.y; + let scz = box.center.z + worldPos.z; + let planes = this.planes; + let plane; + + for (p = 0; p < 6; p++) { + plane = planes[p]; + d = plane.x * scx + plane.y * scy + plane.z * scz + plane.w; + if (d <= -sr) return 0; + if (d > sr) c++; + } + + return c === 6 ? 2 : 1; + } +} diff --git a/src/engine/gfx/graphics/webGpu/core/bound/IBound.ts b/src/engine/gfx/graphics/webGpu/core/bound/IBound.ts new file mode 100644 index 00000000..f7e88906 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/core/bound/IBound.ts @@ -0,0 +1,24 @@ +import { Ray } from '../../math/Ray'; +import { Vector3 } from '../../math/Vector3'; +import { Object3D } from '../entities/Object3D'; +import { Frustum } from './Frustum'; +/** + * @internal + */ +export interface IBound { + center: Vector3; + extents: Vector3; + max: Vector3; + min: Vector3; + size: Vector3; + calculateTransform(obj: Object3D): void; + clone(): IBound; + + merge(bound: IBound); + + intersectsRay(ray: Ray, point: Vector3): boolean; + containsPoint(point: Vector3): boolean; + setFromCenterAndSize(center: Vector3, size: Vector3 | number); + + containsFrustum(object3D: Object3D, frustum: Frustum); +} From b31e149c2f1f841a04d019862e210972c909cb0a Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Mon, 24 Apr 2023 16:58:15 +0800 Subject: [PATCH 049/100] feat(camera): add orbit controller (#62) --- .../components/controller/OrbitController.ts | 338 ++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100644 src/engine/components/controller/OrbitController.ts diff --git a/src/engine/components/controller/OrbitController.ts b/src/engine/components/controller/OrbitController.ts new file mode 100644 index 00000000..a3b6d1e1 --- /dev/null +++ b/src/engine/components/controller/OrbitController.ts @@ -0,0 +1,338 @@ +import { Engine3D } from '../../Engine3D'; +import { Camera3D } from '../../core/Camera3D'; +import { ComponentBase } from '../ComponentBase'; +import { Vector3 } from '../../math/Vector3'; +import { Vector3Ex } from '../../util/Vector3Ex'; +import { clamp } from '../../math/MathUtil'; +import { PointerEvent3D } from '../../event/eventConst/PointerEvent3D'; + +/** + * Orbit Camera Controller + * @group CameraController + */ +export class OrbitController extends ComponentBase { + /** + * internal camera + */ + private _camera: Camera3D; + /** + * Whether to enable automatic rotation + */ + public autoRotate: boolean = false; + /** + * Automatic rotation speed coefficient + */ + public autoRotateSpeed: number = 0.1; + /** + * Rotation speed coefficient + */ + public rotateFactor: number = 0.5; + /** + * Scale speed coefficient + */ + public zoomFactor: number = 0.1; + /** + * Angle translation velocity coefficient + */ + public panFactor: number = 0.25; + + private _smooth: number = 5; + private _minDistance: number = 1; + private _maxDistance: number = 100000; + private _maxPolarAngle: number = 90; + private _minPolarAngle: number = -90; + private _target: Vector3 = new Vector3(0, 0, 0); + private _cTarget: Vector3 = new Vector3(0, 0, 0); + private _position: Vector3 = new Vector3(0, 0, 0); + private _cPosition: Vector3 = new Vector3(0, 0, 0); + private _spherical: Spherical = new Spherical() + private _isMouseDown: boolean = false; + private _lastMouseX: number = -1; + private _lastMouseY: number = -1; + private _isPanning: boolean = false + + /** + * @constructor + */ + constructor() { + super(); + } + /** + * Get the target position + */ + public get target(): Vector3 { + return this._target; + } + /** + * Set the target position + */ + public set target(v: Vector3) { + this._target = v; + } + + /** + * Set smoothing coefficient of controller + */ + public get smooth(): number { + return this._smooth; + } + /** + * Get smoothing coefficient of controller + */ + public set smooth(v: number) { + this._smooth = Math.max(v, 1) + } + /** + * Get the minimum distance between the camera and the target coordinate + * @defaultValue 1 + */ + public get minDistance(): number { + return this._minDistance; + } + /** + * Set the minimum distance between the camera and the target position + * min value: 0.000002 + * max value: `this._maxDistance` {@link maxDistance} + */ + public set minDistance(v: number) { + this._minDistance = clamp(v, 0.000002, this._maxDistance); + } + /** + * Get the max distance between the camera and the target position + * @defaultValue 100000 + */ + public get maxDistance(): number { + return this._maxDistance; + } + /** + * Set the max distance between the camera and the target position + * min - `this._maxDistance` + * max - Infinity + */ + public set maxDistance(v: number) { + this._maxDistance = clamp(v, this._minDistance, Infinity); + } + + /** + * Get the lower elevation limit of the camera from the xz plane + * @defaultValue -90 + */ + public get minPolarAngle(): number { + return this._minPolarAngle; + } + /** + * Set the lower elevation limit of the camera from the xz plane + * min - -90 + * max - {@link maxPolarAngle} + */ + public set minPolarAngle(v: number) { + this._minPolarAngle = clamp(v, -90, this._maxPolarAngle); + } + /** + * Get the upper elevation limit of the camera from the xz plane + * @defaultValue 90 + */ + public get maxPolarAngle(): number { + return this._maxPolarAngle; + } + /** + * Set the upper elevation limit of the camera to the xz plane + * min - less than {@link minPolarAngle} + * max - 90 + */ + public set maxPolarAngle(v: number) { + this._maxPolarAngle = clamp(v, this._minPolarAngle, 90); + } + /** + * @internal + */ + protected start() { + this._camera = this.object3D.getComponent(Camera3D); + this._position = this.object3D.transform.localPosition.clone(); + this._cPosition = this._position.clone(); + this._target = this._camera.lookTarget.clone() + this._cTarget = this._target.clone() + this._spherical.setCoords(this._position.x - this._target.x, this._position.y - this._target.y, this._position.z - this._target.z) + this._camera.lookAt(this._cPosition, this._cTarget, Vector3.UP); + this.addEventListener() + } + /** + * @internal + */ + protected onEnable() { + this.addEventListener() + } + /** + * @internal + */ + protected onDisable() { + this.removeEventListener() + } + /** + * @internal + */ + protected onUpdate() { + let step = this._isPanning ? 1 : this.smooth + let changed = false + if (!this._cPosition.equals(this.object3D.transform.localPosition)) { + this._position.copyFrom(this.object3D.transform.localPosition) + step = 1 + changed = true + } + if (!this._cTarget.equals(this._target)) { + this._cTarget.copyFrom(this._target) + step = 1 + changed = true + } + if (changed) { + this._spherical.setCoords(this._position.x - this._target.x, this._position.y - this._target.y, this._position.z - this._target.z) + } else if (!this._isMouseDown && this.autoRotate) { + this._spherical.theta -= this.autoRotateSpeed * Math.PI / 180; + this.updateCamera(); + } + let x = (this._position.x - this._cPosition.x) / step + let y = (this._position.y - this._cPosition.y) / step + let z = (this._position.z - this._cPosition.z) / step + this._cPosition.x = Math.abs(x) > 1e-10 ? this._cPosition.x + x : this._position.x + this._cPosition.y = Math.abs(y) > 1e-10 ? this._cPosition.y + y : this._position.y + this._cPosition.z = Math.abs(z) > 1e-10 ? this._cPosition.z + z : this._position.z + this._camera.lookAt(this._cPosition, this._cTarget, Vector3.UP); + } + /** + * @internal + */ + private onWheel(e: PointerEvent3D) { + this._spherical.radius += e.deltaY * this.zoomFactor; + this._spherical.radius = clamp(this._spherical.radius, this.minDistance, this.maxDistance); + this.updateCamera(); + } + /** + * @internal + */ + private onPointerDown(e: PointerEvent3D) { + this._isMouseDown = true; + this._lastMouseX = e.mouseX; + this._lastMouseY = e.mouseY; + if (e.mouseCode === 2) + this._isPanning = true + } + /** + * @internal + */ + private onPointerMove(e: PointerEvent3D) { + if (!this._isMouseDown || !this.enable) return; + let mousex = e.mouseX; + let mousey = e.mouseY; + // rotate + if (e.mouseCode === 0 && this._lastMouseX > 0 && this._lastMouseY > 0) { + const ra = -(mousex - this._lastMouseX) * this.rotateFactor; + const rb = (mousey - this._lastMouseY) * this.rotateFactor; + this._spherical.theta += ra * Math.PI / 180; + this._spherical.phi -= rb * Math.PI / 180; + this._spherical.phi = clamp(this._spherical.phi, this.minPolarAngle, this.maxPolarAngle); + this.updateCamera(); + // pan + } else if (e.mouseCode === 2) { + Vector3Ex.mulScale(this.object3D.transform.up, e.movementY * this.panFactor * this._camera.aspect, Vector3.HELP_1); + this._target.y += Vector3.HELP_1.y; + Vector3Ex.mulScale(this.object3D.transform.right, -e.movementX * this.panFactor, Vector3.HELP_1); + this._target.x -= Vector3.HELP_1.x; + this._target.z -= Vector3.HELP_1.z; + this._cTarget.copyFrom(this._target) + this.updateCamera(); + } + this._lastMouseX = mousex; + this._lastMouseY = mousey; + } + /** + * @internal + */ + private onPointerUp(e: PointerEvent3D) { + this._isMouseDown = false; + if (e.mouseCode === 2) { + this._isPanning = false; + } + } + private onPointerLeave() { + this._isMouseDown = false; + this._isPanning = false; + } + /** + * @internal + */ + private updateCamera() { + this._spherical.makeSafe(); + let pos = this._spherical.getCoords(); + this._position.set(pos.x + this._target.x, pos.y + this._target.y, pos.z + this._target.z); + } + /** + * @internal + */ + private addEventListener() { + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_WHEEL, this.onWheel, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_DOWN, this.onPointerDown, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_MOVE, this.onPointerMove, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_UP, this.onPointerUp, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_OUT, this.onPointerLeave, this); + } + /** + * @internal + */ + private removeEventListener() { + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_WHEEL, this.onWheel, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_DOWN, this.onPointerDown, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_MOVE, this.onPointerMove, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_UP, this.onPointerUp, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_OUT, this.onPointerLeave, this); + } +} + +/** + * @internal + */ +class Spherical { + public radius: number; + public phi: number; + public theta: number; + public coords: Vector3; + constructor(radius = 1, phi = 0, theta = 0) { + this.radius = radius; + this.phi = phi; // polar angle + this.theta = theta; // azimuthal angle + this.coords = new Vector3() + return this; + } + public set(radius: number, phi: number, theta: number) { + this.radius = radius; + this.phi = phi; + this.theta = theta; + return this; + } + // restrict phi to be between EPS and PI-EPS + public makeSafe(): this { + const EPS = 0.0002; + this.phi = Math.max(EPS, Math.min(Math.PI - EPS, this.phi)); + return this; + } + public setFromVector3(v: Vector3): this { + return this.setCoords(v.x, v.y, v.z); + } + public setCoords(x: number, y: number, z: number): this { + this.radius = Math.sqrt(x * x + y * y + z * z); + if (this.radius === 0) { + this.theta = 0; + this.phi = 0; + } else { + this.theta = Math.atan2(x, z); + this.phi = Math.acos(clamp(y / this.radius, - 1, 1)); + } + return this; + } + public getCoords(): Vector3 { + const sinPhiRadius = Math.sin(this.phi) * this.radius; + this.coords.x = sinPhiRadius * Math.sin(this.theta); + this.coords.y = Math.cos(this.phi) * this.radius; + this.coords.z = sinPhiRadius * Math.cos(this.theta); + return this.coords; + } +} \ No newline at end of file From 1d6c070729a532be3b841a76e0a15494d4dd3977 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Mon, 24 Apr 2023 17:05:19 +0800 Subject: [PATCH 050/100] feat(material): add materials (#63) add renderer base pass add materials --- src/engine/materials/BlendMode.ts | 150 ++++++++ src/engine/materials/ColorLitMaterial.ts | 48 +++ src/engine/materials/GIProbeMaterial.ts | 52 +++ src/engine/materials/GlassMaterial.ts | 81 ++++ src/engine/materials/LambertMaterial.ts | 77 ++++ src/engine/materials/LitMaterial.ts | 86 +++++ src/engine/materials/MaterialBase.ts | 361 ++++++++++++++++++ src/engine/materials/MaterialPass.ts | 167 ++++++++ .../multiPass/CastPointShadowMaterialPass.ts | 30 ++ .../multiPass/CastShadowMaterialPass.ts | 32 ++ .../materials/multiPass/DepthMaterialPass.ts | 32 ++ src/engine/materials/multiPass/GBufferPass.ts | 63 +++ .../materials/multiPass/SkyGBufferPass.ts | 79 ++++ 13 files changed, 1258 insertions(+) create mode 100644 src/engine/materials/BlendMode.ts create mode 100644 src/engine/materials/ColorLitMaterial.ts create mode 100644 src/engine/materials/GIProbeMaterial.ts create mode 100644 src/engine/materials/GlassMaterial.ts create mode 100644 src/engine/materials/LambertMaterial.ts create mode 100644 src/engine/materials/LitMaterial.ts create mode 100644 src/engine/materials/MaterialBase.ts create mode 100644 src/engine/materials/MaterialPass.ts create mode 100644 src/engine/materials/multiPass/CastPointShadowMaterialPass.ts create mode 100644 src/engine/materials/multiPass/CastShadowMaterialPass.ts create mode 100644 src/engine/materials/multiPass/DepthMaterialPass.ts create mode 100644 src/engine/materials/multiPass/GBufferPass.ts create mode 100644 src/engine/materials/multiPass/SkyGBufferPass.ts diff --git a/src/engine/materials/BlendMode.ts b/src/engine/materials/BlendMode.ts new file mode 100644 index 00000000..880fb13e --- /dev/null +++ b/src/engine/materials/BlendMode.ts @@ -0,0 +1,150 @@ +/** + * Blend mode + * |name|description| + * @group Material + */ +export enum BlendMode { + /** + * Working only in WebGPU may improve the performance of large background images without alpha. + * The source pixel is not mixed with the target pixel, so the GPU will not read colors from the target pixel. + */ + NONE, + /** + * Display objects above the background. When the background is transparent, + * the pixel values of the displayed object are not visible. + */ + ABOVE, + + /** + * Transparent mode + */ + ALPHA, + + /** + * Normal blend mode + */ + NORMAL, + + /** + * Add the values of the component colors of the displayed object to its background color + */ + ADD, + + /** + * Add the values of the component colors of the displayed object to its background color + */ + BELOW, + /** + * Erase the background based on the alpha value of the displayed object. + */ + ERASE, + /** + * Multiply the values of the displayed object's constituent colors by the background color, + * and then divide by 0xFF for normalization to obtain a darker color. + */ + MUL, + /** + * Multiply the inverse of the components of the source and target images, and then calculate the inverse result. + */ + SCREEN, + DIVD, + SOFT_ADD, +} +/** + * @internal + * @group Material + */ +export enum Blend { + src_a, + dest_a, +} +/** + * @internal + * @group Material + */ +export class BlendFactor { + static getBlend(blendMode: BlendMode): any { + let blend: GPUBlendState = { + color: { + srcFactor: 'src-alpha', + dstFactor: 'one', + }, + alpha: { + srcFactor: 'one', + dstFactor: 'one', + }, + }; + + // | "add" + // | "subtract" + // | "reverse-subtract" + // | "min" + // | "max"; + switch (blendMode) { + case BlendMode.NONE: + blend.color.srcFactor = `one`; + blend.color.dstFactor = `zero`; + blend.color.operation = 'add'; + break; + case BlendMode.ABOVE: + blend.color.srcFactor = `one-minus-src-alpha`; + blend.color.dstFactor = `dst-alpha`; + blend.color.operation = 'add'; + break; + case BlendMode.ADD: + blend.color.srcFactor = `one`; + blend.color.dstFactor = 'one'; + blend.color.operation = `add`; + + blend.alpha.srcFactor = `one`; + blend.alpha.dstFactor = `one`; + blend.alpha.operation = `add`; + break; + case BlendMode.ALPHA: + blend.color.srcFactor = `src-alpha`; + blend.color.dstFactor = `one-minus-src-alpha`; + + // blend.alpha.srcFactor = `one`; + // blend.alpha.dstFactor = `one`; + // blend.color.operation = `add`; + break; + case BlendMode.BELOW: + blend.color.srcFactor = `one-minus-src-alpha`; + blend.color.dstFactor = 'one'; + blend.color.operation = 'add'; + break; + case BlendMode.ERASE: + blend.color.srcFactor = `zero`; + blend.color.dstFactor = 'one-minus-src-alpha'; + blend.color.operation = 'add'; + break; + case BlendMode.MUL: + blend.color.srcFactor = `dst`; + blend.color.dstFactor = `one-minus-src-alpha`; + blend.color.operation = 'add'; + break; + case BlendMode.NORMAL: + blend.color.srcFactor = 'one'; + blend.color.dstFactor = 'one-minus-src-alpha'; + blend.color.operation = 'add'; + break; + case BlendMode.SOFT_ADD: + blend.color.srcFactor = `one`; + blend.color.dstFactor = 'one'; + blend.color.operation = `max`; + + blend.alpha.srcFactor = `one`; + blend.alpha.dstFactor = `one`; + blend.alpha.operation = `add`; + break; + case BlendMode.SCREEN: + blend.color.srcFactor = 'one'; + blend.color.dstFactor = `one-minus-src`; + blend.color.operation = 'add'; + break; + default: + break; + } + return blend; + } +} diff --git a/src/engine/materials/ColorLitMaterial.ts b/src/engine/materials/ColorLitMaterial.ts new file mode 100644 index 00000000..035432b5 --- /dev/null +++ b/src/engine/materials/ColorLitMaterial.ts @@ -0,0 +1,48 @@ +import { ShaderLib } from '../assets/shader/ShaderLib'; +import { ColorLitShader } from '../assets/shader/materials/ColorLitShader'; +import { Color } from '../math/Color'; +import { defaultRes } from '../textures/DefaultRes'; +import { PhysicMaterial } from './PhysicMaterial'; +/** + * ColorLitMaterial + * @group Material + */ +export class ColorLitMaterial extends PhysicMaterial { + static count = 0; + /** + * @constructor + */ + constructor() { + super(); + + ShaderLib.register("ColorLitShader", ColorLitShader.Ori_AllShader); + + let shader = this.setShader(`ColorLitShader`, `ColorLitShader`); + shader.setDefine("USE_BRDF", true); + shader.setShaderEntry(`VertMain`, `FragMain`) + shader.setUniformColor(`baseColor`, new Color()); + shader.setUniformColor(`emissiveColor`, new Color()); + shader.setUniformFloat(`envIntensity`, 1); + shader.setUniformFloat(`normalScale`, 1); + shader.setUniformFloat(`roughness`, 0.0); + shader.setUniformFloat(`metallic`, 0.0); + shader.setUniformFloat(`ao`, 1.0); + shader.setUniformFloat(`alphaCutoff`, 0.0); + + let shaderState = shader.shaderState; + shaderState.acceptShadow = true; + shaderState.receiveEnv = true; + shaderState.acceptGI = true; + shaderState.useLight = true; + + shader.setTexture("normalMap", defaultRes.normalTexture); + shader.setTexture("emissiveMap", defaultRes.blackTexture); + } + + clone(): this { + return null; + } + + debug() { + } +} diff --git a/src/engine/materials/GIProbeMaterial.ts b/src/engine/materials/GIProbeMaterial.ts new file mode 100644 index 00000000..14122bd1 --- /dev/null +++ b/src/engine/materials/GIProbeMaterial.ts @@ -0,0 +1,52 @@ +import { GIProbeShader } from '../..'; +import { ShaderLib } from '../assets/shader/ShaderLib'; +import { Engine3D } from '../Engine3D'; +import { Vector4 } from '../math/Vector4'; +import { defaultRes } from '../textures/DefaultRes'; +import { PhysicMaterial } from './PhysicMaterial'; + +/** + * @internal + * @group Material + */ +export enum GIProbeMaterialType { + CastGI = 0, + ReceiveGI = 1, + CastDepth = 2, + Other = 3, +} + +export class GIProbeMaterial extends PhysicMaterial { + static count = 0; + + constructor(type: GIProbeMaterialType = GIProbeMaterialType.CastGI, index: number = 0) { + super(); + + ShaderLib.register("GIProbeShader", GIProbeShader); + this.setShader('GIProbeShader', 'GIProbeShader'); + + let shader = this.getShader(); + shader.setDefine('USE_BRDF', true); + shader.setShaderEntry(`VertMain`, `FragMain`); + shader.setUniformVector4('probeUniform', new Vector4(index, type, 0, 0)); + let shaderState = shader.shaderState; + shaderState.acceptShadow = false; + shaderState.castShadow = false; + shaderState.receiveEnv = false; + shaderState.acceptGI = false; + shaderState.useLight = false; + + let bdrflutTex = Engine3D.res.getTexture(`BRDFLUT`); + this.brdfLUT = bdrflutTex; + + this.baseMap = defaultRes.whiteTexture; + this.normalMap = defaultRes.normalTexture; + // this.aoMap = defaultTexture.whiteTexture; + // this.maskMap = defaultTexture.maskTexture; + // this.maskMap = defaultTexture.grayTexture; + // shader.setDefine(`USE_ARMC`, false); + this.emissiveMap = defaultRes.blackTexture; + } + + debug() { } +} diff --git a/src/engine/materials/GlassMaterial.ts b/src/engine/materials/GlassMaterial.ts new file mode 100644 index 00000000..d43d96e2 --- /dev/null +++ b/src/engine/materials/GlassMaterial.ts @@ -0,0 +1,81 @@ +import { registerMaterial } from '../..'; +import { ShaderLib } from '../assets/shader/ShaderLib'; +import GlassShader from '../assets/shader/materials/GlassShader.wgsl?raw'; +import { Engine3D } from '../Engine3D'; +import { Vector4 } from '../math/Vector4'; +import { defaultRes } from '../textures/DefaultRes'; +import { PhysicMaterial } from './PhysicMaterial'; +/** + * GlassMaterial + * an rendering material implemented by simulating glass surfaces + * @group Material + */ +export class GlassMaterial extends PhysicMaterial { + + /** + * @constructor + */ + constructor() { + super(); + + ShaderLib.register("GlassShader", GlassShader); + this.setShader('GlassShader', 'GlassShader'); + + let shader = this.getShader(); + shader.setDefine("USE_BRDF", true); + shader.setShaderEntry(`VertMain`, `FragMain`) + + let shaderState = shader.shaderState; + shaderState.acceptShadow = true; + shaderState.castShadow = true; + shaderState.receiveEnv = true; + shaderState.acceptGI = true; + shaderState.useLight = true; + + let bdrflutTex = Engine3D.res.getTexture(`BRDFLUT`); + this.brdfLUT = bdrflutTex; + + this.baseMap = defaultRes.whiteTexture; + this.normalMap = defaultRes.normalTexture; + // this.aoMap = defaultTexture.whiteTexture; + // this.maskMap = defaultTexture.maskTexture; + // this.maskMap = defaultTexture.grayTexture; + // shader.setDefine(`USE_ARMC`, false); + this.emissiveMap = defaultRes.blackTexture; + + } + + clone(): this { + console.log(`clone material ${this.name}`); + + let ret = new GlassMaterial(); + ret.baseMap = this.baseMap; + ret.normalMap = this.normalMap; + ret.aoMap = this.aoMap; + if (this.maskMap) ret.maskMap = this.maskMap; + ret.emissiveMap = this.emissiveMap; + this.uvTransform_1 && (ret.uvTransform_1 = new Vector4().copyFrom(this.uvTransform_1)); + this.uvTransform_2 && (ret.uvTransform_2 = new Vector4().copyFrom(this.uvTransform_2)); + ret.baseColor = this.baseColor.clone(); + ret.emissiveColor = this.emissiveColor.clone(); + this.materialF0 && (ret.materialF0 = new Vector4().copyFrom(this.materialF0)); + ret.envIntensity = this.envIntensity; + ret.normalScale = this.normalScale; + ret.roughness = this.roughness; + ret.metallic = this.metallic; + ret.ao = this.ao; + ret.roughness_min = this.roughness_min; + ret.roughness_max = this.roughness_max; + ret.metallic_min = this.metallic_min; + ret.metallic_max = this.metallic_max; + ret.emissiveIntensity = this.emissiveIntensity; + ret.alphaCutoff = this.alphaCutoff; + ret.ior = this.ior; + ret.clearcoatFactor = this.clearcoatFactor; + ret.clearcoatRoughnessFactor = this.clearcoatRoughnessFactor; + return ret as this; + } + +} + +registerMaterial('GlassMaterial', GlassMaterial); \ No newline at end of file diff --git a/src/engine/materials/LambertMaterial.ts b/src/engine/materials/LambertMaterial.ts new file mode 100644 index 00000000..a663a4a0 --- /dev/null +++ b/src/engine/materials/LambertMaterial.ts @@ -0,0 +1,77 @@ + +import { Lambert_shader } from '../assets/shader/materials/Lambert_shader'; +import { ShaderLib } from '../assets/shader/ShaderLib'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { Color } from '../math/Color'; +import { Vector4 } from '../math/Vector4'; +import { defaultRes } from '../textures/DefaultRes'; +import { MaterialBase } from './MaterialBase'; +import { registerMaterial } from "./MaterialRegister"; + +/** + * Lambert Mateiral + * A non glossy surface material without specular highlights. + * @group Material + */ +export class LambertMaterial extends MaterialBase { + /** + * @constructor + */ + constructor() { + super(); + ShaderLib.register("lambert_vert_wgsl", Lambert_shader.lambert_vert_wgsl); + ShaderLib.register("lambert_frag_wgsl", Lambert_shader.lambert_frag_wgsl); + + let shader = this.setShader(`lambert_vert_wgsl`, `lambert_frag_wgsl`); + shader.setUniformVector4(`transformUV1`, new Vector4(0, 0, 1, 1)); + shader.setUniformVector4(`transformUV2`, new Vector4(0, 0, 1, 1)); + shader.setUniformColor(`baseColor`, new Color()); + shader.setUniformVector4(`dirLight`, new Vector4(0, 0, 1, 1)); + shader.setUniformColor(`dirLightColor`, new Color()); + shader.setUniformFloat(`alphaCutoff`, 0.5); + shader.setUniformFloat(`shadowBias`, 0.00035); + + let shaderState = shader.shaderState; + shaderState.acceptShadow = true; + shaderState.castShadow = true; + shaderState.receiveEnv = false; + shaderState.acceptGI = false; + shaderState.useLight = true; + + // default value + this.baseMap = defaultRes.whiteTexture; + this.emissiveMap = defaultRes.blackTexture; + this.baseMap = defaultRes.grayTexture; + } + + /** + * set base color (tint color) + */ + set baseColor(color: Color) { + this.renderShader.setUniformColor(`baseColor`, color); + } + + /** + * get base color (tint color) + */ + get baseColor() { + return this.renderShader.uniforms[`baseColor`].color; + } + + /** + * set environment texture, usually referring to cubemap + */ + public set envMap(texture: Texture) { + //not need env texture + } + + /** + * @internal + * set shadow map + */ + public set shadowMap(texture: Texture) { + //not need shadowMap texture + } + +} +registerMaterial("LambertMaterial", LambertMaterial); \ No newline at end of file diff --git a/src/engine/materials/LitMaterial.ts b/src/engine/materials/LitMaterial.ts new file mode 100644 index 00000000..f1eed728 --- /dev/null +++ b/src/engine/materials/LitMaterial.ts @@ -0,0 +1,86 @@ +import { registerMaterial } from '../..'; +import { Engine3D } from '../Engine3D'; +import { Vector4 } from '../math/Vector4'; +import { defaultRes } from '../textures/DefaultRes'; +import { PhysicMaterial } from './PhysicMaterial'; +/** + * a type of material, based on physical lighting model + * @group Material + */ +export class LitMaterial extends PhysicMaterial { + static count = 0; + + /** + *@constructor + */ + constructor() { + super(); + + this.setShader('PBRLItShader', 'PBRLItShader'); + + let shader = this.getShader(); + shader.setShaderEntry(`VertMain`, `FragMain`) + shader.setDefine("USE_BRDF", true); + shader.setDefine("USE_NORMALFILPY", Engine3D.setting.material.normalYFlip); + + let shaderState = shader.shaderState; + shaderState.acceptShadow = true; + shaderState.castShadow = true; + shaderState.receiveEnv = true; + shaderState.acceptGI = true; + shaderState.useLight = true; + + let bdrflutTex = Engine3D.res.getTexture(`BRDFLUT`); + this.brdfLUT = bdrflutTex; + + this.baseMap = defaultRes.whiteTexture; + this.normalMap = defaultRes.normalTexture; + // this.aoMap = defaultTexture.whiteTexture; + // this.maskMap = defaultTexture.maskTexture; + // this.maskMap = defaultTexture.grayTexture; + // shader.setDefine(`USE_ARMC`, false); + this.emissiveMap = defaultRes.blackTexture; + // this.alphaCutoff = 0.5; + + + } + + public clone(): this { + console.log(`clone LitMaterial ${this.name}`); + + let ret = new LitMaterial(); + ret.baseMap = this.baseMap; + ret.normalMap = this.normalMap; + ret.aoMap = this.aoMap; + if (this.maskMap) ret.maskMap = this.maskMap; + ret.emissiveMap = this.emissiveMap; + this.uvTransform_1 && (ret.uvTransform_1 = new Vector4().copyFrom(this.uvTransform_1)); + this.uvTransform_2 && (ret.uvTransform_2 = new Vector4().copyFrom(this.uvTransform_2)); + ret.baseColor = this.baseColor.clone(); + ret.emissiveColor = this.emissiveColor.clone(); + this.materialF0 && (ret.materialF0 = new Vector4().copyFrom(this.materialF0)); + ret.envIntensity = this.envIntensity; + ret.normalScale = this.normalScale; + ret.roughness = this.roughness; + ret.metallic = this.metallic; + ret.ao = this.ao; + ret.roughness_min = this.roughness_min; + ret.roughness_max = this.roughness_max; + ret.metallic_min = this.metallic_min; + ret.metallic_max = this.metallic_max; + ret.emissiveIntensity = this.emissiveIntensity; + ret.alphaCutoff = this.alphaCutoff; + ret.ior = this.ior; + ret.clearcoatFactor = this.clearcoatFactor; + ret.clearcoatRoughnessFactor = this.clearcoatRoughnessFactor; + return ret as this; + } + + /** + * internal + */ + debug() { + } +} + +registerMaterial("LitMaterial", LitMaterial); diff --git a/src/engine/materials/MaterialBase.ts b/src/engine/materials/MaterialBase.ts new file mode 100644 index 00000000..d4225a66 --- /dev/null +++ b/src/engine/materials/MaterialBase.ts @@ -0,0 +1,361 @@ +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { ShaderState } from '../gfx/graphics/webGpu/shader/value/ShaderState'; +import { RendererType } from '../gfx/renderJob/passRenderer/state/RendererType'; +import { Color } from '../math/Color'; +import { Vector4 } from '../math/Vector4'; +import { UUID } from '../util/Global'; +import { MaterialPass } from './MaterialPass'; +import { registerMaterial } from './MaterialRegister'; + +/** + * + * The base class for all shaders, + * describing how an object's surface should be rendered + * @internal + * @group Material + */ +export class MaterialBase extends MaterialPass { + + /** + * + * name of this material + */ + public name: string; + + /** + * + * Material Unique Identifier + */ + public instanceID: string; + + /** + * is PassMaterial + */ + public isPassMaterial: boolean = false; + + /** + * Whether to receive environment effect + */ + public receiveEnv: boolean = true; + + private _normalMapYFlip: boolean; + + + public get shaderState(): ShaderState { + return this.renderShader.shaderState; + } + + public set shaderState(value: ShaderState) { + this.renderShader.shaderState = value; + } + + + public get normalMapYFlip(): boolean { + return this._normalMapYFlip; + } + + public set normalMapYFlip(value: boolean) { + this._normalMapYFlip = value; + if (value) { + this.renderShader.setDefine("USE_NORMALFILPY", true); + } + } + + /** + * Set shadow map + */ + public set shadowMap(texture: Texture) { + this.renderShader.setTexture(`shadowMap`, texture); + } + + /** + * Set environment map + */ + public set envMap(texture: Texture) { + this.renderShader.setTexture(`envMap`, texture); + } + + /** + * Set base map(main map) + */ + public set baseMap(texture: Texture) { + this.renderShader.setTexture(`baseMap`, texture); + + this.notifyPropertyChange(`baseMap`, texture); + } + + /** + * Get base map(main map) + */ + public get baseMap(): Texture { + return this.renderShader.textures[`baseMap`]; + } + + /** + * Get normal map + */ + public get normalMap(): Texture { + return this.renderShader.textures[`normalMap`]; + } + + /** + * Set normal map + */ + public set normalMap(texture: Texture) { + this.renderShader.setTexture(`normalMap`, texture); + this.notifyPropertyChange(`normalMap`, texture); + } + + /** + * Get emissive map + */ + public get emissiveMap(): Texture { + return this.renderShader.textures[`emissiveMap`]; + } + + /** + * Get emissive color + */ + public get emissiveColor(): Color { + return this.renderShader.uniforms[`emissiveColor`].color; + } + + /** + * Set emissive color + */ + public set emissiveColor(value: Color) { + this.renderShader.setUniformColor(`emissiveColor`, value); + this.notifyPropertyChange(`emissiveColor`, value); + } + + /** + * Set emissive intensity + */ + public set emissiveIntensity(value: number) { + this.renderShader.setUniformFloat(`emissiveIntensity`, value); + this.notifyPropertyChange(`emissiveIntensity`, value); + } + + /** + * Get emissive intensity + */ + public get emissiveIntensity(): number { + return this.renderShader.uniforms[`emissiveIntensity`].value; + } + + + + /** + * Set emissive map + */ + public set emissiveMap(value: Texture) { + // this.textures[7] = value; + this.renderShader.setTexture(`emissiveMap`, value); + this.notifyPropertyChange(`emissiveMap`, value); + // this.onChange = true; + } + + /** + * Get envionment effect intensity + */ + public get envIntensity() { + return this.renderShader.uniforms[`envIntensity`].value; + } + + /** + * Set envionment effect intensity + */ + public set envIntensity(value: number) { + if (`envIntensity` in this.renderShader.uniforms) this.renderShader.uniforms[`envIntensity`].value = value; + this.notifyPropertyChange(`envIntensity`, value); + } + + /** + * Get normal strength + */ + public get normalScale() { + return this.renderShader.uniforms[`normalScale`].value; + } + + /** + * Set normal strength + */ + public set normalScale(value: number) { + if (`normalScale` in this.renderShader.uniforms) this.renderShader.uniforms[`envIntensity`].value = value; + this.notifyPropertyChange(`normalScale`, value); + } + + /** + * Get alphaCutoff, channel transparency threshold parameter + */ + public get alphaCutoff() { + return this.renderShader.uniforms[`alphaCutoff`].value; + } + + /** + * Set alphaCutoff, channel transparency threshold parameter + */ + public set alphaCutoff(value: number) { + if (`alphaCutoff` in this.renderShader.uniforms) { + this.renderShader.uniforms[`alphaCutoff`].value = value; + if (value < 1.0 && value != 0) { + this.renderShader.setDefine("USE_ALPHACUT", true); + console.log("USE_ALPHACUT"); + } else { + this.renderShader.setDefine("USE_ALPHACUT", false); + } + this.notifyPropertyChange(`alphaCutoff`, value); + } + } + + /** + * Get irradiance map + */ + public get irradianceMap(): Texture { + return this.renderShader.textures[`irradianceMap`]; + } + + /** + * Set irradiance map + */ + public set irradianceMap(value: Texture) { + this.renderShader.setTexture(`irradianceMap`, value); + this.notifyPropertyChange(`irradianceMap`, value); + } + + /** + * Get irradiance depth map + */ + public get irradianceDepthMap(): Texture { + return this.renderShader.textures[`irradianceDepthMap`]; + } + + /** + * Set irradiance depth map + */ + public set irradianceDepthMap(value: Texture) { + this.renderShader.setTexture(`irradianceDepthMap`, value); + this.notifyPropertyChange(`irradianceDepthMap`, value); + } + + /** + * Get base color(tint color) + */ + public get baseColor(): Color { + return this.renderShader.uniforms[`baseColor`].color; + } + + /** + * Set base color(tint color) + */ + public set baseColor(value: Color) { + this.renderShader.setUniformColor(`baseColor`, value); + this.notifyPropertyChange(`baseColor`, value); + } + + + /** + * Get uvTransform_1 + */ + public get uvTransform_1(): Vector4 { + return this.renderShader.uniforms[`transformUV1`].vector4; + } + + /** + * Set uvTransform_1 + */ + public set uvTransform_1(value: Vector4) { + this.renderShader.uniforms[`transformUV1`].vector4 = value; + this.notifyPropertyChange(`transformUV1`, value); + } + + /** + * Get uvTransform_2 + */ + public get uvTransform_2(): Vector4 { + return this.renderShader.uniforms[`transformUV2`].vector4; + } + + /** + * Set uvTransform_2 + */ + public set uvTransform_2(value: Vector4) { + this.renderShader.uniforms[`transformUV2`].vector4 = value; + this.notifyPropertyChange(`uvTransform_2`, value); + } + + constructor() { + super(); + this.instanceID = UUID(); + this.renderPasses = new Map(); + } + + protected notifyPropertyChange(property: string, value: any) { + // this.renderPasses.forEach((v, k) => { + // v.forEach((v2) => { + // if (v2 != this) { + // v2[property] = value; + // } + // }) + // }); + } + + /** + * Enable/Disable the definition of shaders + * @param {string} define key + * @param {boolean} [value=true] values + * @memberof MaterialBase + */ + public setDefine(define: string, bool: boolean) { + this.renderShader.setDefine(define, true); + } + + public hasPass(passType: RendererType) { + return this.renderPasses.has(passType); + } + + public addPass(passType: RendererType, pass: MaterialPass, index: number = -1): MaterialPass[] { + if (!this.renderPasses.has(passType)) this.renderPasses.set(passType, []); + + let passList = this.renderPasses.get(passType); + + let has = passList.indexOf(pass) != -1; + if (!has) { + if (index == -1) { + passList.push(pass); + } else { + passList.splice(index, -1, pass); + } + } + return passList; + } + + public removePass(passType: RendererType, index: number) { + if (this.renderPasses.has(passType)) { + let list = this.renderPasses.get(passType); + if (index < list.length) { + list.splice(index, 1); + } + } + } + + + /** + * destroy self + */ + public destroy(): void { + super.destroy(); + } + + + /** + * clone one material + * @returns Material + */ + public clone() { + return null; + } + +} + +registerMaterial("MaterialBase", MaterialBase); \ No newline at end of file diff --git a/src/engine/materials/MaterialPass.ts b/src/engine/materials/MaterialPass.ts new file mode 100644 index 00000000..a2dde7c9 --- /dev/null +++ b/src/engine/materials/MaterialPass.ts @@ -0,0 +1,167 @@ +import { GPUCullMode, RendererType } from "../.."; +import { RenderShader } from "../gfx/graphics/webGpu/shader/RenderShader"; +import { BlendMode } from "./BlendMode"; + +export class MaterialPass { + + public renderPasses: Map; + + /** + * whether the pass is enable + */ + public enable: boolean = true; + + public renderShader: RenderShader; + + private _shaderID: string; + + private _sort: number = 3000; + + private _transparent: boolean = false; + + public get sort(): number { + return this._sort; + } + + public set sort(value: number) { + this._sort = value; + } + + public get shaderID(): string { + return this._shaderID; + } + + public set shaderID(value: string) { + this._shaderID = value; + } + + public setShader(vs: string, fs: string) { + this._shaderID = RenderShader.createShader(vs, fs); + this.renderShader = this.getShader(); + this.renderShader.setDefault(); + return this.renderShader; + } + + public getShader() { + return RenderShader.getShader(this._shaderID); + } + + /** + * Get blend mode, see {@link BlendMode} + */ + public get blendMode(): BlendMode { + return this.renderShader.blendMode; + } + + /** + * Set blend mode, see {@link BlendMode} + */ + public set blendMode(value: BlendMode) { + this.renderShader.blendMode = value; + // this.transparent = value != BlendMode.NONE && value != BlendMode.NORMAL; + } + + /** + * Get whether use transparent mode to render + */ + public get transparent(): boolean { + return this._transparent; + } + + /** + * Set whether use transparent mode to render + */ + public set transparent(value: boolean) { + this._transparent = value; + } + + /** + * Return GPUFrontFace + */ + public get frontFace(): GPUFrontFace { + return this.renderShader.frontFace; + } + + /** + * Set GPUFrontFace + */ + public set frontFace(value: GPUFrontFace) { + this.renderShader.frontFace = value; + } + + /** + * Get whether use double side to render object + */ + public get doubleSide(): boolean { + return this.renderShader.cullMode == GPUCullMode.none; + } + + /** + * Set whether use double side to render object + */ + public set doubleSide(value: boolean) { + this.renderShader.cullMode = value ? GPUCullMode.none : this.renderShader.cullMode; + } + + /** + * get cull mode, see {@link GPUCullMode} + */ + public get cullMode(): GPUCullMode { + return this.renderShader.cullMode; + } + + /** + * set cull mode, see {@link GPUCullMode} + */ + public set cullMode(value: GPUCullMode) { + this.renderShader.cullMode = value ? value : this.renderShader.cullMode; + } + + public get depthBias(): number { + return this.renderShader.depthBias; + } + + public set depthBias(value: number) { + this.renderShader.depthBias = value; + } + + /** + * get depth compare mode, see {@link GPUCompareFunction} + */ + public get depthCompare(): GPUCompareFunction { + return this.renderShader.depthCompare; + } + + /** + * set depth compare mode, see {@link GPUCompareFunction} + */ + public set depthCompare(value: GPUCompareFunction) { + this.renderShader.depthCompare = value ? value : this.renderShader.depthCompare; + } + + /** + * release material pass + */ + public destroy() { + this.renderShader.destroy(); + this.renderShader = null; + + this.renderPasses.forEach((v, k) => { + for (let i = 0; i < v.length; i++) { + const pass = v[i]; + pass.destroy(); + } + v.length = 0; + }); + this.renderPasses.clear(); + this.renderPasses = null; + } + + public clone(): MaterialPass { + return null; + } + + debug() { + throw new Error('Method not implemented.'); + } +} \ No newline at end of file diff --git a/src/engine/materials/multiPass/CastPointShadowMaterialPass.ts b/src/engine/materials/multiPass/CastPointShadowMaterialPass.ts new file mode 100644 index 00000000..b93f11c0 --- /dev/null +++ b/src/engine/materials/multiPass/CastPointShadowMaterialPass.ts @@ -0,0 +1,30 @@ +import { CastShadow } from '../../assets/shader/core/pass/CastShadowPass_wgsl'; +import { ShaderLib } from '../../assets/shader/ShaderLib'; +import { Vector3 } from '../../math/Vector3'; +import { MaterialBase } from '../MaterialBase'; +import { registerMaterial } from "../MaterialRegister"; + +/** + * @internal + * CastPointShadowMaterialPass + * @group Material + */ +export class CastPointShadowMaterialPass extends MaterialBase { + transparency: number; + constructor() { + super(); + this.isPassMaterial = true; + ShaderLib.register("castPointShadowMap_vert_wgsl", CastShadow.castPointShadowMap_vert_wgsl); + ShaderLib.register("shadowCastMap_frag_wgsl", CastShadow.shadowCastMap_frag_wgsl); + + let shader = this.setShader(`castPointShadowMap_vert_wgsl`, `shadowCastMap_frag_wgsl`); + shader.setShaderEntry("main", "main"); + shader.setUniformFloat("cameraFar", 5000); + shader.setUniformVector3("lightWorldPos", Vector3.ZERO); + let shaderState = shader.shaderState; + shaderState.receiveEnv = false; + // this.alphaCutoff = 0.5 ; + } +} + +registerMaterial('CastShadowMaterialPass', CastPointShadowMaterialPass); \ No newline at end of file diff --git a/src/engine/materials/multiPass/CastShadowMaterialPass.ts b/src/engine/materials/multiPass/CastShadowMaterialPass.ts new file mode 100644 index 00000000..930c75aa --- /dev/null +++ b/src/engine/materials/multiPass/CastShadowMaterialPass.ts @@ -0,0 +1,32 @@ +import { Vector3 } from '../../..'; +import { CastShadow } from '../../assets/shader/core/pass/CastShadowPass_wgsl'; +import { ShaderLib } from '../../assets/shader/ShaderLib'; +import { MaterialBase } from '../MaterialBase'; +import { registerMaterial } from "../MaterialRegister"; + +/** + * @internal + * CastShadowMaterialPass + * @group Material + */ +export class CastShadowMaterialPass extends MaterialBase { + transparency: number; + constructor() { + super(); + this.isPassMaterial = true; + //OutLineSubPass this.shaderState + ShaderLib.register("shadowCastMap_vert_wgsl", CastShadow.shadowCastMap_vert_wgsl); + ShaderLib.register("shadowCastMap_frag_wgsl", CastShadow.shadowCastMap_frag_wgsl); + // let shader = this.setShader(`shadowCastMap_vert_wgsl`,`shadowCastMap_frag_wgsl`); + let shader = this.setShader(`shadowCastMap_vert_wgsl`, `shadowCastMap_frag_wgsl`); + shader.setShaderEntry("main"); + shader.setUniformFloat("cameraFar", 5000); + shader.setUniformVector3("lightWorldPos", Vector3.ZERO); + + let shaderState = shader.shaderState; + shaderState.receiveEnv = false; + // this.alphaCutoff = 0.5 ; + } +} + +registerMaterial('CastShadowMaterialPass', CastShadowMaterialPass); \ No newline at end of file diff --git a/src/engine/materials/multiPass/DepthMaterialPass.ts b/src/engine/materials/multiPass/DepthMaterialPass.ts new file mode 100644 index 00000000..9803b8aa --- /dev/null +++ b/src/engine/materials/multiPass/DepthMaterialPass.ts @@ -0,0 +1,32 @@ +import { ShaderLib } from '../../assets/shader/ShaderLib'; +import { MaterialBase } from '../MaterialBase'; +import { registerMaterial } from "../MaterialRegister"; +import { ZPassShader_vs } from '../../assets/shader/core/pass/ZPassShader_vs'; +import ZPassShader_fs from '../../assets/shader/core/pass/ZPassShader_fs.wgsl?raw'; + + +/** + * @internal + * DepthMaterialPass + * @group Material + */ +export class DepthMaterialPass extends MaterialBase { + transparency: number; + constructor() { + super(); + this.isPassMaterial = true; + //OutLineSubPass + + ShaderLib.register("ZPass_shader_vs", ZPassShader_vs); + ShaderLib.register("ZPass_shader_fs", ZPassShader_fs); + + // let shader = this.setShader(`ZPass_shader_vs`,`ZPass_shader_fs`); + let shader = this.setShader(`ZPass_shader_vs`, `ZPass_shader_fs`); + shader.useRz = true; + // shader.setShaderEntry("main"); + + let shaderState = shader.shaderState; + shaderState.receiveEnv = false; + } +} +registerMaterial('DepthMaterialPass', DepthMaterialPass); \ No newline at end of file diff --git a/src/engine/materials/multiPass/GBufferPass.ts b/src/engine/materials/multiPass/GBufferPass.ts new file mode 100644 index 00000000..2c6b43e2 --- /dev/null +++ b/src/engine/materials/multiPass/GBufferPass.ts @@ -0,0 +1,63 @@ +import { ShaderLib } from '../../assets/shader/ShaderLib'; +import { Texture } from '../../gfx/graphics/webGpu/core/texture/Texture'; +import { Color } from '../../math/Color'; +import { defaultRes } from '../../textures/DefaultRes'; +import { BlendMode } from '../BlendMode'; +import { MaterialBase } from '../MaterialBase'; +import { registerMaterial } from "../MaterialRegister"; +import GBuffer_shader from '../../assets/shader/core/pass/GBuffer_shader.wgsl?raw'; + +/** + * @internal + * GBufferPass + * @group Material + */ +export class GBufferPass extends MaterialBase { + transparency: number; + + constructor() { + super(); + this.isPassMaterial = true; + //OutLineSubPass + + ShaderLib.register("gbuffer_vs", GBuffer_shader); + ShaderLib.register("gbuffer_fs", GBuffer_shader); + let shader = this.setShader(`gbuffer_vs`, `gbuffer_fs`); + shader.setShaderEntry(`VertMain`, `FragMain`) + + let shaderState = this.shaderState; + shaderState.cullMode = `none`; + + this.renderShader.setUniformColor(`baseColor`, new Color()); + this.renderShader.setUniformColor(`emissiveColor`, new Color()); + this.renderShader.setUniformFloat(`emissiveIntensity`, 1); + this.renderShader.setUniformFloat(`normalScale`, 1); + this.renderShader.setUniformFloat(`alphaCutoff`, 1); + this.blendMode = BlendMode.NONE; + + this.renderShader.setTexture(`normalMap`, defaultRes.normalTexture); + } + + public set shadowMap(texture: Texture) { } + + public set envMap(texture: Texture) { + // super.envMap = texture; + } + + public set normalScale(v: number) { + this.renderShader.setUniformFloat(`normalScale`, v); + } + + public get normalScale(): number { + return this.renderShader.uniforms['normalScale'].value; + } + + public set alphaCutoff(v: number) { + this.renderShader.setUniformFloat(`alphaCutoff`, v); + } + + public get alphaCutoff(): number { + return this.renderShader.uniforms['alphaCutoff'].value; + } +} +registerMaterial('GBufferPass', GBufferPass); \ No newline at end of file diff --git a/src/engine/materials/multiPass/SkyGBufferPass.ts b/src/engine/materials/multiPass/SkyGBufferPass.ts new file mode 100644 index 00000000..23207c0e --- /dev/null +++ b/src/engine/materials/multiPass/SkyGBufferPass.ts @@ -0,0 +1,79 @@ +import { ShaderLib } from '../../assets/shader/ShaderLib'; +import { Texture } from '../../gfx/graphics/webGpu/core/texture/Texture'; +import { GPUCompareFunction, GPUCullMode } from '../../gfx/graphics/webGpu/WebGPUConst'; +import { MaterialBase } from '../MaterialBase'; +import { registerMaterial } from "../MaterialRegister"; +import SkyGBuffer_fs from '../../assets/shader/core/pass/SkyGBuffer_fs.wgsl?raw'; + +/** + * @internal + * @group Material + */ +export class SkyGBufferPass extends MaterialBase { + transparency: number; + + constructor() { + super(); + this.isPassMaterial = true; + //OutLineSubPass + ShaderLib.register("SkyGBuffer_fs", SkyGBuffer_fs); + + let shader = this.setShader(`sky_vs_frag_wgsl`, `SkyGBuffer_fs`); + shader.setUniformFloat(`exposure`, 1.0); + shader.setUniformFloat(`roughness`, 0.0); + + let shaderState = this.shaderState; + shaderState.frontFace = `ccw`; + shaderState.cullMode = GPUCullMode.front; + shaderState.depthWriteEnabled = false; + shaderState.depthCompare = GPUCompareFunction.less; + } + + public get exposure(): number { + return this.renderShader.uniforms['exposure'].value; + } + + public set exposure(value: number) { + this.renderShader.setUniformFloat(`exposure`, value); + } + + public get roughness(): number { + return this.renderShader.uniforms['roughness'].value; + } + + public set roughness(value: number) { + this.renderShader.setUniformFloat(`roughness`, value); + } + + public set shadowMap(texture: Texture) { } + + public set envMap(texture: Texture) { + // super.envMap = texture; + } + + public set emissiveIntensity(v: number) { + this.renderShader.setUniformFloat(`emissiveIntensity`, v); + } + + public get emissiveIntensity(): number { + return this.renderShader.uniforms['emissiveIntensity'].value; + } + + public set normalScale(v: number) { + this.renderShader.setUniformFloat(`normalScale`, v); + } + + public get normalScale(): number { + return this.renderShader.uniforms['normalScale'].value; + } + + public set alphaCutoff(v: number) { + this.renderShader.setUniformFloat(`alphaCutoff`, v); + } + + public get alphaCutoff(): number { + return this.renderShader.uniforms['alphaCutoff'].value; + } +} + +registerMaterial('SkyGBufferPass', SkyGBufferPass); \ No newline at end of file From 4f18553f520dacf5a42e2b131c5984b28dacb94e Mon Sep 17 00:00:00 2001 From: hellmor Date: Mon, 24 Apr 2023 18:24:18 +0800 Subject: [PATCH 051/100] feat(ECS): Add ECS files (#66) Add ECS framework into engine. --- src/engine/components/AtmosphericComponent.ts | 98 +++ src/engine/components/BillboardComponent.ts | 40 + src/engine/components/ComponentBase.ts | 241 ++++++ src/engine/components/Transform.ts | 808 ++++++++++++++++++ .../post/PostProcessingComponent.ts | 68 ++ .../renderer/GlobalIlluminationComponent.ts | 171 ++++ .../renderer/InstanceDrawComponent.ts | 124 +++ .../components/renderer/MaterialComponent.ts | 43 + .../components/renderer/MeshComponent.ts | 49 ++ .../components/renderer/MeshRenderer.ts | 138 +++ src/engine/components/renderer/RenderNode.ts | 447 ++++++++++ .../renderer/SkinnedMeshRenderer.ts | 121 +++ src/engine/components/renderer/SkyRenderer.ts | 105 +++ 13 files changed, 2453 insertions(+) create mode 100644 src/engine/components/AtmosphericComponent.ts create mode 100644 src/engine/components/BillboardComponent.ts create mode 100644 src/engine/components/ComponentBase.ts create mode 100644 src/engine/components/Transform.ts create mode 100644 src/engine/components/post/PostProcessingComponent.ts create mode 100644 src/engine/components/renderer/GlobalIlluminationComponent.ts create mode 100644 src/engine/components/renderer/InstanceDrawComponent.ts create mode 100644 src/engine/components/renderer/MaterialComponent.ts create mode 100644 src/engine/components/renderer/MeshComponent.ts create mode 100644 src/engine/components/renderer/MeshRenderer.ts create mode 100644 src/engine/components/renderer/RenderNode.ts create mode 100644 src/engine/components/renderer/SkinnedMeshRenderer.ts create mode 100644 src/engine/components/renderer/SkyRenderer.ts diff --git a/src/engine/components/AtmosphericComponent.ts b/src/engine/components/AtmosphericComponent.ts new file mode 100644 index 00000000..e1230419 --- /dev/null +++ b/src/engine/components/AtmosphericComponent.ts @@ -0,0 +1,98 @@ +import { SkyRenderer } from "../.."; +import { AtmosphericScatteringSky, AtmosphericScatteringSkySetting } from "../textures/AtmosphericScatteringSky"; + +/** + * + * Atmospheric Sky Box Component + * @group Components + */ +export class AtmosphericComponent extends SkyRenderer { + + private _atmosphericScatteringSky: AtmosphericScatteringSky; + + public get sunX() { + return this._atmosphericScatteringSky.setting.sunX; + } + + public set sunX(value) { + this._atmosphericScatteringSky.setting.sunX = value; + this._atmosphericScatteringSky.apply(); + } + + public get sunY() { + return this._atmosphericScatteringSky.setting.sunY; + } + + public set sunY(value) { + this._atmosphericScatteringSky.setting.sunY = value; + this._atmosphericScatteringSky.apply(); + } + + public get eyePos() { + return this._atmosphericScatteringSky.setting.eyePos; + } + + public set eyePos(value) { + this._atmosphericScatteringSky.setting.eyePos = value; + this._atmosphericScatteringSky.apply(); + } + + public get sunRadius() { + return this._atmosphericScatteringSky.setting.sunRadius; + } + + public set sunRadius(value) { + this._atmosphericScatteringSky.setting.sunRadius = value; + this._atmosphericScatteringSky.apply(); + } + + public get sunRadiance() { + return this._atmosphericScatteringSky.setting.sunRadiance; + } + + public set sunRadiance(value) { + this._atmosphericScatteringSky.setting.sunRadiance = value; + this._atmosphericScatteringSky.apply(); + } + + public get sunBrightness() { + return this._atmosphericScatteringSky.setting.sunBrightness; + } + + public set sunBrightness(value) { + this._atmosphericScatteringSky.setting.sunBrightness = value; + this._atmosphericScatteringSky.apply(); + } + + public get displaySun() { + return this._atmosphericScatteringSky.setting.displaySun; + } + + public set displaySun(value) { + this._atmosphericScatteringSky.setting.displaySun = value; + this._atmosphericScatteringSky.apply(); + } + + protected init(): void { + super.init(); + this._atmosphericScatteringSky = new AtmosphericScatteringSky(new AtmosphericScatteringSkySetting()); + } + + protected start(): void { + let scene = this.transform.scene3D; + this.map = this._atmosphericScatteringSky; + scene.envMap = this._atmosphericScatteringSky; + super.start(); + } + + protected onEnable(): void { + + } + + protected onDisable(): void { + + } + + public debug() { + } +} diff --git a/src/engine/components/BillboardComponent.ts b/src/engine/components/BillboardComponent.ts new file mode 100644 index 00000000..fa35f0cc --- /dev/null +++ b/src/engine/components/BillboardComponent.ts @@ -0,0 +1,40 @@ +import { Object3DType } from './gui/data/AssetsInfo'; +import { Camera3D } from '../core/Camera3D'; +import { Object3D } from '../core/entities/Object3D'; +import { Vector3 } from '../math/Vector3'; +import { ComponentBase } from './ComponentBase'; + +export class BillboardComponent extends ComponentBase { + public type: Object3DType; + public camera: Camera3D; + private _cameraDirection: Vector3; + + constructor() { + super(); + this._cameraDirection = new Vector3(); + } + + protected onUpdate() { + super.onUpdate(); + if (this.enable && this.transform.view3D.camera) { + this.updateBillboardMatrix(); + } + } + + private updateBillboardMatrix(): void { + let camera = this.transform.view3D.camera; + this._cameraDirection.copyFrom(camera.transform.back); + if (this.type == Object3DType.BillboardXYZ) { + this._cameraDirection.normalize().multiplyScalar(100); + } else if (this.type == Object3DType.BillboardY) { + this._cameraDirection.y = 0; + this._cameraDirection.normalize().multiplyScalar(100); + } + this.transform.lookAt(Vector3.ZERO, this._cameraDirection, camera.transform.up); + } + + public cloneTo(obj: Object3D) { + let component = obj.addComponent(BillboardComponent); + component.type = this.type; + } +} diff --git a/src/engine/components/ComponentBase.ts b/src/engine/components/ComponentBase.ts new file mode 100644 index 00000000..a1c96092 --- /dev/null +++ b/src/engine/components/ComponentBase.ts @@ -0,0 +1,241 @@ +import { View3D } from "../core/View3D"; +import { Object3D } from "../core/entities/Object3D"; +import { CEventDispatcher } from "../event/CEventDispatcher"; +import { ComponentType, SerializeTag } from "../util/SerializeDefine"; +import { Transform } from "./Transform"; + + +/** + * Components are used to attach functionality to object3D, it has an owner object3D. + * The component can receive update events at each frame. + * @group Components + */ +export class ComponentBase { + /** + * owner object3D + */ + public object3D: Object3D = null; + + /** + * @internal + */ + public eventDispatcher: CEventDispatcher; + + /** + * @internal + */ + public componentType: ComponentType = ComponentType.none; + + /** + * @internal + */ + public serializeTag?: SerializeTag; + + /** + * @internal + */ + protected _enable: boolean = true; + + private __isStart: boolean = false; + + constructor() { + this.eventDispatcher = new CEventDispatcher(); + } + + /** + * Return the Transform component attached to the Object3D. + */ + public get transform(): Transform { + return this.object3D.transform; + } + + + /** + * Enable/disable components. The enabled components can be updated, while the disabled components cannot be updated. + */ + public set enable(value: boolean) { + if (this._enable != value) { + this._enable = value; + if (this._enable) { + this.onEnable(); + } else { + this.onDisable(); + } + } + } + + /** + * Enable/disable components. The enabled components can be updated, while the disabled components cannot be updated. + */ + public get enable(): boolean { + return this._enable; + } + + private __init(param?: any) { + this.init(param); + } + + private __start() { + if (this.transform && this.transform.scene3D && this.__isStart == false) { + this.start(); + this.__isStart = true; + } + if (this.transform && this.transform.scene3D) { + this.onEnable(); + } + let hasUpdate = this.onUpdate.toString().replace(/\s+/g, '').length; + if (hasUpdate > 10) { + this._onUpdate(this.onUpdate.bind(this)); + } + let hasLateUpdate = this.onLateUpdate.toString().replace(/\s+/g, '').length; + if (hasLateUpdate > 14) { + this._onLateUpdate(this.onLateUpdate.bind(this)); + } + let hasBeforeUpdate = this.onBeforeUpdate.toString().replace(/\s+/g, '').length; + if (hasBeforeUpdate > 16) { + this._onBeforeUpdate(this.onBeforeUpdate.bind(this)); + } + let hasCompute = this.onCompute.toString().replace(/\s+/g, '').length; + if (hasCompute > 11) { + this._onCompute(this.onCompute.bind(this)); + } + let hasOnGraphic = this.onGraphic.toString().replace(/\s+/g, '').length; + if (hasOnGraphic > 11) { + this._onGraphic(this.onGraphic.bind(this)); + } + } + + private __stop() { + if (this.transform && this.transform.scene3D) { + this.onDisable(); + } + this._onUpdate(null); + this._onLateUpdate(null); + this._onBeforeUpdate(null); + this._onCompute(null); + this._onGraphic(null); + } + + protected init(param?: any) { } + protected start() { } + protected stop() { } + protected onEnable(view?: View3D) { } + protected onDisable(view?: View3D) { } + protected onUpdate(view?: View3D) { } + protected onLateUpdate(view?: View3D) { } + protected onBeforeUpdate(view?: View3D) { } + protected onCompute(view?: View3D, command?: GPUCommandEncoder) { } + protected onGraphic(view?: View3D) { } + + /** + * + * clone component data to target object3D + * @param obj target object3D + */ + public cloneTo(obj: Object3D) { } + + /** + * internal + * Add update function. Will be executed at every frame update. + * @param call callback + */ + private _onUpdate(call: Function) { + if (call != null) { + ComponentBase.componentsUpdateList.set(this, call); + } else { + ComponentBase.componentsUpdateList.delete(this); + } + } + + /** + * Add a delayed update function. + * @param call callback + */ + private _onLateUpdate(call: Function) { + // if(!this.enable) return; + if (call != null) { + ComponentBase.componentsLateUpdateList.set(this, call); + } else { + ComponentBase.componentsLateUpdateList.delete(this); + } + } + + /** + * The function executed before adding frame updates. + * @param call callback + */ + private _onBeforeUpdate(call: Function) { + // if(!this.enable) return; + if (call != null) { + ComponentBase.componentsBeforeUpdateList.set(this, call); + } else { + ComponentBase.componentsBeforeUpdateList.delete(this); + } + } + + /** + * @internal + * Add individual execution compute capability + * @param call callback + */ + private _onCompute(call: Function) { + if (call != null) { + ComponentBase.componentsComputeList.set(this, call); + } else { + ComponentBase.componentsComputeList.delete(this); + } + } + + /** + * Add individual execution drawing ability + * @param call callback + */ + private _onGraphic(call: Function) { + if (call != null) { + ComponentBase.graphicComponent.set(this, call); + } else { + ComponentBase.graphicComponent.delete(this); + } + } + + /** + * release this component + */ + public destroy() { + this.enable = false; + this.stop(); + this._onBeforeUpdate(null); + this._onUpdate(null); + this._onLateUpdate(null); + } + + /** + * @internal + */ + static componentsUpdateList: Map = new Map(); + + /** + * @internal + */ + static componentsLateUpdateList: Map = new Map(); + + /** + * @internal + */ + static componentsBeforeUpdateList: Map = new Map(); + + /** + * @internal + */ + static componentsComputeList: Map = new Map(); + + /** + * @internal + */ + static waitStartComponent: Map = new Map(); + + /** + * @internal + */ + static graphicComponent: Map = new Map(); +} diff --git a/src/engine/components/Transform.ts b/src/engine/components/Transform.ts new file mode 100644 index 00000000..a416c81b --- /dev/null +++ b/src/engine/components/Transform.ts @@ -0,0 +1,808 @@ +import { ComponentBase } from "./ComponentBase"; +import { Object3D } from "../core/entities/Object3D"; +import { Scene3D } from "../core/Scene3D"; +import { CEvent } from "../event/CEvent"; +import { MathUtil } from "../math/MathUtil"; +import { append, makeMatrix44, Matrix4 } from "../math/Matrix4"; +import { Orientation3D } from "../math/Orientation3D"; +import { Quaternion } from "../math/Quaternion"; +import { Vector3 } from "../math/Vector3"; +import { View3D } from "../core/View3D"; +import { ComponentType } from "../util/SerializeDefine"; + +/** + * The Transform component contains the position, rotation, and scaling of an object in 3D space. + * Each object (Object 3D) has a Transform component + * @group Components + */ +export class Transform extends ComponentBase { + /** + * @internal + */ + public static LIMIT: number = 1; + /** + * @internal + */ + public static COMPONENT_NAME = 'UUTransform'; + /** + * @internal + */ + public static COMPONENT_TYPE = 'Transform'; + /** + * @internal + */ + public static POSITION_ONCHANGE: string = 'POSITION_ONCHANGE'; + + /** + * @internal + */ + public static ROTATION_ONCHANGE: string = 'ROTATION_ONCHANGE'; + /** + * @internal + */ + public static SCALE_ONCHANGE: string = 'SCALE_ONCHANGE'; + /** + * @internal + */ + public static PARENT_ONCHANGE: string = 'PARENT_ONCHANGE'; + /** + * @internal + */ + public static CHILDREN_ONCHANGE: string = 'CHILDREN_ONCHANGE'; + /** + * @internal + */ + public static ADD_ONCHANGE: string = 'ADD_ONCHANGE'; + + /** + * @internal + */ + public eventPositionChange: CEvent = new CEvent(Transform.POSITION_ONCHANGE); + /** + * @internal + */ + public eventRotationChange: CEvent = new CEvent(Transform.ROTATION_ONCHANGE); + /** + * @internal + */ + public eventScaleChange: CEvent = new CEvent(Transform.SCALE_ONCHANGE); + /** + * @internal + */ + public onPositionChange: Function; + /** + * @internal + */ + public onRotationChange: Function; + /** + * @internal + */ + public onScaleChange: Function; + + private _scene3d: Scene3D; + + private _parent: Transform; + + private _localPos: Vector3; + private _localRot: Vector3; + private _localRotQuat: Quaternion; + private _localScale: Vector3; + // public localMatrix: Matrix4; + + private _forward: Vector3 = new Vector3(); + private _back: Vector3 = new Vector3(); + private _right: Vector3 = new Vector3(); + private _left: Vector3 = new Vector3(); + private _up: Vector3 = new Vector3(); + private _down: Vector3 = new Vector3(); + public _worldMatrix: Matrix4; + private _localChange: boolean = true; + + private _targetPos: Vector3; + + public get targetPos(): Vector3 { + return this._targetPos; + } + public set targetPos(value: Vector3) { + this._targetPos = value; + } + + public get parent(): Transform { + return this._parent; + } + + public set parent(value: Transform) { + this._parent = value; + let hasRoot = value ? value.scene3D : null; + if (!hasRoot) { + this.object3D.components.forEach((c) => { + c[`__stop`](); + }); + } else { + this._scene3d = hasRoot; + this.object3D.components.forEach((c) => { + this.object3D[`appendLateStart`](c); + }); + } + + this.object3D.entityChildren.forEach((v) => { + v.transform.parent = this; + }); + } + + public set enable(value: boolean) { + if (this.transform._scene3d && value) { + super.enable = true; + } else { + super.enable = false; + } + this.object3D.entityChildren.forEach((v) => { + v.transform.enable = value; + }); + } + public get enable(): boolean { + return this._enable; + } + + public get scene3D(): Scene3D { + return this._scene3d; + } + + public set scene3D(value: Scene3D) { + this._scene3d = value; + } + + public get view3D(): View3D { + if (this._scene3d && this._scene3d.view) { + return this._scene3d.view; + } + return null; + } + + constructor() { + super(); + this.componentType = ComponentType.transform; + // this.localMatrix = new Matrix4(); + this.worldMatrix = new Matrix4(false); + this._localPos = new Vector3(); + this._localRot = new Vector3(); + this._localRotQuat = new Quaternion(); + this._localScale = new Vector3(1, 1, 1); + } + + awake() { } + + start() { } + + stop() { } + + // update() { } + + // lateUpdate() { } + + /** + * @internal + */ + public notifyLocalChange() { + this._localChange = true; + let entityChildren = this.object3D.entityChildren; + for (let i = 0, len = entityChildren.length; i < len; i++) { + const transform = entityChildren[i].transform; + transform.notifyLocalChange(); + } + } + + public get up(): Vector3 { + this.worldMatrix.transformVector(Vector3.UP, this._up); + return this._up; + } + + public set up(value: Vector3) { + this._up.copyFrom(value); + this.notifyLocalChange(); + + if (this.onRotationChange) { + this.onRotationChange(); + } + + if (this.eventRotationChange) { + this.eventDispatcher.dispatchEvent(this.eventRotationChange); + } + } + + public get down(): Vector3 { + this.worldMatrix.transformVector(Vector3.DOWN, this._down); + return this._down; + } + + public set down(value: Vector3) { + this._down.copyFrom(value); + this.notifyLocalChange(); + + if (this.onRotationChange) { + this.onRotationChange(); + } + + if (this.eventRotationChange) { + this.eventDispatcher.dispatchEvent(this.eventRotationChange); + } + } + + public get forward(): Vector3 { + this.worldMatrix.transformVector(Vector3.FORWARD, this._forward); + return this._forward; + } + + public set forward(value: Vector3) { + this._forward.copyFrom(value); + MathUtil.fromToRotation(Vector3.FORWARD, this._forward, Quaternion.HELP_0); + this.transform.localRotQuat = Quaternion.HELP_0; + this.notifyLocalChange(); + + if (this.onRotationChange) { + this.onRotationChange(); + } + + if (this.eventRotationChange) { + this.eventDispatcher.dispatchEvent(this.eventRotationChange); + } + } + + public get back(): Vector3 { + this.worldMatrix.transformVector(Vector3.BACK, this._back); + return this._back; + } + + public set back(value: Vector3) { + this._back.copyFrom(value); + MathUtil.fromToRotation(Vector3.BACK, this._back, Quaternion.HELP_0); + this.transform.localRotQuat = Quaternion.HELP_0; + this.notifyLocalChange(); + + if (this.onRotationChange) { + this.onRotationChange(); + } + + if (this.eventRotationChange) { + this.eventDispatcher.dispatchEvent(this.eventRotationChange); + } + } + + public get left(): Vector3 { + this.worldMatrix.transformVector(Vector3.neg_X_AXIS, this._left); + return this._left; + } + + public set left(value: Vector3) { + this._left.copyFrom(value); + this.notifyLocalChange(); + + if (this.onRotationChange) { + this.onRotationChange(); + } + + if (this.eventRotationChange) { + this.eventDispatcher.dispatchEvent(this.eventRotationChange); + } + } + + public get right(): Vector3 { + this.worldMatrix.transformVector(Vector3.X_AXIS, this._right); + return this._right; + } + + public set right(value: Vector3) { + this._right.copyFrom(value); + this.notifyLocalChange(); + + if (this.onRotationChange) { + this.onRotationChange(); + } + + if (this.eventRotationChange) { + this.eventDispatcher.dispatchEvent(this.eventRotationChange); + } + } + + /** + * + * 物体相对于父级变换属性,以四元数形式存储 + */ + public get localRotQuat(): Quaternion { + return this._localRotQuat; + } + + public set localRotQuat(value: Quaternion) { + this._localRotQuat = value; + this._localRotQuat.getEulerAngles(this._localRot); + + this.notifyLocalChange(); + + if (this.onRotationChange) { + this.onRotationChange(); + } + + if (this.eventRotationChange) { + this.eventDispatcher.dispatchEvent(this.eventRotationChange); + } + } + + /** + * @private + */ + public notifyChange(): void { + this.notifyLocalChange(); + if (this.onRotationChange) { + this.onRotationChange(); + } + + if (this.eventRotationChange) { + this.eventDispatcher.dispatchEvent(this.eventRotationChange); + } + if (this.eventPositionChange) { + this.eventDispatcher.dispatchEvent(this.eventPositionChange); + } + if (this.eventScaleChange) { + this.eventDispatcher.dispatchEvent(this.eventScaleChange); + } + } + + /** + * @internal + */ + public get worldMatrix(): Matrix4 { + this.updateWorldMatrix(); + return this._worldMatrix; + } + + /** + * @internal + */ + public set worldMatrix(value: Matrix4) { + this._worldMatrix = value; + } + + /** + * + * Update the matrix4 in world space + */ + public updateWorldMatrix(force: boolean = false) { + if (this._localChange || force) { + if (this.parent) { + makeMatrix44(this._localRot, this._localPos, this.localScale, this._worldMatrix); + append(this._worldMatrix, this.parent.worldMatrix, this._worldMatrix); + + // WasmMatrix4.makeMatrix44Append(this._localRot, this._localPos, this.localScale, this._worldMatrix, this._worldMatrix, this.parent.worldMatrix, this._worldMatrix); + this._localChange = false; + } else { + makeMatrix44(this._localRot, this._localPos, this.localScale, this._worldMatrix); + // WasmMatrix4.makeMatrix44(this._localRot, this._localPos, this.localScale, this._worldMatrix); + this._localChange = false; + } + } + } + + public lookTarget(target: Vector3, up: Vector3 = Vector3.UP) { + let worldPosition = this.transform.worldPosition; + this.lookAt(worldPosition, target, up); + } + + /** + * Current object's gaze position (global) (modified by its own global transformation) + * @param pos Own position (global) + * @param target Location of the target (global) + * @param up up direction + */ + public lookAt(pos: Vector3, target: Vector3, up: Vector3 = Vector3.UP) { + this._targetPos = target.clone(); + this._localPos.copyFrom(pos); + this.notifyLocalChange(); + + Matrix4.helpMatrix.lookAt(pos, target, up); + Matrix4.helpMatrix.invert(); + var prs: Vector3[] = Matrix4.helpMatrix.decompose(Orientation3D.QUATERNION); + Quaternion.CALCULATION_QUATERNION.x = prs[1].x; + Quaternion.CALCULATION_QUATERNION.y = prs[1].y; + Quaternion.CALCULATION_QUATERNION.z = prs[1].z; + Quaternion.CALCULATION_QUATERNION.w = prs[1].w; + Quaternion.CALCULATION_QUATERNION.toEulerAngles(this._localRot); + + if (this.eventPositionChange) { + this.eventDispatcher.dispatchEvent(this.eventPositionChange); + } + + if (this.onPositionChange) { + this.onPositionChange(); + } + + if (this.onRotationChange) { + this.onRotationChange(); + } + + if (this.eventRotationChange) { + this.eventDispatcher.dispatchEvent(this.eventRotationChange); + } + } + + destroy(): void { + if (this.parent && this.parent.object3D) { + this.parent.object3D.removeChild(this.object3D); + this.scene3D = null; + this.localPosition = null; + this.localRotQuat = null; + this.localRotation = null; + this.localScale = null; + this._worldMatrix = null; + } + super.destroy(); + } + + + public decomposeFromMatrix(matrix: Matrix4, orientationStyle: string = 'eulerAngles'): this { + let prs = matrix.decompose(orientationStyle); + + let transform = this.transform; + + transform.localRotQuat.copyFrom(prs[1]); + transform.localRotQuat = transform.localRotQuat; + + transform.localPosition.copyFrom(prs[0]); + transform.localPosition = transform.localPosition; + + transform.localScale.copyFrom(prs[2]); + transform.localScale = transform.localScale; + this.updateWorldMatrix(); + return this; + } + + /** + * + * Create a new component, copy the properties of the current component, and add it to the target object. + * @param obj source Object3D + */ + cloneTo(obj: Object3D) { + obj.transform.localPosition.copyFrom(this.localPosition); + obj.transform.localRotation.copyFrom(this.localRotation); + obj.transform.localScale.copyFrom(this.localScale); + } + + public set x(value: number) { + if (this._localPos.x != value) { + this._localPos.x = value; + this.notifyLocalChange(); + + if (this.onPositionChange) { + this.onPositionChange(); + } + + if (this.eventPositionChange) { + this.eventDispatcher.dispatchEvent(this.eventPositionChange); + } + } + } + /** + * + * The position of the object relative to its parent X-axis + */ + public get x(): number { + return this._localPos.x; + } + + public set y(value: number) { + if (this._localPos.y != value) { + this._localPos.y = value; + this.notifyLocalChange(); + + if (this.onPositionChange) { + this.onPositionChange(); + } + + if (this.eventPositionChange) { + this.eventDispatcher.dispatchEvent(this.eventPositionChange); + } + } + } + /** + * + * The position of the object relative to its parent Y-axis + */ + public get y(): number { + return this._localPos.y; + } + + public set z(value: number) { + if (this._localPos.z != value) { + this._localPos.z = value; + this.notifyLocalChange(); + + if (this.onPositionChange) { + this.onPositionChange(); + } + + if (this.eventPositionChange) { + this.eventDispatcher.dispatchEvent(this.eventPositionChange); + } + } + } + /** + * + * The position of the object relative to its parent Y-axis + */ + public get z(): number { + return this._localPos.z; + } + + public set scaleX(value: number) { + if (this._localScale.x != value) { + this._localScale.x = value; + this.notifyLocalChange(); + + if (this.eventScaleChange) { + this.eventDispatcher.dispatchEvent(this.eventScaleChange); + } + } + } + /** + * + * The scale of the object relative to its parent X-axis + */ + public get scaleX(): number { + return this._localScale.x; + } + + public set scaleY(value: number) { + if (this._localScale.y != value) { + this._localScale.y = value; + this.notifyLocalChange(); + + if (this.eventScaleChange) { + this.eventDispatcher.dispatchEvent(this.eventScaleChange); + } + } + } + /** + * + * The scale of the object relative to its parent Y-axis + */ + public get scaleY(): number { + return this._localScale.y; + } + + public set scaleZ(value: number) { + if (this._localScale.z != value) { + this._localScale.z = value; + this.notifyLocalChange(); + + if (this.eventScaleChange) { + this.eventDispatcher.dispatchEvent(this.eventScaleChange); + } + } + } + + /** + * + * The scale of the object relative to its parent Z-axis + */ + public get scaleZ(): number { + return this._localScale.z; + } + + public set rotationX(value: number) { + if (this._localRot.x != value) { + this._localRot.x = value; + this.notifyLocalChange(); + + if (this.onRotationChange) { + this.onRotationChange(); + } + + if (this.eventRotationChange) { + this.eventDispatcher.dispatchEvent(this.eventRotationChange); + } + } + } + /** + * + * The rotation of the object relative to its parent X-axis + */ + public get rotationX(): number { + return this._localRot.x; + } + + public set rotationY(value: number) { + if (this._localRot.y != value) { + this._localRot.y = value; + this.notifyLocalChange(); + + if (this.onRotationChange) { + this.onRotationChange(); + } + + if (this.eventRotationChange) { + this.eventDispatcher.dispatchEvent(this.eventRotationChange); + } + } + } + /** + * + * The rotation of the object relative to its parent Y-axis + */ + public get rotationY(): number { + return this._localRot.y; + } + + public set rotationZ(value: number) { + if (this._localRot.z != value) { + this._localRot.z = value; + this.notifyLocalChange(); + + if (this.onRotationChange) { + this.onRotationChange(); + } + + if (this.eventRotationChange) { + this.eventDispatcher.dispatchEvent(this.eventRotationChange); + } + } + } + /** + * + * The rotation of the object relative to its parent Z-axis + */ + public get rotationZ(): number { + return this._localRot.z; + } + /** + * + * world position + */ + public get worldPosition(): Vector3 { + if (this._localChange) { + this.updateWorldMatrix(); + } + return this._worldMatrix.position; + } + + public set localPosition(v: Vector3) { + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.notifyLocalChange(); + + if (this.onPositionChange) { + this.onPositionChange(); + } + + if (this.eventPositionChange) { + this.eventDispatcher.dispatchEvent(this.eventPositionChange); + } + } + /** + * + * The position of an object relative to its parent + */ + public get localPosition(): Vector3 { + return this._localPos; + } + + public set localRotation(v: Vector3) { + this.rotationX = v.x; + this.rotationY = v.y; + this.rotationZ = v.z; + this.notifyLocalChange(); + + if (this.onRotationChange) { + this.onRotationChange(); + } + + if (this.eventRotationChange) { + this.eventDispatcher.dispatchEvent(this.eventRotationChange); + } + } + + /** + * + * The rotaion vector of an object relative to its parent + */ + public get localRotation(): Vector3 { + return this._localRot; + } + + public set localScale(v: Vector3) { + this.scaleX = v.x; + this.scaleY = v.y; + this.scaleZ = v.z; + this.notifyLocalChange(); + + if (this.eventScaleChange) { + this.eventDispatcher.dispatchEvent(this.eventScaleChange); + } + } + /** + * + * The scale of an object relative to its parent + */ + public get localScale(): Vector3 { + return this._localScale; + } + + // private _rotateAroundAxisX:number = 0 ; + // public set rotateAroundAxisX(value:number){ + // this._rotateAroundAxisX = value; + // this.notifyLocalChange(); + + // let quat = Quaternion.HELP_0 ; + // quat.fromAxisAngle(this.right,value); + // // quat.fromEulerAngles(this._rotateAroundAxisX,this._rotateAroundAxisY,this._rotateAroundAxisZ); + // quat.toEulerAngles(this._localRot); + + // this.notifyLocalChange(); + // if( this.onRotationChange ){ + // this.onRotationChange(); + // } + + // if (this.events_rot) { + // this.events.dispatchEvent(this.events_rot); + // } + // } + + // /** + // * + // */ + // public get rotateAroundAxisX():number { + // return this._rotateAroundAxisX ; + // } + + // private _rotateAroundAxisY:number = 0 ; + // public set rotateAroundAxisY(value:number){ + // this._rotateAroundAxisY = value; + // this.notifyLocalChange(); + + // let quat = Quaternion.HELP_0 ; + // quat.fromEulerAngles(this._rotateAroundAxisX,this._rotateAroundAxisY,this._rotateAroundAxisZ); + // quat.toEulerAngles(this._localRot); + + // this.notifyLocalChange(); + // if( this.onRotationChange ){ + // this.onRotationChange(); + // } + + // if (this.events_rot) { + // this.events.dispatchEvent(this.events_rot); + // } + // } + + // /** + // * + // */ + // public get rotateAroundAxisY():number { + // return this._rotateAroundAxisY ; + // } + + // private _rotateAroundAxisZ:number = 0 ; + // public set rotateAroundAxisZ(value:number){ + // this._rotateAroundAxisZ = value; + // this.notifyLocalChange(); + + // let quat = Quaternion.HELP_0 ; + // quat.fromEulerAngles(this._rotateAroundAxisX,this._rotateAroundAxisY,this._rotateAroundAxisZ); + // quat.toEulerAngles(this._localRot); + + // this.notifyLocalChange(); + // if( this.onRotationChange ){ + // this.onRotationChange(); + // } + + // if (this.events_rot) { + // this.events.dispatchEvent(this.events_rot); + // } + // } + + // /** + // * + // */ + // public get rotateAroundAxisZ():number { + // return this._rotateAroundAxisZ ; + // } + +} diff --git a/src/engine/components/post/PostProcessingComponent.ts b/src/engine/components/post/PostProcessingComponent.ts new file mode 100644 index 00000000..c03500be --- /dev/null +++ b/src/engine/components/post/PostProcessingComponent.ts @@ -0,0 +1,68 @@ +import { Ctor, Engine3D } from "../../.."; +import { PostBase } from "../../gfx/renderJob/post/PostBase"; +import { ComponentBase } from "../ComponentBase"; + +export class PostProcessingComponent extends ComponentBase { + private _postList: Map; + protected init(param?: any): void { + this._postList = new Map(); + } + + protected start(): void { + + } + + protected stop(): void { + + } + + protected onEnable(): void { + this.activePost(); + } + + protected onDisable(): void { + this.unActivePost(); + } + + private activePost() { + let view = this.transform.view3D; + let job = Engine3D.getRenderJob(view); + this._postList.forEach((v) => { + job.addPost(v); + }); + } + + private unActivePost() { + let view = this.transform.view3D; + let job = Engine3D.getRenderJob(view); + this._postList.forEach((v) => { + job.removePost(v); + }); + } + + public addPost(c: Ctor): T { + if (this._postList.has(c.prototype)) return; + let post = new c(); + this._postList.set(c.prototype, post); + if (this._enable) + this.activePost(); + // post.onAttach(this.transform.view3D); + // Engine3D.getRenderJob(this.transform.view3D).addPost(post); + return post; + } + + public removePost(c: Ctor) { + if (!this._postList.has(c.prototype)) return; + let post = this._postList.get(c.prototype); + this._postList.delete(c.prototype); + + let view = this.transform.view3D; + let job = Engine3D.getRenderJob(view); + job.removePost(post); + } + + public getPost(c: Ctor): T { + if (!this._postList.has(c.prototype)) return null; + return this._postList.get(c.prototype) as T; + } +} \ No newline at end of file diff --git a/src/engine/components/renderer/GlobalIlluminationComponent.ts b/src/engine/components/renderer/GlobalIlluminationComponent.ts new file mode 100644 index 00000000..1291d60c --- /dev/null +++ b/src/engine/components/renderer/GlobalIlluminationComponent.ts @@ -0,0 +1,171 @@ +import { Engine3D } from '../../Engine3D'; +import { GlobalBindGroup } from '../../gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { EntityCollect } from '../../gfx/renderJob/collect/EntityCollect'; +import { DDGIIrradianceVolume } from '../../gfx/renderJob/passRenderer/ddgi/DDGIIrradianceVolume'; +import { Probe } from '../../gfx/renderJob/passRenderer/ddgi/Probe'; +import { Vector3 } from '../../math/Vector3'; +import { SphereGeometry } from '../../shape/SphereGeometry'; +import { ComponentBase } from '../ComponentBase'; +import { MeshRenderer } from './MeshRenderer'; +import { GIProbeMaterial, GIProbeMaterialType } from '../../materials/GIProbeMaterial'; +import { UnLitMaterial } from '../../materials/UnLitMaterial'; +import { Quaternion } from '../../math/Quaternion'; +import { ComponentType } from '../../util/SerializeDefine'; + +/** + * + * Global Illumination Component + * Use global illumination to achieve more realistic lighting. + * The global illumination system can model the way light reflects or refracts on the surface to other surfaces (indirect lighting), + * rather than limiting that light can only shine from the light source to a certain surface. + * @group Components + */ +export class GlobalIlluminationComponent extends ComponentBase { + public probes: Probe[]; + public volume: DDGIIrradianceVolume; + + private _debugMr: MeshRenderer[] = []; + protected init(): void { + Engine3D.setting.gi.enable = true; + } + + constructor() { + super(); + this.componentType = ComponentType.globalIllumination; + } + + protected start(): void { + this.volume = GlobalBindGroup.getLightEntries(this.transform.scene3D).irradianceVolume; + this.initProbe(); + } + + private initProbe() { + let xCount: number = this.volume.setting.probeXCount; + let yCount: number = this.volume.setting.probeYCount; + let zCount: number = this.volume.setting.probeZCount; + + + let debugGeo = new SphereGeometry(4, 16, 16); + let position: Vector3 = new Vector3(); + this.probes = []; + let unlitMat = new UnLitMaterial(); + for (let x = 0; x < xCount; x++) { + for (let y = 0; y < yCount; y++) { + for (let z = 0; z < zCount; z++) { + let index = x + z * xCount + y * (xCount * zCount); + let probe = new Probe(); + probe.index = index; + + probe.name = `${x}_${y}_${z}`; + let mr = probe.addComponent(MeshRenderer); + mr.material = new GIProbeMaterial(GIProbeMaterialType.CastGI, index); + // mr.material = new GIProbeMaterial(GIProbeMaterialType.CastDepth, index); + // mr.material = unlitMat; + mr.geometry = debugGeo; + mr.castGI = false; + mr.castShadow = false; + + this._debugMr.push(mr); + + this.object3D.addChild(probe); + + this.volume.calcPosition(x, y, z, position); + + probe.x = position.x; + probe.y = position.y; + probe.z = position.z; + + probe.transform.rotationX = 0; + probe.transform.rotationY = 0; + probe.transform.rotationZ = 0; + + this.probes[index] = probe; + + this._debugMr.push(mr); + } + } + } + + for (let i = 0; i < this.probes.length; i++) { + EntityCollect.instance.addGIProbe(this.transform.scene3D, this.probes[i]); + } + + this.object3D.transform.enable = false; + + if (this.volume.setting.debug) { + this.debug(); + } + } + + public debug() { + + } + + private _debugProbeRay(probeIndex: number, array: Float32Array) { + const rayNumber = Engine3D.setting.gi.rayNumber; + let quat = new Quaternion(0.0, -0.7071067811865475, 0.7071067811865475, 0.0); + for (let i = 0; i < rayNumber; i++) { + let ii = probeIndex * rayNumber + i; + let dir = new Vector3( + -array[ii * 4 + 0], + -array[ii * 4 + 1], + -array[ii * 4 + 2], + 0 + ); + quat.transformVector(dir, dir); + let len = array[ii * 4 + 3]; + let id = `showRays${probeIndex}${i}`; + + let start = this.probes[probeIndex].transform.worldPosition.clone(); + let end = dir.scaleBy(len); + end.add(start, end); + + //view.graphic3D.Clear(id); + //view.graphic3D..drawLines(id, [start, end], [new Color(0, 0, 0, 0), new Color(1.0, 1.0, 1.0, 1.0)]); + + } + } + + private changeProbesVolumeData(): void { + this.volume.setVolumeDataChange(); + } + + private changeProbesPosition(): void { + this.volume.setVolumeDataChange(); + let xCount: number = this.volume.setting.probeXCount; + let yCount: number = this.volume.setting.probeYCount; + let zCount: number = this.volume.setting.probeZCount; + let position: Vector3 = new Vector3(); + + for (let x = 0; x < xCount; x++) { + for (let y = 0; y < yCount; y++) { + for (let z = 0; z < zCount; z++) { + let index = x + z * xCount + y * (xCount * zCount); + let probe: Probe = this.probes[index]; + this.volume.calcPosition(x, y, z, position); + + probe.x = position.x; + probe.y = position.y; + probe.z = position.z; + } + } + } + } + + protected onUpdate(): void { + Engine3D.setting.gi.maxDistance = Engine3D.setting.gi.probeSpace * 1.5; + + let camera = this.transform.scene3D.view.camera; + let scale = Vector3.distance(camera.transform.worldPosition, camera.transform.targetPos) / 300; + // console.log(scale); + + if (this._debugMr && this._debugMr.length > 0) { + for (let i = 0; i < this._debugMr.length; i++) { + const debugOBJ = this._debugMr[i].transform; + debugOBJ.scaleX = scale; + debugOBJ.scaleY = scale; + debugOBJ.scaleZ = scale; + } + } + } +} diff --git a/src/engine/components/renderer/InstanceDrawComponent.ts b/src/engine/components/renderer/InstanceDrawComponent.ts new file mode 100644 index 00000000..62d549a5 --- /dev/null +++ b/src/engine/components/renderer/InstanceDrawComponent.ts @@ -0,0 +1,124 @@ +import { GPUContext } from "../../gfx/renderJob/GPUContext"; +import { RTResourceMap } from "../../gfx/renderJob/frame/RTResourceMap"; +import { ClusterLightingRender } from "../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender"; +import { RenderContext } from "../../gfx/renderJob/passRenderer/RenderContext"; +import { RendererPassState } from "../../gfx/renderJob/passRenderer/state/RendererPassState"; +import { RendererType } from "../../gfx/renderJob/passRenderer/state/RendererType"; +import { MeshRenderer } from "./MeshRenderer"; +import { RenderNode } from "./RenderNode"; +import { StorageGPUBuffer } from "../../gfx/graphics/webGpu/core/buffer/StorageGPUBuffer"; +import { View3D } from "../../core/View3D"; + +export class InstanceDrawComponent extends RenderNode { + + private _keyGroup: Map; + private _instanceMatrixBuffer: StorageGPUBuffer; + protected init(param?: any): void { + this._keyGroup = new Map(); + } + + protected start(): void { + + let meshRenders: MeshRenderer[] = []; + this.object3D.getComponents(MeshRenderer, meshRenders, true); + this._instanceMatrixBuffer = new StorageGPUBuffer(meshRenders.length); + this._instanceMatrixBuffer.visibility = GPUShaderStage.VERTEX; + let idArray = new Int32Array(meshRenders.length); + for (let i = 0; i < meshRenders.length; i++) { + const mr = meshRenders[i]; + mr.transform.enable = false; + + idArray[i] = mr.transform.worldMatrix.index; + let key = mr.geometry.uuid; + for (let j = 0; j < mr.materials.length; j++) { + const mat = mr.materials[j]; + key += mat.instanceID; + } + + if (!this._keyGroup.has(key)) { + this._keyGroup.set(key, [mr]); + } else { + this._keyGroup.get(key).push(mr); + } + } + + this.instanceCount = meshRenders.length; + this._instanceMatrixBuffer.setInt32Array("matrixIDs", idArray); + this._instanceMatrixBuffer.apply(); + } + + protected stop(): void { + + } + + public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingRender?: ClusterLightingRender): void { + + + this._keyGroup.forEach((v, k) => { + let renderNode = v[0]; + for (let i = 0; i < renderNode.materials.length; i++) { + let material = renderNode.materials[i]; + let passes = material.renderPasses.get(passType); + if (passes) { + for (let i = 0; i < passes.length; i++) { + const renderShader = passes[i].renderShader;// RenderShader.getShader(passes[i].shaderID); + + renderShader.setDefine("USE_INSTANCEDRAW", true); + renderShader.setStorageBuffer(`instanceDrawID`, this._instanceMatrixBuffer); + } + } + } + renderNode.nodeUpdate(view, passType, renderPassState, clusterLightingRender); + }) + super.nodeUpdate(view, passType, renderPassState, clusterLightingRender); + } + + + public renderPass(view: View3D, passType: RendererType, renderEncoder: RenderContext) { + this._keyGroup.forEach((v, k) => { + let renderNode = v[0]; + // for (let ii = 0; ii < v.length; ii++) { + // const renderNode = v[ii]; + // renderNode.object3D.transform.updateWorldMatrix() + // } + for (let i = 0; i < renderNode.materials.length; i++) { + const material = renderNode.materials[i]; + let passes = material.renderPasses.get(passType); + + if (!passes || passes.length == 0) continue; + + GPUContext.bindGeometryBuffer(renderEncoder.encoder, renderNode.geometry); + let worldMatrix = renderNode.object3D.transform._worldMatrix; + for (let j = 0; j < passes.length; j++) { + if (!passes || passes.length == 0) continue; + let matPass = passes[j]; + if (!matPass.enable) continue; + + for (let jj = passes.length > 1 ? 1 : 0; jj < passes.length; jj++) { + const renderShader = matPass.renderShader; + if (renderShader.shaderState.splitTexture) { + + renderEncoder.endRenderPass(); + RTResourceMap.WriteSplitColorTexture(renderNode.instanceID); + renderEncoder.beginRenderPass(); + + GPUContext.bindCamera(renderEncoder.encoder, view.camera); + GPUContext.bindGeometryBuffer(renderEncoder.encoder, renderNode.geometry); + } + GPUContext.bindPipeline(renderEncoder.encoder, renderShader); + let subGeometries = renderNode.geometry.subGeometries; + for (let k = 0; k < subGeometries.length; k++) { + const subGeometry = subGeometries[k]; + let lodInfos = subGeometry.lodLevels; + let lodInfo = lodInfos[renderNode.lodLevel]; + + GPUContext.drawIndexed(renderEncoder.encoder, lodInfo.indexCount, v.length, lodInfo.indexStart, 0, 0); + } + } + } + } + }) + + } +} + diff --git a/src/engine/components/renderer/MaterialComponent.ts b/src/engine/components/renderer/MaterialComponent.ts new file mode 100644 index 00000000..9c6d672e --- /dev/null +++ b/src/engine/components/renderer/MaterialComponent.ts @@ -0,0 +1,43 @@ +import { Object3D } from '../../core/entities/Object3D'; +import { MaterialBase } from '../../materials/MaterialBase'; +import { ComponentBase } from '../ComponentBase'; +import { MeshComponent } from './MeshComponent'; +import { RenderNode } from './RenderNode'; +/** + * Material component + * @group Components + */ +export class MaterialComponent extends ComponentBase { + private _materials: MaterialBase[]; + constructor() { + super(); + this.materials = []; + } + + public get materials(): MaterialBase[] { + return this._materials; + } + + public set materials(value: MaterialBase[]) { + this._materials = value; + } + + public get material(): MaterialBase { + return this._materials[0]; + } + + public set material(value: MaterialBase) { + this._materials[0] = value; + + let mc = this.object3D.getComponent(MeshComponent); + if (mc && value && mc.geometry) { + let render = this.object3D.addComponent(RenderNode); + // render.initRender(); + } + } + + public cloneTo(obj: Object3D) { + let mc = obj.addComponent(MaterialComponent); + mc.materials.push(...this.materials); + } +} diff --git a/src/engine/components/renderer/MeshComponent.ts b/src/engine/components/renderer/MeshComponent.ts new file mode 100644 index 00000000..79bc30f0 --- /dev/null +++ b/src/engine/components/renderer/MeshComponent.ts @@ -0,0 +1,49 @@ +import { Object3D } from '../../core/entities/Object3D'; +import { GeometryBase } from '../../core/geometry/GeometryBase'; +import { ComponentBase } from '../ComponentBase'; +import { MaterialComponent } from './MaterialComponent'; +import { RenderNode } from './RenderNode'; +/** + * Mesh component + * @group Components + */ +export class MeshComponent extends ComponentBase { + private _geometry: GeometryBase; + public get geometry(): GeometryBase { + return this._geometry; + } + public set geometry(value: GeometryBase) { + this._geometry = value; + this._checkRenderer(); + } + + protected _checkRenderer() { + let mr = this.object3D.getComponent(MaterialComponent); + if (mr && this._geometry && mr.materials.length > 0) { + this.checkRenderer(); + } + } + + protected checkRenderer() { + let render = this.object3D.addComponent(RenderNode); + // render.initRender(); + } + + constructor() { + super(); + } + + protected init() { } + + public cloneTo(obj: Object3D) { + let mc = obj.addComponent(MeshComponent); + mc._geometry = this._geometry; + } + + // public get mesh(): BufferMesh { + // return this._mesh; + // } + // public set mesh(value: BufferMesh) { + // this._mesh = value; + // } +} diff --git a/src/engine/components/renderer/MeshRenderer.ts b/src/engine/components/renderer/MeshRenderer.ts new file mode 100644 index 00000000..bd14c652 --- /dev/null +++ b/src/engine/components/renderer/MeshRenderer.ts @@ -0,0 +1,138 @@ +import { Object3D } from '../../core/entities/Object3D'; +import { GeometryBase } from '../../core/geometry/GeometryBase'; +import { View3D } from '../../core/View3D'; +import { ClusterLightingRender } from '../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender'; +import { RendererMask } from '../../gfx/renderJob/passRenderer/state/RendererMask'; +import { RendererPassState } from '../../gfx/renderJob/passRenderer/state/RendererPassState'; +import { RendererType } from '../../gfx/renderJob/passRenderer/state/RendererType'; +import { MaterialBase } from '../../materials/MaterialBase'; +import { ComponentType } from '../../util/SerializeDefine'; +import { MorphTargetData } from '../anim/morphAnim/MorphTargetData'; +import { RenderNode } from './RenderNode'; + +/** + * The mesh renderer component is a component used to render the mesh + * @group Components + */ +export class MeshRenderer extends RenderNode { + /** + * Enabling this option allows the grid to display any shadows cast on the grid. + */ + public receiveShadow: boolean; + protected morphData: MorphTargetData; + + constructor() { + super(); + this.componentType = ComponentType.meshRenderer; + } + + protected start(): void { } + + protected stop(): void { } + + /** + * The geometry of the mesh determines its shape + */ + public get geometry(): GeometryBase { + return this._geometry; + } + + public set geometry(value: GeometryBase) { + this._geometry = value; + let isMorphTarget = value.morphTargetDictionary != null; + if (isMorphTarget) { + this.morphData ||= new MorphTargetData(); + this.morphData.morphTargetsRelative = value.morphTargetsRelative; + this.morphData.initMorphTarget(value); + } + this.morphData && (this.morphData.enable = isMorphTarget); + if (this.morphData && this.morphData.enable) { + this.addRendererMask(RendererMask.MorphTarget); + } else { + this.removeRendererMask(RendererMask.MorphTarget); + } + + if (this._readyPipeline) { + this.initPipeline(); + } + } + + /** + * material + */ + public get material(): MaterialBase { + return this._materials[0]; + } + + public set material(value: MaterialBase) { + this.materials = [value]; + } + + /** + * Set deformation animation parameters + */ + public setMorphInfluence(key: string, value: number) { + if (this.morphData && this.morphData.enable) { + let index = this._geometry.morphTargetDictionary[key]; + if (index >= 0) { + this.morphData.updateInfluence(index, value); + } + } + } + + public setMorphInfluenceIndex(index: number, value: number) { + if (this.morphData && this.morphData.enable) { + if (index >= 0) { + this.morphData.updateInfluence(index, value); + } + } + } + + + protected onCompute(view: View3D, command: GPUCommandEncoder): void { + if (this.morphData && this.morphData.enable) { + this.morphData.computeMorphTarget(command); + } + } + + /** + * @internal + * @param passType + * @param renderPassState + * @param scene3D + * @param clusterLightingRender + * @param probes + */ + public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingRender?: ClusterLightingRender) { + if (this.morphData && this.morphData.enable) { + for (let i = 0; i < this.materials.length; i++) { + const material = this.materials[i]; + let passes = material.renderPasses.get(passType); + if (passes) { + for (let j = 0; j < passes.length; j++) { + const renderShader = passes[j].renderShader; + this.morphData.applyRenderShader(renderShader); + } + } + } + } + + super.nodeUpdate(view, passType, renderPassState, clusterLightingRender); + } + + cloneTo(obj: Object3D) { + let mr = obj.addComponent(MeshRenderer); + mr.geometry = this.geometry; + mr.material = this.material; + mr.castShadow = this.castShadow; + mr.castGI = this.castGI; + mr.receiveShadow = this.receiveShadow; + mr.rendererMask = this.rendererMask; + } + + drawWireFrame() { + this.object3D.transform.worldPosition; + //view.graphic3D..drawMeshWireframe(`Wireframe_${this.object3D.uuid}`, this.geometry, this.object3D.transform); + } + +} diff --git a/src/engine/components/renderer/RenderNode.ts b/src/engine/components/renderer/RenderNode.ts new file mode 100644 index 00000000..f7e66737 --- /dev/null +++ b/src/engine/components/renderer/RenderNode.ts @@ -0,0 +1,447 @@ +import { GeometryBase } from '../../core/geometry/GeometryBase'; +import { PassGenerate } from '../../gfx/generate/PassGenerate'; +import { ShaderReflection } from '../../gfx/graphics/webGpu/shader/value/ShaderReflectionInfo'; +import { EntityCollect } from '../../gfx/renderJob/collect/EntityCollect'; +import { GPUContext } from '../../gfx/renderJob/GPUContext'; +import { ClusterLightingRender } from '../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender'; +import { RendererType } from '../../gfx/renderJob/passRenderer/state/RendererType'; +import { RendererMaskUtil, RendererMask } from '../../gfx/renderJob/passRenderer/state/RendererMask'; +import { RendererPassState } from '../../gfx/renderJob/passRenderer/state/RendererPassState'; +import { MaterialBase } from '../../materials/MaterialBase'; +import { ComponentBase } from '../ComponentBase'; +import { RenderContext } from '../../gfx/renderJob/passRenderer/RenderContext'; +import { Engine3D } from '../../Engine3D'; +import { View3D } from '../../core/View3D'; +import { GlobalBindGroup } from '../../gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { RenderShader } from '../../gfx/graphics/webGpu/shader/RenderShader'; +import { RTResourceMap } from '../../gfx/renderJob/frame/RTResourceMap'; +import { UUID } from '../../util/Global'; +import { ComponentType } from '../../util/SerializeDefine'; +import { IESProfiles } from '../lights/IESProfiles'; + +/** + * @internal + * @group Components + */ +export class RenderNode extends ComponentBase { + public instanceCount: number = 0; + public lodLevel: number = 0; + public alwaysRender: boolean = false; + public renderOrder: number = 0; + public instanceID: string; + public drawType: number = 0; + + protected _geometry: GeometryBase; + protected _materials: MaterialBase[] = []; + protected _castShadow: boolean = true; + protected _castReflection: boolean = false; + protected _castGI: boolean = false; + protected _rendererMask: number = RendererMask.Default; + protected _inRenderer: boolean = false; + protected _readyPipeline: boolean = false; + protected _combineShaderRefection: ShaderReflection; + protected _ignoreEnvMap?: boolean; + protected _ignorePrefilterMap?: boolean; + + constructor() { + super(); + this.componentType = ComponentType.renderNode; + this.rendererMask = RendererMask.Default; + } + + public get geometry(): GeometryBase { + return this._geometry; + } + + public set geometry(value: GeometryBase) { + this._geometry = value; + } + + public addMask(mask: RendererMask) { + this._rendererMask = RendererMaskUtil.addMask(this.rendererMask, mask) + } + + public removeMask(mask: RendererMask) { + this._rendererMask = RendererMaskUtil.removeMask(this.rendererMask, mask) + } + + public hasMask(mask: RendererMask): boolean { + return RendererMaskUtil.hasMask(this.rendererMask, mask) + } + + public get rendererMask(): number { + return this._rendererMask; + } + + public set rendererMask(value: number) { + this._rendererMask = value; + } + + public get materials(): MaterialBase[] { + return this._materials; + } + + public set materials(value: MaterialBase[]) { + this._materials = value; + let transparent = false; + let sort = 0; + for (let i = 0; i < value.length; i++) { + const element = value[i]; + if (element.transparent) { + transparent = true; + sort = sort > element.sort ? sort : element.sort; + } + } + this.renderOrder = transparent ? this.renderOrder : sort; + + if (!this._readyPipeline) { + this.initPipeline(); + } + } + + protected init() { + // this.renderPasses = new Map(); + this.instanceID = UUID(); + } + + public addRendererMask(tag: RendererMask) { + this._rendererMask = RendererMaskUtil.addMask(this._rendererMask, tag); + } + + public removeRendererMask(tag: RendererMask) { + this._rendererMask = RendererMaskUtil.removeMask(this._rendererMask, tag); + } + + protected onEnable(): void { + if (!this._readyPipeline) { + this.initPipeline(); + + + } + EntityCollect.instance.addRenderNode(this.transform.scene3D, this); + } + + + protected onDisable(): void { + EntityCollect.instance.removeRenderNode(this.transform.scene3D, this); + } + + public selfCloneMaterials(key: string): this { + let newMaterials = []; + for (let i = 0, c = this.materials.length; i < c; i++) { + const material = this.materials[i].clone(); + newMaterials.push(material); + } + this.materials = newMaterials; + + this._readyPipeline = false; + this.initPipeline(); + return this; + } + + protected initPipeline() { + if (this._geometry && this._materials.length > 0) { + for (let i = 0; i < this._materials.length; i++) { + const material = this._materials[i]; + let passList = material.addPass(RendererType.COLOR, material); + for (let i = 0; i < passList.length; i++) { + const pass = passList[i]; + let shader = RenderShader.getShader(pass.shaderID); + if (!shader.shaderReflection) { + shader.preCompile(this._geometry); + } + this._geometry.generate(shader.shaderReflection); + } + + this.object3D.bound = this._geometry.bounds; + } + this._readyPipeline = true; + + let transparent = false; + let sort = 0; + for (let i = 0; i < this.materials.length; i++) { + const element = this.materials[i]; + transparent = element.transparent; + if (element.transparent) { + sort = sort > element.sort ? sort : element.sort; + } else { + sort = Math.max(sort - 3000, 0); + } + this.castNeedPass(element.getShader()); + } + this.renderOrder = sort; + + if (this.enable && this.transform && this.transform.scene3D) { + EntityCollect.instance.addRenderNode(this.transform.scene3D, this); + } + } + } + + protected castNeedPass(shader: RenderShader) { + if (this.castGI) { + for (let i = 0; i < this.materials.length; i++) { + const mat = this.materials[i]; + PassGenerate.createGIPass(this, mat); + } + } + + if (this.castShadow) { + for (let i = 0; i < this.materials.length; i++) { + const mat = this.materials[i]; + if (mat.shaderState.castShadow) { + PassGenerate.createShadowPass(this, mat); + } + } + } + + if (this.castReflection) { + for (let i = 0; i < this.materials.length; i++) { + const mat = this.materials[i]; + if (mat.shaderState.castShadow) { + PassGenerate.createShadowPass(this, mat); + } + } + } + + + // add if alpha == 1 + let ignoreDepthPass = RendererMaskUtil.hasMask(this.rendererMask, RendererMask.IgnoreDepthPass); + if (!ignoreDepthPass && Engine3D.setting.render.zPrePass && shader.shaderState.useZ) { + for (let i = 0; i < this.materials.length; i++) { + const mat = this.materials[i]; + PassGenerate.createDepthPass(this, mat); + } + } else { + for (let i = 0; i < this.materials.length; i++) { + const mat = this.materials[i]; + mat.removePass(RendererType.DEPTH, 0); + } + } + } + + public get castShadow(): boolean { + return this._castShadow; + } + + public set castShadow(value: boolean) { + this._castShadow = value; + } + + public get castGI(): boolean { + return this._castGI; + } + + public set castGI(value: boolean) { + this._castGI = value; + } + + public get castReflection(): boolean { + return this._castReflection; + } + + public set castReflection(value: boolean) { + this._castReflection = value; + } + + + + public renderPass(view: View3D, passType: RendererType, renderContext: RenderContext) { + let renderNode = this; + for (let i = 0; i < renderNode.materials.length; i++) { + const material = renderNode.materials[i]; + let passes = material.renderPasses.get(passType); + + if (!passes || passes.length == 0) continue; + + GPUContext.bindGeometryBuffer(renderContext.encoder, renderNode._geometry); + let worldMatrix = renderNode.object3D.transform._worldMatrix; + for (let j = 0; j < passes.length; j++) { + if (!passes || passes.length == 0) continue; + let matPass = passes[j]; + if (!matPass.enable) continue; + + // for (let j = passes.length > 1 ? 1 : 0 ; j < passes.length; j++) { + const renderShader = matPass.renderShader; + if (renderShader.shaderState.splitTexture) { + + renderContext.endRenderPass(); + RTResourceMap.WriteSplitColorTexture(renderNode.instanceID); + renderContext.beginRenderPass(); + + GPUContext.bindCamera(renderContext.encoder, view.camera); + GPUContext.bindGeometryBuffer(renderContext.encoder, renderNode._geometry); + } + GPUContext.bindPipeline(renderContext.encoder, renderShader); + let subGeometries = renderNode._geometry.subGeometries; + for (let k = 0; k < subGeometries.length; k++) { + const subGeometry = subGeometries[k]; + let lodInfos = subGeometry.lodLevels; + let lodInfo = lodInfos[renderNode.lodLevel]; + + if (renderNode.instanceCount > 0) { + GPUContext.drawIndexed(renderContext.encoder, lodInfo.indexCount, renderNode.instanceCount, lodInfo.indexStart, 0, 0); + } else { + GPUContext.drawIndexed(renderContext.encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); + } + } + } + } + } + + /** + * render pass at passType + * @param pass + * @param encoder + * @returns + */ + public renderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingRender: ClusterLightingRender, encoder: GPURenderPassEncoder, useBundle: boolean = false) { + if (!this.enable) return; + this.nodeUpdate(view, passType, rendererPassState, clusterLightingRender); + + let node = this; + for (let i = 0; i < this.materials.length; i++) { + const material = this.materials[i]; + let passes = material.renderPasses.get(passType); + if (!passes || passes.length == 0) return; + let matPass = passes[i]; + if (!matPass.enable) continue; + + let worldMatrix = node.object3D.transform._worldMatrix; + if (this.drawType == 2) { + for (let i = 0; i < passes.length; i++) { + let renderShader = passes[i].renderShader; + GPUContext.bindPipeline(encoder, renderShader); + GPUContext.draw(encoder, 6, 1, 0, worldMatrix.index); + } + } else { + GPUContext.bindGeometryBuffer(encoder, node._geometry); + for (let i = 0; i < passes.length; i++) { + let renderShader = passes[i].renderShader; + + GPUContext.bindPipeline(encoder, renderShader); + let subGeometries = node._geometry.subGeometries; + for (let k = 0; k < subGeometries.length; k++) { + const subGeometry = subGeometries[k]; + let lodInfos = subGeometry.lodLevels; + let lodInfo = lodInfos[node.lodLevel]; + GPUContext.drawIndexed(encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); + } + } + } + + } + + + } + + public recordRenderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingRender: ClusterLightingRender, encoder: GPURenderPassEncoder, useBundle: boolean = false) { + if (!this.enable) return; + this.nodeUpdate(view, passType, rendererPassState, clusterLightingRender); + + let node = this; + for (let i = 0; i < this.materials.length; i++) { + let material = this.materials[i]; + + let passes = material.renderPasses.get(passType); + if (!passes || passes.length == 0) return; + + let worldMatrix = node.object3D.transform._worldMatrix; + for (let i = 0; i < passes.length; i++) { + const renderShader = passes[i].renderShader; + + GPUContext.bindPipeline(encoder, renderShader); + let subGeometries = node._geometry.subGeometries; + for (let k = 0; k < subGeometries.length; k++) { + const subGeometry = subGeometries[k]; + let lodInfos = subGeometry.lodLevels; + let lodInfo = lodInfos[node.lodLevel]; + GPUContext.drawIndexed(encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); + } + } + } + + } + + private noticeShaderChange() { + if (this.enable) { + this.onEnable(); + } + } + + public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingRender?: ClusterLightingRender) { + + let node = this; + for (let i = 0; i < this.materials.length; i++) { + let material = this.materials[i]; + let passes = material.renderPasses.get(passType); + if (passes) { + for (let i = 0; i < passes.length; i++) { + const pass = passes[i];// RenderShader.getShader(passes[i].shaderID); + const renderShader = pass.renderShader;// RenderShader.getShader(passes[i].shaderID); + + if (renderShader.shaderState.splitTexture) { + let splitTexture = RTResourceMap.CreateSplitTexture(this.instanceID); + renderShader.setTexture("splitTexture_Map", splitTexture); + } + + // renderShader.setUniformVector3("center", this.transform.worldPosition); + + // if(scene3D.envMapChange){ + if (!this._ignoreEnvMap) { + renderShader.setTexture(`envMap`, view.scene.envMap); + } + if (!this._ignorePrefilterMap) { + renderShader.setTexture(`prefilterMap`, view.scene.envMap); + } + // } + + if (renderShader.pipeline) { + renderShader.apply(this._geometry, pass, renderPassState, () => this.noticeShaderChange()); + continue; + } + + let bdrflutTex = Engine3D.res.getTexture(`BRDFLUT`); + renderShader.setTexture(`brdflutMap`, bdrflutTex); + + if (Engine3D.getRenderJob(view).shadowMapPassRenderer.depth2DTextureArray) { + renderShader.setTexture(`shadowMap`, Engine3D.getRenderJob(view).shadowMapPassRenderer.depth2DTextureArray); + } + + // let shadowLight = ShadowLights.list; + // if (shadowLight.length) { + renderShader.setTexture(`pointShadowMap`, Engine3D.getRenderJob(view).pointLightShadowRenderer.cubeTextureArray); + // } + + let iesTexture = IESProfiles.iesTexture; + if (iesTexture) { + renderShader.setTexture(`iesTextureArrayMap`, iesTexture); + } + + if (renderPassState.irradianceBuffer && renderPassState.irradianceBuffer.length > 0) { + renderShader.setTexture(`irradianceMap`, renderPassState.irradianceBuffer[0]); + renderShader.setTexture(`irradianceDepthMap`, renderPassState.irradianceBuffer[1]); + } + + let lightUniformEntries = GlobalBindGroup.getLightEntries(view.scene); + if (lightUniformEntries) { + renderShader.setStorageBuffer(`lightBuffer`, lightUniformEntries.storageGPUBuffer); + if (lightUniformEntries.irradianceVolume) { + renderShader.setStructStorageBuffer(`irradianceData`, lightUniformEntries.irradianceVolume.irradianceVolumeBuffer); + } + } + + + if (clusterLightingRender) { + renderShader.setStorageBuffer(`clustersUniform`, clusterLightingRender.clustersUniformBuffer); + renderShader.setStorageBuffer(`lightAssignBuffer`, clusterLightingRender.lightAssignBuffer); + renderShader.setStorageBuffer(`assignTable`, clusterLightingRender.assignTableBuffer); + renderShader.setStorageBuffer(`clusterBuffer`, clusterLightingRender.clusterBuffer); + } + + renderShader.apply(this._geometry, pass, renderPassState); + } + } + } + } + +} diff --git a/src/engine/components/renderer/SkinnedMeshRenderer.ts b/src/engine/components/renderer/SkinnedMeshRenderer.ts new file mode 100644 index 00000000..ea77f59f --- /dev/null +++ b/src/engine/components/renderer/SkinnedMeshRenderer.ts @@ -0,0 +1,121 @@ +import { Object3D } from '../../core/entities/Object3D'; +import { ClusterLightingRender } from '../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender'; +import { RendererType } from '../../gfx/renderJob/passRenderer/state/RendererType'; +import { RendererPassState } from '../../gfx/renderJob/passRenderer/state/RendererPassState'; +import { SkeletonAnimationComponent } from '../SkeletonAnimationComponent'; +import { MeshRenderer } from './MeshRenderer'; +import { RendererMask } from '../../gfx/renderJob/passRenderer/state/RendererMask'; +import { StorageGPUBuffer, View3D } from '../../..'; + +/** + * Skin Mesh Renderer Component + * Renders a deformable mesh. + * Deformable meshes include skin meshes (meshes with bones and bound poses), + * meshes with mixed shapes, and meshes running cloth simulations. + * @group Components + */ +export class SkinnedMeshRenderer extends MeshRenderer { + public skinJointsName: Array; + protected mInverseBindMatrixData: Array; + protected mInverseBindMatrixBuffer: StorageGPUBuffer; + protected mSkeletonAnimation: SkeletonAnimationComponent; + protected mJointIndexTableBuffer: StorageGPUBuffer; + + constructor() { + super(); + this.addRendererMask(RendererMask.SkinnedMesh); + } + + protected start() { + super.start(); + this.skeletonAnimation = this.object3D.getComponent(SkeletonAnimationComponent); + if (!this.skeletonAnimation) { + let comps = this.object3D.parentObject.parentObject.getComponentsInChild(SkeletonAnimationComponent); + if (comps.length > 0) { + this.skeletonAnimation = comps[0]; + } + if (!this.skeletonAnimation) { + this.skeletonAnimation = this.object3D.getComponentFromParent(SkeletonAnimationComponent); + } + } + } + + public get skeletonAnimation(): SkeletonAnimationComponent { + return this.mSkeletonAnimation; + } + + public set skeletonAnimation(value: SkeletonAnimationComponent) { + this.mSkeletonAnimation = value; + if (!value) { + return; + } + + if (!this.mJointIndexTableBuffer) { + let skinJointIndexData = this.mSkeletonAnimation.getJointIndexTable(this.skinJointsName); + this.mJointIndexTableBuffer = new StorageGPUBuffer(skinJointIndexData.length * 4, 0, new Float32Array(skinJointIndexData)); + this.mJointIndexTableBuffer.visibility = GPUShaderStage.VERTEX | GPUShaderStage.COMPUTE; + } + } + + public get skinInverseBindMatrices(): Array { + return this.mInverseBindMatrixData; + } + + public set skinInverseBindMatrices(inverseBindMatrices: Array) { + this.mInverseBindMatrixData = inverseBindMatrices; + var inverseBindMatricesData = new Float32Array(inverseBindMatrices.length * 16); + for (let i = 0; i < inverseBindMatrices.length; i++) { + let index = i * 16; + let mat4x4 = inverseBindMatrices[i]; + inverseBindMatricesData.set(mat4x4, index); + } + this.mInverseBindMatrixBuffer = new StorageGPUBuffer(inverseBindMatricesData.byteLength, 0, inverseBindMatricesData); + this.mInverseBindMatrixBuffer.visibility = GPUShaderStage.VERTEX | GPUShaderStage.COMPUTE; + } + + public get inverseBindMatrixBuffer(): StorageGPUBuffer { + return this.mInverseBindMatrixBuffer; + } + + public get jointIndexTableBuffer(): GPUBuffer { + return this.mJointIndexTableBuffer.buffer; + } + + public cloneTo(obj: Object3D) { + let skinnedMesh = obj.addComponent(SkinnedMeshRenderer); + skinnedMesh.geometry = this.geometry; + skinnedMesh.material = this.material.clone(); + skinnedMesh.castShadow = this.castShadow; + skinnedMesh.castGI = this.castGI; + skinnedMesh.receiveShadow = this.receiveShadow; + skinnedMesh.rendererMask = this.rendererMask; + skinnedMesh.skinJointsName = this.skinJointsName; + skinnedMesh.skinInverseBindMatrices = this.skinInverseBindMatrices; + skinnedMesh.mJointIndexTableBuffer = this.mJointIndexTableBuffer; + } + + /** + * @internal + * @param passType + * @param renderPassState + * @param scene3D + * @param clusterLightingRender + * @param probes + */ + public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingRender?: ClusterLightingRender) { + for (let i = 0; i < this.materials.length; i++) { + const material = this.materials[i]; + let passes = material.renderPasses.get(passType); + if (passes) for (let i = 0; i < passes.length; i++) { + const renderShader = passes[i].renderShader; + if (!renderShader.pipeline) { + renderShader.setStorageBuffer('jointsMatrixIndexTable', this.mSkeletonAnimation.jointMatrixIndexTableBuffer); + renderShader.setStorageBuffer('jointsInverseMatrix', this.mInverseBindMatrixBuffer); + renderShader.setStorageBuffer('jointsIndexMapingTable', this.mJointIndexTableBuffer); + } + } + } + super.nodeUpdate(view, passType, renderPassState, clusterLightingRender); + } + +} diff --git a/src/engine/components/renderer/SkyRenderer.ts b/src/engine/components/renderer/SkyRenderer.ts new file mode 100644 index 00000000..41267069 --- /dev/null +++ b/src/engine/components/renderer/SkyRenderer.ts @@ -0,0 +1,105 @@ + +import { BoundingBox } from '../../core/bound/BoundingBox'; +import { Texture } from '../../gfx/graphics/webGpu/core/texture/Texture'; +import { EntityCollect } from '../../gfx/renderJob/collect/EntityCollect'; +import { SkyMaterial } from '../../materials/SkyMaterial'; +import { Vector3 } from '../../math/Vector3'; +import { MeshRenderer } from './MeshRenderer'; +import { RendererMask } from '../../gfx/renderJob/passRenderer/state/RendererMask'; +import { ClusterLightingRender } from '../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender'; +import { RendererPassState } from '../../gfx/renderJob/passRenderer/state/RendererPassState'; +import { Engine3D } from '../../Engine3D'; +import { View3D } from '../../core/View3D'; +import { RendererType } from '../../gfx/renderJob/passRenderer/state/RendererType'; +import { SphereGeometry } from '../../shape/SphereGeometry'; +import { ComponentType } from '../../util/SerializeDefine'; +/** + * + * Sky Box Renderer Component + * @group Components + */ +export class SkyRenderer extends MeshRenderer { + /** + * The material used in the Sky Box. + */ + public skyMaterial: SkyMaterial; + + constructor() { + super(); + this.componentType = ComponentType.skyRenderer; + this.castShadow = false; + this.castGI = true; + this.addRendererMask(RendererMask.Sky); + this.alwaysRender = true; + } + + protected init(): void { + super.init(); + this.object3D.bound = new BoundingBox(Vector3.ZERO.clone(), Vector3.MAX); + this.geometry = new SphereGeometry(Engine3D.setting.sky.defaultFar, 20, 20); + this.skyMaterial ||= new SkyMaterial(); + } + + protected onEnable(): void { + if (!this._readyPipeline) { + this.initPipeline(); + } else { + this.castNeedPass(this.materials[0].getShader()); + + if (!this._inRenderer && this.transform.scene3D) { + EntityCollect.instance.sky = this; + this._inRenderer = true; + } + } + } + + protected onDisable(): void { + if (this._inRenderer && this.transform.scene3D) { + this._inRenderer = false; + EntityCollect.instance.sky = null; + } + } + + public renderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingRender: ClusterLightingRender, encoder: GPURenderPassEncoder, useBundle: boolean = false) { + this.transform.updateWorldMatrix(); + super.renderPass2(view, passType, rendererPassState, clusterLightingRender, encoder, useBundle); + // this.transform.localPosition = Camera3D.mainCamera.transform.localPosition ; + } + + /** + * set environment texture + */ + public set map(texture: Texture) { + this.skyMaterial.baseMap = texture; + if (this.skyMaterial.name == null) { + this.skyMaterial.name = 'skyMaterial'; + } + this.material = this.skyMaterial; + } + + /** + * get environment texture + */ + public get map(): Texture { + return this.skyMaterial.baseMap; + } + + public get exposure() { + return this.skyMaterial.exposure; + } + + public set exposure(value) { + if (this.skyMaterial) + this.skyMaterial.exposure = value; + } + + public get roughness() { + return this.skyMaterial.roughness; + } + + public set roughness(value) { + if (this.skyMaterial) + this.skyMaterial.roughness = value; + } + +} From a89c1bd7fd9cb404d56dc6934c3e838c5f817e92 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Mon, 24 Apr 2023 18:25:44 +0800 Subject: [PATCH 052/100] feat(light): add cluster lighting (#64) add cluster light render add direction light add point light add spot light add light ies --- src/engine/components/lights/DirectLight.ts | 89 ++++++ src/engine/components/lights/GILighting.ts | 23 ++ src/engine/components/lights/IESProfiles.ts | 46 ++++ src/engine/components/lights/LightBase.ts | 253 ++++++++++++++++++ src/engine/components/lights/LightData.ts | 107 ++++++++ src/engine/components/lights/PointLight.ts | 148 ++++++++++ src/engine/components/lights/SpotLight.ts | 180 +++++++++++++ .../cluster/ClusterLightingRender.ts | 123 +++++++++ 8 files changed, 969 insertions(+) create mode 100644 src/engine/components/lights/DirectLight.ts create mode 100644 src/engine/components/lights/GILighting.ts create mode 100644 src/engine/components/lights/IESProfiles.ts create mode 100644 src/engine/components/lights/LightBase.ts create mode 100644 src/engine/components/lights/LightData.ts create mode 100644 src/engine/components/lights/PointLight.ts create mode 100644 src/engine/components/lights/SpotLight.ts create mode 100644 src/engine/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts diff --git a/src/engine/components/lights/DirectLight.ts b/src/engine/components/lights/DirectLight.ts new file mode 100644 index 00000000..9c043395 --- /dev/null +++ b/src/engine/components/lights/DirectLight.ts @@ -0,0 +1,89 @@ +import { Camera3D } from '../../core/Camera3D'; +import { UUID } from '../../util/Global'; +import { LightBase } from './LightBase'; +import { LightType } from './LightData'; +/** + * + *Directional light source. + *The light of this light source is parallel, for example, sunlight. This light source can generate shadows. + * @group Lights + */ +export class DirectLight extends LightBase { + public shadowCamera: Camera3D; + + constructor() { + super(); + } + + protected init(): void { + super.init(); + if (this.object3D.name == "") { + this.object3D.name = "DirectionLight_" + UUID(); + } + this.radius = 9999999;// Number.MAX_SAFE_INTEGER; + this.lightData.lightType = LightType.DirectionLight; + this.lightData.linear = 0; + } + + protected start(): void { + super.start(); + this.castGI = true; + } + + /** + * + * Get the radius of a directional light source + */ + public get radius(): number { + return this.lightData.range as number; + } + + /** + * Set the radius of a directional light source + */ + public set radius(value: number) { + this.lightData.range = value; + this.onChange(); + } + + /** + * + * Get the radius of a directional light source + */ + public get indirect(): number { + return this.lightData.quadratic as number; + } + + /** + * Set the radius of a directional light source + */ + public set indirect(value: number) { + this.lightData.quadratic = value; + this.onChange(); + } + + /** + * Set cast shadow + * @param value + **/ + public set castShadow(value: boolean) { + if (value != this._castShadow) { + this.onChange(); + } + this._castShadow = value; + } + + /** + * get cast shadow + * @return boolean + * */ + public get castShadow(): boolean { + return this.lightData.castShadowIndex as number >= 0; + } + + /** + * enable light debug gui + */ + public debug() { + } +} diff --git a/src/engine/components/lights/GILighting.ts b/src/engine/components/lights/GILighting.ts new file mode 100644 index 00000000..947ed8a6 --- /dev/null +++ b/src/engine/components/lights/GILighting.ts @@ -0,0 +1,23 @@ +import { LightBase } from './LightBase'; + +/** + * Collecting and storing light that affects GI + * @internal + * @group Lights + */ +export class GILighting { + public static list: LightBase[] = []; + public static add(light: LightBase) { + let index = this.list.indexOf(light); + if (index == -1) { + this.list.push(light); + } + } + + public static remove(light: LightBase) { + let index = this.list.indexOf(light); + if (index != -1) { + this.list.splice(index, 1); + } + } +} diff --git a/src/engine/components/lights/IESProfiles.ts b/src/engine/components/lights/IESProfiles.ts new file mode 100644 index 00000000..19ee7d61 --- /dev/null +++ b/src/engine/components/lights/IESProfiles.ts @@ -0,0 +1,46 @@ +import { ITexture } from "../../gfx/graphics/webGpu/core/texture/ITexture"; +import { Texture } from "../../gfx/graphics/webGpu/core/texture/Texture"; +import { GPUAddressMode } from "../../gfx/graphics/webGpu/WebGPUConst"; +import { BitmapTexture2D } from "../../textures/BitmapTexture2D"; +import { BitmapTexture2DArray } from "../../textures/BitmapTexture2DArray"; + +export class IESProfiles { + public static use: boolean = false; + public static iesTexture: BitmapTexture2DArray; + public static ies_list: IESProfiles[] = []; + private _iesTexture: Texture; + public index: number = 0; + constructor() { + } + + /** + * create ies image form ies file + */ + private generateIES(file: any) { + //TODO add create ies image form ies file + } + + public set IESTexture(texture: Texture) { + this._iesTexture = texture; + texture.addressModeU = GPUAddressMode.repeat; + texture.addressModeV = GPUAddressMode.repeat; + texture.addressModeW = GPUAddressMode.repeat; + if (IESProfiles.ies_list.indexOf(this) == -1) { + this.index = IESProfiles.ies_list.length; + IESProfiles.ies_list.push(this); + if (!IESProfiles.iesTexture) { + IESProfiles.create(texture.width, texture.height); + } + IESProfiles.iesTexture.addTexture(texture as BitmapTexture2D); + } + } + + public get IESTexture(): Texture { + return this._iesTexture; + } + + public static create(width: number, height: number) { + let count = 48; + this.iesTexture = new BitmapTexture2DArray(width, height, count); + } +} \ No newline at end of file diff --git a/src/engine/components/lights/LightBase.ts b/src/engine/components/lights/LightBase.ts new file mode 100644 index 00000000..219a3e80 --- /dev/null +++ b/src/engine/components/lights/LightBase.ts @@ -0,0 +1,253 @@ +import { BoundingBox } from '../../core/bound/BoundingBox'; +import { EntityCollect } from '../../gfx/renderJob/collect/EntityCollect'; +import { Color } from '../../math/Color'; +import { Vector3 } from '../../math/Vector3'; +import { ComponentBase } from '../ComponentBase'; +import { Transform } from '../Transform'; +import { GILighting } from './GILighting'; +import { LightData } from './LightData'; +import { ShadowLightsCollect } from '../../gfx/renderJob/collect/ShadowLightsCollect'; +import { IESProfiles } from './IESProfiles'; +import { ComponentType } from '../../util/SerializeDefine'; + +/** + * @internal + * @group Lights + */ +export class LightBase extends ComponentBase { + /** + * light name + */ + public name: string; + /** + * light size + */ + public size: number = 1; + + /** + * light source data + */ + public lightData: LightData; + + /** + * fix light direction + */ + public dirFix: number = 1; + + /** + * Callback function when binding changes + */ + public bindOnChange: () => void; + + public needUpdateShadow: boolean = true; + + /** + * Whether to enable real-time rendering of shadows + */ + public realTimeShadow: boolean = true; + + protected _castGI: boolean = false; + protected _castShadow: boolean = false; + private _iesPofiles: IESProfiles; + + constructor() { + super(); + this.componentType = ComponentType.light; + } + + protected init(): void { + this.transform.object3D.bound = new BoundingBox(new Vector3(), new Vector3()); + + this.lightData = new LightData(); + this.lightData.lightMatrixIndex = this.transform.worldMatrix.index; + } + + protected onChange() { + if (this.bindOnChange) this.bindOnChange(); + this.transform.object3D.bound.setFromCenterAndSize(this.transform.worldPosition, new Vector3(this.size, this.size, this.size)); + if (this._castGI) { + EntityCollect.instance.state.giLightingChange = true; + } + if (this._castShadow) { + this.needUpdateShadow = true; + ShadowLightsCollect.addShadowLight(this); + } else { + ShadowLightsCollect.removeShadowLight(this); + } + } + + protected start(): void { + this.transform.onScaleChange = () => this.onScaleChange(); + this.transform.onRotationChange = () => this.onRotChange(); + this.onRotChange(); + this.onScaleChange(); + } + + protected onRotChange() { + if (this.dirFix == 1) { + this.lightData.direction.copyFrom(this.transform.forward); + } else { + this.lightData.direction.copyFrom(this.transform.back); + } + this.lightData.lightTangent.copyFrom(this.transform.up); + this.onChange(); + } + + protected onScaleChange() { + this.onChange(); + } + + protected onEnable(): void { + this.onChange(); + EntityCollect.instance.addLight(this.transform.scene3D, this); + } + + protected onDisable(): void { + this.onChange(); + EntityCollect.instance.removeLight(this.transform.scene3D, this); + } + + public set iesPofile(iesPofiles: IESProfiles) { + this._iesPofiles = iesPofiles; + this.lightData.iesPofiles = iesPofiles.index; + IESProfiles.use = true; + this.onChange(); + } + + public get iesPofile(): IESProfiles { + return this._iesPofiles; + } + + /** + * Get the red component of the lighting color + */ + public get r(): number { + return this.lightData.lightColor.r; + } + + /** + * Set the red component of the lighting color + */ + public set r(value: number) { + this.lightData.lightColor.r = value; + this.onChange(); + } + + /** + * Get the green component of the lighting color + */ + public get g(): number { + return this.lightData.lightColor.g; + } + + /** + * Set the green component of the lighting color + */ + public set g(value: number) { + this.lightData.lightColor.g = value; + this.onChange(); + } + + /** + * Get the blue component of the lighting color + */ + public get b(): number { + return this.lightData.lightColor.b; + } + /** + * Set the blue component of the lighting color + */ + public set b(value: number) { + this.lightData.lightColor.b = value; + this.onChange(); + } + /** + * Get light source color + * @return Color + */ + public get lightColor(): Color { + return this.lightData.lightColor; + } + /** + * Set light source color + * @param Color + */ + public set lightColor(value: Color) { + this.lightData.lightColor = value; + this.onChange(); + } + /** + * Get Illumination intensity of light source + * @return number + */ + public get intensity(): number { + return this.lightData.intensity as number; + } + /** + * Set Illumination intensity of light source + * @param value + */ + public set intensity(value: number) { + this.lightData.intensity = value; + this.onChange(); + } + /** + * get cast shadow + * @return boolean + * */ + public get castShadow(): boolean { + return this.lightData.castShadowIndex as number >= 0; + } + + /** + * get shadow index at shadow map list + */ + public get shadowIndex(): number { + return this.lightData.castShadowIndex as number; + } + /** + * set cast shadow + * @param value is true , that can cast shadow + * */ + public set castShadow(value: boolean) { + if (value) this.onChange(); + } + + /** + * get gi is enable + * @return boolean + * */ + public get castGI(): boolean { + return this._castGI; + } + /** + * set gi is enable + * @param value + * */ + public set castGI(value: boolean) { + if (value) { + GILighting.add(this); + } else { + GILighting.remove(this); + } + this._castGI = value; + if (value) this.onChange(); + } + + /** + * light source direction + * @return Vector3 + * */ + public get direction(): Vector3 { + return this.lightData.direction; + } + + public destroy(): void { + this.lightData = null; + this.bindOnChange = null; + this.transform.eventDispatcher.removeEventListener(Transform.ROTATION_ONCHANGE, this.onRotChange, this); + this.transform.eventDispatcher.removeEventListener(Transform.SCALE_ONCHANGE, this.onScaleChange, this); + super.destroy(); + } + +} diff --git a/src/engine/components/lights/LightData.ts b/src/engine/components/lights/LightData.ts new file mode 100644 index 00000000..15a36410 --- /dev/null +++ b/src/engine/components/lights/LightData.ts @@ -0,0 +1,107 @@ +import { Color } from '../../math/Color'; +import { Vector3 } from '../../math/Vector3'; +import { Struct } from '../../util/struct/Struct'; + +/** + *Type of light source + * + *Type Description| + * |:---:|:---:| + *None| + *PointLight| + *DirectionLight| + *SpotLight| + *SkyLight| + * @group Lights + */ +export enum LightType { + None, + PointLight, + DirectionLight, + SpotLight, + SkyLight, +} + +/** + * Data structure of light sources + * @internal + * @group Lights + */ +export class LightData extends Struct { + public static lightSize: number = 24; + + public index: number = -1; + /** + * Light source type + * @see LightType + * */ + public lightType: number = -1; + + /** + * + * Light source radius + */ + public radius: number = 0.5; + + /** + * + * The illumination distance of the light source, which is 0, means that the intensity of the light will not decrease due to the distance + */ + public linear: number = 1.0; + + public lightPosition: Vector3 = new Vector3(); + + public lightMatrixIndex: number = -1; + + /** + * Light source direction + */ + public direction: Vector3 = new Vector3(); + + public quadratic: number = 0.032; + + /** + * + * The color of the light source + */ + public lightColor: Color = new Color(1, 1, 1, 1); + + /** + * + * The intensity of light exposure + */ + public intensity: number = 1; + + /** + * + * Inner cone angle of light source + */ + public innerAngle: number = 0; + /** + * + * Outer cone angle of light source + */ + public outerAngle: number = 1; + + /** + * + * The size of the light source range and the distance emitted from the center of the light source object. Only Point and Spotlight have this parameter. + */ + public range: number = 100; + + /** + * + * shadow at shadow map index + */ + public castShadowIndex: number = -1; + + /** + * Tangent direction of light + */ + public lightTangent: Vector3 = Vector3.FORWARD; + + /** + * Whether to use lighting ies + */ + public iesPofiles: number = -1; +} diff --git a/src/engine/components/lights/PointLight.ts b/src/engine/components/lights/PointLight.ts new file mode 100644 index 00000000..1466c17d --- /dev/null +++ b/src/engine/components/lights/PointLight.ts @@ -0,0 +1,148 @@ +import { Engine3D } from '../../Engine3D'; +import { View3D } from '../../core/View3D'; +import { Vector3 } from '../../math/Vector3'; +import { UUID } from '../../util/Global'; +import { LightBase } from './LightBase'; +import { LightType } from './LightData'; +/** + *Point light source. + *A single point light source that illuminates all directions. + *A common example is to simulate the light emitted by a light bulb, where a point light source cannot create shadows. + * @group Lights + */ +export class PointLight extends LightBase { + + constructor() { + super(); + } + + protected init(): void { + super.init(); + this.lightData.lightType = LightType.PointLight; + if (this.object3D.name == "") { + this.object3D.name = "PointLight" + UUID(); + } + } + + + /** + * + * Get the range of the light source + * @return {number} + */ + public get range(): number { + return this.lightData.range as number; + } + /** + * + * Set the range of the light source + * @param {number} + */ + public set range(value: number) { + this.lightData.range = value; + this.onChange(); + } + + /** + * + * Get the illumination distance of the light source + * @type {number} + * @memberof PointLight + */ + public get at(): number { + return this.lightData.linear as number; + } + + /** + * + * Set the illumination distance of the light source + * @param {value} It will decay linearly from the maximum value to the current light position at a distance of 0, + * with a default value of 0. This means that the intensity of the light will not decrease due to distance + * @memberof PointLight + */ + public set at(value: number) { + this.lightData.linear = value; + this.onChange(); + } + + /** + * Get the radius to control the light + */ + public get radius(): number { + return this.lightData.radius as number; + } + + /** + * Set the radius of the control light + */ + public set radius(value: number) { + this.lightData.radius = value; + this.onChange(); + } + + /** + * Get the radius to control the light + */ + public get quadratic(): number { + return this.lightData.quadratic as number; + } + + /** + * Set the radius of the control light + */ + public set quadratic(value: number) { + this.lightData.quadratic = value; + this.onChange(); + } + + /** + * Cast Light Shadow + * @param value + * */ + public set castShadow(value: boolean) { + if (value != this._castShadow) { + this.onChange(); + } + this._castShadow = value; + } + + protected start(): void { + this.transform.rotationX = 90; + super.start(); + } + + protected onUpdate(): void { + this.transform.updateWorldMatrix(true); + } + + protected onGraphic(view?: View3D): void { + let custom = Engine3D.getRenderJob(view).graphic3D.createCustomShape( + `PointLight_${this.object3D.uuid}`, + this.transform, + ); + custom.buildAxis(); + custom.buildCircle(Vector3.ZERO, this.range, 32, Vector3.X_AXIS); + custom.buildCircle(Vector3.ZERO, this.range, 32, Vector3.Y_AXIS); + custom.buildCircle(Vector3.ZERO, this.range, 32, Vector3.Z_AXIS); + } + + /** + * enable GUI debug + */ + public debug() { + } + + public debugDraw(show: boolean) { + // if (this.mShowDebugLine != show) { + // if (show) { + // this.drawDebugLine(); + // } else { + // let view = this.transform.view3D; + // view.graphic3D.Clear(`PointLight_${this.object3D.uuid}`); + // } + // this.mShowDebugLine = show; + // } + } + +} + diff --git a/src/engine/components/lights/SpotLight.ts b/src/engine/components/lights/SpotLight.ts new file mode 100644 index 00000000..a4b183e3 --- /dev/null +++ b/src/engine/components/lights/SpotLight.ts @@ -0,0 +1,180 @@ +import { Engine3D } from '../../Engine3D'; +import { View3D } from '../../core/View3D'; +import { clamp, DEGREES_TO_RADIANS, RADIANS_TO_DEGREES } from '../../math/MathUtil'; +import { Vector3 } from '../../math/Vector3'; +import { UUID } from '../../util/Global'; +import { LightBase } from './LightBase'; +import { LightType } from './LightData'; + +/** + * Spotlight source. + * Light shines from a point in one direction, and as the light shines further away, the size of the light cone gradually increases. + * Similar to a desk lamp, chandelier, or flashlight, this light source can produce shadows. + * @group Lights + */ +export class SpotLight extends LightBase { + constructor() { + super(); + } + + protected init(): void { + super.init(); + this.lightData.lightType = LightType.SpotLight; + if (this.object3D.name == "") { + this.object3D.name = "SpotLight" + UUID(); + } + } + + + + /** + * Get the inner cone angle of the light source (as a percentage relative to the outer cone angle) + */ + public get innerAngle(): number { + return (this.lightData.innerAngle as number) / (this.lightData.outerAngle as number) * 100.0; + } + + /** + * + * Set the inner cone angle of the light source (as a percentage relative to the outer cone angle) + * @param {value} 0.0 - 100.0 + */ + public set innerAngle(value: number) { + this.lightData.innerAngle = clamp(value, 0.0, 100.0) / 100.0 * (this.lightData.outerAngle as number); + this.onChange(); + } + + /** + * Get the outer cone angle of the light source + * @return number + */ + public get outerAngle(): number { + return (this.lightData.outerAngle as number) * RADIANS_TO_DEGREES * 2; + } + + /** + * Set the outer cone angle of the light source + * @param {value} 1.0 - 179.0 + */ + public set outerAngle(value: number) { + this.lightData.outerAngle = clamp(value, 1.0, 179.0) * DEGREES_TO_RADIANS * 0.5; + this.onChange(); + } + + /** + * + * Get the radius of the light source + * @return number + */ + public get radius(): number { + return this.lightData.radius as number; + } + + /** + * + * Set the radius of the light source + * @param {value} + */ + public set radius(value: number) { + this.lightData.radius = value; + this.onChange(); + } + + /** + * Get the range of the light source + */ + public get range(): number { + return this.lightData.range as number; + } + + /** + * + * Set the range of the light source + * @param {value} + */ + public set range(value: number) { + this.lightData.range = value; + this.onChange(); + } + + /** + * Get the illumination distance of the light source + */ + public get at(): number { + return this.lightData.linear as number; + } + + /** + * Set the illumination distance of the light source + */ + public set at(value: number) { + this.lightData.linear = value; + this.onChange(); + } + + /** + * Cast Light Shadow + * @param value + * */ + public set castShadow(value: boolean) { + if (value != this._castShadow) { + this.onChange(); + } + this._castShadow = value; + } + + protected start(): void { + super.start(); + this.lightData.lightType = LightType.SpotLight; + } + + protected onUpdate(): void { + this.transform.updateWorldMatrix(true); + } + + protected onGraphic(view: View3D) { + let custom = Engine3D.getRenderJob(view).graphic3D.createCustomShape( + `SpotLight_${this.object3D.uuid}`, + this.transform, + ); + + const range = this.range; + const outerAngle = this.outerAngle / 2.0; + custom.buildAxis(); + + let angle = (90 - outerAngle) * DEGREES_TO_RADIANS; + let v0 = range * Math.cos(angle); + let v1 = range * Math.sin(angle); + custom.buildLines([Vector3.ZERO, new Vector3(0, v0, v1)]); + custom.buildLines([Vector3.ZERO, new Vector3(v0, 0, v1)]); + + angle = (90 + outerAngle) * DEGREES_TO_RADIANS; + v0 = range * Math.cos(angle); + v1 = range * Math.sin(angle); + custom.buildLines([Vector3.ZERO, new Vector3(0, v0, v1)]); + custom.buildLines([Vector3.ZERO, new Vector3(v0, 0, v1)]); + custom.buildArcLine(Vector3.ZERO, range, 90 - outerAngle, 90 + outerAngle, 16, Vector3.X_AXIS); + custom.buildArcLine(Vector3.ZERO, range, 90 - outerAngle, 90 + outerAngle, 16, Vector3.Y_AXIS); + custom.buildCircle(new Vector3(0, 0, range * Math.sin(angle)), range * Math.cos(angle), 32, Vector3.Z_AXIS); + } + + /** + * enable GUI debug + */ + public debug() { + } + + public debugDraw(show: boolean) { + // if (this.mShowDebugLine != show) { + // if (show) { + // this.drawDebugLine(); + // } else { + // //view.graphic3D.Clear(`SpotLight_${this.object3D.uuid}`); + // } + // this.mShowDebugLine = show; + // } + } + +} + + diff --git a/src/engine/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts b/src/engine/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts new file mode 100644 index 00000000..cce8ef61 --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts @@ -0,0 +1,123 @@ +import ClusterBoundsSource_cs from '../../../../assets/shader/cluster/ClusterBoundsSource_cs.wgsl?raw'; +import ClusterLighting_cs from '../../../../assets/shader/cluster/ClusterLighting_cs.wgsl?raw'; + +import { LightBase } from '../../../../components/lights/LightBase'; +import { View3D } from '../../../../core/View3D'; +import { GlobalBindGroup } from '../../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { ComputeGPUBuffer } from '../../../graphics/webGpu/core/buffer/ComputeGPUBuffer'; +import { UniformGPUBuffer } from '../../../graphics/webGpu/core/buffer/UniformGPUBuffer'; +import { ComputeShader } from '../../../graphics/webGpu/shader/ComputeShader'; +import { webGPUContext } from '../../../graphics/webGpu/Context3D'; +import { EntityCollect } from '../../collect/EntityCollect'; +import { GPUContext } from '../../GPUContext'; +import { OcclusionSystem } from '../../occlusion/OcclusionSystem'; +import { RendererBase } from '../RendererBase'; +import { RendererType } from '../state/RendererType'; +/** + * @internal + * @group Post + */ +export class ClusterLightingRender extends RendererBase { + public clusterTileX = 16; + public clusterTileY = 12; + public clusterTileZ = 24; + public maxNumLights = 128; + public maxNumLightsPerCluster = 100; + public clusterPix = 1; + public clusterBuffer: ComputeGPUBuffer; + public lightAssignBuffer: ComputeGPUBuffer; + public assignTableBuffer: ComputeGPUBuffer; + public clustersUniformBuffer: UniformGPUBuffer; + + private _clusterGenerateCompute: ComputeShader; + private _clusterLightingCompute: ComputeShader; + constructor(view: View3D) { + super(); + + this.passType = RendererType.Cluster; + this.initCompute(view); + } + + private initCompute(view: View3D) { + + this._clusterGenerateCompute = new ComputeShader(ClusterBoundsSource_cs); + this._clusterLightingCompute = new ComputeShader(ClusterLighting_cs); + + let size = webGPUContext.presentationSize; + let numClusters = this.clusterTileX * this.clusterTileY * this.clusterTileZ; + + let camera = view.camera; + let near = camera.near; + let far = camera.far; + + this.clusterBuffer = new ComputeGPUBuffer(numClusters * /*two vec4*/ 2 * /*vec4*/4); + this.clustersUniformBuffer = new UniformGPUBuffer(10); + this.clustersUniformBuffer.visibility = GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; + + this.clustersUniformBuffer.setFloat('clusterTileX', this.clusterTileX); + this.clustersUniformBuffer.setFloat('clusterTileY', this.clusterTileY); + this.clustersUniformBuffer.setFloat('clusterTileZ', this.clusterTileZ); + this.clustersUniformBuffer.setFloat('numLights', this.maxNumLights); + this.clustersUniformBuffer.setFloat('maxNumLightsPerCluster', this.maxNumLightsPerCluster); + + this.clustersUniformBuffer.setFloat('near', near); + this.clustersUniformBuffer.setFloat('far', far); + + this.clustersUniformBuffer.setFloat('screenWidth', size[0]); + this.clustersUniformBuffer.setFloat('screenHeight', size[1]); + this.clustersUniformBuffer.setFloat('clusterPix', this.clusterPix); + this.clustersUniformBuffer.apply(); + + let standBindGroup = GlobalBindGroup.getCameraGroup(camera); + this._clusterGenerateCompute.setUniformBuffer(`globalUniform`, standBindGroup.uniformGPUBuffer); + this._clusterLightingCompute.setUniformBuffer(`globalUniform`, standBindGroup.uniformGPUBuffer); + this._clusterGenerateCompute.setUniformBuffer(`clustersUniform`, this.clustersUniformBuffer); + this._clusterGenerateCompute.setStorageBuffer(`clusterBuffer`, this.clusterBuffer); + + let lightBuffer = GlobalBindGroup.getLightEntries(view.scene); + this.lightAssignBuffer = new ComputeGPUBuffer(numClusters * this.maxNumLightsPerCluster); + this.lightAssignBuffer.visibility = GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; + this.assignTableBuffer = new ComputeGPUBuffer(numClusters * 4); // it has start and count + this.assignTableBuffer.visibility = GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; + this._clusterLightingCompute.setStorageBuffer(`models`, GlobalBindGroup.modelMatrixBindGroup.matrixBufferDst); + this._clusterLightingCompute.setUniformBuffer(`clustersUniform`, this.clustersUniformBuffer); + this._clusterLightingCompute.setStorageBuffer(`clusterBuffer`, this.clusterBuffer); + this._clusterLightingCompute.setStorageBuffer(`lightBuffer`, lightBuffer.storageGPUBuffer); + this._clusterLightingCompute.setStorageBuffer(`lightAssignBuffer`, this.lightAssignBuffer); + this._clusterLightingCompute.setStorageBuffer(`assignTable`, this.assignTableBuffer); + + this.debug(view); + } + + render(view: View3D, occlusionSystem: OcclusionSystem) { + let camera = view.camera; + let scene = view.scene; + let near = camera.near; + let far = camera.far; + + let lights: LightBase[] = EntityCollect.instance.getLights(scene); + let size = webGPUContext.presentationSize; + // this.clustersUniformBuffer.setFloat('screenWidth', size[0] ); + // this.clustersUniformBuffer.setFloat('screenHeight', size[1] ); + this.clustersUniformBuffer.setFloat('numLights', lights.length); + + this.clustersUniformBuffer.apply(); + + this._clusterGenerateCompute.workerSizeX = this.clusterTileZ; + this._clusterLightingCompute.workerSizeX = this.clusterTileZ; + + let command = GPUContext.beginCommandEncoder(); + // if(!this._createGrid){ + // this._createGrid = true ; + GPUContext.computeCommand(command, [this._clusterGenerateCompute, this._clusterLightingCompute]); + // }else{ + // GPUContext.compute_command(command,[this.clusterLightingCompute]); + // } + GPUContext.endCommandEncoder(command); + } + + private _createGrid: boolean = false; + + private debug(view: View3D) { + } +} From 199609f393ebf6d8275910235c1ce88458f14963 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Mon, 24 Apr 2023 18:26:07 +0800 Subject: [PATCH 053/100] feat(shadow ): add shadow renderer (#65) add direction shadow map renderer add point shadow map renderer --- .../shadow/PointLightShadowRenderer.ts | 228 +++++++++++++++++ .../shadow/ShadowMapPassRenderer.ts | 232 ++++++++++++++++++ 2 files changed, 460 insertions(+) create mode 100644 src/engine/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts create mode 100644 src/engine/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts diff --git a/src/engine/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts b/src/engine/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts new file mode 100644 index 00000000..5b2a9fd7 --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts @@ -0,0 +1,228 @@ +import { CameraUtil, PointShadowCubeCamera, RendererPassState, RenderNode, RenderShader, RTDescriptor as RTDescriptor, Vector3, WebGPUDescriptorCreator, DepthCubeArrayTexture, Time, View3D } from '../../../../..'; +import { LightBase } from '../../../../components/lights/LightBase'; +import { LightType } from '../../../../components/lights/LightData'; +import { ShadowLightsCollect } from '../../collect/ShadowLightsCollect'; +import { Camera3D } from '../../../../core/Camera3D'; +import { CubeCamera } from '../../../../core/CubeCamera'; +import { Scene3D } from '../../../../core/Scene3D'; +import { Engine3D } from '../../../../Engine3D'; +import { VirtualTexture } from '../../../../textures/VirtualTexture'; +import { GPUTextureFormat } from '../../../graphics/webGpu/WebGPUConst'; +import { CollectInfo } from '../../collect/CollectInfo'; +import { EntityCollect } from '../../collect/EntityCollect'; +import { GPUContext } from '../../GPUContext'; +import { RTFrame } from '../../frame/RTFrame'; +import { OcclusionSystem } from '../../occlusion/OcclusionSystem'; +import { RendererBase } from '../RendererBase'; +import { RendererType } from '../state/RendererType'; + +type CubeShadowMapInfo = { + cubeCamera: CubeCamera, + depthTexture: VirtualTexture[], + rendererPassState: RendererPassState[] +} + +/** + * @internal + * @group Post + */ +export class PointLightShadowRenderer extends RendererBase { + public shadowPassCount: number; + private _forceUpdate = false; + private _shadowCameraDic: Map; + public shadowCamera: Camera3D; + public cubeTextureArray: DepthCubeArrayTexture; + public colorTexture: VirtualTexture; + public shadowSize: number = 1024; + constructor() { + super(); + this.passType = RendererType.POINT_SHADOW; + + // this.shadowSize = Engine3D.setting.shadow.pointShadowSize; + this._shadowCameraDic = new Map(); + this.cubeTextureArray = new DepthCubeArrayTexture(this.shadowSize, this.shadowSize, 8); + this.colorTexture = new VirtualTexture(this.shadowSize, this.shadowSize, GPUTextureFormat.bgra8unorm, false); + } + + + + public getShadowCamera(view: View3D, lightBase: LightBase): CubeShadowMapInfo { + let cubeShadowMapInfo: CubeShadowMapInfo; + if (this._shadowCameraDic.has(lightBase)) { + cubeShadowMapInfo = this._shadowCameraDic.get(lightBase); + } else { + let camera = new PointShadowCubeCamera(view.camera.near, view.camera.far, 90, true); + camera.label = lightBase.name; + let depths: VirtualTexture[] = []; + let rendererPassStates: RendererPassState[] = []; + for (let i = 0; i < 6; i++) { + + let depthTexture = new VirtualTexture(this.shadowSize, this.shadowSize, this.cubeTextureArray.format, false); + let rtFrame = new RTFrame([this.colorTexture], [new RTDescriptor()]); + depthTexture.name = `shadowDepthTexture_` + lightBase.name + i + "_face"; + rtFrame.depthTexture = depthTexture; + rtFrame.label = "shadowRender" + rtFrame.customSize = true; + + let rendererPassState = WebGPUDescriptorCreator.createRendererPassState(rtFrame); + rendererPassStates[i] = rendererPassState; + depths[i] = depthTexture; + + Engine3D.getRenderJob(view).postRenderer.setDebugTexture([depthTexture]); + Engine3D.getRenderJob(view).debug(); + } + cubeShadowMapInfo = { + cubeCamera: camera, + depthTexture: depths, + rendererPassState: rendererPassStates, + } + this._shadowCameraDic.set(lightBase, cubeShadowMapInfo); + } + return cubeShadowMapInfo; + } + + render(view: View3D, occlusionSystem: OcclusionSystem) { + // return ; + if (!Engine3D.setting.shadow.enable) + return; + // return ; + this.shadowPassCount = 0; + + let camera = view.camera; + let scene = view.scene; + // return ; + // if (!Engine3D.engineSetting.Shadow.needUpdate) return; + // if (!(Time.frame % Engine3D.engineSetting.Shadow.updateFrameRate == 0)) return; + // return ;// + //*********************/ + //***shadow light******/ + //*********************/ + let collectInfo = EntityCollect.instance.getRenderNodes(scene); + + + let shadowLight = ShadowLightsCollect.getPointShadowLightWhichScene(scene); + let li = 0; + let shadowLightCount = shadowLight.length; + for (let si = 0; si < shadowLightCount; si++) { + let light = shadowLight[si]; + if (light.lightData.lightType == LightType.DirectionLight) + continue; + if (light.lightData.castShadowIndex > -1 && (light.needUpdateShadow || this._forceUpdate || Time.frame < 5 || light.realTimeShadow)) { + light.needUpdateShadow = false; + + let cubeShadowMapInfo = this.getShadowCamera(view, light); + let worldPos = light.transform.worldPosition; + + cubeShadowMapInfo.cubeCamera.x = worldPos.x; + cubeShadowMapInfo.cubeCamera.y = worldPos.y; + cubeShadowMapInfo.cubeCamera.z = worldPos.z; + + cubeShadowMapInfo.cubeCamera.transform.updateWorldMatrix(true); + { + occlusionSystem.update(cubeShadowMapInfo.cubeCamera.right_camera, scene); + this.renderSceneOnce(0, cubeShadowMapInfo, view, cubeShadowMapInfo.cubeCamera.right_camera, collectInfo, occlusionSystem); + + occlusionSystem.update(cubeShadowMapInfo.cubeCamera.left_camera, scene); + this.renderSceneOnce(1, cubeShadowMapInfo, view, cubeShadowMapInfo.cubeCamera.left_camera, collectInfo, occlusionSystem); + + occlusionSystem.update(cubeShadowMapInfo.cubeCamera.up_camera, scene); + this.renderSceneOnce(2, cubeShadowMapInfo, view, cubeShadowMapInfo.cubeCamera.up_camera, collectInfo, occlusionSystem); + + occlusionSystem.update(cubeShadowMapInfo.cubeCamera.down_camera, scene); + this.renderSceneOnce(3, cubeShadowMapInfo, view, cubeShadowMapInfo.cubeCamera.down_camera, collectInfo, occlusionSystem); + + occlusionSystem.update(cubeShadowMapInfo.cubeCamera.front_camera, scene); + this.renderSceneOnce(4, cubeShadowMapInfo, view, cubeShadowMapInfo.cubeCamera.front_camera, collectInfo, occlusionSystem); + + occlusionSystem.update(cubeShadowMapInfo.cubeCamera.back_camera, scene); + this.renderSceneOnce(5, cubeShadowMapInfo, view, cubeShadowMapInfo.cubeCamera.back_camera, collectInfo, occlusionSystem); + } + let qCommand = GPUContext.beginCommandEncoder(); + for (let i = 0; i < 6; i++) { + qCommand.copyTextureToTexture( + { + texture: cubeShadowMapInfo.depthTexture[i].getGPUTexture(), + mipLevel: 0, + origin: { x: 0, y: 0, z: 0 }, + }, + { + texture: this.cubeTextureArray.getGPUTexture(), + mipLevel: 0, + origin: { x: 0, y: 0, z: light.shadowIndex * 6 + i }, + }, + { + width: this.shadowSize, + height: this.shadowSize, + depthOrArrayLayers: 1, + }, + ); + } + GPUContext.endCommandEncoder(qCommand); + // Camera3D.mainCamera.cubeShadowCameras[li] = cubeShadowMapInfo.cubeCamera; + li++; + } + } + this._forceUpdate = false; + } + + + private renderSceneOnce(face: number, cubeShadowMapInfo: CubeShadowMapInfo, view: View3D, shadowCamera: Camera3D, collectInfo: CollectInfo, occlusionSystem: OcclusionSystem) { + this.rendererPassState = cubeShadowMapInfo.rendererPassState[face]; + let command = GPUContext.beginCommandEncoder(); + let encoder = GPUContext.beginRenderPass(command, this.rendererPassState); + + encoder.setViewport(0, 0, this.shadowSize, this.shadowSize, 0.0, 1.0); + encoder.setScissorRect(0, 0, this.shadowSize, this.shadowSize); + + shadowCamera.onUpdate(); + shadowCamera.transform.updateWorldMatrix(true); + + this.drawShadowRenderNodes(view, shadowCamera, encoder, collectInfo.opaqueList, occlusionSystem); + this.drawShadowRenderNodes(view, shadowCamera, encoder, collectInfo.transparentList, occlusionSystem); + + GPUContext.endPass(encoder); + GPUContext.endCommandEncoder(command); + } + + protected drawShadowRenderNodes(view: View3D, shadowCamera: Camera3D, encoder: GPURenderPassEncoder, nodes: RenderNode[], occlusionSystem: OcclusionSystem) { + GPUContext.bindCamera(encoder, shadowCamera); + for (let i = Engine3D.setting.render.drawOpMin; i < Math.min(nodes.length, Engine3D.setting.render.drawOpMax); ++i) { + let renderNode = nodes[i]; + let matrixIndex = renderNode.transform.worldMatrix.index; + if (!renderNode.transform.enable) + continue; + if (!occlusionSystem.renderCommitTesting(shadowCamera, renderNode)) + continue; + if (!renderNode.enable) + continue; + renderNode.nodeUpdate(view, this._rendererType, this.rendererPassState); + + for (let i = 0; i < renderNode.materials.length; i++) { + const material = renderNode.materials[i]; + let passes = material.renderPasses.get(this._rendererType); + if (!passes || passes.length == 0) + continue; + + GPUContext.bindGeometryBuffer(encoder, renderNode.geometry); + let worldMatrix = renderNode.object3D.transform._worldMatrix; + for (let i = 0; i < passes.length; i++) { + const renderShader = passes[i].renderShader; + // const renderShader = RenderShader.getShader(passes[i].shaderID); + + renderShader.setUniformFloat("cameraFar", shadowCamera.far); + renderShader.setUniformVector3("lightWorldPos", shadowCamera.transform.worldPosition); + renderShader.materialDataUniformBuffer.apply(); + + GPUContext.bindPipeline(encoder, renderShader); + let subGeometries = renderNode.geometry.subGeometries; + for (let k = 0; k < subGeometries.length; k++) { + const subGeometry = subGeometries[k]; + let lodInfos = subGeometry.lodLevels; + let lodInfo = lodInfos[renderNode.lodLevel]; + GPUContext.drawIndexed(encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); + } + } + } + } + } +} diff --git a/src/engine/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts b/src/engine/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts new file mode 100644 index 00000000..655202a7 --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts @@ -0,0 +1,232 @@ +import { LightType } from '../../../../components/lights/LightData'; +import { ShadowLightsCollect } from '../../collect/ShadowLightsCollect'; +import { RenderNode } from '../../../../components/renderer/RenderNode'; +import { BoundingBox } from '../../../../core/bound/BoundingBox'; +import { Camera3D } from '../../../../core/Camera3D'; +import { Engine3D } from '../../../../Engine3D'; +import { clamp } from '../../../../math/MathUtil'; +import { Ray } from '../../../../math/Ray'; +import { Vector3 } from '../../../../math/Vector3'; +import { Depth2DTextureArray } from '../../../../textures/Depth2DTextureArray'; +import { VirtualTexture } from '../../../../textures/VirtualTexture'; +import { Time } from '../../../../util/Time'; +import { WebGPUDescriptorCreator } from '../../../graphics/webGpu/descriptor/WebGPUDescriptorCreator'; +import { GPUTextureFormat } from '../../../graphics/webGpu/WebGPUConst'; +import { EntityCollect } from '../../collect/EntityCollect'; +import { GPUContext } from '../../GPUContext'; +import { RTFrame } from '../../frame/RTFrame'; +import { OcclusionSystem } from '../../occlusion/OcclusionSystem'; +import { RendererBase } from '../RendererBase'; +import { RendererPassState } from '../state/RendererPassState'; +import { RendererType } from '../state/RendererType'; +import { View3D } from '../../../../core/View3D'; +import { DirectLight } from '../../../../components/lights/DirectLight'; +/** + * @internal + * @group Post + */ +export class ShadowMapPassRenderer extends RendererBase { + // public shadowCamera: Camera3D; + public shadowPassCount: number; + public depth2DTextureArray: Depth2DTextureArray; + public rendererPassStates: RendererPassState[]; + private _forceUpdate = false; + constructor() { + super(); + this.passType = RendererType.SHADOW; + this.setShadowMap(Engine3D.setting.shadow.shadowSize); + if (Engine3D.setting.shadow.debug) { + this.debug(); + } + } + + debug() { + } + + setShadowMap(size: number) { + this.rendererPassStates = []; + this.depth2DTextureArray = new Depth2DTextureArray(size, size); + + for (let i = 0; i < 8; i++) { + let rtFrame = new RTFrame([], []); + const tex = new VirtualTexture(size, size, GPUTextureFormat.depth32float, false); + tex.name = `shadowDepthTexture_${i}`; + rtFrame.depthTexture = tex; + rtFrame.label = "shadowRender" + rtFrame.customSize = true; + rtFrame.depthCleanValue = 1; + let rendererPassState = WebGPUDescriptorCreator.createRendererPassState(rtFrame); + this.rendererPassStates[i] = rendererPassState; + } + + } + + + render(view: View3D, occlusionSystem: OcclusionSystem) { + // return ; + if (!Engine3D.setting.shadow.enable) + return; + + let camera = view.camera; + let scene = view.scene; + + // return ; + this.shadowPassCount = 0; + + // return ; + if (!Engine3D.setting.shadow.needUpdate) + return; + if (!(Time.frame % Engine3D.setting.shadow.updateFrameRate == 0)) + return; + // return ;// + camera.transform.updateWorldMatrix(); + //*********************/ + //***shadow light******/ + //*********************/ + let shadowLight = ShadowLightsCollect.getDirectShadowLightWhichScene(scene); + let li = 0; + for (let si = 0; si < shadowLight.length; si++) { + const light = shadowLight[si] as DirectLight; + if (light.lightData.lightType != LightType.DirectionLight) + continue; + + this.rendererPassState = this.rendererPassStates[light.shadowIndex]; + if ((light.castShadow && light.needUpdateShadow || this._forceUpdate) || (light.castShadow && Engine3D.setting.shadow.autoUpdate)) { + light.needUpdateShadow = false; + let shadowFar = clamp(Engine3D.setting.shadow.shadowFar, camera.near, camera.far); + + let shadowPos = Vector3.HELP_4; + let shadowLookTarget = Vector3.HELP_5; + shadowLookTarget.copy(camera.lookTarget); + shadowPos.copy(light.direction); + shadowPos.normalize(); + let dis = Vector3.distance(camera.transform.worldPosition, shadowLookTarget); + shadowPos.scaleBy(-shadowFar); + shadowPos.add(shadowLookTarget, shadowPos); + light.shadowCamera.transform.lookAt(shadowPos, shadowLookTarget); + let w = Engine3D.setting.shadow.shadowBound; + let h = Engine3D.setting.shadow.shadowBound; + light.shadowCamera.orthoOffCenter(w / -2, w / 2, h / -2, h / 2, camera.near, camera.far); + this.renderShadow(view, light.shadowCamera, occlusionSystem); + li++; + } + + let qCommand = GPUContext.beginCommandEncoder(); + qCommand.copyTextureToTexture( + { + texture: this.rendererPassStates[light.shadowIndex].depthTexture.getGPUTexture(), + mipLevel: 0, + origin: { x: 0, y: 0, z: 0 }, + }, + { + texture: this.depth2DTextureArray.getGPUTexture(), + mipLevel: 0, + origin: { x: 0, y: 0, z: light.shadowIndex }, + }, + { + width: Engine3D.setting.shadow.shadowSize, + height: Engine3D.setting.shadow.shadowSize, + depthOrArrayLayers: 1, + }, + ); + GPUContext.endCommandEncoder(qCommand); + } + + this._forceUpdate = false; + } + + public beforeCompute() { + + } + + private renderShadow(view: View3D, shadowCamera: Camera3D, occlusionSystem: OcclusionSystem) { + let collectInfo = EntityCollect.instance.getRenderNodes(view.scene); + let command = GPUContext.beginCommandEncoder(); + let encoder = GPUContext.beginRenderPass(command, this.rendererPassState); + + shadowCamera.transform.updateWorldMatrix(); + occlusionSystem.update(shadowCamera, view.scene); + GPUContext.bindCamera(encoder, shadowCamera); + let op_bundleList = this.renderShadowBundleOp(view, shadowCamera); + let tr_bundleList = this.renderShadowBundleTr(view, shadowCamera); + + if (op_bundleList.length > 0) { + encoder.executeBundles(op_bundleList); + } + this.drawShadowRenderNodes(view, shadowCamera, encoder, collectInfo.opaqueList); + if (tr_bundleList.length > 0) { + encoder.executeBundles(tr_bundleList); + } + + this.drawShadowRenderNodes(view, shadowCamera, encoder, collectInfo.transparentList); + GPUContext.endPass(encoder); + GPUContext.endCommandEncoder(command); + } + + protected renderShadowBundleOp(view: View3D, shadowCamera: Camera3D) { + let entityBatchCollect = EntityCollect.instance.getOpRenderGroup(view.scene); + if (entityBatchCollect) { + let bundlerList = []; + entityBatchCollect.renderGroup.forEach((v) => { + if (v.bundleMap.has(this._rendererType)) { + bundlerList.push(v.bundleMap.get(this._rendererType)); + } else { + let renderBundleEncoder = GPUContext.recordBundleEncoder(this.rendererPassState.renderBundleEncoderDescriptor); + this.recordShadowRenderBundleNode(view, shadowCamera, renderBundleEncoder, v.renderNodes); + let newBundle = renderBundleEncoder.finish(); + v.bundleMap.set(this._rendererType, newBundle); + bundlerList.push(newBundle); + } + }); + return bundlerList; + } + return []; + } + + protected renderShadowBundleTr(view: View3D, shadowCamera: Camera3D) { + let entityBatchCollect = EntityCollect.instance.getTrRenderGroup(view.scene); + if (entityBatchCollect) { + let bundlerList = []; + entityBatchCollect.renderGroup.forEach((v) => { + if (v.bundleMap.has(this._rendererType)) { + bundlerList.push(v.bundleMap.get(this._rendererType)); + } else { + let renderBundleEncoder = GPUContext.recordBundleEncoder(this.rendererPassState.renderBundleEncoderDescriptor); + this.recordShadowRenderBundleNode(view, shadowCamera, renderBundleEncoder, v.renderNodes); + let newBundle = renderBundleEncoder.finish(); + v.bundleMap.set(this._rendererType, newBundle); + bundlerList.push(newBundle); + } + }); + return bundlerList; + } + return []; + } + + + protected recordShadowRenderBundleNode(view: View3D, shadowCamera: Camera3D, encoder, nodes: RenderNode[]) { + GPUContext.bindCamera(encoder, shadowCamera); + GPUContext.bindGeometryBuffer(encoder, nodes[0].geometry); + for (let i = 0; i < nodes.length; ++i) { + let renderNode = nodes[i]; + let matrixIndex = renderNode.transform.worldMatrix.index; + if (!renderNode.transform.enable) + continue; + renderNode.recordRenderPass2(view, this._rendererType, this.rendererPassState, this.clusterLightingRender, encoder); + } + } + + protected drawShadowRenderNodes(view: View3D, shadowCamera: Camera3D, encoder: GPURenderPassEncoder, nodes: RenderNode[]) { + GPUContext.bindCamera(encoder, shadowCamera); + for (let i = Engine3D.setting.render.drawOpMin; i < Math.min(nodes.length, Engine3D.setting.render.drawOpMax); ++i) { + let renderNode = nodes[i]; + // let matrixIndex = renderNode.transform.worldMatrix.index; + // if (!occlusionSystem.renderCommitTesting(camera,renderNode) ) continue; + if (!renderNode.transform.enable) + continue; + if (!renderNode.enable) + continue; + renderNode.renderPass2(view, this._rendererType, this.rendererPassState, this.clusterLightingRender, encoder); + } + } +} From c3154b65e0ea127174e116e58056a61fe1f94b40 Mon Sep 17 00:00:00 2001 From: seven1031 <99984608+seven1031@users.noreply.github.com> Date: Tue, 25 Apr 2023 18:44:51 +0800 Subject: [PATCH 054/100] feat(setting): add settings (#67) add settings --- .../setting/GlobalIlluminationSetting.ts | 122 ++++++++++++++++++ src/engine/setting/LightSetting.ts | 11 ++ src/engine/setting/MaterialSetting.ts | 5 + src/engine/setting/OcclusionQuerySetting.ts | 10 ++ src/engine/setting/PickSetting.ts | 20 +++ src/engine/setting/RenderSetting.ts | 50 +++++++ src/engine/setting/ShadowSetting.ts | 69 ++++++++++ src/engine/setting/SkySetting.ts | 28 ++++ src/engine/setting/post/BloomSetting.ts | 31 +++++ src/engine/setting/post/DepthOfViewSetting.ts | 26 ++++ src/engine/setting/post/GTAOSetting.ts | 41 ++++++ src/engine/setting/post/GlobalFogSetting.ts | 42 ++++++ src/engine/setting/post/OutlineSetting.ts | 32 +++++ src/engine/setting/post/SSRSetting.ts | 44 +++++++ src/engine/setting/post/TAASetting.ts | 32 +++++ 15 files changed, 563 insertions(+) create mode 100644 src/engine/setting/GlobalIlluminationSetting.ts create mode 100644 src/engine/setting/LightSetting.ts create mode 100644 src/engine/setting/MaterialSetting.ts create mode 100644 src/engine/setting/OcclusionQuerySetting.ts create mode 100644 src/engine/setting/PickSetting.ts create mode 100644 src/engine/setting/RenderSetting.ts create mode 100644 src/engine/setting/ShadowSetting.ts create mode 100644 src/engine/setting/SkySetting.ts create mode 100644 src/engine/setting/post/BloomSetting.ts create mode 100644 src/engine/setting/post/DepthOfViewSetting.ts create mode 100644 src/engine/setting/post/GTAOSetting.ts create mode 100644 src/engine/setting/post/GlobalFogSetting.ts create mode 100644 src/engine/setting/post/OutlineSetting.ts create mode 100644 src/engine/setting/post/SSRSetting.ts create mode 100644 src/engine/setting/post/TAASetting.ts diff --git a/src/engine/setting/GlobalIlluminationSetting.ts b/src/engine/setting/GlobalIlluminationSetting.ts new file mode 100644 index 00000000..8a08ea91 --- /dev/null +++ b/src/engine/setting/GlobalIlluminationSetting.ts @@ -0,0 +1,122 @@ +/** + * GI setting + * @group Setting + */ +export type GlobalIlluminationSetting = { + debug: boolean; + /** + * + */ + debugCamera?: boolean; + /** + * enable + */ + enable: boolean; + /** + * offset position X of volume of GI + */ + offsetX: number; + /** + * offset position Y of volume of GI + */ + offsetY: number; + /** + * offset position Z of volume of GI + */ + offsetZ: number; + /** + * Number of probes on the x-axis + */ + probeXCount: number; + /** + * Number of probes on the y-axis + */ + probeYCount: number; + /** + * Number of probes on the z-axis + */ + probeZCount: number; + /** + * The size of the data sampled by a probe on the map + */ + probeSize: number; + /** + * @internal + * The distance between probes + */ + probeSpace: number; + /** + * @internal + * The textute size of probe + */ + probeSourceTextureSize: number; + /** + * @internal + * Set the overall size of octahedral texture + */ + octRTMaxSize: number; + /** + * @internal + * Set square size of each octahedral texture + */ + octRTSideSize: number; + /** + * @internal + * Set max depth distance of probes + */ + maxDistance: number; + /** + * @internal + */ + normalBias: number; + /** + * @internal + */ + depthSharpness: number; + /** + * @internal + */ + hysteresis: number; + /** + * @internal + * Set hysteresis value (default 0.01) + */ + lerpHysteresis: number; + /** + * @internal + */ + irradianceChebyshevBias: number; + /** + * @internal + */ + rayNumber: number; + /** + * @internal + */ + irradianceDistanceBias: number; + /** + * Illumination intensity of indirect light + */ + indirectIntensity: number; + /** + * + */ + ddgiGamma: number, + /** + * The intensity of light rebound + */ + bounceIntensity: number; + /** + * @internal + * Set probe roughness + */ + probeRoughness: number; + /** + * Set whether to use real-time update GI + */ + realTimeGI: boolean; + /** + * Set whether the probe automatically render scene + */ + autoRenderProbe: boolean; +}; \ No newline at end of file diff --git a/src/engine/setting/LightSetting.ts b/src/engine/setting/LightSetting.ts new file mode 100644 index 00000000..0ef27eb5 --- /dev/null +++ b/src/engine/setting/LightSetting.ts @@ -0,0 +1,11 @@ + +/** + * Light Setting + * @group Setting + */ +export type LightSetting = { + /** + * Maximum number of lights + */ + maxLight: number; +}; \ No newline at end of file diff --git a/src/engine/setting/MaterialSetting.ts b/src/engine/setting/MaterialSetting.ts new file mode 100644 index 00000000..89256482 --- /dev/null +++ b/src/engine/setting/MaterialSetting.ts @@ -0,0 +1,5 @@ +export type MaterialSetting = { + materialChannelDebug?: boolean; + materialDebug?: boolean; + normalYFlip?: boolean; +} \ No newline at end of file diff --git a/src/engine/setting/OcclusionQuerySetting.ts b/src/engine/setting/OcclusionQuerySetting.ts new file mode 100644 index 00000000..a11854f7 --- /dev/null +++ b/src/engine/setting/OcclusionQuerySetting.ts @@ -0,0 +1,10 @@ + +/** + * Occlusion query settings + * @internal + * @group Setting + */ +export type OcclusionQuerySetting = { + enable: boolean; + debug: boolean; +}; \ No newline at end of file diff --git a/src/engine/setting/PickSetting.ts b/src/engine/setting/PickSetting.ts new file mode 100644 index 00000000..0377ae66 --- /dev/null +++ b/src/engine/setting/PickSetting.ts @@ -0,0 +1,20 @@ + + +/** + * Pick setting + * @group Setting + */ +export type PickSetting = { + /** + * enable + */ + enable: boolean; + /** + * pick mode: use pixel mode, or bound mode + */ + mode: `pixel` | `bound`; + /** + * @internal + */ + detail: `mesh` | `mesh|pos` | `mesh|normal` | `mesh|pos|normal`; +}; \ No newline at end of file diff --git a/src/engine/setting/RenderSetting.ts b/src/engine/setting/RenderSetting.ts new file mode 100644 index 00000000..a9dca3d1 --- /dev/null +++ b/src/engine/setting/RenderSetting.ts @@ -0,0 +1,50 @@ +import { BloomSetting } from "./post/BloomSetting"; +import { DepthOfViewSetting } from "./post/DepthOfViewSetting"; +import { GlobalFogSetting } from "./post/GlobalFogSetting"; +import { GTAOSetting } from "./post/GTAOSetting"; +import { OutlineSetting } from "./post/OutlineSetting"; +import { SSRSetting } from "./post/SSRSetting"; +import { TAASetting } from "./post/TAASetting"; + +export type RenderSetting = { + debug: boolean; + renderPassState: number; + renderState_left: number; + renderState_right: number; + renderState_split: number; + quadScale: number; + hdrExposure: number; + debugQuad: number; + maxPointLight: number; + maxDirectLight: number; + maxSportLight: number; + drawOpMin: number; + drawOpMax: number; + drawTrMin: number; + drawTrMax: number; + zPrePass: boolean; + gi: boolean; + /** + * post effect + */ + postProcessing: { + enable?: boolean; + bloom?: BloomSetting; + ssao?: { + debug: any; + enable: boolean; + radius: number; + bias: number; + aoPower: number; + }; + ssr?: SSRSetting; + taa?: TAASetting; + gtao?: GTAOSetting; + outline?: OutlineSetting; + globalFog?: GlobalFogSetting; + fxaa?: { + enable: boolean; + }; + depthOfView?: DepthOfViewSetting; + }; +} \ No newline at end of file diff --git a/src/engine/setting/ShadowSetting.ts b/src/engine/setting/ShadowSetting.ts new file mode 100644 index 00000000..840f69f6 --- /dev/null +++ b/src/engine/setting/ShadowSetting.ts @@ -0,0 +1,69 @@ + +/** + * Shadow setting + * @group Setting + */ +export type ShadowSetting = { + debug: any; + /** + * enable + */ + enable: boolean; + /** + * + */ + needUpdate: boolean; + /** + * update shadown automatic + */ + autoUpdate: boolean; + + /** + * frequency for shadows update + */ + updateFrameRate: number; + + /** + * Percentage-Closer Filtering(PCF)is a simple, often seen technique for removing shadow edges. + * Soft shadow, is a soft and blurred shadow that is farther away from the object when the light is shot down. + * Hard shadow, is a sharper shadow, at the exchange (connection) with the object or the place where the light hits and close to the object, + or the occluded place where the sunlight cannot reach. + */ + type: `PCF` | `HARD` | `SOFT`; + /** + * Shadow offset + */ + shadowBias: number; + /** + * Offset of point light shadow + */ + pointShadowBias: number; + /** + * Shadow quality + */ + shadowQuality: number; + /** + * shadow boundary + */ + shadowBound: number; + /** + * shadow mapping Size + */ + shadowSize: number; + /** + * Shadow softness + */ + shadowSoft: number; + /** + * Point shadow mapping size + */ + pointShadowSize: number; + /** + * Shadow near section + */ + shadowNear: number; + /** + * Shadow Far Section + */ + shadowFar: number; +}; \ No newline at end of file diff --git a/src/engine/setting/SkySetting.ts b/src/engine/setting/SkySetting.ts new file mode 100644 index 00000000..4c225212 --- /dev/null +++ b/src/engine/setting/SkySetting.ts @@ -0,0 +1,28 @@ +import { HDRTextureCube } from "../.."; + +/** + * Sky setting + * @group Setting + */ +export type SkySetting = { + /** + * sky texture type + */ + type: `HDRSKY` | `ShaderSky`; + /** + * HDRTextureCube + */ + sky: HDRTextureCube; + /** + * exposure + */ + skyExposure: number; + /** + * default far + */ + defaultFar: number; + /** + * default near + */ + defaultNear: number; +}; \ No newline at end of file diff --git a/src/engine/setting/post/BloomSetting.ts b/src/engine/setting/post/BloomSetting.ts new file mode 100644 index 00000000..c04b25f4 --- /dev/null +++ b/src/engine/setting/post/BloomSetting.ts @@ -0,0 +1,31 @@ + +/** + * Bloom + * @group Setting + */ +export type BloomSetting = { + /** + * enable + */ + enable: boolean; + /** + * Screen horizontal blur radius + */ + blurX: number; + /** + * Screen vertical blur radius + */ + blurY: number; + /** + * Strength setting + */ + intensity: number; + /** + * Brightness setting + */ + brightness: number; + /** + * use debug or not + */ + debug: boolean; +}; \ No newline at end of file diff --git a/src/engine/setting/post/DepthOfViewSetting.ts b/src/engine/setting/post/DepthOfViewSetting.ts new file mode 100644 index 00000000..1e265b8c --- /dev/null +++ b/src/engine/setting/post/DepthOfViewSetting.ts @@ -0,0 +1,26 @@ + + +/** + * dpeth of view effect + * @group Setting + */ +export type DepthOfViewSetting = { + enable: boolean; + /** + * Blur Effect Iterations + */ + iterationCount: number; + /** + * the distance of Blur effect pixel diffusion + */ + pixelOffset: number; // = 1.0; + /** + * the pixel below this distance to camera will not be blurred + */ + near: number; // = 150; + /** + * the pixel above this distance will experience maximum blurring, + * [near,far]: the pixel between near and far will be blurred with linear interpolation coefficients between [0,1] + */ + far: number; // = 300; +}; \ No newline at end of file diff --git a/src/engine/setting/post/GTAOSetting.ts b/src/engine/setting/post/GTAOSetting.ts new file mode 100644 index 00000000..a851ea5e --- /dev/null +++ b/src/engine/setting/post/GTAOSetting.ts @@ -0,0 +1,41 @@ + +/** + * Setting of GTAO + * @group Setting + */ +export type GTAOSetting = { + enable: boolean; + /** + * Set the maximum distance to search around 3D space during ao sampling + */ + maxDistance: number; + /** + * Set the maximum distance when searching for surrounding pixels during ao sampling + */ + maxPixel: number; + /** + * Set the coefficient of ao value to participate in outputting to the screen, 1: output all, 0: not output + */ + darkFactor: number; + /** + * Set the number of steps for AO sampling. A larger value will result in better quality AO effects while consuming more performance + */ + rayMarchSegment: number; + /** + * Simulate color rebound or not + */ + multiBounce: boolean; + /** + * true:Calculate the position value of GBuffer using f32 to obtain more accurate values (water and other effects may not be supported) + * false: We will use the position value of GBuffer in f16 for operations, with a wider coverage + */ + usePosFloat32: boolean; + /** + * True: will be mixed with the mainColor of GBuffer; False: will only output the colors of ao + */ + blendColor: boolean; + /** + * + */ + debug: boolean; +}; \ No newline at end of file diff --git a/src/engine/setting/post/GlobalFogSetting.ts b/src/engine/setting/post/GlobalFogSetting.ts new file mode 100644 index 00000000..d9703079 --- /dev/null +++ b/src/engine/setting/post/GlobalFogSetting.ts @@ -0,0 +1,42 @@ +import { Color } from "../../.."; + +/** + * Global fog effect setting + * @group Setting + */ +export type GlobalFogSetting = { + debug: any; + /** + * enable + */ + enable: boolean; + /** + * type of fog: + * 0: linear exponent 2:squar exponent + */ + fogType: number; + /** + * Setting the Influence of Height on Fog + */ + height: number; + /** + * If the distance between the object and the camera is set as distance, the fog concentration will be linear interpolation between start and end + */ + start: number; + /** + * If the distance between the object and the camera is set as distance, the fog concentration will be linear interpolation between start and end + */ + end: number; + /** + * When the type is exponential square fog, the fog concentration coefficient is added + */ + density: number; + /** + * The effect of setting height on fog (working together with height) + */ + ins: number; + /** + * fog color + */ + fogColor: Color; +}; \ No newline at end of file diff --git a/src/engine/setting/post/OutlineSetting.ts b/src/engine/setting/post/OutlineSetting.ts new file mode 100644 index 00000000..8222f028 --- /dev/null +++ b/src/engine/setting/post/OutlineSetting.ts @@ -0,0 +1,32 @@ +/** + * Outline Setting + * @group Setting + */ +export type OutlineSetting = { + enable: boolean; + /** + * Group settings can be set up to 8 groups: through functions opened by OutlineManager, + * Pass in different Object 3D lists and color parameters to obtain grouped stroke effects. + */ + groupCount: number; + /** + * Pixel width of stroke hard edges + */ + outlinePixel: number; + /** + * Stroke Fade Pixel Width + */ + fadeOutlinePixel: number; + /** + * Stroke strength + */ + strength: number; + /** + * Blend mode: true Use overlay mode, false Use default alpha blend + */ + useAddMode: boolean; + /** + * + */ + debug: boolean; +}; \ No newline at end of file diff --git a/src/engine/setting/post/SSRSetting.ts b/src/engine/setting/post/SSRSetting.ts new file mode 100644 index 00000000..6f09b3fd --- /dev/null +++ b/src/engine/setting/post/SSRSetting.ts @@ -0,0 +1,44 @@ + +/** + * Screen Space Reflection Setting + * @group Setting + */ +export type SSRSetting = { + debug: any; + /** + * enable + */ + enable: boolean; + /** + * pixel ratio, Smaller pixel ratios can achieve better performance, but the visual effect will decrease + */ + pixelRatio: number; + /** + * fade out when pixel is closed to edge + */ + fadeEdgeRatio: number; //fade alpha from edge + /** + * fade alpha from ray trace step count + */ + rayMarchRatio: number; + /** + * fade alpha by distance from camera to hit point (min) + */ + fadeDistanceMin: number; + /** + * fade alpha by distance from camera to hit point (max) + */ + fadeDistanceMax: number; + /** + * threshold of roughness, determine effect refrection + */ + roughnessThreshold: number; + /** + * Pow parameter of normal and reflection dot product + */ + powDotRN: number; + /** + * SSR color mixing parameter: If the position difference between the current frame and the previous frame exceeds the mixThreshold at a certain pixel position, the current frame will be quickly retained to have more. + */ + mixThreshold: number; +}; \ No newline at end of file diff --git a/src/engine/setting/post/TAASetting.ts b/src/engine/setting/post/TAASetting.ts new file mode 100644 index 00000000..725e54ff --- /dev/null +++ b/src/engine/setting/post/TAASetting.ts @@ -0,0 +1,32 @@ +/** + * TAA Setting + * @group Setting + */ +export type TAASetting = { + enable: boolean; + /** + * The number of random seed for dithering camera is 8 by default. + * Reducing the number can solve some problems with noticeable jitter, but the jagginess will become more pronounced + */ + jitterSeedCount: number; + /** + * Merge the coefficients of the historical frame and the current frame. The smaller the parameter, the smaller the proportion of the current frame + */ + blendFactor: number; + /** + * The scaling coefficient of the random offset value of the jitter camera [0,1]: The smaller the coefficient, the weaker the anti aliasing effect, and the weaker the pixel jitter + */ + temporalJitterScale: number; + /** + * Image sharpening coefficient [0.1-0.9]: The smaller the coefficient, the weaker the sharpening effect, the better the anti aliasing effect. Conversely, the stronger the sharpening, the weaker the anti aliasing effect + */ + sharpFactor: number; + /** + * Image sharpening sampling coefficient scaling coefficient: Scales the sampling offset during sharpening. + */ + sharpPreBlurFactor: number; + /** + * + */ + debug: boolean; +}; From ea1b2da723241f12c30542028ca20e35c744465e Mon Sep 17 00:00:00 2001 From: seven1031 <99984608+seven1031@users.noreply.github.com> Date: Tue, 25 Apr 2023 18:46:20 +0800 Subject: [PATCH 055/100] feat(materials): add materials (#68) feat(materials): add materials --- src/engine/materials/MaterialRegister.ts | 40 ++ src/engine/materials/PavementMaterial.ts | 67 ++++ src/engine/materials/PhysicMaterial.ts | 353 ++++++++++++++++++ src/engine/materials/PointMaterial.ts | 59 +++ src/engine/materials/SkyMaterial.ts | 63 ++++ src/engine/materials/UnLitMaterial.ts | 60 +++ .../materials/effectPass/OutLinePass.ts | 47 +++ 7 files changed, 689 insertions(+) create mode 100644 src/engine/materials/MaterialRegister.ts create mode 100644 src/engine/materials/PavementMaterial.ts create mode 100644 src/engine/materials/PhysicMaterial.ts create mode 100644 src/engine/materials/PointMaterial.ts create mode 100644 src/engine/materials/SkyMaterial.ts create mode 100644 src/engine/materials/UnLitMaterial.ts create mode 100644 src/engine/materials/effectPass/OutLinePass.ts diff --git a/src/engine/materials/MaterialRegister.ts b/src/engine/materials/MaterialRegister.ts new file mode 100644 index 00000000..858f4e11 --- /dev/null +++ b/src/engine/materials/MaterialRegister.ts @@ -0,0 +1,40 @@ +import { Ctor } from "../util/Global"; +import { MaterialBase } from "../materials/MaterialBase"; +/** + * + * @internal + * @group Material + */ +export type MaterialClassName = + 'MaterialBase' + | 'GBufferPass' + | 'GUIMaterial' + | 'ChromaKeyMaterial' + | 'LambertMaterial' + | 'PhysicMaterial' + | 'SkyMaterial' + | 'UnLitMaterial' + | 'VideoMaterial' + | 'DepthMaterialPass' + | 'CastShadowMaterialPass' + | 'SkyGBufferPass' + | 'FlameSimulatorMaterial' + | 'FlowImgSimulatorMaterial' + | 'FluidSimulatorMaterial' + | 'FluidSimulatorMaterial2' + | 'HairSimulatorMaterial' + | 'LitMaterial' + | 'BoxMaterial' + | 'SkeletonMaterial' + | 'GlassMaterial' + | 'PavementMaterial' + | 'PointMaterial' + | 'none'; + +export let materialClassToName: Map, MaterialClassName> = new Map, MaterialClassName>(); +export let materialNameToClass: Map> = new Map>(); + +export function registerMaterial(name: MaterialClassName, cls: Ctor): void { + materialClassToName.set(cls, name); + materialNameToClass.set(name, cls); +} \ No newline at end of file diff --git a/src/engine/materials/PavementMaterial.ts b/src/engine/materials/PavementMaterial.ts new file mode 100644 index 00000000..5555dfee --- /dev/null +++ b/src/engine/materials/PavementMaterial.ts @@ -0,0 +1,67 @@ +import { ShaderLib } from '../assets/shader/ShaderLib'; +import { PavementShader } from '../assets/shader/materials/PavementShader'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { Color } from '../math/Color'; +import { defaultRes } from '../textures/DefaultRes'; +import { PhysicMaterial } from './PhysicMaterial'; +import { registerMaterial } from "../materials/MaterialRegister"; +/** + * PavementMaterial + * @group Material + */ +export class PavementMaterial extends PhysicMaterial { + /** + * @constructor + */ + constructor() { + super(); + + ShaderLib.register("PavementShader", PavementShader); + + let shader = this.setShader(`PavementShader`, `PavementShader`); + shader.setShaderEntry(`VertMain`, `FragMain`) + shader.setUniformColor(`baseColor`, new Color()); + shader.setUniformColor(`emissiveColor`, new Color()); + shader.setUniformFloat(`envIntensity`, 1); + shader.setUniformFloat(`normalScale`, 1); + shader.setUniformFloat(`roughness`, 0.0); + shader.setUniformFloat(`metallic`, 0.0); + shader.setUniformFloat(`ao`, 1.0); + shader.setUniformFloat(`alphaCutoff`, 0.0); + + shader.setDefine("USE_BRDF", true); + + let shaderState = shader.shaderState; + shaderState.acceptShadow = true; + shaderState.receiveEnv = true; + shaderState.acceptGI = true; + shaderState.useLight = true; + shader.setTexture("normalMap", defaultRes.normalTexture); + shader.setTexture("emissiveMap", defaultRes.blackTexture); + + // default value + this.baseMap = defaultRes.whiteTexture; + + this.transparent = true; + } + + /** + * set environment texture, usually referring to cubemap + */ + public set envMap(texture: Texture) { + //not need env texture + } + + /** + * @internal + * set shadow map + */ + public set shadowMap(texture: Texture) { + //not need shadowMap texture + } + + debug() { + } +} + +registerMaterial('PavementMaterial', PavementMaterial); \ No newline at end of file diff --git a/src/engine/materials/PhysicMaterial.ts b/src/engine/materials/PhysicMaterial.ts new file mode 100644 index 00000000..89b7fcd5 --- /dev/null +++ b/src/engine/materials/PhysicMaterial.ts @@ -0,0 +1,353 @@ +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { Color } from '../math/Color'; +import { Vector4 } from '../math/Vector4'; +import { defaultRes } from '../textures/DefaultRes'; +import { MaterialBase } from './MaterialBase'; +import { registerMaterial } from "./MaterialRegister"; + +/** + * @internal + * @group Material + */ +export class PhysicMaterial extends MaterialBase { + + /** + * get transformUV1 + */ + public get uvTransform_1(): Vector4 { + return this.renderShader.uniforms[`transformUV1`].vector4; + } + + /** + * set transformUV1 + */ + public set uvTransform_1(value: Vector4) { + // this.renderShader.uniforms[`transformUV1`].v4 = value; + this.renderShader.setUniformVector4(`transformUV1`, value); + } + + /** + * get transformUV2 + */ + public get uvTransform_2(): Vector4 { + return this.renderShader.uniforms[`transformUV2`].vector4; + } + + /** + * set transformUV2 + */ + public set uvTransform_2(value: Vector4) { + // this.renderShader.uniforms[`transformUV2`].v4 = value; + this.renderShader.setUniformVector4(`transformUV2`, value); + } + + /** + * get reflectivity + */ + public get materialF0(): Vector4 { + return this.renderShader.uniforms[`materialF0`].vector4; + } + + /** + * set reflectivity + */ + public set materialF0(value: Vector4) { + this.renderShader.setUniformVector4(`materialF0`, value); + } + + /** + * get roughness + */ + public get roughness(): number { + return this.renderShader.uniforms[`roughness`].value; + } + + /** + * set roughness + */ + public set roughness(value: number) { + this.renderShader.setUniformFloat(`roughness`, value); + } + + /** + * get metallic + */ + public get metallic(): number { + return this.renderShader.uniforms[`metallic`].value; + } + + /** + * set metallic + */ + public set metallic(value: number) { + this.renderShader.setUniformFloat(`metallic`, value); + } + + /** + * get Ambient Occlussion, dealing with the effect of ambient light on object occlusion + */ + public get ao(): number { + return this.renderShader.uniforms[`ao`].value; + } + + /** + * set Ambient Occlussion, dealing with the effect of ambient light on object occlusion + */ + public set ao(value: number) { + this.renderShader.setUniformFloat(`ao`, value); + } + + /** + * get min metallic + */ + public get metallic_min(): number { + return this.renderShader.uniforms[`metallic_min`].value; + } + + /** + * set min metallic + */ + public set metallic_min(value: number) { + this.renderShader.setUniformFloat(`metallic_min`, value); + } + + /** + * get max metallic + */ + public get metallic_max(): number { + return this.renderShader.uniforms[`metallic_max`].value; + } + + /** + * set max metallic + */ + public set metallic_max(value: number) { + this.renderShader.setUniformFloat(`metallic_max`, value); + } + + /** + * get min roughness + */ + public get roughness_min(): number { + return this.renderShader.uniforms[`roughness_min`].value; + } + + /** + * set min roughness + */ + public set roughness_min(value: number) { + this.renderShader.setUniformFloat(`roughness_min`, value); + } + + /** + * get max roughness + */ + public get roughness_max(): number { + return this.renderShader.uniforms[`roughness_max`].value; + } + + /** + * set max roughness + */ + public set roughness_max(value: number) { + this.renderShader.setUniformFloat(`roughness_max`, value); + } + + /** + * Get the influence of Normal mapping on materials + */ + public get normalScale(): number { + return this.renderShader.uniforms[`normalScale`].value; + } + + /** + * Set the influence of Normal mapping on materials + */ + public set normalScale(value: number) { + this.renderShader.setUniformFloat(`normalScale`, value); + } + + /** + * get Mask Map + * R_chanel -> AoMap + * G_chanel -> Roughness + * B_chanel -> Metallic + * A_chanel -> C + */ + public get maskMap(): Texture { + return this.renderShader.textures[`maskMap`]; + } + + /** + * set Mask Map + * R_chanel -> AoMap + * G_chanel -> Roughness + * B_chanel -> Metallic + * A_chanel -> C + */ + public set maskMap(value: Texture) { + this.renderShader.setDefine(`USE_ARMC`, true); + this.renderShader.setTexture(`maskMap`, value); + } + + /** + * set Ambient Occlussion Map, dealing with the effect of ambient light on object occlusion + */ + public set aoMap(value: Texture) { + if (!value) return; + this.renderShader.setTexture(`aoMap`, value); + if (value != defaultRes.whiteTexture) { + this.renderShader.setDefine(`USE_AOTEX`, true); + } + } + + /** + * get Ambient Occlussion Map, dealing with the effect of ambient light on object occlusion + */ + public get aoMap(): Texture { + return this.renderShader.textures[`aoMap`]; + } + + /** + * set clearCoatRoughnessMap + */ + public set clearCoatRoughnessMap(value: Texture) { + if (!value) return; + this.renderShader.setTexture(`clearCoatRoughnessMap`, value); + this.renderShader.setDefine(`USE_CLEARCOAT_ROUGHNESS`, true); + } + + /** + * get clearCoatRoughnessMap + */ + public get clearCoatRoughnessMap(): Texture { + return this.renderShader.textures[`clearCoatRoughnessMap`]; + } + + /** + * get brdf query map + */ + public get brdfLUT(): Texture { + return this.renderShader.textures[`brdfLUT`]; + } + + /** + * set brdf query map + */ + public set brdfLUT(value: Texture) { + this.renderShader.setTexture(`brdfLUT`, value); + this.renderShader.setTexture(`brdflutMap`, value); + } + + /** + * get emissive map + */ + public get emissiveMap(): Texture { + return this.renderShader.textures[`emissiveMap`]; + } + + /** + * set emissive map + */ + public set emissiveMap(value: Texture) { + this.renderShader.setTexture(`emissiveMap`, value); + } + + /** + * set intensity of environment light or color of sampled by texture + */ + public set envIntensity(value: number) { + this.renderShader.setUniformFloat(`envIntensity`, value); + } + + /** + * get intensity of environment light or color of sampled by texture + */ + public get envIntensity() { + return this.renderShader.uniforms[`envIntensity`].value; + } + + /** + * set factor of refractive + */ + public set ior(value: number) { + this.renderShader.setUniformFloat(`ior`, value); + } + + /** + * get factor of refractive + */ + public get ior(): number { + return this.renderShader.uniforms[`ior`].value; + } + + /** + * valid USE_CLEARCOAT define in shader + */ + public useCleanCoat() { + this.renderShader.setDefine("USE_CLEARCOAT", true); + } + + /** + * Set the factor of the clearcoat + */ + public set clearcoatFactor(value: number) { + this.renderShader.setUniformFloat(`clearcoatFactor`, value); + } + + /** + * get the factor of the clearcoat + */ + public get clearcoatFactor(): number { + return this.renderShader.uniforms[`clearcoatFactor`].value; + } + + /** + * set the factor of the clearcoat Roughness + */ + public set clearcoatRoughnessFactor(value: number) { + this.renderShader.setUniformFloat(`clearcoatRoughnessFactor`, value); + } + + /** + * get the factor of the clearcoat Roughness + */ + public get clearcoatRoughnessFactor(): number { + return this.renderShader.uniforms[`clearcoatRoughnessFactor`].value; + } + + /** + * set the weight of the clearcoat + */ + public set clearcoatWeight(value: number) { + this.renderShader.setUniformFloat(`clearcoatWeight`, value); + } + + /** + * get the weight of the clearcoat + */ + public get clearcoatWeight(): number { + return this.renderShader.uniforms[`clearcoatWeight`].value; + } + + /** + * get the color of the clearcoat + */ + public set clearcoatColor(value: Color) { + this.renderShader.setUniformColor(`clearcoatColor`, value); + } + + /** + * set the color of the clearcoat + */ + public get clearcoatColor(): Color { + return this.renderShader.uniforms[`clearcoatColor`].color; + } + + + public debug() { + + } +} + +registerMaterial("PhysicMaterial", PhysicMaterial); \ No newline at end of file diff --git a/src/engine/materials/PointMaterial.ts b/src/engine/materials/PointMaterial.ts new file mode 100644 index 00000000..7ba88a07 --- /dev/null +++ b/src/engine/materials/PointMaterial.ts @@ -0,0 +1,59 @@ +import { PointShadowDebug } from '../..'; +import { ShaderLib } from '../assets/shader/ShaderLib'; +import UnLit from '../assets/shader/materials/UnLit.wgsl?raw'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { Color } from '../math/Color'; +import { Vector4 } from '../math/Vector4'; +import { defaultRes } from '../textures/DefaultRes'; +import { MaterialBase } from './MaterialBase'; +import { registerMaterial } from "./MaterialRegister"; + +/** + * PointMaterial + * @group Material + */ +export class PointMaterial extends MaterialBase { + /** + * @constructor + */ + constructor() { + super(); + ShaderLib.register("UnLitShader", UnLit); + ShaderLib.register("PointShadowDebug", PointShadowDebug); + + let shader = this.setShader(`UnLitShader`, `PointShadowDebug`); + shader.setShaderEntry(`VertMain`, `FragMain`) + + shader.setUniformVector4(`transformUV1`, new Vector4(0, 0, 1, 1)); + shader.setUniformVector4(`transformUV2`, new Vector4(0, 0, 1, 1)); + shader.setUniformColor(`baseColor`, new Color()); + shader.setUniformFloat(`alphaCutoff`, 0.5); + let shaderState = shader.shaderState; + shaderState.acceptShadow = false; + shaderState.receiveEnv = false; + shaderState.acceptGI = false; + shaderState.useLight = false; + + // default value + this.baseMap = defaultRes.whiteTexture; + } + + /** + * set environment texture, usually referring to cubemap + */ + public set envMap(texture: Texture) { + //not need env texture + } + + /** + * set shadow map + */ + public set shadowMap(texture: Texture) { + //not need shadowMap texture + } + + debug() { + } +} + +registerMaterial('PointMaterial', PointMaterial); \ No newline at end of file diff --git a/src/engine/materials/SkyMaterial.ts b/src/engine/materials/SkyMaterial.ts new file mode 100644 index 00000000..508b15ab --- /dev/null +++ b/src/engine/materials/SkyMaterial.ts @@ -0,0 +1,63 @@ +import { Engine3D } from '../Engine3D'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { GPUCompareFunction, GPUCullMode } from '../gfx/graphics/webGpu/WebGPUConst'; +import { Vector3 } from '../math/Vector3'; +import { MaterialBase } from './MaterialBase'; +import { registerMaterial } from "./MaterialRegister"; + +/** + * @internal + * @group Material + */ +export class SkyMaterial extends MaterialBase { + transparency: number; + // roughness: number; + metallic: number; + + constructor() { + super(); + + this.setShader('sky_vs_frag_wgsl', 'sky_fs_frag_wgsl'); + this.getShader().setUniformVector3(`eyesPos`, new Vector3()); + this.getShader().setUniformFloat(`exposure`, 1.0); + this.getShader().setUniformFloat(`roughness`, 0.0); + + let shaderState = this.getShader().shaderState; + shaderState.frontFace = `cw`; + shaderState.cullMode = GPUCullMode.back; + shaderState.depthWriteEnabled = false; + shaderState.depthCompare = GPUCompareFunction.less; + } + + // public get baseMap(): Texture { + // return this.renderShader.textures[0]; + // } + + // public set baseMap(value: Texture) { + // this.renderShader.setTexture( `baseMap` , value ); + // } + + public set envMap(texture: Texture) { + //not need env texture + } + + public set shadowMap(texture: Texture) { + //not need shadowMap texture + } + + public get exposure() { + return Engine3D.setting.sky.skyExposure; + } + public set exposure(value: number) { + Engine3D.setting.sky.skyExposure = value; + } + + public get roughness() { + return this.renderShader.uniforms[`roughness`].value; + } + public set roughness(value: number) { + if (`roughness` in this.renderShader.uniforms) this.renderShader.uniforms[`roughness`].value = value; + } +} + +registerMaterial('SkyMaterial', SkyMaterial); \ No newline at end of file diff --git a/src/engine/materials/UnLitMaterial.ts b/src/engine/materials/UnLitMaterial.ts new file mode 100644 index 00000000..7b99143c --- /dev/null +++ b/src/engine/materials/UnLitMaterial.ts @@ -0,0 +1,60 @@ +import { ShaderLib } from '../assets/shader/ShaderLib'; +import UnLit from '../assets/shader/materials/UnLit.wgsl?raw'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { Color } from '../math/Color'; +import { Vector4 } from '../math/Vector4'; +import { defaultRes } from '../textures/DefaultRes'; +import { MaterialBase } from './MaterialBase'; +import { registerMaterial } from "./MaterialRegister"; + +/** + * material without light + * A basic material that can be rendered solely based on color and texture information without calculating lighting + * @group Material + */ +export class UnLitMaterial extends MaterialBase { + /** + *@constructor + */ + constructor() { + super(); + ShaderLib.register("UnLitShader", UnLit); + + let shader = this.setShader(`UnLitShader`, `UnLitShader`); + shader.setShaderEntry(`VertMain`, `FragMain`) + + shader.setUniformVector4(`transformUV1`, new Vector4(0, 0, 1, 1)); + shader.setUniformVector4(`transformUV2`, new Vector4(0, 0, 1, 1)); + shader.setUniformColor(`baseColor`, new Color()); + shader.setUniformFloat(`alphaCutoff`, 0.5); + let shaderState = shader.shaderState; + shaderState.acceptShadow = false; + shaderState.receiveEnv = false; + shaderState.acceptGI = false; + shaderState.useLight = false; + + shader.setUniformColor("ccc", new Color(1.0, 0.0, 0.0, 1.0)); + + // default value + this.baseMap = defaultRes.whiteTexture; + } + + /** + * Set material environment map + */ + public set envMap(texture: Texture) { + //not need env texture + } + + /** + * Set material shadow map + */ + public set shadowMap(texture: Texture) { + //not need shadowMap texture + } + + debug() { + } +} + +registerMaterial('UnLitMaterial', UnLitMaterial); \ No newline at end of file diff --git a/src/engine/materials/effectPass/OutLinePass.ts b/src/engine/materials/effectPass/OutLinePass.ts new file mode 100644 index 00000000..1d322b74 --- /dev/null +++ b/src/engine/materials/effectPass/OutLinePass.ts @@ -0,0 +1,47 @@ +import { BlendMode, Color, ColorLitShader, defaultRes, GPUCompareFunction, ShaderLib } from "../../.."; +import { MaterialPass } from "../MaterialPass"; + +import OutlineShaderPass from "../../assets/shader/materials/OutlinePass.wgsl?raw" + +export class OutLinePass extends MaterialPass { + constructor(lineWeight: number = 10) { + super(); + + ShaderLib.register("OutlineShaderPass", OutlineShaderPass); + + let shader = this.setShader(`OutlineShaderPass`, `OutlineShaderPass`); + shader.setShaderEntry(`VertMain`, `FragMain`) + shader.setUniformColor(`baseColor`, new Color(1.0, 0.0, 0.0)); + shader.setUniformFloat(`lineWeight`, lineWeight); + + let shaderState = shader.shaderState; + shaderState.acceptShadow = false; + shaderState.receiveEnv = false; + shaderState.acceptGI = false; + shaderState.useLight = false; + shaderState.depthWriteEnabled = false; + shaderState.depthCompare = GPUCompareFunction.always; + // shaderState.blendMode = BlendMode.ADD ; + + shader.setTexture("baseMap", defaultRes.whiteTexture); + } + + private _lineWeight: number = 0; + public get lineWeight(): number { + return this._lineWeight; + } + + public set lineWeight(value: number) { + this._lineWeight = value; + this.renderShader.setUniformFloat("lineWeight", value); + } + + private _baseColor: Color; + public get baseColor(): Color { + return this._baseColor; + } + public set baseColor(value: Color) { + this._baseColor = value; + this.renderShader.setUniformColor("baseColor", value); + } +} \ No newline at end of file From ddce85f65d1513a3ddcb53ff88e92a14f0cbbe78 Mon Sep 17 00:00:00 2001 From: seven1031 <99984608+seven1031@users.noreply.github.com> Date: Tue, 25 Apr 2023 18:46:47 +0800 Subject: [PATCH 056/100] feat(shape): add shape (#69) feat(shape): add shape --- src/engine/shape/BoxGeometry.ts | 203 +++++++++++++++++++++++ src/engine/shape/CylinderGeometry.ts | 236 +++++++++++++++++++++++++++ src/engine/shape/PlaneGeometry.ts | 146 +++++++++++++++++ src/engine/shape/SphereGeometry.ts | 162 ++++++++++++++++++ src/engine/shape/TorusGeometry.ts | 122 ++++++++++++++ 5 files changed, 869 insertions(+) create mode 100644 src/engine/shape/BoxGeometry.ts create mode 100644 src/engine/shape/CylinderGeometry.ts create mode 100644 src/engine/shape/PlaneGeometry.ts create mode 100644 src/engine/shape/SphereGeometry.ts create mode 100644 src/engine/shape/TorusGeometry.ts diff --git a/src/engine/shape/BoxGeometry.ts b/src/engine/shape/BoxGeometry.ts new file mode 100644 index 00000000..c68456b2 --- /dev/null +++ b/src/engine/shape/BoxGeometry.ts @@ -0,0 +1,203 @@ +import { BoundingBox } from '../core/bound/BoundingBox'; +import { GeometryBase } from '../core/geometry/GeometryBase'; +import { VertexAttributeName } from '../core/geometry/VertexAttributeName'; +import { Vector3 } from '../math/Vector3'; + +/** + * Box geometry + * @group Geometry + */ +export class BoxGeometry extends GeometryBase { + /** + * box width + */ + public width: number; + /** + * box height + */ + public height: number; + /** + * box depth + */ + public depth: number; + /** + * + * @constructor + * @param width {number} box width, default value is 1 + * @param height {number} box height, default value is 1 + * @param depth {number} box depth, default value is 1 + */ + constructor(width: number = 1, height: number = 1, depth: number = 1) { + super(); + // this.geometrySource = new SerializeGeometrySource().setPrimitive('primitive-box'); + this.width = width; + this.height = height; + this.depth = depth; + // this.name = 'BoxGeometry'; + this.initVertex(); + } + + private initVertex() { + let halfW = this.width / 2.0; + let halfH = this.height / 2.0; + let halfD = this.depth / 2.0; + + this.bounds = new BoundingBox(Vector3.ZERO.clone(), new Vector3(this.width, this.height, this.depth)); + + let position_arr = new Float32Array([ + //up + -halfW, + halfH, + halfD, + halfW, + halfH, + halfD, + halfW, + halfH, + -halfD, + -halfW, + halfH, + -halfD, + -halfW, + halfH, + halfD, + halfW, + halfH, + -halfD, + //buttom + halfW, + -halfH, + halfD, + -halfW, + -halfH, + halfD, + -halfW, + -halfH, + -halfD, + halfW, + -halfH, + -halfD, + halfW, + -halfH, + halfD, + -halfW, + -halfH, + -halfD, + //left + -halfW, + -halfH, + halfD, + -halfW, + halfH, + halfD, + -halfW, + halfH, + -halfD, + -halfW, + -halfH, + -halfD, + -halfW, + -halfH, + halfD, + -halfW, + halfH, + -halfD, + //right + halfW, + halfH, + halfD, + halfW, + -halfH, + halfD, + halfW, + -halfH, + -halfD, + halfW, + halfH, + -halfD, + halfW, + halfH, + halfD, + halfW, + -halfH, + -halfD, + //front + halfW, + halfH, + halfD, + -halfW, + halfH, + halfD, + -halfW, + -halfH, + halfD, + -halfW, + -halfH, + halfD, + halfW, + -halfH, + halfD, + halfW, + halfH, + halfD, + //back + halfW, + -halfH, + -halfD, + -halfW, + -halfH, + -halfD, + -halfW, + halfH, + -halfD, + halfW, + halfH, + -halfD, + halfW, + -halfH, + -halfD, + -halfW, + halfH, + -halfD, + ]); + + let normal_arr = new Float32Array([ + //up + 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, + + //buttom + 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, + + //left + -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, + + //right + 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, + + //front + 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, + + //back + 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, + ]); + + let uv_arr = new Float32Array([1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0]); + + let indices_arr = [0, 2, 1, 3, 5, 4, 6, 8, 7, 9, 11, 10, 12, 14, 13, 15, 17, 16, 18, 20, 19, 21, 23, 22, 24, 26, 25, 27, 29, 28, 30, 32, 31, 33, 35, 34]; + let indicesData = new Uint16Array(indices_arr.reverse()); + + this.setIndices(indicesData); + this.setAttribute(VertexAttributeName.position, position_arr); + this.setAttribute(VertexAttributeName.normal, normal_arr); + this.setAttribute(VertexAttributeName.uv, uv_arr); + this.setAttribute(VertexAttributeName.TEXCOORD_1, uv_arr); + + this.addSubGeometry({ + indexStart: 0, + indexCount: indices_arr.length, + vertexStart: 0, + index: 0, + }); + } + +} diff --git a/src/engine/shape/CylinderGeometry.ts b/src/engine/shape/CylinderGeometry.ts new file mode 100644 index 00000000..97584dcc --- /dev/null +++ b/src/engine/shape/CylinderGeometry.ts @@ -0,0 +1,236 @@ +import { GeometryBase } from '../core/geometry/GeometryBase'; +import { VertexAttributeName } from '../core/geometry/VertexAttributeName'; +import { Vector2 } from '../math/Vector2'; +import { Vector3 } from '../math/Vector3'; +import { UUID } from '../util/Global'; + +/** + * Cylinder geometry + * @group Geometry + */ +export class CylinderGeometry extends GeometryBase { + /** + * The radius of the top of the cylinder + */ + public radiusTop: number; + /** + * The radius of the bottom of the cylinder + */ + public radiusBottom: number; + /** + * The height of the cylinder + */ + public height: number; + /** + * Number of segments around the side of the cylinder + */ + public radialSegments: number; + /** + * The number of segments along the height of the cylindrical side + */ + public heightSegments: number; + /** + * Indicate whether the bottom surface of the cone is open or capped. The default value is false, which means that the bottom surface is capped by default. + */ + public openEnded: boolean; + /** + * Starting angle of the first segment + */ + public thetaStart: number; + /** + * The center angle of the circular sector on the bottom of the cylinder, with a default value of 2 * PI, makes it a complete cylinder. + */ + public thetaLength: number; + + /** + * + * @constructor + * @param radiusTop + * @param radiusBottom + * @param height + * @param radialSegments + * @param heightSegments + * @param openEnded + * @param thetaStart + * @param thetaLength + */ + constructor(radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 8, heightSegments = 8, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2) { + super(); + this.radiusTop = radiusTop; + this.radiusBottom = radiusBottom; + this.height = height; + this.radialSegments = radialSegments; + this.heightSegments = heightSegments; + this.openEnded = openEnded; + this.thetaStart = thetaStart; + this.thetaLength = thetaLength; + this.uuid = UUID(); + this.buildGeometry(); + } + + /** + * @internal + * @param start + * @param count + * @param index + */ + private addGroup(start, count, index) { + this.addSubGeometry({ + indexStart: start, + indexCount: count, + vertexStart: start, + index: index, + }); + } + + protected buildGeometry(): void { + const that = this; + + this.radialSegments = Math.floor(this.radialSegments); + this.heightSegments = Math.floor(this.heightSegments); + + const vertices = []; + const normals = []; + const uvs = []; + const indices = []; + + let index = 0; + const indexArray = []; + const halfHeight = this.height / 2; + let groupStart = 0; + + generateTorso(); + + if (this.openEnded === false) { + if (this.radiusTop > 0) generateCap(true); + if (this.radiusBottom > 0) generateCap(false); + } + + let position_arr = new Float32Array(vertices); + let normal_arr = new Float32Array(normals); + let uv_arr = new Float32Array(uvs); + let indices_arr = new Uint16Array(indices); + + this.setAttribute(VertexAttributeName.position, position_arr); + this.setAttribute(VertexAttributeName.normal, normal_arr); + this.setAttribute(VertexAttributeName.uv, uv_arr); + this.setAttribute(VertexAttributeName.TEXCOORD_1, uv_arr); + this.setIndices(indices_arr); + + function generateTorso() { + const normal = new Vector3(); + const vertex = new Vector3(); + + let groupCount = 0; + + const slope = (that.radiusBottom - that.radiusTop) / that.height; + for (let y = 0; y <= that.heightSegments; y++) { + const indexRow = []; + + const v = y / that.heightSegments; + + const radius = v * (that.radiusBottom - that.radiusTop) + that.radiusTop; + + for (let x = 0; x <= that.radialSegments; x++) { + const u = x / that.radialSegments; + + const theta = u * that.thetaLength + that.thetaStart; + + const sinTheta = Math.sin(theta); + const cosTheta = Math.cos(theta); + + // vertex + vertex.x = radius * sinTheta; + vertex.y = -v * that.height + halfHeight; + vertex.z = radius * cosTheta; + vertices.push(vertex.x, vertex.y, vertex.z); + + // normal + normal.set(sinTheta, slope, cosTheta).normalize(); + normals.push(normal.x, normal.y, normal.z); + + // uv + uvs.push(u, 1 - v); + + indexRow.push(index++); + } + + indexArray.push(indexRow); + } + + for (let x = 0; x < that.radialSegments; x++) { + for (let y = 0; y < that.heightSegments; y++) { + const a = indexArray[y][x]; + const b = indexArray[y + 1][x]; + const c = indexArray[y + 1][x + 1]; + const d = indexArray[y][x + 1]; + + indices.push(a, b, d); + indices.push(b, c, d); + + groupCount += 6; + } + } + + that.addGroup(groupStart, groupCount, 0); + groupStart += groupCount; + } + + function generateCap(top) { + const centerIndexStart = index; + + const uv = new Vector2(); + const vertex = new Vector3(); + + let groupCount = 0; + + const radius = top === true ? that.radiusTop : that.radiusBottom; + const sign = top === true ? 1 : -1; + + for (let x = 1; x <= that.radialSegments; x++) { + vertices.push(0, halfHeight * sign, 0); + normals.push(0, sign, 0); + uvs.push(0.5, 0.5); + index++; + } + + const centerIndexEnd = index; + for (let x = 0; x <= that.radialSegments; x++) { + const u = x / that.radialSegments; + const theta = u * that.thetaLength + that.thetaStart; + + const cosTheta = Math.cos(theta); + const sinTheta = Math.sin(theta); + + vertex.x = radius * sinTheta; + vertex.y = halfHeight * sign; + vertex.z = radius * cosTheta; + vertices.push(vertex.x, vertex.y, vertex.z); + + normals.push(0, sign, 0); + + uv.x = cosTheta * 0.5 + 0.5; + uv.y = sinTheta * 0.5 * sign + 0.5; + uvs.push(uv.x, uv.y); + + index++; + } + + for (let x = 0; x < that.radialSegments; x++) { + const c = centerIndexStart + x; + const i = centerIndexEnd + x; + + if (top === true) { + indices.push(i, i + 1, c); + } else { + indices.push(i + 1, i, c); + } + + groupCount += 3; + } + that.addGroup(groupStart, groupCount, top === true ? 1 : 2); + groupStart += groupCount; + } + } + +} diff --git a/src/engine/shape/PlaneGeometry.ts b/src/engine/shape/PlaneGeometry.ts new file mode 100644 index 00000000..fc08ca29 --- /dev/null +++ b/src/engine/shape/PlaneGeometry.ts @@ -0,0 +1,146 @@ +import { BoundingBox } from "../core/bound/BoundingBox"; +import { GeometryBase } from "../core/geometry/GeometryBase"; +import { VertexAttributeName } from "../core/geometry/VertexAttributeName"; +import { Vector3 } from "../math/Vector3"; + +/** + * Plane geometry + * @group Geometry + */ +export class PlaneGeometry extends GeometryBase { + /** + * Width of the plane + */ + public width: number; + /** + * Height of the plane + */ + public height: number; + /** + * Number of width segments of a plane + */ + public segmentW: number; + /** + * Number of height segments of a plane + */ + public segmentH: number; + /** + * Define the normal vector of a plane + */ + public up: Vector3; + + /** + * + * @constructor + * @param width Width of the plane + * @param height Height of the plane + * @param segmentW Number of width segments of a plane + * @param segmentH Number of height segments of a plane + * @param up Define the normal vector of a plane + */ + constructor(width: number, height: number, segmentW: number = 1, segmentH: number = 1, up: Vector3 = Vector3.Y_AXIS) { + super(); + // this.geometrySource = new SerializeGeometrySource().setPrimitive('primitive-plane'); + this.width = width; + this.height = height; + this.segmentW = segmentW; + this.segmentH = segmentH; + this.up = up; + this.buildGeometry(this.up); + } + + private buildGeometry(axis: Vector3): void { + //3 3 3 2 2 4 + var x: number, y: number; + var numIndices: number; + var base: number; + var tw: number = this.segmentW + 1; + var numVertices: number = (this.segmentH + 1) * tw; + + this.bounds = new BoundingBox(Vector3.ZERO.clone(), new Vector3(this.width, 1.0, this.height)); + numIndices = this.segmentH * this.segmentW * 6; + + let vertexCount = (this.segmentW + 1) * (this.segmentH + 1); + let position_arr = new Float32Array(vertexCount * 3); + let normal_arr = new Float32Array(vertexCount * 3); + let uv_arr = new Float32Array(vertexCount * 2); + let indices_arr = new Uint16Array(this.segmentW * this.segmentH * 2 * 3); + + numIndices = 0; + var indexP: number = 0; + var indexN: number = 0; + var indexU: number = 0; + for (var yi: number = 0; yi <= this.segmentH; ++yi) { + for (var xi: number = 0; xi <= this.segmentW; ++xi) { + x = (xi / this.segmentW - 0.5) * this.width; + y = (yi / this.segmentH - 0.5) * this.height; + switch (axis) { + case Vector3.Y_AXIS: + position_arr[indexP++] = x; + position_arr[indexP++] = 0; + position_arr[indexP++] = y; + + normal_arr[indexN++] = 0; + normal_arr[indexN++] = 1; + normal_arr[indexN++] = 0; + break; + case Vector3.Z_AXIS: + position_arr[indexP++] = x; + position_arr[indexP++] = -y; + position_arr[indexP++] = 0; + + normal_arr[indexN++] = 0; + normal_arr[indexN++] = 0; + normal_arr[indexN++] = -1; + break; + case Vector3.X_AXIS: + position_arr[indexP++] = 0; + position_arr[indexP++] = x; + position_arr[indexP++] = y; + + normal_arr[indexN++] = 1; + normal_arr[indexN++] = 0; + normal_arr[indexN++] = 0; + break; + default: + position_arr[indexP++] = x; + position_arr[indexP++] = 0; + position_arr[indexP++] = y; + + normal_arr[indexN++] = 0; + normal_arr[indexN++] = 1; + normal_arr[indexN++] = 0; + break; + } + + uv_arr[indexU++] = xi / this.segmentW; + uv_arr[indexU++] = yi / this.segmentH; + + if (xi != this.segmentW && yi != this.segmentH) { + base = xi + yi * tw; + indices_arr[numIndices++] = (base + 1); //1 + indices_arr[numIndices++] = base; //0 + indices_arr[numIndices++] = (base + tw); //2 + + indices_arr[numIndices++] = (base + 1); //1 + indices_arr[numIndices++] = (base + tw); //2 + indices_arr[numIndices++] = (base + tw + 1); //3 + } + } + } + + this.setIndices(indices_arr); + this.setAttribute(VertexAttributeName.position, position_arr); + this.setAttribute(VertexAttributeName.normal, normal_arr); + this.setAttribute(VertexAttributeName.uv, uv_arr); + this.setAttribute(VertexAttributeName.TEXCOORD_1, uv_arr); + + this.addSubGeometry({ + indexStart: 0, + indexCount: indices_arr.length, + vertexStart: 0, + index: 0, + }); + } + +} diff --git a/src/engine/shape/SphereGeometry.ts b/src/engine/shape/SphereGeometry.ts new file mode 100644 index 00000000..036ac90b --- /dev/null +++ b/src/engine/shape/SphereGeometry.ts @@ -0,0 +1,162 @@ +import { GeometryBase } from "../core/geometry/GeometryBase"; +import { VertexAttributeName } from "../core/geometry/VertexAttributeName"; + +/** + * Sphere Geometry + * @group Geometry + */ +export class SphereGeometry extends GeometryBase { + public shape_vertices = []; + public shape_indices = []; + + /** + * radius of sphere + */ + public radius: number; + /** + * Define the number of horizontal segments + */ + public widthSegments: number; + /** + * Define the number of vertical segments + */ + public heightSegments: number; + /** + * The starting point radian of the equatorial line of a sphere + */ + public phiStart: number; + /** + * The arc length of the equatorial line of a sphere + */ + public phiLength: number; + /** + * The radian of the starting point of the sphere's meridian + */ + public thetaStart: number; + /** + * Arc length of sphere meridian + */ + public thetaLength: number; + + /** + * + * @constructor + * @param radius radius of sphere + * @param widthSegments Define the number of horizontal segments + * @param heightSegments Define the number of vertical segments + * @param phiStart The starting point radian of the equatorial line of a sphere + * @param phiLength The arc length of the equatorial line of a sphere + * @param thetaStart The radian of the starting point of the sphere's meridian + * @param thetaLength Arc length of sphere meridian + */ + constructor(radius, widthSegments, heightSegments, phiStart?, phiLength?, thetaStart?, thetaLength?) { + super(); + // this.geometrySource = new SerializeGeometrySource().setPrimitive('primitive-sphere'); + // this.v_Stride = 1 + 3 + 3 + 3 + 2 + 2 + 4; + // this.vertexFormat = VertexFormat.INDEX | VertexFormat.POSITION | VertexFormat.NORMAL | VertexFormat.TANGENT | VertexFormat.UV0 | VertexFormat.UV1 | VertexFormat.COLOR; + + this.radius = radius; + this.widthSegments = widthSegments; + this.heightSegments = heightSegments; + this.phiStart = phiStart; + this.phiLength = phiLength; + this.thetaStart = thetaStart; + this.thetaLength = thetaLength; + + this.buildGeometry(); + } + + protected buildGeometry(): void { + var i: number, + j: number, + triIndex: number = 0; + let _segmentsH = this.heightSegments; + let _segmentsW = this.widthSegments; + let _radius = this.radius; + var vertexCount: number = (_segmentsH + 1) * (_segmentsW + 1); + let position_arr = new Float32Array(vertexCount * 3); + let normal_arr = new Float32Array(vertexCount * 3); + let uv_arr = new Float32Array(vertexCount * 2); + let indice_arr = new Uint16Array(_segmentsW * _segmentsH * 2 * 3); + + let pi = 0; + let ni = 0; + let ui = 0; + for (j = 0; j <= _segmentsH; ++j) { + var horAngle: number = (Math.PI * j) / _segmentsH; + var z: number = -_radius * Math.cos(horAngle); + var ringRadius: number = _radius * Math.sin(horAngle); + + for (i = 0; i <= _segmentsW; ++i) { + var verAngle: number = (2 * Math.PI * i) / _segmentsW; + var x: number = ringRadius * Math.cos(verAngle); + var y: number = ringRadius * Math.sin(verAngle); + var normLen: number = 1 / Math.sqrt(x * x + y * y + z * z); + let index = i * _segmentsW + j; + position_arr[pi++] = x; + position_arr[pi++] = y; + position_arr[pi++] = z; + + normal_arr[ni++] = x * normLen; + normal_arr[ni++] = y * normLen; + normal_arr[ni++] = z * normLen; + + uv_arr[ui++] = i / _segmentsW; + uv_arr[ui++] = j / _segmentsH; + + if (i > 0 && j > 0) { + var a: number = (_segmentsW + 1) * j + i; + var b: number = (_segmentsW + 1) * j + i - 1; + var c: number = (_segmentsW + 1) * (j - 1) + i - 1; + var d: number = (_segmentsW + 1) * (j - 1) + i; + + if (j == _segmentsH) { + indice_arr[triIndex++] = a; + indice_arr[triIndex++] = c; + indice_arr[triIndex++] = d; + } else if (j == 1) { + indice_arr[triIndex++] = a; + indice_arr[triIndex++] = b; + indice_arr[triIndex++] = c; + } else { + indice_arr[triIndex++] = a; + indice_arr[triIndex++] = b; + indice_arr[triIndex++] = c; + indice_arr[triIndex++] = a; + indice_arr[triIndex++] = c; + indice_arr[triIndex++] = d; + } + } + } + } + + // let att_info: GeometryAttribute = {}; + // att_info[VertexAttributeName.position] = { name: VertexAttributeName.position, data: position_arr }; + // att_info[VertexAttributeName.normal] = { name: VertexAttributeName.normal, data: normal_arr }; + // att_info[VertexAttributeName.uv] = { name: VertexAttributeName.uv, data: uv_arr }; + // att_info[VertexAttributeName.TEXCOORD_1] = { name: VertexAttributeName.TEXCOORD_1, data: uv_arr }; + // this.vertexBuffer.addAttribute(VertexAttributeName.position, VertexAttributeLocation.position, VertexAttributeStride.position, position_arr); + // this.vertexBuffer.addAttribute(VertexAttributeName.normal, VertexAttributeLocation.normal, VertexAttributeStride.normal, normal_arr); + // this.vertexBuffer.addAttribute(VertexAttributeName.uv, VertexAttributeLocation.uv, VertexAttributeStride.uv, uv_arr); + // this.vertexBuffer.addAttribute(VertexAttributeName.TEXCOORD_1, VertexAttributeLocation.TEXCOORD_1, VertexAttributeStride.TEXCOORD_1, uv_arr); + // att_info[VertexAttributeName.indices] = { name: VertexAttributeName.indices, data: indice_arr }; + // this.setAttributes('default-sphereGeometry', att_info); + // this.vertexBuffer = new CompositeVertexGeometryBuffer(); + // this.indexBuffer = new IndexGeometryBuffer(indice_arr.length, indice_arr); + // GeometryUtil.composite(this, [VertexAttributeName.position, VertexAttributeName.normal, VertexAttributeName.uv, VertexAttributeName.TEXCOORD_1]); + + this.setIndices(indice_arr); + this.setAttribute(VertexAttributeName.position, position_arr); + this.setAttribute(VertexAttributeName.normal, normal_arr); + this.setAttribute(VertexAttributeName.uv, uv_arr); + this.setAttribute(VertexAttributeName.TEXCOORD_1, uv_arr); + + this.addSubGeometry({ + indexStart: 0, + indexCount: indice_arr.length, + vertexStart: 0, + index: 0, + }); + } + +} diff --git a/src/engine/shape/TorusGeometry.ts b/src/engine/shape/TorusGeometry.ts new file mode 100644 index 00000000..77965607 --- /dev/null +++ b/src/engine/shape/TorusGeometry.ts @@ -0,0 +1,122 @@ +import { BoundingBox } from "../core/bound/BoundingBox"; +import { GeometryBase } from "../core/geometry/GeometryBase"; +import { VertexAttributeName } from "../core/geometry/VertexAttributeName"; +import { Vector3 } from "../math/Vector3"; + +/** + * Torus Geometry + * @group Geometry + */ +export class TorusGeometry extends GeometryBase { + /** + * Radius of torus + */ + public radius: number; + + /** + * Pipe radius + */ + public tube: number; + + /** + * Number of torus segments. + */ + public radialSegments: number; + + /** + * Number of pipeline segments. + */ + public tubularSegments: number; + + /** + * + * @constructor + * @param radius {number} Radius of torus, default value is 0.4 + * @param tube {number} Pipe radius, default value is 0.1。 + * @param radialSegments {number}Number of torus segments, default value is 32。 + * @param tubularSegments {number} Number of pipeline segments, defualt value is 32。 + */ + constructor(radius: number = 0.4, tube: number = 0.1, radialSegments: number = 32, tubularSegments: number = 32) { + super(); + // this.geometrySource = new SerializeGeometrySource().setPrimitive('primitive-torus'); + this.radius = radius; + this.tube = tube; + this.radialSegments = radialSegments; + this.tubularSegments = tubularSegments; + // this.name = 'TorusGeometry'; + this.initVertex(); + } + + private initVertex() { + + const arc = 2.0 * Math.PI; + const radius = this.radius; + const tube = this.tube; + const radialSegments = this.radialSegments; + const tubularSegments = this.tubularSegments; + + this.bounds = new BoundingBox(Vector3.ZERO.clone(), new Vector3(radius * 2, tube * 2, radius * 2)); + + var vertexCount: number = (radialSegments + 1) * (tubularSegments + 1); + let position_arr = new Float32Array(vertexCount * 3); + let normal_arr = new Float32Array(vertexCount * 3); + let uv_arr = new Float32Array(vertexCount * 2); + let indicesData = new Uint16Array(radialSegments * tubularSegments * 2 * 3); + + let pi = 0; + let ni = 0; + let ui = 0; + let triIndex = 0; + for (let j = 0; j <= radialSegments; j++) { + for (let i = 0; i <= tubularSegments; i++) { + const u = i / tubularSegments; + const v = j / radialSegments; + + const u1 = u * arc; + const v1 = v * Math.PI * 2; + + position_arr[pi++] = (radius + tube * Math.cos(v1)) * Math.sin(u1); + position_arr[pi++] = tube * Math.sin(v1); + position_arr[pi++] = (radius + tube * Math.cos(v1)) * Math.cos(u1); + + normal_arr[ni++] = Math.sin(u1) * Math.cos(v1); + normal_arr[ni++] = Math.sin(v1); + normal_arr[ni++] = Math.cos(u1) * Math.cos(v1); + + uv_arr[ui++] = u; + uv_arr[ui++] = v; + + if ((i < tubularSegments) && (j < radialSegments)) { + const segment = tubularSegments + 1; + const a = segment * j + i; + const b = segment * (j + 1) + i; + const c = segment * (j + 1) + i + 1; + const d = segment * j + i + 1; + + indicesData[triIndex++] = a; + indicesData[triIndex++] = d; + indicesData[triIndex++] = b; + + indicesData[triIndex++] = d; + indicesData[triIndex++] = c; + indicesData[triIndex++] = b; + } + } + } + + this.setIndices(indicesData); + this.setAttribute(VertexAttributeName.position, position_arr); + this.setAttribute(VertexAttributeName.normal, normal_arr); + this.setAttribute(VertexAttributeName.uv, uv_arr); + this.setAttribute(VertexAttributeName.TEXCOORD_1, uv_arr); + + this.addSubGeometry({ + indexStart: 0, + indexCount: indicesData.length, + vertexStart: 0, + index: 0, + }); + + } + +} From e48e85ebcb6ae89e928717823a82406b7e1603ff Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Thu, 27 Apr 2023 15:45:12 +0800 Subject: [PATCH 057/100] chore: folder error (#71) change bound folder fix Matrix4*4 bug fix components auto bind check error change camera folder replace the new registration method --- src/engine/components/ComponentBase.ts | 54 +++++------ .../graphics/webGpu => }/core/Camera3D.ts | 2 - .../graphics/webGpu => }/core/CameraType.ts | 0 .../graphics/webGpu => }/core/CubeCamera.ts | 0 .../webGpu => }/core/PointShadowCubeCamera.ts | 0 src/engine/core/Scene3D.ts | 97 +++++++++++++++++++ src/engine/core/View3D.ts | 85 ++++++++++++++++ .../graphics/webGpu => }/core/ViewQuad.ts | 0 .../webGpu => }/core/bound/BoundingBox.ts | 0 .../webGpu => }/core/bound/BoundingSphere.ts | 0 .../webGpu => }/core/bound/Frustum.ts | 0 .../graphics/webGpu => }/core/bound/IBound.ts | 0 src/engine/math/Matrix4.ts | 34 ++++--- 13 files changed, 225 insertions(+), 47 deletions(-) rename src/engine/{gfx/graphics/webGpu => }/core/Camera3D.ts (99%) rename src/engine/{gfx/graphics/webGpu => }/core/CameraType.ts (100%) rename src/engine/{gfx/graphics/webGpu => }/core/CubeCamera.ts (100%) rename src/engine/{gfx/graphics/webGpu => }/core/PointShadowCubeCamera.ts (100%) create mode 100644 src/engine/core/Scene3D.ts create mode 100644 src/engine/core/View3D.ts rename src/engine/{gfx/graphics/webGpu => }/core/ViewQuad.ts (100%) rename src/engine/{gfx/graphics/webGpu => }/core/bound/BoundingBox.ts (100%) rename src/engine/{gfx/graphics/webGpu => }/core/bound/BoundingSphere.ts (100%) rename src/engine/{gfx/graphics/webGpu => }/core/bound/Frustum.ts (100%) rename src/engine/{gfx/graphics/webGpu => }/core/bound/IBound.ts (100%) diff --git a/src/engine/components/ComponentBase.ts b/src/engine/components/ComponentBase.ts index a1c96092..1dc9a660 100644 --- a/src/engine/components/ComponentBase.ts +++ b/src/engine/components/ComponentBase.ts @@ -1,10 +1,8 @@ import { View3D } from "../core/View3D"; import { Object3D } from "../core/entities/Object3D"; import { CEventDispatcher } from "../event/CEventDispatcher"; -import { ComponentType, SerializeTag } from "../util/SerializeDefine"; import { Transform } from "./Transform"; - /** * Components are used to attach functionality to object3D, it has an owner object3D. * The component can receive update events at each frame. @@ -21,16 +19,6 @@ export class ComponentBase { */ public eventDispatcher: CEventDispatcher; - /** - * @internal - */ - public componentType: ComponentType = ComponentType.none; - - /** - * @internal - */ - public serializeTag?: SerializeTag; - /** * @internal */ @@ -72,35 +60,31 @@ export class ComponentBase { } private __init(param?: any) { + this.init(param); } private __start() { - if (this.transform && this.transform.scene3D && this.__isStart == false) { + if (this.start && this.transform && this.transform.scene3D && this.__isStart == false) { this.start(); this.__isStart = true; } - if (this.transform && this.transform.scene3D) { + if (this.onEnable && this.transform && this.transform.scene3D) { this.onEnable(); } - let hasUpdate = this.onUpdate.toString().replace(/\s+/g, '').length; - if (hasUpdate > 10) { + if (this.onUpdate) { this._onUpdate(this.onUpdate.bind(this)); } - let hasLateUpdate = this.onLateUpdate.toString().replace(/\s+/g, '').length; - if (hasLateUpdate > 14) { + if (this.onLateUpdate) { this._onLateUpdate(this.onLateUpdate.bind(this)); } - let hasBeforeUpdate = this.onBeforeUpdate.toString().replace(/\s+/g, '').length; - if (hasBeforeUpdate > 16) { + if (this.onBeforeUpdate) { this._onBeforeUpdate(this.onBeforeUpdate.bind(this)); } - let hasCompute = this.onCompute.toString().replace(/\s+/g, '').length; - if (hasCompute > 11) { + if (this.onCompute) { this._onCompute(this.onCompute.bind(this)); } - let hasOnGraphic = this.onGraphic.toString().replace(/\s+/g, '').length; - if (hasOnGraphic > 11) { + if (this.onGraphic) { this._onGraphic(this.onGraphic.bind(this)); } } @@ -114,18 +98,26 @@ export class ComponentBase { this._onBeforeUpdate(null); this._onCompute(null); this._onGraphic(null); + + this.onEnable = null; + this.onDisable = null; + this.onUpdate = null; + this.onLateUpdate = null; + this.onBeforeUpdate = null; + this.onCompute = null; + this.onGraphic = null; } protected init(param?: any) { } protected start() { } protected stop() { } - protected onEnable(view?: View3D) { } - protected onDisable(view?: View3D) { } - protected onUpdate(view?: View3D) { } - protected onLateUpdate(view?: View3D) { } - protected onBeforeUpdate(view?: View3D) { } - protected onCompute(view?: View3D, command?: GPUCommandEncoder) { } - protected onGraphic(view?: View3D) { } + protected onEnable?(view?: View3D); + protected onDisable?(view?: View3D); + protected onUpdate?(view?: View3D); + protected onLateUpdate?(view?: View3D); + protected onBeforeUpdate?(view?: View3D); + protected onCompute?(view?: View3D, command?: GPUCommandEncoder); + protected onGraphic?(view?: View3D); /** * diff --git a/src/engine/gfx/graphics/webGpu/core/Camera3D.ts b/src/engine/core/Camera3D.ts similarity index 99% rename from src/engine/gfx/graphics/webGpu/core/Camera3D.ts rename to src/engine/core/Camera3D.ts index 2f060101..de5d80be 100644 --- a/src/engine/gfx/graphics/webGpu/core/Camera3D.ts +++ b/src/engine/core/Camera3D.ts @@ -11,7 +11,6 @@ import { CameraUtil } from '../util/CameraUtil'; import { Frustum } from './bound/Frustum'; import { CameraType } from './CameraType'; import { CubeCamera } from './CubeCamera'; -import { ComponentType } from "../util/SerializeDefine"; import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; /** @@ -98,7 +97,6 @@ export class Camera3D extends ComponentBase { constructor() { super(); - this.componentType = ComponentType.camera3D; } protected init() { diff --git a/src/engine/gfx/graphics/webGpu/core/CameraType.ts b/src/engine/core/CameraType.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/CameraType.ts rename to src/engine/core/CameraType.ts diff --git a/src/engine/gfx/graphics/webGpu/core/CubeCamera.ts b/src/engine/core/CubeCamera.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/CubeCamera.ts rename to src/engine/core/CubeCamera.ts diff --git a/src/engine/gfx/graphics/webGpu/core/PointShadowCubeCamera.ts b/src/engine/core/PointShadowCubeCamera.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/PointShadowCubeCamera.ts rename to src/engine/core/PointShadowCubeCamera.ts diff --git a/src/engine/core/Scene3D.ts b/src/engine/core/Scene3D.ts new file mode 100644 index 00000000..727bd29a --- /dev/null +++ b/src/engine/core/Scene3D.ts @@ -0,0 +1,97 @@ +import { Engine3D } from '../Engine3D'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { EntityCollect } from '../gfx/renderJob/collect/EntityCollect'; +import { defaultRes } from '../textures/DefaultRes'; +import { View3D } from './View3D'; +import { Object3D } from './entities/Object3D'; + + +/** + * It represents an independent 3D scene where 3D objects can be created and manipulated. + * @group Entity + */ +export class Scene3D extends Object3D { + private _envMap: Texture; + private skyObject: Object3D; + public envMapChange: boolean = true; + public view: View3D; + /** + * + * @constructor + */ + constructor() { + super(); + this.transform.scene3D = this; + this.skyObject = new Object3D(); + this.skyObject.serializeTag = "dont-serialize"; + this.addChild(this.skyObject); + this._isScene3D = true; + this.envMap ||= defaultRes.defaultSky; + } + + /** + * + * get environment texture + */ + public get envMap(): Texture { + return this._envMap; + } + + /** + * set environment texture + */ + public set envMap(value: Texture) { + if (this._envMap != value) { + this.envMapChange = true; + } + this._envMap = value; + if (EntityCollect.instance.sky) + EntityCollect.instance.sky.map = value; + } + + public showSky() { + // if (EntityCollect.instance.sky) + // EntityCollect.instance.sky.enable = true; + } + + public hideSky() { + // if (EntityCollect.instance.sky) + // EntityCollect.instance.sky.enable = false; + } + + /** + * Exposure of Sky Box. A larger value produces a sky box with stronger exposure and a brighter appearance. + * A smaller value produces a sky box with weaker exposure and a darker appearance. + */ + public get exposure() { + if (EntityCollect.instance.sky) + return EntityCollect.instance.sky.exposure; + return 0; + } + + /** + * Set the exposure of the Sky Box. + */ + public set exposure(value) { + if (EntityCollect.instance.sky) + EntityCollect.instance.sky.exposure = value; + Engine3D.setting.sky.skyExposure = value; + } + + /** + * Get the roughness of the Sky Box. + */ + public get roughness() { + if (EntityCollect.instance.sky) + return EntityCollect.instance.sky.roughness; + } + + /** + * Set the roughness of the Sky Box. + */ + public set roughness(value) { + if (EntityCollect.instance.sky) + EntityCollect.instance.sky.skyMaterial.roughness = value; + } + +} diff --git a/src/engine/core/View3D.ts b/src/engine/core/View3D.ts new file mode 100644 index 00000000..5483f9e6 --- /dev/null +++ b/src/engine/core/View3D.ts @@ -0,0 +1,85 @@ +import { Engine3D, Graphic3D, Object3D, PickUI, UICanvas } from "../.."; +import { CEventListener } from "../event/CEventListener"; +import { PickFire } from "../io/PickFire"; +import { Vector4 } from "../math/Vector4"; +import { Camera3D } from "./Camera3D"; +import { Scene3D } from "./Scene3D"; + +export class View3D extends CEventListener { + private _camera: Camera3D; + private _scene: Scene3D; + private _viewPort: Vector4; + private _enablePick: boolean = false; + public pickUI: PickUI; + public pickFire: PickFire; + public canvas: UICanvas; + + constructor(x: number = 0, y: number = 0, width: number = 0, height: number = 0) { + super(); + this._viewPort = new Vector4(x, y, width, height); + this.enablePick = true; + } + + public get enablePick(): boolean { + return this._enablePick; + } + + public set enablePick(value: boolean) { + if (this._enablePick != value) { + this.pickFire = new PickFire(this); + this.pickFire.start(); + } + this._enablePick = value; + } + + public get scene(): Scene3D { + return this._scene; + } + public set scene(value: Scene3D) { + this._scene = value; + value.view = this; + + if (value && this.canvas) + value.addChild(this.canvas.object3D); + } + public get camera(): Camera3D { + return this._camera; + } + public set camera(value: Camera3D) { + this._camera = value; + + if (this.canvas) + this.canvas.camera = this.camera; + } + public get viewPort(): Vector4 { + return this._viewPort; + } + public set viewPort(value: Vector4) { + this._viewPort = value; + } + + public enableGUI(): UICanvas { + let obj = new Object3D(); + obj.name = 'GUIManager'; + obj.serializeTag = 'dont-serialize'; + this.canvas = obj.addComponent(UICanvas); + this.canvas.camera = this.camera; + this.scene.addChild(obj); + + this.pickUI = new PickUI(); + this.pickUI.init(this); + + return this.canvas; + } + + public disableGUI() { + if (this.canvas.transform.parent) { + this.canvas.transform.parent.object3D.removeChild(this.canvas.object3D); + } + } + + public get graphic3D(): Graphic3D { + return Engine3D.getRenderJob(this).graphic3D; + } + +} \ No newline at end of file diff --git a/src/engine/gfx/graphics/webGpu/core/ViewQuad.ts b/src/engine/core/ViewQuad.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/ViewQuad.ts rename to src/engine/core/ViewQuad.ts diff --git a/src/engine/gfx/graphics/webGpu/core/bound/BoundingBox.ts b/src/engine/core/bound/BoundingBox.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/bound/BoundingBox.ts rename to src/engine/core/bound/BoundingBox.ts diff --git a/src/engine/gfx/graphics/webGpu/core/bound/BoundingSphere.ts b/src/engine/core/bound/BoundingSphere.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/bound/BoundingSphere.ts rename to src/engine/core/bound/BoundingSphere.ts diff --git a/src/engine/gfx/graphics/webGpu/core/bound/Frustum.ts b/src/engine/core/bound/Frustum.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/bound/Frustum.ts rename to src/engine/core/bound/Frustum.ts diff --git a/src/engine/gfx/graphics/webGpu/core/bound/IBound.ts b/src/engine/core/bound/IBound.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/bound/IBound.ts rename to src/engine/core/bound/IBound.ts diff --git a/src/engine/math/Matrix4.ts b/src/engine/math/Matrix4.ts index 4116fad5..c0b51837 100644 --- a/src/engine/math/Matrix4.ts +++ b/src/engine/math/Matrix4.ts @@ -398,7 +398,7 @@ export class Matrix4 { public multiply(mat4: Matrix4): void { let a = this.rawData; let b = mat4.rawData; - let r = Matrix4.helpMatrix; + let r = Matrix4.helpMatrix.rawData; r[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12]; r[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13]; @@ -763,9 +763,9 @@ export class Matrix4 { } /* normalize "left" */ invLen = 1.0 / Math.sqrt(left.dotProduct(left)); - left[0] *= invLen; - left[1] *= invLen; - left[2] *= invLen; + left.x *= invLen; + left.y *= invLen; + left.z *= invLen; left.crossProduct(fromDirection, up); @@ -2297,7 +2297,11 @@ export class Matrix4 { return this; } - private setElements(n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44) { + private setElements( + n11: number, n12: number, n13: number, n14: number, + n21: number, n22: number, n23: number, n24: number, + n31: number, n32: number, n33: number, n34: number, + n41: number, n42: number, n43: number, n44: number) { const te = this.rawData; @@ -2309,6 +2313,16 @@ export class Matrix4 { return this; } + + /** + * @internal + */ + public makeMatrix44ByQuaternion(pos: Vector3, scale: Vector3, rot: Quaternion) { + this.identity(); + Quaternion.quaternionToMatrix(rot, this); + this.appendTranslation(pos.x, pos.y, pos.z); + this.appendScale(scale.x, scale.y, scale.z); + } } /** @@ -2323,15 +2337,7 @@ export function multiplyMatrices4x4REF(lhs: Matrix4, rhs: Matrix4, res: Matrix4) } } -/** - * @internal - */ -export function makeMatrix44ByQuaternion(pos: Vector3, scale: Vector3, rot: Quaternion) { - this.identity(); - Quaternion.quaternionToMatrix(rot, this); - this.appendTranslation(pos.x, pos.y, pos.z); - this.appendScale(scale.x, scale.y, scale.z); -} + /** * @internal From dc8bc2d7784dced7a1a019d41f0c59b15c561c2c Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Thu, 27 Apr 2023 16:09:37 +0800 Subject: [PATCH 058/100] feat(events): add events (#72) add UIEvents add PointEvent3D add Object3DEvent add LoaderEvent add KeyEvent --- src/engine/event/eventConst/KeyEvent.ts | 33 +++ src/engine/event/eventConst/LoaderEvent.ts | 10 + src/engine/event/eventConst/Object3DEvent.ts | 12 ++ src/engine/event/eventConst/PointerEvent3D.ts | 192 ++++++++++++++++++ src/engine/event/eventConst/UIEvent.ts | 11 + tsconfig.json | 2 +- 6 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 src/engine/event/eventConst/KeyEvent.ts create mode 100644 src/engine/event/eventConst/LoaderEvent.ts create mode 100644 src/engine/event/eventConst/Object3DEvent.ts create mode 100644 src/engine/event/eventConst/PointerEvent3D.ts create mode 100644 src/engine/event/eventConst/UIEvent.ts diff --git a/src/engine/event/eventConst/KeyEvent.ts b/src/engine/event/eventConst/KeyEvent.ts new file mode 100644 index 00000000..f0ba2986 --- /dev/null +++ b/src/engine/event/eventConst/KeyEvent.ts @@ -0,0 +1,33 @@ +import { CEvent } from '../CEvent'; + +/** + * enum keyboard event{@link InputSystem} + * @group Events + */ +export class KeyEvent extends CEvent { + /** + * + * Constant Definition Key Press Event Identification + * Event response status: Responds every time the keyboard is pressed. + * Response event parameters: keyboard key + * @platform Web,Native + */ + public static KEY_DOWN: string = 'onKeyDown'; + + /** + * + * Constant Definition Key up Event Identification + * Event response status: Responds every time the keyboard is released. + * Response event parameters: keyboard key + * @platform Web,Native + */ + public static KEY_UP: string = 'onKeyUp'; + + /** + * + * Key code value, enumeration type see KeyCode {@link KeyCode} + * @default 0 + * @platform Web,Native + */ + public keyCode: number = 0; +} diff --git a/src/engine/event/eventConst/LoaderEvent.ts b/src/engine/event/eventConst/LoaderEvent.ts new file mode 100644 index 00000000..e6cb25be --- /dev/null +++ b/src/engine/event/eventConst/LoaderEvent.ts @@ -0,0 +1,10 @@ +import { CEvent } from '../CEvent'; +/** + * enum loader event + * @internal + * @group Events + */ +export class LoaderEvent extends CEvent { + public static LOADER_PROGRESS: string = 'loaderProgress'; + public static LOADER_COMPLETE: string = 'loaderComplete'; +} diff --git a/src/engine/event/eventConst/Object3DEvent.ts b/src/engine/event/eventConst/Object3DEvent.ts new file mode 100644 index 00000000..9b1dcaad --- /dev/null +++ b/src/engine/event/eventConst/Object3DEvent.ts @@ -0,0 +1,12 @@ +import { CEvent } from '../CEvent'; +/** + * enum Object3D event + * @internal + * @group Events + */ +export class Object3DEvent extends CEvent { + public static ADDED: string = 'added'; + public static REMOVED: string = 'removed'; + public static CHILD_ADD_EVENT: string = 'childAddEvent'; + public static CHILD_REMOVED: string = 'childRemoved'; +} diff --git a/src/engine/event/eventConst/PointerEvent3D.ts b/src/engine/event/eventConst/PointerEvent3D.ts new file mode 100644 index 00000000..ce31bdf8 --- /dev/null +++ b/src/engine/event/eventConst/PointerEvent3D.ts @@ -0,0 +1,192 @@ +import { CEvent } from '../CEvent'; + +/** + * enum event type of pointer. + * {@link InputSystem} + * @group Events + */ +export class PointerEvent3D extends CEvent { + + /** + * Triggered when the touch point enters the collision + */ + public static PICK_OVER = 'onPickOver'; + + /** + * Triggered when the touch point enters the interactive GUI + */ + public static PICK_OVER_GUI = 'onPickOverGUI'; + + /** + * Triggered when the touch point clicked the collision + */ + public static PICK_CLICK = 'onPickClick'; + + /** + * Triggered when the touch point clicked the interactive GUI + */ + public static PICK_CLICK_GUI = 'onPickClickGUI'; + + /** + * Triggered when the touch point leave the collision + */ + public static PICK_OUT = 'onPickOut'; + + /** + * Triggered when the touch point leave the interactive GUI + */ + public static PICK_OUT_GUI = 'onPickOutGUI'; + + /** + * Triggered when the touch point move on the collision + */ + public static PICK_MOVE = 'onPickMove'; + + /** + * Triggered when the touch point release from the collision + */ + public static PICK_UP = 'onPickUp'; + + /** + * Triggered when the touch point release from the interactive GUI + */ + public static PICK_UP_GUI = 'onPickUpGUI'; + + /** + * Triggered when the touch point pressed the collision + */ + public static PICK_DOWN = 'onPickDown'; + + /** + * Triggered when the touch point pressed the interactive GUI + */ + public static PICK_DOWN_GUI = 'onPickDownGUI'; + + /** + * + * Triggered when the right pointer clicked + */ + static POINTER_RIGHT_CLICK: string = 'onPointerRightClick'; + /** + * + * Triggered when the middle pointer released + */ + static POINTER_MID_UP: string = 'onPointerMidUp'; + /** + * + * Triggered when the middle pointer pressed + */ + static POINTER_MID_DOWN: string = 'onPointerMidDown'; + + /** + * Triggered when the pointer clicked + */ + static POINTER_CLICK: string = 'onPointerClick'; + + /** + * + * Triggered when the pointer moved + */ + static POINTER_MOVE: string = 'onPointerMove'; + + /** + * + * Triggered when the pointer pressed + */ + static POINTER_DOWN: string = 'onPointerDown'; + + /** + * + * Triggered when the pointer released + */ + static POINTER_UP: string = 'onPointerUp'; + + /** + * + * Triggered when the pointer move out + */ + static POINTER_OUT: string = 'onPointerOut'; + + /** + * + * Triggered when the pointer move over + */ + static POINTER_OVER: string = 'onPointerOver'; + + /** + * + * Triggered when the wheel pointer is used + */ + static POINTER_WHEEL: string = 'onPointerWheel'; + + /** + * A unique identifier for an event caused by a pointer. + */ + public pointerId: number; + + /** + * event type + */ + public pointerType: string; + + /** + * whether it's the preferred pointer in this type of pointer. + */ + public isPrimary: boolean; + + /** + * Normalize values + */ + public pressure: number; + + /** + * coord x of mouse + */ + public mouseX: number; + + /** + * coord y of mouse + */ + public mouseY: number; + + /** + * delta of coord x of mouse + */ + public movementX: number; + + /** + * delta of coord y of mouse + */ + public movementY: number; + + /** + * Returns a negative value when scrolling left, + * a positive value when scrolling right, otherwise 0. + */ + public deltaX: number; + + /** + * Returns a positive value when scrolling down, + * a negative value when scrolling up, otherwise 0. + */ + public deltaY: number; + + /** + * @internal + */ + public deltaZ: number; + + /** + * @internal + */ + public reset() { + super.reset(); + this.mouseX = 0; + this.mouseY = 0; + this.movementX = 0; + this.movementY = 0; + this.deltaX = 0; + this.deltaY = 0; + this.deltaZ = 0; + } +} diff --git a/src/engine/event/eventConst/UIEvent.ts b/src/engine/event/eventConst/UIEvent.ts new file mode 100644 index 00000000..68195914 --- /dev/null +++ b/src/engine/event/eventConst/UIEvent.ts @@ -0,0 +1,11 @@ +import { CEvent } from '../CEvent'; +/** + * enum event type of user interface + * @internal + * @group Events + */ +export class UIEvent extends CEvent { + public static SHOW: string = 'show'; + public static HIDE: string = 'hide'; + public static UPDATE: string = 'update'; +} diff --git a/tsconfig.json b/tsconfig.json index fa5c0df4..142a36cf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,7 +22,7 @@ "noUnusedParameters": true, "noImplicitReturns": true, "allowJs": true, - "strict": true + "strict": false }, "include": ["src", "test"], "exclude": ["node_modules", "dist", "public"] From c54bbf6c1e11e2530ddd0bd94a02ab54c1a23f14 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Thu, 27 Apr 2023 16:46:49 +0800 Subject: [PATCH 059/100] feat(shader): add shader add compute shader add render shader --- .../webGpu/descriptor/RTDescriptor.ts | 5 + .../descriptor/WebGPUDescriptorCreator.ts | 171 ++++ .../graphics/webGpu/shader/ComputeShader.ts | 273 ++++++ .../graphics/webGpu/shader/RenderShader.ts | 915 ++++++++++++++++++ .../gfx/graphics/webGpu/shader/ShaderBase.ts | 232 +++++ 5 files changed, 1596 insertions(+) create mode 100644 src/engine/gfx/graphics/webGpu/descriptor/RTDescriptor.ts create mode 100644 src/engine/gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/ComputeShader.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/RenderShader.ts create mode 100644 src/engine/gfx/graphics/webGpu/shader/ShaderBase.ts diff --git a/src/engine/gfx/graphics/webGpu/descriptor/RTDescriptor.ts b/src/engine/gfx/graphics/webGpu/descriptor/RTDescriptor.ts new file mode 100644 index 00000000..83d4749d --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/descriptor/RTDescriptor.ts @@ -0,0 +1,5 @@ +export class RTDescriptor { + public storeOp: string = 'store'; + public loadOp: GPULoadOp = `clear`; + public clearValue: GPUColor = [0, 0, 0, 0]; +} \ No newline at end of file diff --git a/src/engine/gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator.ts b/src/engine/gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator.ts new file mode 100644 index 00000000..21a99b80 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator.ts @@ -0,0 +1,171 @@ +import { RTFrame } from '../../../renderJob/frame/RTFrame'; +import { RTResourceConfig } from '../../../renderJob/config/RTResourceConfig'; +import { GPUTextureFormat } from '../WebGPUConst'; +import { webGPUContext } from '../Context3D'; +import { RendererPassState } from '../../../renderJob/state/RendererPassState'; +/** + * @internal + * @author sirxu + */ +export class WebGPUDescriptorCreator { + public static bindGroupDescriptorCount: number = 0; + public static bindTextureDescriptorCount: number = 0; + public static renderPassDescriptorCount: number = 0; + public static pipelineDescriptorCount: number = 0; + + public static createRendererPassState(rtFrame: RTFrame, loadOp: GPULoadOp = null) { + let rps = new RendererPassState(); + rps.label = rtFrame.label; + rps.customSize = rtFrame.customSize; + rps.rtFrame = rtFrame; + rps.zPreTexture = rtFrame.zPreTexture; + rps.depthTexture = rtFrame.depthTexture; + rps.depthViewIndex = rtFrame.depthViewIndex; + rps.isOutTarget = rtFrame.isOutTarget; + rps.depthCleanValue = rtFrame.depthCleanValue; + rps.depthLoadOp = rtFrame.depthLoadOp; + if (rtFrame && rtFrame.attachments.length > 0) { + rps.renderTargets = rtFrame.attachments; + rps.rtTextureDescripts = rtFrame.rtDescriptors; + + rps.renderPassDescriptor = WebGPUDescriptorCreator.getRenderPassDescriptor(rps); + rps.renderBundleEncoderDescriptor = WebGPUDescriptorCreator.getRenderBundleDescriptor(rps); + rps.outAttachments = []; + for (let i = 0; i < rtFrame.attachments.length; i++) { + const element = rtFrame.attachments[i]; + rps.outAttachments[i] = { + format: element.format, + }; + if (element.name.indexOf(RTResourceConfig.colorBufferTex_NAME) != -1) { + rps.outColor = i; + } + } + } else { + rps.renderPassDescriptor = WebGPUDescriptorCreator.getRenderPassDescriptor(rps, loadOp); + rps.renderBundleEncoderDescriptor = WebGPUDescriptorCreator.getRenderBundleDescriptor(rps); + // if(!rps.customSize){ + rps.outAttachments = [ + { + format: GPUTextureFormat.bgra8unorm, + }, + ]; + // } + rps.outColor = 0; + } + return rps; + } + + /** + * Get RenderPass Descriptor + * Use AttachMentTextures , Texture Format Is Key + * @param attachMentTextures + * @param useDepth + * @param cleanColor + * @returns + */ + // static getRenderPassDescriptor(attachMentTextures: VirtualTexture[], renderPassState:RenderPassState): any { + public static getRenderPassDescriptor(renderPassState: RendererPassState, loadOp: GPULoadOp = null): any { + let device = webGPUContext.device; + let presentationSize = webGPUContext.presentationSize; + let attachMentTexture = []; + + let size = []; + if (renderPassState.renderTargets && renderPassState.renderTargets.length > 0) { + size = [renderPassState.renderTargets[0].width, renderPassState.renderTargets[0].height]; + for (let i = 0; i < renderPassState.renderTargets.length; i++) { + const texture = renderPassState.renderTargets[i]; + const rtDesc = renderPassState.rtTextureDescripts[i]; + attachMentTexture.push({ + view: texture.getGPUView(), + resolveTarget: undefined, + loadOp: rtDesc.loadOp,// webGPUContext.canvasConfig && webGPUContext.canvasConfig.alpha ? `load` : `clear`, + clearValue: rtDesc.clearValue, + storeOp: rtDesc.storeOp, + }); + } + } else { + if (!renderPassState.customSize) { + let clearValue = webGPUContext.canvasConfig && webGPUContext.canvasConfig.alpha ? [1.0, 1.0, 1.0, 0.0] : [0.0, 0.0, 0.0, 1.0] + size = presentationSize; + if (renderPassState.isOutTarget == true) { + attachMentTexture.push({ + view: undefined, + resolveTarget: undefined, + loadOp: (webGPUContext.canvasConfig && webGPUContext.canvasConfig.alpha) || loadOp != null ? `load` : `clear`, + clearValue: clearValue, + storeOp: 'store', + }); + } + } + } + + let renderPassDescriptor: GPURenderPassDescriptor = null; + if (renderPassState.depthTexture || renderPassState.zPreTexture) { + //if set zPreTexture + if (renderPassState.zPreTexture) { + renderPassState.depthTexture = renderPassState.zPreTexture; + } + + renderPassDescriptor = { + label: `${renderPassState.label} renderPassDescriptor zPreTexture${renderPassState.zPreTexture ? `load` : `clear`}`, + colorAttachments: attachMentTexture, + depthStencilAttachment: { + view: renderPassState.depthTexture.getGPUView() as GPUTextureView, + depthLoadOp: renderPassState.zPreTexture ? `load` : renderPassState.depthLoadOp, + depthClearValue: renderPassState.zPreTexture ? 1 : renderPassState.depthCleanValue, + depthStoreOp: "store", + // stencilClearValue: 0, + // stencilLoadOp: 'clear', + // stencilStoreOp: 'store', + }, + }; + } else { + renderPassDescriptor = { + colorAttachments: attachMentTexture, + label: 'renderPassDescriptor not writeDepth', + }; + } + + this.renderPassDescriptorCount++; + return renderPassDescriptor; + } + + /** + * Get RenderPass Descriptor + * Use AttachMentTextures , Texture Format Is Key + * @param attachMentTextures + * @param useDepth + * @param cleanColor + * @returns + */ + public static getRenderBundleDescriptor(renderPassState: RendererPassState): GPURenderBundleEncoderDescriptor { + let presentationSize = webGPUContext.presentationSize; + let attachMentTexture = []; + let size = []; + if (renderPassState.renderTargets && renderPassState.renderTargets.length > 0) { + size = [renderPassState.renderTargets[0].width, renderPassState.renderTargets[0].height]; + for (let i = 0; i < renderPassState.renderTargets.length; i++) { + const renderTarget = renderPassState.renderTargets[i]; + attachMentTexture.push(renderTarget.format); + } + } else { + size = presentationSize; + // attachMentTexture.push(GPUTextureFormat.bgra8unorm); + // attachMentTexture.push(); + } + + let renderPassDescriptor: GPURenderBundleEncoderDescriptor = null; + if (renderPassState.depthTexture) { + renderPassDescriptor = { + colorFormats: attachMentTexture, + depthStencilFormat: renderPassState.depthTexture.format, + }; + } else { + renderPassDescriptor = { + colorFormats: attachMentTexture, + }; + } + this.renderPassDescriptorCount++; + return renderPassDescriptor; + } +} diff --git a/src/engine/gfx/graphics/webGpu/shader/ComputeShader.ts b/src/engine/gfx/graphics/webGpu/shader/ComputeShader.ts new file mode 100644 index 00000000..9bea1446 --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/ComputeShader.ts @@ -0,0 +1,273 @@ +import { Texture } from '../core/texture/Texture'; +import { webGPUContext } from '../Context3D'; +import { ShaderBase } from './ShaderBase'; +import { ShaderReflection, ShaderReflectionVarInfo } from './value/ShaderReflectionInfo'; +import { Preprocessor } from './util/Preprocessor'; + +/** + * @internal + * @author sirxu + * compute shader kernel + */ +export class ComputeShader extends ShaderBase { + /** + * Compute shader entry point name + */ + public entryPoint: string = `CsMain`; + + /** + * Compute shader x worker number + */ + public workerSizeX: number = 1; + + /** + * Compute shader y worker number + */ + public workerSizeY: number = 0; + + /** + * Compute shader z worker number + */ + public workerSizeZ: number = 0; + + protected _computePipeline: GPUComputePipeline; + protected _csShaderModule: GPUShaderModule; + protected _destCS: string; + protected _sourceCS: string; + private _storageTextureDic: Map; + private _sampleTextureDic: Map; + private _groupsShaderReflectionVarInfos: ShaderReflectionVarInfo[][]; + + /** + * + * @param computeShader wgsl compute shader + */ + constructor(computeShader: string) { + super(); + this._sourceCS = computeShader; + ShaderReflection.getShaderReflection2(computeShader, this); + this._storageTextureDic = new Map(); + this._sampleTextureDic = new Map(); + } + + /** + * set write or read storage texture , use textureLod + * @param name + * @param texture + */ + public setStorageTexture(name: string, texture: Texture) { + if (!this._storageTextureDic.has(name)) { + this._storageTextureDic.set(name, texture); + } + } + + /** + * set samplerTexture , use textureSample or other sample texture api + * @param name + * @param texture + */ + public setSamplerTexture(name: string, texture: Texture) { + // if (!this.sampleTextureDic.has(name)) { + this._sampleTextureDic.set(name, texture); + // this.useSampler.set(name, useSampler); + // } + } + + /** + * Record the compute shader distribution command + * @param computePass Compute pass encoder + */ + public compute(computePass: GPUComputePassEncoder) { + if (!this._computePipeline) { + this.genComputePipeline(); + } + + computePass.setPipeline(this._computePipeline); + for (let i = 0; i < this.bindGroups.length; ++i) { + computePass.setBindGroup(i, this.bindGroups[i]); + } + + if (this.workerSizeX && this.workerSizeY && this.workerSizeZ) { + computePass.dispatchWorkgroups(this.workerSizeX, this.workerSizeY, this.workerSizeZ); + } else if (this.workerSizeX && this.workerSizeY) { + computePass.dispatchWorkgroups(this.workerSizeX, this.workerSizeY); + } else { + computePass.dispatchWorkgroups(this.workerSizeX); + } + } + + public readHeap() { + } + + protected genGroups(groupIndex: number, infos: ShaderReflectionVarInfo[][], force: boolean = false) { + if (!this.bindGroups[groupIndex] || force) { + const shaderRefs: ShaderReflectionVarInfo[] = infos[groupIndex]; + + let entries: GPUBindGroupEntry[] = []; + for (let j = 0; j < shaderRefs.length; ++j) { + const refs = shaderRefs[j]; + if (!refs) continue; + + switch (refs.varType) { + case `uniform`: + { + let buffer = this._bufferDic.get(refs.varName); + if (buffer) { + let entry: GPUBindGroupEntry = { + binding: refs.binding, + resource: { + buffer: buffer.buffer, + offset: 0, //buffer.memory.shareFloat32Array.byteOffset, + size: buffer.memory.shareDataBuffer.byteLength, + }, + } + entries.push(entry); + } else { + console.error(`ComputeShader(${this.instanceID})`, `buffer ${refs.varName} is missing!`); + } + } + break; + case `storage-read`: + case `storage-read_write`: + { + let buffer = this._bufferDic.get(refs.varName); + if (buffer) { + let entry: GPUBindGroupEntry = { + binding: refs.binding, + resource: { + buffer: buffer.buffer, + offset: 0,//buffer.memory.shareFloat32Array.byteOffset, + size: buffer.memory.shareDataBuffer.byteLength, + }, + } + entries.push(entry); + } else { + console.error(`ComputeShader(${this.instanceID})`, `buffer ${refs.varName} is missing!`); + } + } + break; + case `var`: + { + if (refs.dataType == `sampler`) { + let textureName = refs.varName.replace(`Sampler`, ``); + let texture = this._sampleTextureDic.get(textureName); + if (texture) { + let entry: GPUBindGroupEntry = { + binding: refs.binding, + resource: texture.gpuSampler, + } + entries.push(entry); + } else { + console.error(`ComputeShader(${this.instanceID})`, `texture ${refs.varName} is missing! `); + } + } else if (refs.dataType == `sampler_comparison`) { + let textureName = refs.varName.replace(`Sampler`, ``); + let texture = this._sampleTextureDic.get(textureName); + if (texture) { + let entry: GPUBindGroupEntry = { + binding: refs.binding, + resource: texture.gpuSampler_comparison, + } + entries.push(entry); + } else { + console.error(`ComputeShader(${this.instanceID})`, `texture ${refs.varName} is missing! `); + } + } else if (refs.dataType.indexOf('texture_storage') != -1) { + let texture = this._storageTextureDic.get(refs.varName); + if (texture) { + let entry: GPUBindGroupEntry = { + binding: refs.binding, + resource: texture.getGPUView(), + } + entries.push(entry); + } else { + console.error(`ComputeShader(${this.instanceID})`, `texture ${refs.varName} is missing! `); + } + } else if (refs.dataType.indexOf('texture') != -1) { + let texture = this._sampleTextureDic.get(refs.varName); + if (texture) { + let entry: GPUBindGroupEntry = { + binding: refs.binding, + resource: texture.getGPUView(), + } + entries.push(entry); + } else { + console.error(`ComputeShader(${this.instanceID})`, `texture ${refs.varName} is missing! `); + } + } + } + break; + default: + console.error(`unprocessed type:`, refs.varType); + break; + } + } + + let gpubindGroup = webGPUContext.device.createBindGroup({ + layout: this._computePipeline.getBindGroupLayout(groupIndex), + entries: entries + }); + this.bindGroups[groupIndex] = gpubindGroup; + } + } + + protected genComputePipeline() { + this.preCompileShader(this._sourceCS); + this.genReflection(); + + this._computePipeline = webGPUContext.device.createComputePipeline({ + layout: `auto`, + compute: { + module: this.compileShader(), + entryPoint: this.entryPoint, + }, + }); + + this._groupsShaderReflectionVarInfos = []; + let shaderReflection = this.shaderReflection; + + this.bindGroups = []; + for (let i = 0; i < shaderReflection.groups.length; ++i) { + let srvs = shaderReflection.groups[i]; + this._groupsShaderReflectionVarInfos[i] = srvs; + this.genGroups(i, this._groupsShaderReflectionVarInfos); + } + } + + protected preCompileShader(shader: string) { + for (const key in this.constValues) { + if (Object.prototype.hasOwnProperty.call(this.constValues, key)) { + const value = this.constValues[key]; + shader = shader.replaceAll(`&${key}`, value.toString()); + } + } + this._destCS = Preprocessor.parseComputeShader(shader, this.defineValue); + } + + protected compileShader(): GPUShaderModule { + let shaderModule = webGPUContext.device.createShaderModule({ + label: `ComputeShader(${this.instanceID})`, + code: this._destCS, + }); + + shaderModule.getCompilationInfo().then((e) => { + if (e.messages.length > 0) { + console.log(this._destCS); + } + }); + + this._csShaderModule = shaderModule; + return shaderModule; + } + + private genReflection() { + this.shaderVariant += ShaderReflection.genComputeShaderVariant(this); + let reflection = ShaderReflection.poolGetReflection(this.shaderVariant); + if (!reflection) { + ShaderReflection.getShaderReflection2(this._destCS, this); + ShaderReflection.combineShaderReflectionVarInfo(this.shaderReflection, this.shaderReflection.cs_variables); + } else { + this.shaderReflection = reflection; + } + } +} diff --git a/src/engine/gfx/graphics/webGpu/shader/RenderShader.ts b/src/engine/gfx/graphics/webGpu/shader/RenderShader.ts new file mode 100644 index 00000000..fabaa1fd --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/RenderShader.ts @@ -0,0 +1,915 @@ +import { ShaderLib } from "../../../../assets/shader/ShaderLib"; +import { IESProfiles } from "../../../../components/lights/IESProfiles"; +import { GeometryBase } from "../../../../core/geometry/GeometryBase"; +import { VertexAttributeName } from "../../../../core/geometry/VertexAttributeName"; +import { Engine3D } from "../../../../Engine3D"; +import { BlendFactor, BlendMode } from "../../../../materials/BlendMode"; +import { MaterialBase } from "../../../../materials/MaterialBase"; +import { MaterialPass } from "../../../../materials/MaterialPass"; +import { Color } from "../../../../math/Color"; +import { Vector4 } from "../../../../math/Vector4"; +import { defaultRes } from "../../../../textures/DefaultRes"; +import { GPUContext } from "../../../renderJob/GPUContext"; +import { GlobalBindGroupLayout } from "../core/bindGroups/GlobalBindGroupLayout"; +import { GPUBufferBase } from "../core/buffer/GPUBufferBase"; +import { MaterialDataUniformGPUBuffer } from "../core/buffer/MaterialDataUniformGPUBuffer"; +import { Texture } from "../core/texture/Texture"; +import { UniformNode } from "../core/uniforms/UniformNode"; +import { webGPUContext } from "../Context3D"; +import { ShaderConverter } from "./converter/ShaderConverter"; +import { ShaderBase } from "./ShaderBase"; +import { ShaderStage } from "./ShaderStage"; +import { Preprocessor } from "./util/Preprocessor"; +import { ShaderReflection, ShaderReflectionVarInfo } from "./value/ShaderReflectionInfo"; +import { ShaderState } from "./value/ShaderState"; +import { RendererPassState } from "../../../renderJob/state/RendererPassState"; +import { RendererType } from "../../../renderJob/state/RendererType"; + +export class RenderShader extends ShaderBase { + public useRz: boolean = false; + + /** + * Vertex shader name + */ + public vsName: string; + + /** + * Fragment shader name + */ + public fsName: string; + + /** + * State of the shader + */ + public shaderState: ShaderState; + + /** + * The collection of textures used in shading + */ + public textures: { [name: string]: Texture }; + + /** + * Render pipeline + */ + public pipeline: GPURenderPipeline; + + /** + * BindGroup layout + */ + public bindGroupLayouts: GPUBindGroupLayout[]; + + /** + * Uniform data for materials + */ + public materialDataUniformBuffer: MaterialDataUniformGPUBuffer; + + protected _sourceVS: string; + protected _sourceFS: string; + protected _destVS: string; + protected _destFS: string; + protected _vsShaderModule: GPUShaderModule; + protected _fsShaderModule: GPUShaderModule; + protected _textureGroup: number = -1; + protected _textureChange: boolean = false; + + private static _renderShaderModulePool: Map = new Map(); + private static _renderShader: Map = new Map(); + private _vs_limit = []; + private _fs_limit = []; + private _cs_limit = []; + private _groupsShaderReflectionVarInfos: ShaderReflectionVarInfo[][]; + private _passShaderCache: Map = new Map(); + + constructor(vs: string, fs: string) { + super(); + + this.vsName = vs.toLowerCase(); + this.fsName = fs.toLowerCase(); + + if (!(this.vsName in ShaderLib)) { + console.error(`Shader Not Register, Please Register Shader!`, this.vsName); + } + + if (!(this.fsName in ShaderLib)) { + console.error(`Shader Not Register, Please Register Shader!`, this.fsName); + } + + if (ShaderLib[this.vsName]) { + this._sourceVS = ShaderLib[this.vsName]; + } + + if (ShaderLib[this.fsName]) { + this._sourceFS = ShaderLib[this.fsName]; + } + + this.textures = {}; + this.bindGroups = []; + this.shaderState = new ShaderState(); + + this.materialDataUniformBuffer = new MaterialDataUniformGPUBuffer(); + this.materialDataUniformBuffer.visibility = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT; + this._bufferDic.set(`global`, this.materialDataUniformBuffer); + this._bufferDic.set(`materialUniform`, this.materialDataUniformBuffer); + } + + /** + * Cull mode + */ + public get cullMode(): GPUCullMode { + return this.shaderState.cullMode; + } + + public set cullMode(value: GPUCullMode) { + if (this.shaderState.cullMode != value) { + this._stateChange = true; + } + this.shaderState.cullMode = value; + } + + /** + * Front face + */ + public get frontFace(): GPUFrontFace { + return this.shaderState.frontFace; + } + + public set frontFace(value: GPUFrontFace) { + if (this.shaderState.frontFace != value) { + this._stateChange = true; + } + this.shaderState.frontFace = value; + } + + /** + * Depth bias + */ + public get depthBias(): number { + return this.shaderState.depthBias; + } + + public set depthBias(value: number) { + if (this.shaderState.depthBias != value) { + this._stateChange = true; + } + this.shaderState.depthBias = value; + } + + /** + * Primitive topology + */ + public get topology(): GPUPrimitiveTopology { + return this.shaderState.topology; + } + + public set topology(value: GPUPrimitiveTopology) { + if (this.shaderState.topology != value) { + this._stateChange = true; + } + this.shaderState.topology = value; + } + + /** + * Blend mode + */ + public get blendMode(): BlendMode { + return this.shaderState.blendMode; + } + + public set blendMode(value: BlendMode) { + if (this.shaderState.blendMode != value) { + this._stateChange = true; + } + this.shaderState.blendMode = value; + } + + /** + * Depth compare function + */ + public get depthCompare(): GPUCompareFunction { + return this.shaderState.depthCompare; + } + + public set depthCompare(value: GPUCompareFunction) { + if (this.shaderState.depthCompare != value) { + this._stateChange = true; + } + this.shaderState.depthCompare = value; + } + + /** + * Create a RenderShader with vertex shaders and fragment shaders + * @param vs Vertex shader name + * @param fs Fragment shader name + * @returns Returns the instance ID of the RenderShader + */ + public static createShader(vs: string, fs: string): string { + let shader = new RenderShader(vs, fs); + RenderShader._renderShader.set(shader.instanceID, shader); + return shader.instanceID; + } + + /** + * Destroy a RenderShader object + * @param instanceID instance ID of the RenderShader + */ + public static destroyShader(instanceID: string) { + if (RenderShader._renderShader.has(instanceID)) { + let shader = RenderShader._renderShader.get(instanceID); + shader.destroy(); + RenderShader._renderShader.delete(instanceID) + } + } + + /** + * Get the RenderShader object by specifying the RenderShader instance ID + * @param instanceID instance ID of the RenderShader + * @returns RenderShader object + */ + public static getShader(instanceID: string) { + return RenderShader._renderShader.get(instanceID); + } + + /** + * Set the material shader for the specified render type + * @param rendererType + * @param materialPass + */ + public setPassShader(rendererType: RendererType, materialPass: MaterialBase) { + this._passShaderCache.set(rendererType, materialPass); + } + + /** + * Get the material shader for the specified render type + * @param rendererType + * @returns + */ + public getPassShader(rendererType: RendererType): MaterialBase { + return this._passShaderCache.get(rendererType); + } + + + /** + * Sets the entry point names for the RenderShader vertex phase and fragment phase + * @param vsEntryPoint + * @param fsEntryPoint + */ + public setShaderEntry(vsEntryPoint: string = '', fsEntryPoint: string = '') { + this.vsEntryPoint = vsEntryPoint; + this.fsEntryPoint = fsEntryPoint; + } + + /** + * Set the texture used in the Render Shader code + * @param name Name in the shader code + * @param texture Texture object + */ + public setTexture(name: string, texture: Texture) { + if (texture && this.textures[name] != texture) { + if (this.textures[name]) { + this.textures[name].unBindStateChange(this); + } + this._textureChange = true; + this.textures[name] = texture; + texture.bindStateChange(() => { + this._textureChange = true; + }, this); + } + } + + /** + * Get the texture used in the Render Shader code + * @param name Name in the shader code + * @returns Texture object + */ + public getTexture(name: string) { + return this.textures[name]; + } + + /** + * Create a rendering pipeline + * @param geometry + * @param renderPassState + */ + public genRenderPipeline(geometry: GeometryBase, renderPassState: RendererPassState) { + let layouts = this.createGroupLayouts(); + this.createPipeline(geometry, renderPassState, layouts); + } + + /** + * Recompile the shader and create the rendering pipeline + * @param geometry + * @param rendererPassState + */ + public reBuild(geometry: GeometryBase, rendererPassState: RendererPassState) { + this.compileShader(ShaderStage.vertex, this._destVS, rendererPassState); + this.compileShader(ShaderStage.fragment, this._destFS, rendererPassState); + this.genRenderPipeline(geometry, rendererPassState); + // this.apply(geometry,rendererPassState); + } + + /** + * Apply render shader state value + * @param geometry + * @param materialPass + * @param rendererPassState + * @param noticeFun + */ + public apply(geometry: GeometryBase, materialPass: MaterialPass, rendererPassState: RendererPassState, noticeFun?: Function) { + this.materialDataUniformBuffer.apply(); + + if (this._textureChange && this._textureGroup != -1) { + this._textureChange = false; + this.genGroups(this._textureGroup, this.shaderReflection.groups, true); + } + + if (this._stateChange) { + if (this._shaderChange) { + this.preCompile(geometry); + this._shaderChange = false; + } + this.reBuild(geometry, rendererPassState); + + this._stateChange = false; + // this.genRenderPipeline(geometry, rendererPassState); + if (noticeFun) { + noticeFun(); + } + } + } + + /** + * Precompile the shader code + * @param geometry + */ + public preCompile(geometry: GeometryBase) { + this.preDefine(geometry); + this.preCompileShader(ShaderStage.vertex, this._sourceVS.concat()); + this.preCompileShader(ShaderStage.fragment, this._sourceFS.concat()); + this.genReflection(); + } + + /** + * Apply defines syntax values + * @param shader + * @param renderPassState + * @returns + */ + public applyPostDefine(shader: string, renderPassState: RendererPassState) { + //*********************************/ + //添加渲染输出附件******************/ + + //TODO 需要修改细节版本 + if (Engine3D.setting.pick.mode == `pixel`) { + this.defineValue[`USE_WORLDPOS`] = true; + } + if (renderPassState.outAttachments.length > 1) { + this.defineValue[`USE_WORLDPOS`] = true; + this.defineValue[`USEGBUFFER`] = true; + } else { + this.defineValue[`USE_WORLDPOS`] = false; + this.defineValue[`USEGBUFFER`] = false; + } + if (Engine3D.setting.gi.enable) { + this.defineValue[`USEGI`] = true; + } else { + this.defineValue[`USEGI`] = false; + } + if (Engine3D.setting.material.materialChannelDebug) { + this.defineValue[`USE_DEBUG`] = true; + } + if (this.shaderState.useLight) { + this.defineValue[`USE_LIGHT`] = true; + } else { + this.defineValue[`USE_LIGHT`] = false; + } + //*********************************/ + //*********************************/ + return Preprocessor.parse(shader, this.defineValue); + } + + /** + * Set GPUBindGroup to the specified index slot + * @param groupIndex + * @param group + */ + public setBindGroup(groupIndex: number, group: GPUBindGroup) { + this.bindGroups[groupIndex] = group; + } + + /** + * Set the render shader default value + */ + public setDefault() { + this.setUniformFloat(`shadowBias`, 0.00035); + this.setUniformVector4(`transformUV1`, new Vector4(0, 0, 1, 1)); + this.setUniformVector4(`transformUV2`, new Vector4(0, 0, 1, 1)); + this.setUniformColor(`baseColor`, new Color()); + this.setUniformColor(`emissiveColor`, new Color(1, 1, 1)); + this.setUniformVector4(`materialF0`, new Vector4(0.04, 0.04, 0.04, 1)); + this.setUniformFloat(`envIntensity`, 1); + this.setUniformFloat(`normalScale`, 1); + this.setUniformFloat(`roughness`, 1.0); + this.setUniformFloat(`metallic`, 0.0); + this.setUniformFloat(`ao`, 1.0); + this.setUniformFloat(`roughness_min`, 0.0); + this.setUniformFloat(`roughness_max`, 1.0); + this.setUniformFloat(`metallic_min`, 0.0); + this.setUniformFloat(`metallic_max`, 1.0); + this.setUniformFloat(`emissiveIntensity`, 0.0); + this.setUniformFloat(`alphaCutoff`, 0.0); + this.setUniformFloat(`ior`, 1.5); + this.setUniformFloat(`clearcoatFactor`, 0.0); + this.setUniformFloat(`clearcoatRoughnessFactor`, 0.0); + this.setUniformColor(`clearcoatColor`, new Color(1, 1, 1)); + this.setUniformFloat(`clearcoatWeight`, 0.0); + } + + /** + * Destroy and release render shader related resources + */ + public destroy() { + this.bindGroups.length = 0; + this._passShaderCache.clear(); + this.shaderState = null; + this.textures = null; + this.pipeline = null; + this.bindGroupLayouts = null; + this._sourceVS = null; + this._sourceFS = null; + this._destVS = null; + this._destFS = null; + this._vsShaderModule = null; + this._fsShaderModule = null; + this.materialDataUniformBuffer.destroy();; + this.materialDataUniformBuffer = null; + } + + protected checkBuffer(bufferName: string, buffer: GPUBufferBase) { + return; + } + + protected preCompileShader(stage: ShaderStage, code: string, format?: string) { + let shader: string = code; + if (shader.indexOf(`version `) != -1) { + var wgsl = ShaderConverter.convertGLSL(shader); + shader = wgsl.sourceCode; + } + + for (const key in this.constValues) { + if (Object.prototype.hasOwnProperty.call(this.constValues, key)) { + const value = this.constValues[key]; + shader = shader.replaceAll(`&${key}`, value.toString()); + } + } + + switch (stage) { + case ShaderStage.vertex: + this._destVS = shader; + break; + case ShaderStage.fragment: + this._destFS = shader; + break; + } + } + + protected compileShader(stage: ShaderStage, code: string, renderPassState: RendererPassState) { + let shader: string = code; + + shader = this.applyPostDefine(shader, renderPassState); + let key = code; + for (let k in this.defineValue) { + key += `${k}=${this.defineValue[k]},`; + } + + let shaderModule = RenderShader._renderShaderModulePool.get(key); + if (!shaderModule) { + shader = this.applyPostDefine(shader, renderPassState); + + shaderModule = webGPUContext.device.createShaderModule({ + label: stage == ShaderStage.vertex ? this.vsName : this.fsName, + code: shader, + }); + + shaderModule.getCompilationInfo().then((e) => { + if (e.messages.length > 0) { + console.log(shader); + console.log(e); + } + }); + RenderShader._renderShaderModulePool.set(key, shaderModule); + } + + switch (stage) { + case ShaderStage.vertex: + this._vsShaderModule = shaderModule; + this._destVS = shader; + break; + case ShaderStage.fragment: + this._fsShaderModule = shaderModule; + this._destFS = shader; + break; + } + + // this._sourceVS = "" ; + // this._sourceFS = "" ; + } + + protected getGroupLayout(index: number, infos: ShaderReflectionVarInfo[]): GPUBindGroupLayoutEntry[] { + let entries: GPUBindGroupLayoutEntry[] = []; + for (let i = 0; i < infos.length; i++) { + const info = infos[i]; + if (!info) { + continue; + // console.error( `info is null` , this.vsName , this.fsName ); + } + if (info.varType == `uniform`) { + if (!this._bufferDic.has(info.varName)) { + console.error(`not set ${info.varName} buffer`); + } + let visibility = this._bufferDic.get(info.varName).visibility; + let entry: GPUBindGroupLayoutEntry = { + binding: info.binding, + visibility: visibility, + buffer: { + type: 'uniform', + }, + } + entries.push(entry); + } else if (info.varType == `storage-read`) { + if (!this._bufferDic.has(info.varName)) { + console.error(`not set ${info.varName} buffer`); + } + let visibility = this._bufferDic.get(info.varName).visibility; + let entry: GPUBindGroupLayoutEntry = { + binding: info.binding, + visibility: visibility, + buffer: { + type: 'read-only-storage', + }, + } + entries.push(entry); + } else if (info.varType == `var`) { + switch (info.dataType) { + case `sampler`: + { + let textureName = info.varName.replace(`Sampler`, ``); + let texture = this.textures[textureName] ? this.textures[textureName] : defaultRes.redTexture; + let entry: GPUBindGroupLayoutEntry = { + binding: info.binding, + visibility: texture.visibility, + sampler: texture.samplerBindingLayout, + } + entries.push(entry); + this._textureGroup = index; + // console.log(info.binding, entry ); + } + break; + case `sampler_comparison`: + { + let textureName = info.varName.replace(`Sampler`, ``); + let texture = this.textures[textureName] ? this.textures[textureName] : defaultRes.redTexture; + let entry: GPUBindGroupLayoutEntry = { + binding: info.binding, + visibility: texture.visibility, + sampler: texture.sampler_comparisonBindingLayout + } + entries.push(entry); + this._textureGroup = index; + // console.log(info.binding, entry ); + } + break; + case `texture_2d`: + case `texture_2d_array`: + case `texture_cube`: + case `texture_depth_2d`: + case `texture_depth_2d_array`: + case `texture_depth_cube`: + case `texture_depth_cube_array`: + { + let texture = this.textures[info.varName] ? this.textures[info.varName] : defaultRes.redTexture; + let entry: GPUBindGroupLayoutEntry = { + binding: info.binding, + visibility: texture.visibility, + texture: texture.textureBindingLayout, + } + entries.push(entry); + this._textureGroup = index; + // console.log(info.binding, entry ); + // if(info.binding == 8){ + // console.log(info.binding, entry ); + // } + } + break; + case `texture_external`: + { + let texture = this.textures[info.varName] ? this.textures[info.varName] : defaultRes.redTexture; + let entry: GPUBindGroupLayoutEntry = { + binding: info.binding, + visibility: texture.visibility, + externalTexture: {} + } + entries.push(entry); + this._textureGroup = index; + // console.log(info.binding, entry ); + } + break; + default: + { + let texture = this.textures[info.varName] ? this.textures[info.varName] : defaultRes.redTexture; + let entry: GPUBindGroupLayoutEntry = { + binding: info.binding, + visibility: texture.visibility, + texture: texture.textureBindingLayout, + } + entries.push(entry); + this._textureGroup = index; + // console.log(info.binding, entry ); + } + break; + } + } else { + debugger + console.error("bind group can't empty"); + } + } + return entries; + } + + protected genGroups(groupIndex: number, infos: ShaderReflectionVarInfo[][], force: boolean = false) { + if (!this.bindGroups[groupIndex] || force) { + const shaderRefs: ShaderReflectionVarInfo[] = infos[groupIndex]; + let entries = []; + for (let j = 0; j < shaderRefs.length; j++) { + const refs = shaderRefs[j]; + if (!refs) continue; + if (refs.varType == `uniform`) { + let buffer = this._bufferDic.get(refs.varName); + if (buffer) { + if (buffer instanceof MaterialDataUniformGPUBuffer) { + let uniforms: UniformNode[] = []; + for (let i = 0; i < refs.dataFields.length; i++) { + const field = refs.dataFields[i]; + if (!this.uniforms[field.name]) { + console.error(`shader-${this.vsName}:${this.fsName} ${field.name}is empty`); + } + uniforms.push(this.uniforms[field.name]); + } + this.materialDataUniformBuffer.initDataUniform(uniforms); + } + + let entry: GPUBindGroupEntry = { + binding: refs.binding, + resource: { + buffer: buffer.buffer, + offset: 0,//buffer.memory.shareFloat32Array.byteOffset, + size: buffer.memory.shareDataBuffer.byteLength, + }, + } + entries.push(entry); + + this.checkBuffer(refs.varName, buffer); + + } else { + console.error(`shader${this.vsName}-${this.fsName}`, `buffer ${refs.varName} is missing!`); + } + } else if (refs.varType == `storage-read`) { + let buffer = this._bufferDic.get(refs.varName); + if (buffer) { + let entry: GPUBindGroupEntry = { + binding: refs.binding, + resource: { + buffer: buffer.buffer, + offset: 0,//buffer.memory.shareFloat32Array.byteOffset, + size: buffer.memory.shareDataBuffer.byteLength, + }, + } + entries.push(entry); + this.checkBuffer(refs.varName, buffer); + } else { + console.error(`buffer ${refs.varName} is missing!`); + } + } else if (refs.varType == `var`) { + if (refs.dataType == `sampler`) { + let textureName = refs.varName.replace(`Sampler`, ``); + let texture = this.textures[textureName]; + if (!texture) { + texture = defaultRes.blackTexture; + this.setTexture(textureName, texture); + } + if (texture) { + let entry: GPUBindGroupEntry = { + binding: refs.binding, + resource: texture.gpuSampler + } + entries.push(entry); + // console.log(refs.binding, entry ); + } else { + console.error(`shader${this.vsName}-${this.fsName}`, `texture ${refs.varName} is missing! `); + } + } else if (refs.dataType == `sampler_comparison`) { + let textureName = refs.varName.replace(`Sampler`, ``); + let texture = this.textures[textureName]; + if (texture) { + let entry: GPUBindGroupEntry = { + binding: refs.binding, + resource: texture.gpuSampler_comparison + } + entries.push(entry); + // console.log(refs.binding, entry ); + } else { + console.error(`shader${this.vsName}-${this.fsName}`, `texture ${refs.varName} is missing! `); + } + } else { + let texture = this.textures[refs.varName]; + if (!texture) { + texture = defaultRes.whiteTexture; + this.setTexture(refs.varName, texture); + } + if (texture) { + let entry: GPUBindGroupEntry = { + binding: refs.binding, + resource: texture.getGPUView(), + } + entries.push(entry); + // console.log(refs.binding, texture ); + // if(refs.binding == 9){ + // console.log(refs.binding, texture ); + // } + } else { + console.error(`shader${this.vsName}-${this.fsName}`, `texture ${refs.varName} is missing! `); + } + } + } + } + + let gpubindGroup = webGPUContext.device.createBindGroup({ + layout: this.bindGroupLayouts[groupIndex], + entries: entries + }); + this.bindGroups[groupIndex] = gpubindGroup; + } + } + + private createPipeline(geometry: GeometryBase, renderPassState: RendererPassState, layouts: GPUPipelineLayout) { + let bufferMesh = geometry; + let shaderState = this.shaderState; + + let targets = renderPassState.outAttachments; + if (renderPassState.outColor != -1) { + let target = targets[renderPassState.outColor]; + target.blend = BlendFactor.getBlend(shaderState.blendMode); + } + + let renderPipelineDescriptor: GPURenderPipelineDescriptor = { + label: this.vsName + '|' + this.fsName, + layout: layouts, + primitive: { + topology: shaderState.topology, + cullMode: shaderState.cullMode, + frontFace: shaderState.frontFace, + }, + vertex: undefined, + }; + + if (this.vsEntryPoint != ``) { + renderPipelineDescriptor[`vertex`] = { + module: this._vsShaderModule, + entryPoint: this.vsEntryPoint, + buffers: bufferMesh.vertexBuffer.vertexBufferLayouts, + } + } + + if (this.fsEntryPoint != '') { + renderPipelineDescriptor[`fragment`] = { + module: this._fsShaderModule, + entryPoint: this.fsEntryPoint, + targets: targets + } + } + + if (shaderState.multisample > 0) { + renderPipelineDescriptor[`multisample`] = { + count: shaderState.multisample + } + } + + if (renderPassState.zPreTexture || renderPassState.depthTexture) { + let blendEnable = shaderState.blendMode != BlendMode.NONE; + // let depthWriteEnabled = !blendEnable ;!blendEnable && + if (Engine3D.setting.render.zPrePass && renderPassState.zPreTexture && shaderState.useZ) { + // if (!blendEnable && !shaderState.depthWriteEnabled && Engine3D.engineSetting.Render.zPrePass && renderPassState.depthMask && shaderState.useZ ) { + renderPipelineDescriptor[`depthStencil`] = { + depthWriteEnabled: shaderState.depthWriteEnabled, + depthCompare: shaderState.depthCompare, + format: renderPassState.zPreTexture.format, + }; + } else { + renderPipelineDescriptor[`depthStencil`] = { + depthWriteEnabled: shaderState.depthWriteEnabled, + depthCompare: shaderState.depthCompare, + format: renderPassState.depthTexture.format, + // depthBias:-0.5 + }; + + if (this.useRz) { + // tmpDes[`depthStencil`].depthCompare = GPUCompareFunction.less ; + } + } + } + + this.pipeline = GPUContext.createPipeline(renderPipelineDescriptor as GPURenderPipelineDescriptor); + } + + private createGroupLayouts() { + this._groupsShaderReflectionVarInfos = []; + let shaderReflection = this.shaderReflection; + this.bindGroupLayouts = [GlobalBindGroupLayout.getGlobalDataBindGroupLayout()]; + + // Binding Group 1 is Global , skip + for (let i = 1; i < shaderReflection.groups.length; i++) { + let shaderRefs = shaderReflection.groups[i]; + if (shaderRefs) { + let entries = this.getGroupLayout(i, shaderRefs); + this._groupsShaderReflectionVarInfos[i] = shaderRefs; + let layout = webGPUContext.device.createBindGroupLayout({ + entries, + label: `vs${this.vsName} fs${this.fsName}` + }); + this.bindGroupLayouts[i] = layout; + } else { + console.error("can't set empty group!", i); + } + } + + let layouts = webGPUContext.device.createPipelineLayout({ + bindGroupLayouts: this.bindGroupLayouts, + }); + + // Binding Group 1 is Global + if (this._groupsShaderReflectionVarInfos[0]) { + // this.genGroups(0, this.groupsShaderReflectionVarInfos); + } + if (this._groupsShaderReflectionVarInfos[1]) { + this.genGroups(1, this._groupsShaderReflectionVarInfos); + } + if (this._groupsShaderReflectionVarInfos[2]) { + this.genGroups(2, this._groupsShaderReflectionVarInfos); + } + if (this._groupsShaderReflectionVarInfos[3]) { + this.genGroups(3, this._groupsShaderReflectionVarInfos); + } + + return layouts; + } + + private preDefine(geometry: GeometryBase) { + // this.vertexAttributes = "" ; + // check geometry vertex attributes + let isSkeleton = geometry.hasAttribute(VertexAttributeName.joints0); + // this.vertexAttributes += `isSkeleton:${isSkeleton}` ; + let hasMorphTarget = geometry.hasAttribute(VertexAttributeName.a_morphPositions_0); + // this.vertexAttributes += `isMorpher:${isMorpher}` ; + let useTangent = geometry.hasAttribute(VertexAttributeName.TANGENT); + // this.vertexAttributes += `useTangent:${useTangent}` ; + let useVertexColor = geometry.hasAttribute(VertexAttributeName.color); + // this.vertexAttributes += `useVertexColor:${useVertexColor}` ; + + let useGI = this.shaderState.acceptGI; + let useLight = this.shaderState.useLight; + + this.defineValue[`USE_SKELETON`] = isSkeleton; + this.defineValue[`USE_MORPHTARGETS`] = hasMorphTarget; + this.defineValue[`USE_TANGENT`] = useTangent; + this.defineValue[`USE_GI`] = useGI; + this.defineValue[`USE_CASTSHADOW`] = this.shaderState.castShadow; + this.defineValue[`USE_SHADOWMAPING`] = this.shaderState.acceptShadow; + this.defineValue[`USE_LIGHT`] = useLight; + this.defineValue[`USE_VERTXCOLOR`] = useVertexColor; + + this.defineValue[`USE_PCF_SHADOW`] = Engine3D.setting.shadow.type == `PCF`; + this.defineValue[`USE_HARD_SHADOW`] = Engine3D.setting.shadow.type == `HARD`; + this.defineValue[`USE_SOFT_SHADOW`] = Engine3D.setting.shadow.type == `SOFT`; + this.defineValue[`USE_IES_PROFILE`] = IESProfiles.use; + } + + private genReflection() { + this.shaderVariant += ShaderReflection.genRenderShaderVariant(this); + let reflection = ShaderReflection.poolGetReflection(this.shaderVariant); + if (!reflection) { + //TODO: key check shader compile info + let vsPreShader = Preprocessor.parse(this._destVS, this.defineValue); + vsPreShader = Preprocessor.parse(vsPreShader, this.defineValue); + ShaderReflection.getShaderReflection2(vsPreShader, this); + let fsPreShader = Preprocessor.parse(this._destFS, this.defineValue); + fsPreShader = Preprocessor.parse(fsPreShader, this.defineValue); + ShaderReflection.getShaderReflection2(fsPreShader, this); + ShaderReflection.final(this); + } else { + this.shaderReflection = reflection; + } + + this.shaderState.splitTexture = this.shaderReflection.useSplit; + } +} + + diff --git a/src/engine/gfx/graphics/webGpu/shader/ShaderBase.ts b/src/engine/gfx/graphics/webGpu/shader/ShaderBase.ts new file mode 100644 index 00000000..3f36ac8a --- /dev/null +++ b/src/engine/gfx/graphics/webGpu/shader/ShaderBase.ts @@ -0,0 +1,232 @@ +import { GPUBufferBase } from "../core/buffer/GPUBufferBase"; +import { UUID } from "../../../../util/Global"; +import { Color } from "../../../../math/Color"; +import { Vector2 } from "../../../../math/Vector2"; +import { Vector3 } from "../../../../math/Vector3"; +import { Vector4 } from "../../../../math/Vector4"; +import { Struct } from "../../../../util/struct/Struct"; +import { StorageGPUBuffer } from "../core/buffer/StorageGPUBuffer"; +import { StructStorageGPUBuffer } from "../core/buffer/StructStorageGPUBuffer"; +import { UniformGPUBuffer } from "../core/buffer/UniformGPUBuffer"; +import { UniformNode } from "../core/uniforms/UniformNode"; +import { ShaderReflection } from "./value/ShaderReflectionInfo"; + + +export class ShaderBase { + /** + * Shader Unique instance id + */ + public readonly instanceID: string; + + /** + * Shader variant value + */ + public shaderVariant: string; + + /** + * Vertex stage entry point name + */ + public vsEntryPoint: string = `main`; + + /** + * Fragment stage entry point name + */ + public fsEntryPoint: string = `main`; + + /** + * BindGroup collection + */ + public bindGroups: GPUBindGroup[]; + + /** + * Shader reflection info + */ + public shaderReflection: ShaderReflection; + + /** + * The defined syntax value of the Shader when it is precompiled + */ + public defineValue: { [name: string]: any }; + + /** + * The constant value of the Shader when it is precompiled + */ + public constValues: { [name: string]: any }; + + /** + * Uniforms data collection + */ + public uniforms: { [name: string]: UniformNode }; + + protected _bufferDic: Map; + protected _shaderChange: boolean = false; + protected _stateChange: boolean = false; + + constructor() { + this.instanceID = UUID(); + this.defineValue = {}; + this.constValues = {}; + this.uniforms = {}; + this._bufferDic = new Map(); + }; + + /** + * notice shader change + */ + public noticeShaderChange() { + this._shaderChange = true; + } + + /** + * notice shader state change + */ + public noticeStateChange() { + this._stateChange = true; + } + + /** + * set storage gpu buffer + * @param name buffer name + * @param buffer storage useAge gpu buffer + */ + public setStorageBuffer(name: string, buffer: StorageGPUBuffer) { + if (!this._bufferDic.has(name)) { + this._bufferDic.set(name, buffer); + } + } + + /** + * set struct storage gpu buffer + * @param name buffer name + * @param buffer struct storage useAge gpu buffer + */ + public setStructStorageBuffer(name: string, buffer: StructStorageGPUBuffer) { + if (!this._bufferDic.has(name)) { + this._bufferDic.set(name, buffer); + } + } + + /** + * set uniform gpu buffer min size 256 + * @param name + * @param buffer + */ + public setUniformBuffer(name: string, buffer: UniformGPUBuffer) { + if (!this._bufferDic.has(name)) { + this._bufferDic.set(name, buffer); + } + } + + /** + * set define value + * @param defineName + * @param value + */ + public setDefine(defineName: string, value: any) { + this.defineValue[defineName] = value; + this.noticeShaderChange(); + } + + /** + * Whether there is a define key + * @param defineName + * @returns + */ + public hasDefine(defineName: string) { + return this.defineValue[defineName] != null; + } + + /** + * delete define value + * @param defineName + */ + public deleteDefine(defineName: string) { + delete this.defineValue[defineName]; + this.noticeShaderChange(); + } + + /** + * set uniform float value + * @param name + * @param value + */ + public setUniformFloat(name: string, value: number) { + if (!this.uniforms[name]) { + this.uniforms[name] = new UniformNode(value); + this.noticeStateChange(); + } else { + this.uniforms[name].value = value; + } + } + + /** + * set uniform vector2 value + * @param name + * @param value + */ + public setUniformVector2(name: string, value: Vector2) { + if (!this.uniforms[name]) { + this.uniforms[name] = new UniformNode(value); + } else { + this.uniforms[name].vector2 = value; + } + } + + /** + * set uniform vector3 value + * @param name + * @param value + */ + public setUniformVector3(name: string, value: Vector3) { + if (!this.uniforms[name]) { + this.uniforms[name] = new UniformNode(value); + } else { + this.uniforms[name].vector3 = value; + } + } + + /** + * set uniform vector4 value + * @param name + * @param value + */ + public setUniformVector4(name: string, value: Vector4) { + if (!this.uniforms[name]) { + this.uniforms[name] = new UniformNode(value); + } else { + this.uniforms[name].vector4 = value; + } + } + + /** + * set uniform color value + * @param name + * @param value + */ + public setUniformColor(name: string, value: Color) { + if (!this.uniforms[name]) { + this.uniforms[name] = new UniformNode(value); + } else { + this.uniforms[name].color = value; + } + } + + /** + * set uniform array value + * @param name + * @param value + */ + public setUniformArray(name: string, value: Float32Array) { + if (!this.uniforms[name]) { + this.uniforms[name] = new UniformNode(value); + } else { + this.uniforms[name].float32Array(value); + } + } + + /** + * destroy + */ + public destroy() { + } +} From 23a62794b041b36e2110d11c1ebfe10a82c73f57 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Thu, 27 Apr 2023 17:00:08 +0800 Subject: [PATCH 060/100] feat(Mesh): add InstanceMesh (#75) add InstanceMesh --- src/engine/core/entities/InstancedMesh.ts | 59 +++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/engine/core/entities/InstancedMesh.ts diff --git a/src/engine/core/entities/InstancedMesh.ts b/src/engine/core/entities/InstancedMesh.ts new file mode 100644 index 00000000..c3bb5441 --- /dev/null +++ b/src/engine/core/entities/InstancedMesh.ts @@ -0,0 +1,59 @@ +import { MeshRenderer } from "../../components/renderer/MeshRenderer"; +import { MaterialBase } from "../../materials/MaterialBase"; +import { Matrix4 } from "../../math/Matrix4"; +import { Orientation3D } from "../../math/Orientation3D"; +import { Vector3 } from "../../math/Vector3"; +import { GeometryBase } from "../geometry/GeometryBase"; +import { Object3D } from "./Object3D"; + + +export class InstancedMesh extends Object3D { + private _geometry: GeometryBase; + private _material: MaterialBase; + private _instanceList: Object3D[]; + + constructor(geometry: GeometryBase, material: MaterialBase, length: number) { + super(); + this._geometry = geometry; + this._material = material; + this._instanceList = []; + for (let i = 0; i < length; i++) { + let component: MeshRenderer; + let child = new Object3D(); + component = child.addComponent(MeshRenderer); + component.geometry = this._geometry; + component.material = this._material; + this.addChild(child); + this._instanceList.push(child) + } + } + + public setMatrixAt(index: number, matrix: Matrix4): this { + let instance = this._instanceList[index]; + let prs: Vector3[] = matrix.decompose(Orientation3D.QUATERNION); + let transform = instance.transform; + + transform.localRotQuat.copyFrom(prs[1]); + transform.localRotQuat = transform.localRotQuat; + + transform.localPosition.copyFrom(prs[0]); + transform.localPosition = transform.localPosition; + + transform.localScale.copyFrom(prs[2]); + transform.localScale = transform.localScale; + return this; + } + + // public setMatrixAt1(index: number, matrix: Matrix4) { + // let instance = this.getIndex(index); + // let p = new Vector3(); + // let r = new Quaternion(); + // let s = new Vector3(); + // matrix.decompose1(p, r, s); + // let childTransform = instance.transform; + // childTransform.localRotQuat = r; + // childTransform.localPosition = p; + // childTransform.localScale = s; + // } + +} \ No newline at end of file From 1af21cd7bb2552172557ad8ec29c8daa6b5b0ade Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Thu, 27 Apr 2023 17:57:29 +0800 Subject: [PATCH 061/100] chore(import): update import url (#76) update class import url check lost class and add clear not use class add some class docs --- src/engine/assets/Res.ts | 63 ---- src/engine/assets/shader/ShaderLib.ts | 14 +- src/engine/components/AtmosphericComponent.ts | 2 +- src/engine/components/BillboardComponent.ts | 13 +- src/engine/components/ColliderComponent.ts | 14 +- src/engine/components/Transform.ts | 5 +- .../curveAnim/curveAnim/AnimationMonitor.ts | 8 +- .../curveAnim/curveAnim/AttributeAnimCurve.ts | 3 +- .../curveAnim/curveAnim/PropertyAnimation.ts | 6 +- .../curveAnim/PropertyAnimationEvent.ts | 2 +- .../anim/morphAnim/MorphTargetBlender.ts | 2 +- .../anim/morphAnim/MorphTargetData.ts | 3 +- .../anim/skeletonAnim/SkeletonPose.ts | 2 +- .../controller/FirstPersonCameraController.ts | 8 +- .../controller/FlyCameraController.ts | 10 +- .../controller/HoverCameraController.ts | 12 +- .../controller/ThirdPersonCameraController.ts | 8 +- src/engine/components/lights/LightBase.ts | 2 - .../post/PostProcessingComponent.ts | 3 +- .../renderer/GlobalIlluminationComponent.ts | 171 --------- .../renderer/InstanceDrawComponent.ts | 4 +- .../components/renderer/MeshRenderer.ts | 2 - src/engine/components/renderer/RenderNode.ts | 44 +-- .../renderer/SkinnedMeshRenderer.ts | 17 +- src/engine/components/renderer/SkyRenderer.ts | 15 +- .../components/shape/BoxColliderShape.ts | 11 +- src/engine/components/shape/ColliderShape.ts | 7 +- .../components/shape/MeshColliderShape.ts | 2 +- .../components/shape/SphereColliderShape.ts | 11 +- src/engine/core/CubeCamera.ts | 2 +- src/engine/core/Scene3D.ts | 1 - src/engine/core/View3D.ts | 31 +- src/engine/core/ViewQuad.ts | 2 +- src/engine/core/bound/BoundingBox.ts | 2 +- src/engine/core/entities/Object3D.ts | 2 - src/engine/core/geometry/GeometryBase.ts | 2 +- .../core/geometry/VertexAttributeData.ts | 2 +- src/engine/event/CEvent.ts | 3 +- src/engine/gfx/generate/PassGenerate.ts | 14 +- .../gfx/generate/convert/ErpImage2CubeMap.ts | 2 +- .../gfx/generate/convert/IBLEnvMapCreator.ts | 3 +- .../generate/convert/TextureCubeStdCreator.ts | 3 +- .../webGpu/core/bindGroups/GlobalBindGroup.ts | 2 + .../core/bindGroups/GlobalUniformGroup.ts | 10 + .../core/bindGroups/groups/LightEntries.ts | 12 +- .../core/bindGroups/groups/ProbeEntries.ts | 53 --- .../webGpu/core/buffer/GPUBufferBase.ts | 15 +- .../buffer/MaterialDataUniformGPUBuffer.ts | 3 - .../graphics/webGpu/core/texture/Texture.ts | 2 - .../core/texture/TextureMipmapCompute.ts | 2 +- .../core/texture/TextureMipmapGenerator.ts | 2 +- .../descriptor/WebGPUDescriptorCreator.ts | 2 +- .../graphics/webGpu/shader/RenderShader.ts | 8 +- .../shader/value/ShaderReflectionInfo.ts | 2 +- src/engine/gfx/renderJob/GPUContext.ts | 23 +- .../gfx/renderJob/collect/EntityCollect.ts | 57 +-- .../renderJob/collect/ShadowLightsCollect.ts | 4 +- .../gfx/renderJob/color/ColorPassRenderer.ts | 17 +- .../gfx/renderJob/frame/ProbeGBufferFrame.ts | 4 +- .../gfx/renderJob/jobs/ForwardRenderJob.ts | 39 +- src/engine/gfx/renderJob/jobs/RendererJob.ts | 51 +-- .../renderJob/passRenderer/RendererBase.ts | 38 +- .../graphic/Graphic3DBatchRenderer.ts | 2 +- .../graphic/Graphic3DFillRenderer.ts | 2 +- .../graphic/Graphic3DFixedRenderPipeline.ts | 5 +- .../graphic/Graphic3DLineBatchRenderer.ts | 2 +- .../passRenderer/graphic/Graphic3DRender.ts | 1 - .../passRenderer/post/PostRenderer.ts | 72 ++++ .../preDepth/PreDepthPassRenderer.ts | 59 +++ .../preDepth/ZCullingCompute.ts | 7 +- .../shadow/PointLightShadowRenderer.ts | 9 +- .../shadow/ShadowMapPassRenderer.ts | 45 ++- .../{ => passRenderer}/state/RendererMask.ts | 0 .../state/RendererPassState.ts | 10 +- .../{ => passRenderer}/state/RendererType.ts | 0 .../gfx/renderJob/post/DepthOfFieldPost.ts | 209 +++++++++++ src/engine/gfx/renderJob/post/FXAAPost.ts | 56 +++ src/engine/gfx/renderJob/post/GTAOPost.ts | 277 ++++++++++++++ src/engine/gfx/renderJob/post/GlobalFog.ts | 149 ++++++++ src/engine/gfx/renderJob/post/HDRBloomPost.ts | 178 +++++++++ src/engine/gfx/renderJob/post/OutlinePost.ts | 347 ++++++++++++++++++ src/engine/gfx/renderJob/post/PostBase.ts | 93 +++++ src/engine/gfx/renderJob/post/SSRPost.ts | 314 ++++++++++++++++ src/engine/gfx/renderJob/post/TAAPost.ts | 260 +++++++++++++ .../preDepth/PreDepthPassRenderer.ts | 105 ------ src/engine/io/InputSystem.ts | 45 +-- src/engine/io/PickFire.ts | 5 +- src/engine/io/PickResult.ts | 1 - src/engine/io/picker/PickCompute.ts | 3 +- src/engine/loader/parser/AtlasParser.ts | 46 --- src/engine/loader/parser/B3DMParser.ts | 5 +- src/engine/loader/parser/FntParser.ts | 175 --------- src/engine/loader/parser/OBJParser.ts | 14 +- src/engine/loader/parser/b3dm/B3DMLoader.ts | 11 +- src/engine/loader/parser/gltf/GLBParser.ts | 2 - src/engine/loader/parser/gltf/GLTFParser.ts | 1 - .../parser/gltf/GLTFSubParserConverter.ts | 24 +- src/engine/materials/GIProbeMaterial.ts | 52 --- src/engine/materials/GlassMaterial.ts | 2 +- src/engine/materials/LitMaterial.ts | 2 +- src/engine/materials/MaterialPass.ts | 3 +- src/engine/materials/PointMaterial.ts | 2 +- .../materials/effectPass/OutLinePass.ts | 5 +- .../multiPass/CastShadowMaterialPass.ts | 2 +- src/engine/math/MathUtil.ts | 63 +++- src/engine/math/Matrix4.ts | 26 +- src/engine/math/Random.ts | 2 +- src/engine/setting/SkySetting.ts | 2 +- src/engine/setting/post/GlobalFogSetting.ts | 2 +- .../textures/AtmosphericScatteringSky.ts | 3 +- src/engine/textures/BitmapTexture2D.ts | 2 - src/engine/textures/BitmapTexture2DArray.ts | 2 +- src/engine/textures/BitmapTextureCube.ts | 6 +- src/engine/textures/DefaultRes.ts | 9 - src/engine/textures/Float16ArrayTexture.ts | 2 +- src/engine/textures/Float32ArrayTexture.ts | 2 +- src/engine/textures/HDRTexture.ts | 5 +- src/engine/textures/HDRTextureCube.ts | 4 +- src/engine/textures/Uint16Texture.ts | 2 +- src/engine/textures/Uint8ArrayTexture.ts | 2 +- tsconfig.json | 6 +- 121 files changed, 2481 insertions(+), 1140 deletions(-) delete mode 100644 src/engine/components/renderer/GlobalIlluminationComponent.ts delete mode 100644 src/engine/gfx/graphics/webGpu/core/bindGroups/groups/ProbeEntries.ts create mode 100644 src/engine/gfx/renderJob/passRenderer/post/PostRenderer.ts create mode 100644 src/engine/gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer.ts rename src/engine/gfx/renderJob/{ => passRenderer}/preDepth/ZCullingCompute.ts (99%) rename src/engine/gfx/renderJob/{ => passRenderer}/state/RendererMask.ts (100%) rename src/engine/gfx/renderJob/{ => passRenderer}/state/RendererPassState.ts (76%) rename src/engine/gfx/renderJob/{ => passRenderer}/state/RendererType.ts (100%) create mode 100644 src/engine/gfx/renderJob/post/DepthOfFieldPost.ts create mode 100644 src/engine/gfx/renderJob/post/FXAAPost.ts create mode 100644 src/engine/gfx/renderJob/post/GTAOPost.ts create mode 100644 src/engine/gfx/renderJob/post/GlobalFog.ts create mode 100644 src/engine/gfx/renderJob/post/HDRBloomPost.ts create mode 100644 src/engine/gfx/renderJob/post/OutlinePost.ts create mode 100644 src/engine/gfx/renderJob/post/PostBase.ts create mode 100644 src/engine/gfx/renderJob/post/SSRPost.ts create mode 100644 src/engine/gfx/renderJob/post/TAAPost.ts delete mode 100644 src/engine/gfx/renderJob/preDepth/PreDepthPassRenderer.ts delete mode 100644 src/engine/loader/parser/AtlasParser.ts delete mode 100644 src/engine/loader/parser/FntParser.ts delete mode 100644 src/engine/materials/GIProbeMaterial.ts diff --git a/src/engine/assets/Res.ts b/src/engine/assets/Res.ts index 4f00da16..77f19a8e 100644 --- a/src/engine/assets/Res.ts +++ b/src/engine/assets/Res.ts @@ -12,15 +12,9 @@ import { BitmapTextureCube } from '../textures/BitmapTextureCube'; import { HDRTextureCube } from '../textures/HDRTextureCube'; import { B3DMParser } from '../loader/parser/B3DMParser'; import { I3DMParser } from "../loader/parser/I3DMParser"; -import { FntParser, FontInfo } from "../loader/parser/FntParser"; -import { AtlasParser } from "../loader/parser/AtlasParser"; -import { GUIAtlasTexture } from '../components/gui/core/GUIAtlasTexture'; -import { GUISubTexture } from '../components/gui/core/GUISubTexture'; import { GLTF_Info } from '../loader/parser/gltf/GLTFInfo'; import { HDRTexture } from '../textures/HDRTexture'; import { LDRTextureCube } from '../textures/LDRTextureCube'; -import { fonts } from './Fonts'; -// import { PrefabLoader } from '../plugins/serialize/unserialize/PrefabLoader'; /** * Resource management classes for textures, materials, models, and preset bodies. @@ -30,8 +24,6 @@ export class Res { private _texturePool: Map; private _materialPool: Map; private _prefabPool: Map; - // private _prefabLoaderPool: Map; - private _atlasList: Map; private _gltfPool: Map; /** @@ -41,8 +33,6 @@ export class Res { this._texturePool = new Map(); this._materialPool = new Map(); this._prefabPool = new Map(); - // this._prefabLoaderPool = new Map; - this._atlasList = new Map(); this._gltfPool = new Map; } @@ -50,27 +40,6 @@ export class Res { return this._gltfPool.get(url); } - // public getPrefabLoader(url: string): PrefabLoader { - // return this._prefabLoaderPool.get(url); - // } - - public addAtlas(name: string, atlas: GUIAtlasTexture) { - atlas.name = name; - this._atlasList.set(name, atlas); - } - - public getAtlas(name: string) { - return this._atlasList.get(name); - } - - public getSubTexture(id: string): GUISubTexture { - for (let item of this._atlasList.values()) { - let tex = item.getTexture(id); - if (tex) return tex; - } - return null; - } - /** * add a texture with reference of url * @param url file path @@ -209,32 +178,6 @@ export class Res { return obj; } - /** - * load font file by url - * @param url font file url - * @param loaderFunctions callback - * @returns - */ - public async loadFont(url: string, loaderFunctions?: LoaderFunctions, userData?: any): Promise { - let loader = new FileLoader(); - let parser = await loader.load(url, FntParser, loaderFunctions, userData); - let data = parser.data as FontInfo; - fonts.addFontData(data.face, data.size, data) - return parser.data; - } - - /** - * load a atlas file by url - * @param url file path - * @param loaderFunctions callback - * @returns - */ - public async loadAtlas(url: string, loaderFunctions?: LoaderFunctions): Promise { - let loader = new FileLoader(); - let parser = await loader.load(url, AtlasParser, loaderFunctions, url); - return parser.data; - } - /** * load texture by url * @param url texture path @@ -247,7 +190,6 @@ export class Res { return this._texturePool.get(url); } let texture = new BitmapTexture2D(); - texture.textureSource.setNetImage(url); texture.flipY = flipY; await texture.load(url, loaderFunctions); this._texturePool.set(url, texture); @@ -266,7 +208,6 @@ export class Res { } let hdrTexture = new HDRTexture(); - hdrTexture.textureSource.setHDRNetImage(url); hdrTexture = await hdrTexture.load(url, loaderFunctions); this._texturePool.set(url, hdrTexture); return hdrTexture; @@ -285,7 +226,6 @@ export class Res { } let hdrTexture = new HDRTextureCube(); hdrTexture = await hdrTexture.load(url, loaderFunctions); - hdrTexture.textureSource.setCubeHDR(url); this._texturePool.set(url, hdrTexture); return hdrTexture; } @@ -302,7 +242,6 @@ export class Res { } let ldrTextureCube = new LDRTextureCube(); ldrTextureCube = await ldrTextureCube.load(url, loaderFunctions); - ldrTextureCube.textureSource.setCubeLDR(url); this._texturePool.set(url, ldrTextureCube); return ldrTextureCube; } @@ -321,7 +260,6 @@ export class Res { let textureCube = new BitmapTextureCube(); await textureCube.load(urls); - textureCube.textureSource.setCubeFace6(urls); this._texturePool.set(urls[0], textureCube); return textureCube; } @@ -338,7 +276,6 @@ export class Res { let cubeMap = new BitmapTextureCube(); await cubeMap.loadStd(url); - cubeMap.textureSource.setCubeStd(url); return cubeMap; } diff --git a/src/engine/assets/shader/ShaderLib.ts b/src/engine/assets/shader/ShaderLib.ts index dadd690e..634540fe 100644 --- a/src/engine/assets/shader/ShaderLib.ts +++ b/src/engine/assets/shader/ShaderLib.ts @@ -1,4 +1,3 @@ -import { Bloom_shader, CubeSky_Shader, IrradianceVolumeData_frag, ParticleDataStructShader, Quad_shader, UnLitMaterialUniform_frag, UnLit_frag, VideoUniform_frag } from "../../.."; import { VertexAttributes } from "./core/struct/VertexAttributes" import ColorPassFragmentOutput from "./core/struct/ColorPassFragmentOutput.wgsl?raw"; import Common_frag from "./core/base/Common_frag.wgsl?raw"; @@ -31,7 +30,12 @@ import PBRLItShader from '../shader/materials/PBRLItShader.wgsl?raw' import ColorUtil from './utils/ColorUtil.wgsl?raw' import GenerayRandomDir from './utils/GenerayRandomDir.wgsl?raw' import IESProfiles_frag from './lighting/IESProfiles_frag.wgsl?raw' -import { ShaderLibs } from "./ShaderLibs"; +import { UnLit_frag } from "./lighting/UnLit_frag"; +import { UnLitMaterialUniform_frag } from "./materials/uniforms/UnLitMaterialUniform_frag"; +import { VideoUniform_frag } from "./materials/uniforms/VideoUniform_frag"; +import { Bloom_shader } from "./post/Bloom_shader"; +import { Quad_shader } from "./quad/Quad_shader"; +import { CubeSky_Shader } from "./sky/CubeSky_Shader"; /** * @internal @@ -39,7 +43,6 @@ import { ShaderLibs } from "./ShaderLibs"; export class ShaderLib { public static init() { - ShaderLibs.init(); ShaderLib.register('MathShader', MathShader); ShaderLib.register('FastMathShader', FastMathShader); @@ -68,7 +71,7 @@ export class ShaderLib { ShaderLib.register('ShadowMapping_frag', ShadowMapping_frag); ShaderLib.register('Irradiance_frag', Irradiance_frag); - ShaderLib.register('IrradianceVolumeData_frag', IrradianceVolumeData_frag); + // ShaderLib.register('IrradianceVolumeData_frag', IrradianceVolumeData_frag); ShaderLib.register('BrdfLut_frag', BrdfLut_frag); ShaderLib.register('EnvMap_frag', EnvMap_frag); @@ -99,9 +102,6 @@ export class ShaderLib { ShaderLib.register('Bloom_Brightness_frag_wgsl', Bloom_shader.Bloom_Brightness_frag_wgsl); ShaderLib.register('Bloom_blur_frag_wgsl', Bloom_shader.Bloom_blur_frag_wgsl); ShaderLib.register('Bloom_composite_frag_wgsl', Bloom_shader.Bloom_composite_frag_wgsl); - - - ShaderLib.register('ParticleDataStruct', ParticleDataStructShader); } public static register(keyName: string, code: string) { diff --git a/src/engine/components/AtmosphericComponent.ts b/src/engine/components/AtmosphericComponent.ts index e1230419..e637920a 100644 --- a/src/engine/components/AtmosphericComponent.ts +++ b/src/engine/components/AtmosphericComponent.ts @@ -1,5 +1,5 @@ -import { SkyRenderer } from "../.."; import { AtmosphericScatteringSky, AtmosphericScatteringSkySetting } from "../textures/AtmosphericScatteringSky"; +import { SkyRenderer } from "./renderer/SkyRenderer"; /** * diff --git a/src/engine/components/BillboardComponent.ts b/src/engine/components/BillboardComponent.ts index fa35f0cc..1419e2bd 100644 --- a/src/engine/components/BillboardComponent.ts +++ b/src/engine/components/BillboardComponent.ts @@ -1,11 +1,16 @@ -import { Object3DType } from './gui/data/AssetsInfo'; import { Camera3D } from '../core/Camera3D'; import { Object3D } from '../core/entities/Object3D'; import { Vector3 } from '../math/Vector3'; import { ComponentBase } from './ComponentBase'; +export enum BillboardType { + Normal = 0, + BillboardY = 9, + BillboardXYZ = 10, +} + export class BillboardComponent extends ComponentBase { - public type: Object3DType; + public type: BillboardType; public camera: Camera3D; private _cameraDirection: Vector3; @@ -24,9 +29,9 @@ export class BillboardComponent extends ComponentBase { private updateBillboardMatrix(): void { let camera = this.transform.view3D.camera; this._cameraDirection.copyFrom(camera.transform.back); - if (this.type == Object3DType.BillboardXYZ) { + if (this.type == BillboardType.BillboardXYZ) { this._cameraDirection.normalize().multiplyScalar(100); - } else if (this.type == Object3DType.BillboardY) { + } else if (this.type == BillboardType.BillboardY) { this._cameraDirection.y = 0; this._cameraDirection.normalize().multiplyScalar(100); } diff --git a/src/engine/components/ColliderComponent.ts b/src/engine/components/ColliderComponent.ts index d408ce81..9d25b2ff 100644 --- a/src/engine/components/ColliderComponent.ts +++ b/src/engine/components/ColliderComponent.ts @@ -1,10 +1,9 @@ -import { Engine3D } from '../../Engine3D'; -import { Ray } from '../../math/Ray'; -import { Vector3 } from '../../math/Vector3'; -import { ComponentType } from '../../util/SerializeDefine'; -import { ComponentBase } from '../ComponentBase'; -import { BoxColliderShape } from './shape/BoxColliderShape'; -import { ColliderShape } from './shape/ColliderShape'; +import { Engine3D } from "../Engine3D"; +import { Ray } from "../math/Ray"; +import { Vector3 } from "../math/Vector3"; +import { ComponentBase } from "./ComponentBase"; +import { BoxColliderShape } from "./shape/BoxColliderShape"; +import { ColliderShape } from "./shape/ColliderShape"; /** * collider component @@ -16,7 +15,6 @@ export class ColliderComponent extends ComponentBase { constructor() { super(); this._shape = new BoxColliderShape(); - this.componentType = ComponentType.collider; } /** * @internal diff --git a/src/engine/components/Transform.ts b/src/engine/components/Transform.ts index a416c81b..1b24df54 100644 --- a/src/engine/components/Transform.ts +++ b/src/engine/components/Transform.ts @@ -8,7 +8,6 @@ import { Orientation3D } from "../math/Orientation3D"; import { Quaternion } from "../math/Quaternion"; import { Vector3 } from "../math/Vector3"; import { View3D } from "../core/View3D"; -import { ComponentType } from "../util/SerializeDefine"; /** * The Transform component contains the position, rotation, and scaling of an object in 3D space. @@ -161,8 +160,6 @@ export class Transform extends ComponentBase { constructor() { super(); - this.componentType = ComponentType.transform; - // this.localMatrix = new Matrix4(); this.worldMatrix = new Matrix4(false); this._localPos = new Vector3(); this._localRot = new Vector3(); @@ -306,7 +303,7 @@ export class Transform extends ComponentBase { /** * - * 物体相对于父级变换属性,以四元数形式存储 + * The transformation property of the object relative to the parent, stored in the form of a quaternion */ public get localRotQuat(): Quaternion { return this._localRotQuat; diff --git a/src/engine/components/anim/curveAnim/curveAnim/AnimationMonitor.ts b/src/engine/components/anim/curveAnim/curveAnim/AnimationMonitor.ts index 8ebccc7c..b2b7f424 100644 --- a/src/engine/components/anim/curveAnim/curveAnim/AnimationMonitor.ts +++ b/src/engine/components/anim/curveAnim/curveAnim/AnimationMonitor.ts @@ -1,8 +1,8 @@ -import { Object3D } from '../../../core/entities/Object3D'; -import { clamp, repeat } from '../../../math/MathUtil'; -import { Matrix4 } from '../../../math/Matrix4'; -import { PropertyAnimation } from './PropertyAnimation'; +import { Object3D } from '../../../../core/entities/Object3D'; +import { repeat, clamp } from '../../../../math/MathUtil'; +import { Matrix4 } from '../../../../math/Matrix4'; import { PropertyAnimClip, WrapMode } from './PropertyAnimClip'; +import { PropertyAnimation } from './PropertyAnimation'; import { PropertyHelp } from './PropertyHelp'; /** * @internal diff --git a/src/engine/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts b/src/engine/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts index b3c42c97..11eda502 100644 --- a/src/engine/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts +++ b/src/engine/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts @@ -1,4 +1,5 @@ -import { AnimationCurve } from '../../../math/AnimationCurve'; +import { AnimationCurve } from "../../../../math/AnimationCurve"; + /** * @internal * @group Animation diff --git a/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimation.ts b/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimation.ts index 3699124f..ea97d7e1 100644 --- a/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimation.ts +++ b/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimation.ts @@ -1,6 +1,6 @@ -import { Object3D } from '../../../core/entities/Object3D'; -import { Time } from '../../../util/Time'; -import { ComponentBase } from '../../ComponentBase'; +import { Object3D } from '../../../../core/entities/Object3D'; +import { Time } from '../../../../util/Time'; +import { ComponentBase } from '../../../ComponentBase'; import { AnimationMonitor } from './AnimationMonitor'; import { AnimatorEventKeyframe, PropertyAnimationEvent } from './PropertyAnimationEvent'; import { PropertyAnimClip } from './PropertyAnimClip'; diff --git a/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts b/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts index 672fb87a..2d7f547a 100644 --- a/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts +++ b/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts @@ -1,4 +1,4 @@ -import { CEvent } from '../../../event/CEvent'; +import { CEvent } from '../../../../event/CEvent'; import { PropertyAnimation } from './PropertyAnimation'; /** * @internal diff --git a/src/engine/components/anim/morphAnim/MorphTargetBlender.ts b/src/engine/components/anim/morphAnim/MorphTargetBlender.ts index 96d58a6d..13d33aaf 100644 --- a/src/engine/components/anim/morphAnim/MorphTargetBlender.ts +++ b/src/engine/components/anim/morphAnim/MorphTargetBlender.ts @@ -1,12 +1,12 @@ import { MorphTargetMapper } from "./MorphTargetKey"; import { Object3D } from "../../../core/entities/Object3D"; -import { RendererMask, RendererMaskUtil } from "../../../gfx/renderJob/passRenderer/state/RendererMask"; import { Matrix4 } from "../../../math/Matrix4"; import { Quaternion } from "../../../math/Quaternion"; import { Vector3 } from "../../../math/Vector3"; import { ComponentBase } from "../../ComponentBase"; import { MorphTargetFrame } from "./MorphTargetFrame"; import { MeshRenderer } from "../../renderer/MeshRenderer"; +import { RendererMask, RendererMaskUtil } from "../../../gfx/renderJob/passRenderer/state/RendererMask"; export class MorphTargetBlender extends ComponentBase { private _targetRenderers: { [key: string]: MeshRenderer[] } = {}; diff --git a/src/engine/components/anim/morphAnim/MorphTargetData.ts b/src/engine/components/anim/morphAnim/MorphTargetData.ts index afc0521d..af274400 100644 --- a/src/engine/components/anim/morphAnim/MorphTargetData.ts +++ b/src/engine/components/anim/morphAnim/MorphTargetData.ts @@ -4,7 +4,8 @@ import { MorphTarget_shader } from '../../../components/anim/morphAnim/MorphTarg import { ComputeShader } from '../../../gfx/graphics/webGpu/shader/ComputeShader'; import { GPUContext } from '../../../gfx/renderJob/GPUContext'; import { RenderShader } from '../../../gfx/graphics/webGpu/shader/RenderShader'; -import { VertexAttributeData, GeometryBase } from '../../../..'; +import { GeometryBase } from '../../../core/geometry/GeometryBase'; +import { VertexAttributeData } from '../../../core/geometry/VertexAttributeData'; type MorphTargetCollectData = { mtCount: number; diff --git a/src/engine/components/anim/skeletonAnim/SkeletonPose.ts b/src/engine/components/anim/skeletonAnim/SkeletonPose.ts index a2b7cb8c..2cc7d5b4 100644 --- a/src/engine/components/anim/skeletonAnim/SkeletonPose.ts +++ b/src/engine/components/anim/skeletonAnim/SkeletonPose.ts @@ -1,4 +1,4 @@ -import { makeMatrix44, Matrix4, multiplyMatrices4x4REF } from '../../../..'; +import { Matrix4, makeMatrix44, multiplyMatrices4x4REF } from '../../../math/Matrix4'; import { Quaternion } from '../../../math/Quaternion'; import { Vector3 } from '../../../math/Vector3'; import { JointPose } from './JointPose'; diff --git a/src/engine/components/controller/FirstPersonCameraController.ts b/src/engine/components/controller/FirstPersonCameraController.ts index b74d3930..7bd75f43 100644 --- a/src/engine/components/controller/FirstPersonCameraController.ts +++ b/src/engine/components/controller/FirstPersonCameraController.ts @@ -1,4 +1,9 @@ -import { Camera3D, ComponentBase, Engine3D, Object3D, PointerEvent3D, Vector3 } from '../../..'; +import { Engine3D } from "../../Engine3D"; +import { Camera3D } from "../../core/Camera3D"; +import { Object3D } from "../../core/entities/Object3D"; +import { PointerEvent3D } from "../../event/eventConst/PointerEvent3D"; +import { Vector3 } from "../../math/Vector3"; +import { ComponentBase } from "../ComponentBase"; /** * @internal @@ -13,7 +18,6 @@ export class FirstPersonCameraController extends ComponentBase { constructor() { super(); - this.serializeTag = 'dont-serialize'; } protected start() { diff --git a/src/engine/components/controller/FlyCameraController.ts b/src/engine/components/controller/FlyCameraController.ts index de8a9c72..d902df9a 100644 --- a/src/engine/components/controller/FlyCameraController.ts +++ b/src/engine/components/controller/FlyCameraController.ts @@ -1,4 +1,11 @@ -import { clamp, ComponentBase, Engine3D, KeyCode, KeyEvent, lerp, PointerEvent3D, Time, Vector3 } from "../../.."; +import { Engine3D } from "../../Engine3D"; +import { KeyCode } from "../../event/KeyCode"; +import { KeyEvent } from "../../event/eventConst/KeyEvent"; +import { PointerEvent3D } from "../../event/eventConst/PointerEvent3D"; +import { clamp, lerp } from "../../math/MathUtil"; +import { Vector3 } from "../../math/Vector3"; +import { Time } from "../../util/Time"; +import { ComponentBase } from "../ComponentBase"; /** * Free camera controller. @@ -46,7 +53,6 @@ export class FlyCameraController extends ComponentBase { constructor() { super(); - this.serializeTag = 'dont-serialize'; this._lastPos = new Vector3(); this._keyState = { front: false, diff --git a/src/engine/components/controller/HoverCameraController.ts b/src/engine/components/controller/HoverCameraController.ts index 5a8834e3..8416b625 100644 --- a/src/engine/components/controller/HoverCameraController.ts +++ b/src/engine/components/controller/HoverCameraController.ts @@ -1,5 +1,14 @@ -import { Camera3D, clamp, ComponentBase, Engine3D, Object3D, PointerEvent3D, Quaternion, Time, Vector3, Vector3Ex } from "../../.."; +import { Engine3D } from "../../Engine3D"; +import { Camera3D } from "../../core/Camera3D"; +import { Object3D } from "../../core/entities/Object3D"; +import { PointerEvent3D } from "../../event/eventConst/PointerEvent3D"; +import { clamp } from "../../math/MathUtil"; +import { Quaternion } from "../../math/Quaternion"; +import { Vector3 } from "../../math/Vector3"; import { Object3DUtil } from "../../util/Object3DUtil"; +import { Time } from "../../util/Time"; +import { Vector3Ex } from "../../util/Vector3Ex"; +import { ComponentBase } from "../ComponentBase"; /** * Hovering camera controller @@ -99,7 +108,6 @@ export class HoverCameraController extends ComponentBase { */ constructor() { super(); - this.serializeTag = 'dont-serialize'; this._currentPos = new Object3D(); this._targetPos = new Object3D(); } diff --git a/src/engine/components/controller/ThirdPersonCameraController.ts b/src/engine/components/controller/ThirdPersonCameraController.ts index 921fd0ec..d5e541ed 100644 --- a/src/engine/components/controller/ThirdPersonCameraController.ts +++ b/src/engine/components/controller/ThirdPersonCameraController.ts @@ -1,4 +1,9 @@ -import { Camera3D, ComponentBase, Engine3D, Object3D, PointerEvent3D, Vector3 } from "../../.."; +import { Engine3D } from "../../Engine3D"; +import { Camera3D } from "../../core/Camera3D"; +import { Object3D } from "../../core/entities/Object3D"; +import { PointerEvent3D } from "../../event/eventConst/PointerEvent3D"; +import { Vector3 } from "../../math/Vector3"; +import { ComponentBase } from "../ComponentBase"; /** * @internal @@ -14,7 +19,6 @@ export class ThirdPersonCameraController extends ComponentBase { constructor() { super(); - this.serializeTag = 'dont-serialize'; } protected start() { diff --git a/src/engine/components/lights/LightBase.ts b/src/engine/components/lights/LightBase.ts index 219a3e80..b6b48618 100644 --- a/src/engine/components/lights/LightBase.ts +++ b/src/engine/components/lights/LightBase.ts @@ -8,7 +8,6 @@ import { GILighting } from './GILighting'; import { LightData } from './LightData'; import { ShadowLightsCollect } from '../../gfx/renderJob/collect/ShadowLightsCollect'; import { IESProfiles } from './IESProfiles'; -import { ComponentType } from '../../util/SerializeDefine'; /** * @internal @@ -52,7 +51,6 @@ export class LightBase extends ComponentBase { constructor() { super(); - this.componentType = ComponentType.light; } protected init(): void { diff --git a/src/engine/components/post/PostProcessingComponent.ts b/src/engine/components/post/PostProcessingComponent.ts index c03500be..5b81bb27 100644 --- a/src/engine/components/post/PostProcessingComponent.ts +++ b/src/engine/components/post/PostProcessingComponent.ts @@ -1,5 +1,6 @@ -import { Ctor, Engine3D } from "../../.."; +import { Engine3D } from "../../Engine3D"; import { PostBase } from "../../gfx/renderJob/post/PostBase"; +import { Ctor } from "../../util/Global"; import { ComponentBase } from "../ComponentBase"; export class PostProcessingComponent extends ComponentBase { diff --git a/src/engine/components/renderer/GlobalIlluminationComponent.ts b/src/engine/components/renderer/GlobalIlluminationComponent.ts deleted file mode 100644 index 1291d60c..00000000 --- a/src/engine/components/renderer/GlobalIlluminationComponent.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { Engine3D } from '../../Engine3D'; -import { GlobalBindGroup } from '../../gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup'; -import { EntityCollect } from '../../gfx/renderJob/collect/EntityCollect'; -import { DDGIIrradianceVolume } from '../../gfx/renderJob/passRenderer/ddgi/DDGIIrradianceVolume'; -import { Probe } from '../../gfx/renderJob/passRenderer/ddgi/Probe'; -import { Vector3 } from '../../math/Vector3'; -import { SphereGeometry } from '../../shape/SphereGeometry'; -import { ComponentBase } from '../ComponentBase'; -import { MeshRenderer } from './MeshRenderer'; -import { GIProbeMaterial, GIProbeMaterialType } from '../../materials/GIProbeMaterial'; -import { UnLitMaterial } from '../../materials/UnLitMaterial'; -import { Quaternion } from '../../math/Quaternion'; -import { ComponentType } from '../../util/SerializeDefine'; - -/** - * - * Global Illumination Component - * Use global illumination to achieve more realistic lighting. - * The global illumination system can model the way light reflects or refracts on the surface to other surfaces (indirect lighting), - * rather than limiting that light can only shine from the light source to a certain surface. - * @group Components - */ -export class GlobalIlluminationComponent extends ComponentBase { - public probes: Probe[]; - public volume: DDGIIrradianceVolume; - - private _debugMr: MeshRenderer[] = []; - protected init(): void { - Engine3D.setting.gi.enable = true; - } - - constructor() { - super(); - this.componentType = ComponentType.globalIllumination; - } - - protected start(): void { - this.volume = GlobalBindGroup.getLightEntries(this.transform.scene3D).irradianceVolume; - this.initProbe(); - } - - private initProbe() { - let xCount: number = this.volume.setting.probeXCount; - let yCount: number = this.volume.setting.probeYCount; - let zCount: number = this.volume.setting.probeZCount; - - - let debugGeo = new SphereGeometry(4, 16, 16); - let position: Vector3 = new Vector3(); - this.probes = []; - let unlitMat = new UnLitMaterial(); - for (let x = 0; x < xCount; x++) { - for (let y = 0; y < yCount; y++) { - for (let z = 0; z < zCount; z++) { - let index = x + z * xCount + y * (xCount * zCount); - let probe = new Probe(); - probe.index = index; - - probe.name = `${x}_${y}_${z}`; - let mr = probe.addComponent(MeshRenderer); - mr.material = new GIProbeMaterial(GIProbeMaterialType.CastGI, index); - // mr.material = new GIProbeMaterial(GIProbeMaterialType.CastDepth, index); - // mr.material = unlitMat; - mr.geometry = debugGeo; - mr.castGI = false; - mr.castShadow = false; - - this._debugMr.push(mr); - - this.object3D.addChild(probe); - - this.volume.calcPosition(x, y, z, position); - - probe.x = position.x; - probe.y = position.y; - probe.z = position.z; - - probe.transform.rotationX = 0; - probe.transform.rotationY = 0; - probe.transform.rotationZ = 0; - - this.probes[index] = probe; - - this._debugMr.push(mr); - } - } - } - - for (let i = 0; i < this.probes.length; i++) { - EntityCollect.instance.addGIProbe(this.transform.scene3D, this.probes[i]); - } - - this.object3D.transform.enable = false; - - if (this.volume.setting.debug) { - this.debug(); - } - } - - public debug() { - - } - - private _debugProbeRay(probeIndex: number, array: Float32Array) { - const rayNumber = Engine3D.setting.gi.rayNumber; - let quat = new Quaternion(0.0, -0.7071067811865475, 0.7071067811865475, 0.0); - for (let i = 0; i < rayNumber; i++) { - let ii = probeIndex * rayNumber + i; - let dir = new Vector3( - -array[ii * 4 + 0], - -array[ii * 4 + 1], - -array[ii * 4 + 2], - 0 - ); - quat.transformVector(dir, dir); - let len = array[ii * 4 + 3]; - let id = `showRays${probeIndex}${i}`; - - let start = this.probes[probeIndex].transform.worldPosition.clone(); - let end = dir.scaleBy(len); - end.add(start, end); - - //view.graphic3D.Clear(id); - //view.graphic3D..drawLines(id, [start, end], [new Color(0, 0, 0, 0), new Color(1.0, 1.0, 1.0, 1.0)]); - - } - } - - private changeProbesVolumeData(): void { - this.volume.setVolumeDataChange(); - } - - private changeProbesPosition(): void { - this.volume.setVolumeDataChange(); - let xCount: number = this.volume.setting.probeXCount; - let yCount: number = this.volume.setting.probeYCount; - let zCount: number = this.volume.setting.probeZCount; - let position: Vector3 = new Vector3(); - - for (let x = 0; x < xCount; x++) { - for (let y = 0; y < yCount; y++) { - for (let z = 0; z < zCount; z++) { - let index = x + z * xCount + y * (xCount * zCount); - let probe: Probe = this.probes[index]; - this.volume.calcPosition(x, y, z, position); - - probe.x = position.x; - probe.y = position.y; - probe.z = position.z; - } - } - } - } - - protected onUpdate(): void { - Engine3D.setting.gi.maxDistance = Engine3D.setting.gi.probeSpace * 1.5; - - let camera = this.transform.scene3D.view.camera; - let scale = Vector3.distance(camera.transform.worldPosition, camera.transform.targetPos) / 300; - // console.log(scale); - - if (this._debugMr && this._debugMr.length > 0) { - for (let i = 0; i < this._debugMr.length; i++) { - const debugOBJ = this._debugMr[i].transform; - debugOBJ.scaleX = scale; - debugOBJ.scaleY = scale; - debugOBJ.scaleZ = scale; - } - } - } -} diff --git a/src/engine/components/renderer/InstanceDrawComponent.ts b/src/engine/components/renderer/InstanceDrawComponent.ts index 62d549a5..b7bcfc82 100644 --- a/src/engine/components/renderer/InstanceDrawComponent.ts +++ b/src/engine/components/renderer/InstanceDrawComponent.ts @@ -2,12 +2,12 @@ import { GPUContext } from "../../gfx/renderJob/GPUContext"; import { RTResourceMap } from "../../gfx/renderJob/frame/RTResourceMap"; import { ClusterLightingRender } from "../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender"; import { RenderContext } from "../../gfx/renderJob/passRenderer/RenderContext"; -import { RendererPassState } from "../../gfx/renderJob/passRenderer/state/RendererPassState"; -import { RendererType } from "../../gfx/renderJob/passRenderer/state/RendererType"; import { MeshRenderer } from "./MeshRenderer"; import { RenderNode } from "./RenderNode"; import { StorageGPUBuffer } from "../../gfx/graphics/webGpu/core/buffer/StorageGPUBuffer"; import { View3D } from "../../core/View3D"; +import { RendererPassState } from "../../gfx/renderJob/passRenderer/state/RendererPassState"; +import { RendererType } from "../../gfx/renderJob/passRenderer/state/RendererType"; export class InstanceDrawComponent extends RenderNode { diff --git a/src/engine/components/renderer/MeshRenderer.ts b/src/engine/components/renderer/MeshRenderer.ts index bd14c652..a5585c6e 100644 --- a/src/engine/components/renderer/MeshRenderer.ts +++ b/src/engine/components/renderer/MeshRenderer.ts @@ -6,7 +6,6 @@ import { RendererMask } from '../../gfx/renderJob/passRenderer/state/RendererMas import { RendererPassState } from '../../gfx/renderJob/passRenderer/state/RendererPassState'; import { RendererType } from '../../gfx/renderJob/passRenderer/state/RendererType'; import { MaterialBase } from '../../materials/MaterialBase'; -import { ComponentType } from '../../util/SerializeDefine'; import { MorphTargetData } from '../anim/morphAnim/MorphTargetData'; import { RenderNode } from './RenderNode'; @@ -23,7 +22,6 @@ export class MeshRenderer extends RenderNode { constructor() { super(); - this.componentType = ComponentType.meshRenderer; } protected start(): void { } diff --git a/src/engine/components/renderer/RenderNode.ts b/src/engine/components/renderer/RenderNode.ts index f7e66737..db08d8cc 100644 --- a/src/engine/components/renderer/RenderNode.ts +++ b/src/engine/components/renderer/RenderNode.ts @@ -1,23 +1,23 @@ -import { GeometryBase } from '../../core/geometry/GeometryBase'; -import { PassGenerate } from '../../gfx/generate/PassGenerate'; -import { ShaderReflection } from '../../gfx/graphics/webGpu/shader/value/ShaderReflectionInfo'; -import { EntityCollect } from '../../gfx/renderJob/collect/EntityCollect'; -import { GPUContext } from '../../gfx/renderJob/GPUContext'; -import { ClusterLightingRender } from '../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender'; -import { RendererType } from '../../gfx/renderJob/passRenderer/state/RendererType'; -import { RendererMaskUtil, RendererMask } from '../../gfx/renderJob/passRenderer/state/RendererMask'; -import { RendererPassState } from '../../gfx/renderJob/passRenderer/state/RendererPassState'; -import { MaterialBase } from '../../materials/MaterialBase'; -import { ComponentBase } from '../ComponentBase'; -import { RenderContext } from '../../gfx/renderJob/passRenderer/RenderContext'; -import { Engine3D } from '../../Engine3D'; -import { View3D } from '../../core/View3D'; -import { GlobalBindGroup } from '../../gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup'; -import { RenderShader } from '../../gfx/graphics/webGpu/shader/RenderShader'; -import { RTResourceMap } from '../../gfx/renderJob/frame/RTResourceMap'; -import { UUID } from '../../util/Global'; -import { ComponentType } from '../../util/SerializeDefine'; -import { IESProfiles } from '../lights/IESProfiles'; +import { Engine3D } from "../../Engine3D"; +import { View3D } from "../../core/View3D"; +import { GeometryBase } from "../../core/geometry/GeometryBase"; +import { PassGenerate } from "../../gfx/generate/PassGenerate"; +import { GlobalBindGroup } from "../../gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup"; +import { RenderShader } from "../../gfx/graphics/webGpu/shader/RenderShader"; +import { ShaderReflection } from "../../gfx/graphics/webGpu/shader/value/ShaderReflectionInfo"; +import { GPUContext } from "../../gfx/renderJob/GPUContext"; +import { EntityCollect } from "../../gfx/renderJob/collect/EntityCollect"; +import { RTResourceMap } from "../../gfx/renderJob/frame/RTResourceMap"; +import { RenderContext } from "../../gfx/renderJob/passRenderer/RenderContext"; +import { ClusterLightingRender } from "../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender"; +import { RendererMask, RendererMaskUtil } from "../../gfx/renderJob/passRenderer/state/RendererMask"; +import { RendererPassState } from "../../gfx/renderJob/passRenderer/state/RendererPassState"; +import { RendererType } from "../../gfx/renderJob/passRenderer/state/RendererType"; +import { MaterialBase } from "../../materials/MaterialBase"; +import { UUID } from "../../util/Global"; +import { ComponentBase } from "../ComponentBase"; +import { IESProfiles } from "../lights/IESProfiles"; + /** * @internal @@ -45,7 +45,6 @@ export class RenderNode extends ComponentBase { constructor() { super(); - this.componentType = ComponentType.renderNode; this.rendererMask = RendererMask.Default; } @@ -425,9 +424,6 @@ export class RenderNode extends ComponentBase { let lightUniformEntries = GlobalBindGroup.getLightEntries(view.scene); if (lightUniformEntries) { renderShader.setStorageBuffer(`lightBuffer`, lightUniformEntries.storageGPUBuffer); - if (lightUniformEntries.irradianceVolume) { - renderShader.setStructStorageBuffer(`irradianceData`, lightUniformEntries.irradianceVolume.irradianceVolumeBuffer); - } } diff --git a/src/engine/components/renderer/SkinnedMeshRenderer.ts b/src/engine/components/renderer/SkinnedMeshRenderer.ts index ea77f59f..866d1d16 100644 --- a/src/engine/components/renderer/SkinnedMeshRenderer.ts +++ b/src/engine/components/renderer/SkinnedMeshRenderer.ts @@ -1,11 +1,12 @@ -import { Object3D } from '../../core/entities/Object3D'; -import { ClusterLightingRender } from '../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender'; -import { RendererType } from '../../gfx/renderJob/passRenderer/state/RendererType'; -import { RendererPassState } from '../../gfx/renderJob/passRenderer/state/RendererPassState'; -import { SkeletonAnimationComponent } from '../SkeletonAnimationComponent'; -import { MeshRenderer } from './MeshRenderer'; -import { RendererMask } from '../../gfx/renderJob/passRenderer/state/RendererMask'; -import { StorageGPUBuffer, View3D } from '../../..'; +import { View3D } from "../../core/View3D"; +import { Object3D } from "../../core/entities/Object3D"; +import { StorageGPUBuffer } from "../../gfx/graphics/webGpu/core/buffer/StorageGPUBuffer"; +import { ClusterLightingRender } from "../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender"; +import { RendererMask } from "../../gfx/renderJob/passRenderer/state/RendererMask"; +import { RendererPassState } from "../../gfx/renderJob/passRenderer/state/RendererPassState"; +import { RendererType } from "../../gfx/renderJob/passRenderer/state/RendererType"; +import { SkeletonAnimationComponent } from "../SkeletonAnimationComponent"; +import { MeshRenderer } from "./MeshRenderer"; /** * Skin Mesh Renderer Component diff --git a/src/engine/components/renderer/SkyRenderer.ts b/src/engine/components/renderer/SkyRenderer.ts index 41267069..2cd818c4 100644 --- a/src/engine/components/renderer/SkyRenderer.ts +++ b/src/engine/components/renderer/SkyRenderer.ts @@ -1,18 +1,18 @@ +import { Engine3D } from '../../Engine3D'; +import { View3D } from '../../core/View3D'; import { BoundingBox } from '../../core/bound/BoundingBox'; import { Texture } from '../../gfx/graphics/webGpu/core/texture/Texture'; import { EntityCollect } from '../../gfx/renderJob/collect/EntityCollect'; -import { SkyMaterial } from '../../materials/SkyMaterial'; -import { Vector3 } from '../../math/Vector3'; -import { MeshRenderer } from './MeshRenderer'; -import { RendererMask } from '../../gfx/renderJob/passRenderer/state/RendererMask'; import { ClusterLightingRender } from '../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender'; +import { RendererMask } from '../../gfx/renderJob/passRenderer/state/RendererMask'; import { RendererPassState } from '../../gfx/renderJob/passRenderer/state/RendererPassState'; -import { Engine3D } from '../../Engine3D'; -import { View3D } from '../../core/View3D'; import { RendererType } from '../../gfx/renderJob/passRenderer/state/RendererType'; +import { SkyMaterial } from '../../materials/SkyMaterial'; +import { Vector3 } from '../../math/Vector3'; import { SphereGeometry } from '../../shape/SphereGeometry'; -import { ComponentType } from '../../util/SerializeDefine'; +import { MeshRenderer } from './MeshRenderer'; + /** * * Sky Box Renderer Component @@ -26,7 +26,6 @@ export class SkyRenderer extends MeshRenderer { constructor() { super(); - this.componentType = ComponentType.skyRenderer; this.castShadow = false; this.castGI = true; this.addRendererMask(RendererMask.Sky); diff --git a/src/engine/components/shape/BoxColliderShape.ts b/src/engine/components/shape/BoxColliderShape.ts index 4f1e090b..1e57b40f 100644 --- a/src/engine/components/shape/BoxColliderShape.ts +++ b/src/engine/components/shape/BoxColliderShape.ts @@ -1,8 +1,9 @@ -import { BoundingBox } from '../../../core/bound/BoundingBox'; -import { Matrix4 } from '../../../math/Matrix4'; -import { Ray } from '../../../math/Ray'; -import { Vector3 } from '../../../math/Vector3'; -import { ColliderShape, ColliderShapeType } from './ColliderShape'; +import { BoundingBox } from "../../core/bound/BoundingBox"; +import { Matrix4 } from "../../math/Matrix4"; +import { Ray } from "../../math/Ray"; +import { Vector3 } from "../../math/Vector3"; +import { ColliderShape, ColliderShapeType } from "./ColliderShape"; + /** * Box shaped collision body. diff --git a/src/engine/components/shape/ColliderShape.ts b/src/engine/components/shape/ColliderShape.ts index eadbec52..6749e021 100644 --- a/src/engine/components/shape/ColliderShape.ts +++ b/src/engine/components/shape/ColliderShape.ts @@ -1,6 +1,7 @@ -import { Matrix4 } from '../../../math/Matrix4'; -import { Ray } from '../../../math/Ray'; -import { Vector3 } from '../../../math/Vector3'; +import { Matrix4 } from "../../math/Matrix4"; +import { Ray } from "../../math/Ray"; +import { Vector3 } from "../../math/Vector3"; + export enum ColliderShapeType { None, diff --git a/src/engine/components/shape/MeshColliderShape.ts b/src/engine/components/shape/MeshColliderShape.ts index fdc76cbe..79a037ff 100644 --- a/src/engine/components/shape/MeshColliderShape.ts +++ b/src/engine/components/shape/MeshColliderShape.ts @@ -1,4 +1,4 @@ -import { MeshComponent } from '../../renderer/MeshComponent'; +import { MeshComponent } from '../renderer/MeshComponent'; import { ColliderShape, ColliderShapeType } from './ColliderShape'; /** * Mesh collision body diff --git a/src/engine/components/shape/SphereColliderShape.ts b/src/engine/components/shape/SphereColliderShape.ts index 5daf06bf..55900262 100644 --- a/src/engine/components/shape/SphereColliderShape.ts +++ b/src/engine/components/shape/SphereColliderShape.ts @@ -1,8 +1,9 @@ -import { ColliderShape, ColliderShapeType } from './ColliderShape'; -import { Matrix4 } from '../../../math/Matrix4'; -import { Ray } from '../../../math/Ray'; -import { Vector3 } from '../../../math/Vector3'; -import { BoundingSphere } from '../../../core/bound/BoundingSphere'; +import { BoundingSphere } from "../../core/bound/BoundingSphere"; +import { Matrix4 } from "../../math/Matrix4"; +import { Ray } from "../../math/Ray"; +import { Vector3 } from "../../math/Vector3"; +import { ColliderShape, ColliderShapeType } from "./ColliderShape"; + /** * Spherical collision body diff --git a/src/engine/core/CubeCamera.ts b/src/engine/core/CubeCamera.ts index 0a287425..6aa491a3 100644 --- a/src/engine/core/CubeCamera.ts +++ b/src/engine/core/CubeCamera.ts @@ -1,7 +1,7 @@ -import { CameraType } from '../..'; import { Vector3 } from '../math/Vector3'; import { CameraUtil } from '../util/CameraUtil'; import { Camera3D } from './Camera3D'; +import { CameraType } from './CameraType'; import { Object3D } from './entities/Object3D'; /** diff --git a/src/engine/core/Scene3D.ts b/src/engine/core/Scene3D.ts index 727bd29a..8a75d6df 100644 --- a/src/engine/core/Scene3D.ts +++ b/src/engine/core/Scene3D.ts @@ -23,7 +23,6 @@ export class Scene3D extends Object3D { super(); this.transform.scene3D = this; this.skyObject = new Object3D(); - this.skyObject.serializeTag = "dont-serialize"; this.addChild(this.skyObject); this._isScene3D = true; this.envMap ||= defaultRes.defaultSky; diff --git a/src/engine/core/View3D.ts b/src/engine/core/View3D.ts index 5483f9e6..b59f4bb5 100644 --- a/src/engine/core/View3D.ts +++ b/src/engine/core/View3D.ts @@ -1,5 +1,6 @@ -import { Engine3D, Graphic3D, Object3D, PickUI, UICanvas } from "../.."; +import { Engine3D } from "../Engine3D"; import { CEventListener } from "../event/CEventListener"; +import { Graphic3D } from "../gfx/renderJob/passRenderer/graphic/Graphic3DRender"; import { PickFire } from "../io/PickFire"; import { Vector4 } from "../math/Vector4"; import { Camera3D } from "./Camera3D"; @@ -10,9 +11,7 @@ export class View3D extends CEventListener { private _scene: Scene3D; private _viewPort: Vector4; private _enablePick: boolean = false; - public pickUI: PickUI; public pickFire: PickFire; - public canvas: UICanvas; constructor(x: number = 0, y: number = 0, width: number = 0, height: number = 0) { super(); @@ -38,18 +37,12 @@ export class View3D extends CEventListener { public set scene(value: Scene3D) { this._scene = value; value.view = this; - - if (value && this.canvas) - value.addChild(this.canvas.object3D); } public get camera(): Camera3D { return this._camera; } public set camera(value: Camera3D) { this._camera = value; - - if (this.canvas) - this.canvas.camera = this.camera; } public get viewPort(): Vector4 { return this._viewPort; @@ -58,26 +51,6 @@ export class View3D extends CEventListener { this._viewPort = value; } - public enableGUI(): UICanvas { - let obj = new Object3D(); - obj.name = 'GUIManager'; - obj.serializeTag = 'dont-serialize'; - this.canvas = obj.addComponent(UICanvas); - this.canvas.camera = this.camera; - this.scene.addChild(obj); - - this.pickUI = new PickUI(); - this.pickUI.init(this); - - return this.canvas; - } - - public disableGUI() { - if (this.canvas.transform.parent) { - this.canvas.transform.parent.object3D.removeChild(this.canvas.object3D); - } - } - public get graphic3D(): Graphic3D { return Engine3D.getRenderJob(this).graphic3D; } diff --git a/src/engine/core/ViewQuad.ts b/src/engine/core/ViewQuad.ts index 93655478..5a599a65 100644 --- a/src/engine/core/ViewQuad.ts +++ b/src/engine/core/ViewQuad.ts @@ -7,7 +7,6 @@ import { WebGPUDescriptorCreator } from '../gfx/graphics/webGpu/descriptor/WebGP import { GPUCompareFunction } from '../gfx/graphics/webGpu/WebGPUConst'; import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; import { RTFrame } from '../gfx/renderJob/frame/RTFrame'; -import { RendererPassState } from '../gfx/renderJob/passRenderer/state/RendererPassState'; import { BlendMode } from '../materials/BlendMode'; import { MaterialBase } from '../materials/MaterialBase'; import { Color } from '../math/Color'; @@ -15,6 +14,7 @@ import { PlaneGeometry } from '../shape/PlaneGeometry'; import { defaultRes } from '../textures/DefaultRes'; import { VirtualTexture } from '../textures/VirtualTexture'; import { Object3D } from './entities/Object3D'; +import { RendererPassState } from '../gfx/renderJob/passRenderer/state/RendererPassState'; /** * @internal * @group Entity diff --git a/src/engine/core/bound/BoundingBox.ts b/src/engine/core/bound/BoundingBox.ts index 4a6def06..a11622f1 100644 --- a/src/engine/core/bound/BoundingBox.ts +++ b/src/engine/core/bound/BoundingBox.ts @@ -1,7 +1,7 @@ -import { Frustum } from '../../..'; import { Ray } from '../../math/Ray'; import { Vector3 } from '../../math/Vector3'; import { Object3D } from '../entities/Object3D'; +import { Frustum } from './Frustum'; import { IBound } from './IBound'; /** diff --git a/src/engine/core/entities/Object3D.ts b/src/engine/core/entities/Object3D.ts index 941adf31..65ef26df 100644 --- a/src/engine/core/entities/Object3D.ts +++ b/src/engine/core/entities/Object3D.ts @@ -4,14 +4,12 @@ import { Quaternion } from '../../math/Quaternion'; import { Vector3 } from '../../math/Vector3'; import { Entity } from './Entity'; import { Ctor } from "../../util/Global"; -import { SerializeTag } from '../../util/SerializeDefine'; /** * The base class of most objects provides a series of properties and methods for manipulating objects in three-dimensional space. * @group Entity */ export class Object3D extends Entity { protected _isScene3D: boolean; - public serializeTag?: SerializeTag; public prefabRef?: string; /** diff --git a/src/engine/core/geometry/GeometryBase.ts b/src/engine/core/geometry/GeometryBase.ts index 4c629a81..e1fd6b2f 100644 --- a/src/engine/core/geometry/GeometryBase.ts +++ b/src/engine/core/geometry/GeometryBase.ts @@ -6,8 +6,8 @@ import { BoundingBox } from "../bound/BoundingBox"; import { VertexAttributeName } from "./VertexAttributeName"; import { GeometryVertexBuffer } from "./GeometryVertexBuffer"; import { GeometryIndicesBuffer } from "./GeometryIndicesBuffer"; -import { VertexAttributeData } from "../../.."; import { GeometryVertexType } from "./GeometryVertexType"; +import { VertexAttributeData } from "./VertexAttributeData"; export type LodLevel = { indexStart: number; diff --git a/src/engine/core/geometry/VertexAttributeData.ts b/src/engine/core/geometry/VertexAttributeData.ts index 915fe22c..9d4595e6 100644 --- a/src/engine/core/geometry/VertexAttributeData.ts +++ b/src/engine/core/geometry/VertexAttributeData.ts @@ -1,4 +1,4 @@ -import { ArrayBufferData } from "../../.."; +import { ArrayBufferData } from "../../gfx/graphics/webGpu/core/buffer/GPUBufferBase"; export type VertexAttributeData = { attribute: string, diff --git a/src/engine/event/CEvent.ts b/src/engine/event/CEvent.ts index 65e2503b..1eeaa660 100644 --- a/src/engine/event/CEvent.ts +++ b/src/engine/event/CEvent.ts @@ -1,4 +1,5 @@ -import { Object3D, View3D } from '../..'; +import { View3D } from '../core/View3D'; +import { Object3D } from '../core/entities/Object3D'; import { TouchData } from '../io/TouchData'; import { CEventListener } from './CEventListener'; /** diff --git a/src/engine/gfx/generate/PassGenerate.ts b/src/engine/gfx/generate/PassGenerate.ts index 7b037461..a84d21e0 100644 --- a/src/engine/gfx/generate/PassGenerate.ts +++ b/src/engine/gfx/generate/PassGenerate.ts @@ -1,12 +1,14 @@ import { RenderNode } from '../../components/renderer/RenderNode'; -import { DepthMaterialPass } from '../../materials/multiPass/DepthMaterialPass'; -import { CastShadowMaterialPass } from '../../materials/multiPass/CastShadowMaterialPass'; -import { RendererType } from '../renderJob/passRenderer/state/RendererType'; -import { RendererMask, RendererMaskUtil } from '../renderJob/passRenderer/state/RendererMask'; import { GLTFParser } from '../../loader/parser/gltf/GLTFParser'; -import { SkyGBufferPass } from '../../materials/multiPass/SkyGBufferPass'; -import { Color, ColorLitMaterial, GBufferPass, MaterialBase, RenderShader } from '../../..'; +import { MaterialBase } from '../../materials/MaterialBase'; import { CastPointShadowMaterialPass } from '../../materials/multiPass/CastPointShadowMaterialPass'; +import { CastShadowMaterialPass } from '../../materials/multiPass/CastShadowMaterialPass'; +import { DepthMaterialPass } from '../../materials/multiPass/DepthMaterialPass'; +import { GBufferPass } from '../../materials/multiPass/GBufferPass'; +import { SkyGBufferPass } from '../../materials/multiPass/SkyGBufferPass'; +import { RendererMaskUtil, RendererMask } from '../renderJob/passRenderer/state/RendererMask'; +import { RendererType } from '../renderJob/passRenderer/state/RendererType'; + /** * @internal * @group GFX diff --git a/src/engine/gfx/generate/convert/ErpImage2CubeMap.ts b/src/engine/gfx/generate/convert/ErpImage2CubeMap.ts index 8db7ded8..a7d1e4b0 100644 --- a/src/engine/gfx/generate/convert/ErpImage2CubeMap.ts +++ b/src/engine/gfx/generate/convert/ErpImage2CubeMap.ts @@ -1,10 +1,10 @@ -import { GPUContext } from '../../../..'; import ErpImage2CubeMapCreateCube_compute from '../../../assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl?raw'; import ErpImage2CubeMapRgbe2rgba_compute from '../../../assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl?raw'; import { VirtualTexture } from '../../../textures/VirtualTexture'; import { Texture } from '../../graphics/webGpu/core/texture/Texture'; import { webGPUContext } from '../../graphics/webGpu/Context3D'; import { TextureCubeUtils } from './TextureCubeUtils'; +import { GPUContext } from '../../renderJob/GPUContext'; /** * @internal * @group GFX diff --git a/src/engine/gfx/generate/convert/IBLEnvMapCreator.ts b/src/engine/gfx/generate/convert/IBLEnvMapCreator.ts index 60bc52b0..9477a05b 100644 --- a/src/engine/gfx/generate/convert/IBLEnvMapCreator.ts +++ b/src/engine/gfx/generate/convert/IBLEnvMapCreator.ts @@ -2,7 +2,8 @@ import { Texture } from '../../graphics/webGpu/core/texture/Texture'; import { webGPUContext } from '../../graphics/webGpu/Context3D'; import IBLEnvMapCreator_compute from '../../../assets/shader/compute/IBLEnvMapCreator_compute.wgsl?raw'; import { TextureCubeUtils } from './TextureCubeUtils'; -import { GPUContext } from '../../../..'; +import { GPUContext } from '../../renderJob/GPUContext'; + /** * @internal * @group GFX diff --git a/src/engine/gfx/generate/convert/TextureCubeStdCreator.ts b/src/engine/gfx/generate/convert/TextureCubeStdCreator.ts index 8ff70551..cbad6d1e 100644 --- a/src/engine/gfx/generate/convert/TextureCubeStdCreator.ts +++ b/src/engine/gfx/generate/convert/TextureCubeStdCreator.ts @@ -1,6 +1,7 @@ import { Texture } from '../../graphics/webGpu/core/texture/Texture'; import { webGPUContext } from '../../graphics/webGpu/Context3D'; -import { GPUContext, VirtualTexture } from '../../../..'; +import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { GPUContext } from '../../renderJob/GPUContext'; /** * @internal diff --git a/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts b/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts index 1a177369..c7a6ccc3 100644 --- a/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts +++ b/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts @@ -1,3 +1,5 @@ +import { Camera3D } from "../../../../../core/Camera3D"; +import { Scene3D } from "../../../../../core/Scene3D"; import { GlobalUniformGroup } from "./GlobalUniformGroup"; import { LightEntries } from "./groups/LightEntries"; import { MatrixBindGroup } from "./MatrixBindGroup"; diff --git a/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts b/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts index 8558a48c..3df006b0 100644 --- a/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts +++ b/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts @@ -1,3 +1,13 @@ +import { Engine3D } from "../../../../../Engine3D"; +import { Camera3D } from "../../../../../core/Camera3D"; +import { Matrix4 } from "../../../../../math/Matrix4"; +import { UUID } from "../../../../../util/Global"; +import { Time } from "../../../../../util/Time"; +import { ShadowLightsCollect } from "../../../../renderJob/collect/ShadowLightsCollect"; +import { webGPUContext } from "../../Context3D"; +import { UniformGPUBuffer } from "../buffer/UniformGPUBuffer"; +import { GlobalBindGroupLayout } from "./GlobalBindGroupLayout"; +import { MatrixBindGroup } from "./MatrixBindGroup"; /** diff --git a/src/engine/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts b/src/engine/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts index 1f146ba5..71a0711d 100644 --- a/src/engine/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts +++ b/src/engine/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts @@ -1,13 +1,20 @@ //TODO dynamic lights need fixed + +import { Engine3D } from "../../../../../../Engine3D"; +import { LightData } from "../../../../../../components/lights/LightData"; +import { View3D } from "../../../../../../core/View3D"; +import { MemoryInfo } from "../../../../../../core/pool/memory/MemoryInfo"; +import { EntityCollect } from "../../../../../renderJob/collect/EntityCollect"; +import { StorageGPUBuffer } from "../../buffer/StorageGPUBuffer"; + /** * @internal * @group GFX */ export class LightEntries { public storageGPUBuffer: StorageGPUBuffer; - public irradianceVolume: DDGIIrradianceVolume; private _lightList: MemoryInfo[] = []; constructor() { @@ -20,10 +27,7 @@ export class LightEntries { let memory = this.storageGPUBuffer.memory.allocation_node(LightData.lightSize * 4); this._lightList.push(memory); } - this.storageGPUBuffer.visibility = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; - this.irradianceVolume = new DDGIIrradianceVolume(); - this.irradianceVolume.init(Engine3D.setting.gi); } public update(view: View3D) { diff --git a/src/engine/gfx/graphics/webGpu/core/bindGroups/groups/ProbeEntries.ts b/src/engine/gfx/graphics/webGpu/core/bindGroups/groups/ProbeEntries.ts deleted file mode 100644 index 6d3eb90a..00000000 --- a/src/engine/gfx/graphics/webGpu/core/bindGroups/groups/ProbeEntries.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { MemoryDO } from '../../../../../../core/pool/memory/MemoryDO'; -import { MemoryInfo } from '../../../../../../core/pool/memory/MemoryInfo'; -import { Probe } from '../../../../../renderJob/passRenderer/ddgi/Probe'; -import { webGPUContext } from '../../../Context3D'; -/** - * @internal - * @group GFX - */ -export class ProbeEntries { - public gpuBuffer: GPUBuffer; - public probes: Probe[]; - public memoryDo: MemoryDO; - private _probeInfoList: MemoryInfo[]; - - public initDataUniform(probes: Probe[]) { - this.memoryDo = new MemoryDO(); - this.probes = probes; - this._probeInfoList = []; - - let len = 0; - this.memoryDo.destroy(); - this.memoryDo.allocation(probes.length * 17 * 4); - for (let i = 0; i < probes.length; i++) { - var size = 17; - len += size; - let memoryInfo = this.memoryDo.allocation_node(size * 4); - this._probeInfoList.push(memoryInfo); - - let probeWorldPos = probes[i].transform.worldPosition; - memoryInfo.setArray(0, [probeWorldPos.x, probeWorldPos.y, probeWorldPos.z]); - } - - len = Math.max(64, len); - - this.gpuBuffer = webGPUContext.device.createBuffer({ - size: this.memoryDo.shareDataBuffer.byteLength, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE, - label: 'ProbeBuffer', - mappedAtCreation: false, - }); - } - - private updateGPUBuffer() { - const bufferData = this.memoryDo.shareDataBuffer; - let totalBytes = this.memoryDo.shareDataBuffer.byteLength; - let offsetBytes = 0;//this.memoryDo.shareDataBuffer.byteOffset; - const space = 5000 * 64; - while (offsetBytes < totalBytes) { - webGPUContext.device.queue.writeBuffer(this.gpuBuffer, offsetBytes, bufferData, offsetBytes, Math.floor(Math.min(space, totalBytes - offsetBytes))); - offsetBytes += space; - } - } -} diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts b/src/engine/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts index 718ade80..f10e54c7 100644 --- a/src/engine/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts +++ b/src/engine/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts @@ -1,4 +1,13 @@ -import { Color, GPUContext, Matrix4, MemoryDO, MemoryInfo, Quaternion, Struct, Vector2, Vector3, Vector4 } from "../../../../../.."; +import { MemoryDO } from "../../../../../core/pool/memory/MemoryDO"; +import { MemoryInfo } from "../../../../../core/pool/memory/MemoryInfo"; +import { Color } from "../../../../../math/Color"; +import { Matrix4 } from "../../../../../math/Matrix4"; +import { Quaternion } from "../../../../../math/Quaternion"; +import { Vector2 } from "../../../../../math/Vector2"; +import { Vector3 } from "../../../../../math/Vector3"; +import { Vector4 } from "../../../../../math/Vector4"; +import { Struct } from "../../../../../util/struct/Struct"; +import { GPUContext } from "../../../../renderJob/GPUContext"; import { webGPUContext } from "../../Context3D"; export type ArrayBufferData = Uint8Array | Uint16Array | Uint32Array | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array @@ -16,7 +25,7 @@ export class GPUBufferBase { public byteSize: number; public usage: GPUBufferUsageFlags; public visibility: number = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; - + private _readBuffer: GPUBuffer; constructor() { @@ -333,7 +342,7 @@ export class GPUBufferBase { } private _readFlag: boolean = false; - private readBuffer() { + public readBuffer() { if (!this._readBuffer) { this._readBuffer = webGPUContext.device.createBuffer({ size: this.memory.shareDataBuffer.byteLength, diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts b/src/engine/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts index 216a3b87..76facef3 100644 --- a/src/engine/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts +++ b/src/engine/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts @@ -1,6 +1,3 @@ -import { ShaderReflectionStructInfo } from '../../../../../..'; -import { MemoryDO } from '../../../../../core/pool/memory/MemoryDO'; -import { webGPUContext } from '../../Context3D'; import { UniformNode } from '../uniforms/UniformNode'; import { GPUBufferBase } from './GPUBufferBase'; /** diff --git a/src/engine/gfx/graphics/webGpu/core/texture/Texture.ts b/src/engine/gfx/graphics/webGpu/core/texture/Texture.ts index 46f45163..1679b6ab 100644 --- a/src/engine/gfx/graphics/webGpu/core/texture/Texture.ts +++ b/src/engine/gfx/graphics/webGpu/core/texture/Texture.ts @@ -1,6 +1,5 @@ import { webGPUContext } from "../../Context3D"; import { GPUAddressMode } from "../../WebGPUConst"; -import { SerializeTextureSource } from "./SerializeTextureSource"; import { TextureMipmapGenerator } from "./TextureMipmapGenerator"; /** @@ -9,7 +8,6 @@ import { TextureMipmapGenerator } from "./TextureMipmapGenerator"; */ export class Texture implements GPUSamplerDescriptor { - public readonly textureSource: SerializeTextureSource = new SerializeTextureSource(); /** * name of texture */ diff --git a/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapCompute.ts b/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapCompute.ts index 1ad92bc1..84fada1e 100644 --- a/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapCompute.ts +++ b/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapCompute.ts @@ -1,4 +1,4 @@ -import { GPUContext } from '../../../../../..'; +import { GPUContext } from '../../../../renderJob/GPUContext'; import { webGPUContext } from '../../Context3D'; import { Texture } from './Texture'; diff --git a/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapGenerator.ts b/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapGenerator.ts index a8b3e384..1791ea2f 100644 --- a/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapGenerator.ts +++ b/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapGenerator.ts @@ -1,4 +1,4 @@ -import { GPUContext } from '../../../../../..'; +import { GPUContext } from '../../../../renderJob/GPUContext'; import { webGPUContext } from '../../Context3D'; import { Texture } from './Texture'; /** diff --git a/src/engine/gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator.ts b/src/engine/gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator.ts index 21a99b80..4e3b43c1 100644 --- a/src/engine/gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator.ts +++ b/src/engine/gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator.ts @@ -2,7 +2,7 @@ import { RTFrame } from '../../../renderJob/frame/RTFrame'; import { RTResourceConfig } from '../../../renderJob/config/RTResourceConfig'; import { GPUTextureFormat } from '../WebGPUConst'; import { webGPUContext } from '../Context3D'; -import { RendererPassState } from '../../../renderJob/state/RendererPassState'; +import { RendererPassState } from '../../../renderJob/passRenderer/state/RendererPassState'; /** * @internal * @author sirxu diff --git a/src/engine/gfx/graphics/webGpu/shader/RenderShader.ts b/src/engine/gfx/graphics/webGpu/shader/RenderShader.ts index fabaa1fd..90ca4cca 100644 --- a/src/engine/gfx/graphics/webGpu/shader/RenderShader.ts +++ b/src/engine/gfx/graphics/webGpu/shader/RenderShader.ts @@ -22,8 +22,8 @@ import { ShaderStage } from "./ShaderStage"; import { Preprocessor } from "./util/Preprocessor"; import { ShaderReflection, ShaderReflectionVarInfo } from "./value/ShaderReflectionInfo"; import { ShaderState } from "./value/ShaderState"; -import { RendererPassState } from "../../../renderJob/state/RendererPassState"; -import { RendererType } from "../../../renderJob/state/RendererType"; +import { RendererPassState } from "../../../renderJob/passRenderer/state/RendererPassState"; +import { RendererType } from "../../../renderJob/passRenderer/state/RendererType"; export class RenderShader extends ShaderBase { public useRz: boolean = false; @@ -356,9 +356,7 @@ export class RenderShader extends ShaderBase { */ public applyPostDefine(shader: string, renderPassState: RendererPassState) { //*********************************/ - //添加渲染输出附件******************/ - - //TODO 需要修改细节版本 + //******************/ if (Engine3D.setting.pick.mode == `pixel`) { this.defineValue[`USE_WORLDPOS`] = true; } diff --git a/src/engine/gfx/graphics/webGpu/shader/value/ShaderReflectionInfo.ts b/src/engine/gfx/graphics/webGpu/shader/value/ShaderReflectionInfo.ts index f9cefe31..1e10551d 100644 --- a/src/engine/gfx/graphics/webGpu/shader/value/ShaderReflectionInfo.ts +++ b/src/engine/gfx/graphics/webGpu/shader/value/ShaderReflectionInfo.ts @@ -1,5 +1,5 @@ -import { VertexFormat } from '../../../../../..'; import { VertexAttributeSize } from '../../../../../core/geometry/VertexAttributeSize'; +import { VertexFormat } from '../../../../../core/geometry/VertexFormat'; import { ComputeShader } from '../ComputeShader'; import { RenderShader } from '../RenderShader'; import { ShaderBase } from '../ShaderBase'; diff --git a/src/engine/gfx/renderJob/GPUContext.ts b/src/engine/gfx/renderJob/GPUContext.ts index 45193ae5..75361633 100644 --- a/src/engine/gfx/renderJob/GPUContext.ts +++ b/src/engine/gfx/renderJob/GPUContext.ts @@ -1,13 +1,16 @@ -import { ProfilerUtil, RenderShader, View3D } from '../../..'; -import { Camera3D } from '../../core/Camera3D'; -import { GeometryBase } from '../../core/geometry/GeometryBase'; -import { ViewQuad } from '../../core/ViewQuad'; -import { GlobalBindGroup } from '../graphics/webGpu/core/bindGroups/GlobalBindGroup'; -import { Texture } from '../graphics/webGpu/core/texture/Texture'; -import { ComputeShader } from '../graphics/webGpu/shader/ComputeShader'; -import { webGPUContext } from '../graphics/webGpu/Context3D'; -import { RendererType } from './passRenderer/state/RendererType'; -import { RendererPassState } from './passRenderer/state/RendererPassState'; +import { Camera3D } from "../../core/Camera3D"; +import { View3D } from "../../core/View3D"; +import { ViewQuad } from "../../core/ViewQuad"; +import { GeometryBase } from "../../core/geometry/GeometryBase"; +import { ProfilerUtil } from "../../util/ProfilerUtil"; +import { webGPUContext } from "../graphics/webGpu/Context3D"; +import { GlobalBindGroup } from "../graphics/webGpu/core/bindGroups/GlobalBindGroup"; +import { Texture } from "../graphics/webGpu/core/texture/Texture"; +import { ComputeShader } from "../graphics/webGpu/shader/ComputeShader"; +import { RenderShader } from "../graphics/webGpu/shader/RenderShader"; +import { RendererPassState } from "./passRenderer/state/RendererPassState"; +import { RendererType } from "./passRenderer/state/RendererType"; + /** * WebGPU api use context diff --git a/src/engine/gfx/renderJob/collect/EntityCollect.ts b/src/engine/gfx/renderJob/collect/EntityCollect.ts index d2f2d090..bf4eba4f 100644 --- a/src/engine/gfx/renderJob/collect/EntityCollect.ts +++ b/src/engine/gfx/renderJob/collect/EntityCollect.ts @@ -1,9 +1,9 @@ -import { Graphic3DBatchRenderer, Graphic3DFillRenderer, Graphic3DLineBatchRenderer, ReflectionProbeComponent, RendererMaskUtil, RenderLayer, RenderLayerUtil } from '../../../..'; import { LightBase } from '../../../components/lights/LightBase'; import { RenderNode } from '../../../components/renderer/RenderNode'; import { SkyRenderer } from '../../../components/renderer/SkyRenderer'; import { Scene3D } from '../../../core/Scene3D'; -import { Probe } from '../passRenderer/ddgi/Probe'; +import { RenderLayerUtil, RenderLayer } from '../config/RenderLayer'; +import { Graphic3DBatchRenderer } from '../passRenderer/graphic/Graphic3DBatchRenderer'; import { CollectInfo } from './CollectInfo'; import { EntityBatchCollect } from './EntityBatchCollect'; import { RenderGroup } from './RenderGroup'; @@ -14,8 +14,6 @@ import { RenderGroup } from './RenderGroup'; export class EntityCollect { // private static _sceneRenderList: Map; private _sceneLights: Map; - private _sceneGIProbes: Map; - private _sceneReflectionProbes: Map; private _source_opaqueRenderNodes: Map; private _source_transparentRenderNodes: Map; @@ -49,8 +47,6 @@ export class EntityCollect { constructor() { // this._sceneRenderList = new Map(); this._sceneLights = new Map(); - this._sceneGIProbes = new Map(); - this._sceneReflectionProbes = new Map(); this._source_opaqueRenderNodes = new Map(); this._source_transparentRenderNodes = new Map(); @@ -161,60 +157,11 @@ export class EntityCollect { } } } - - public addGIProbe(root: Scene3D, probe: Probe) { - if (!this._sceneGIProbes.has(root)) { - this._sceneGIProbes.set(root, [probe]); - } else { - this._sceneGIProbes.get(root).push(probe); - } - } - - public removeGIProbe(root: Scene3D, probe: Probe) { - if (this._sceneGIProbes.has(root)) { - let list = this._sceneGIProbes.get(root); - let index = list.indexOf(probe); - if (index != -1) { - list.splice(index, 1); - } - } - } - - - public addReflectionProbe(root: Scene3D, probe: ReflectionProbeComponent) { - if (!this._sceneReflectionProbes.has(root)) { - this._sceneReflectionProbes.set(root, [probe]); - } else { - this._sceneReflectionProbes.get(root).push(probe); - } - } - - public removeReflectionProbe(root: Scene3D, probe: ReflectionProbeComponent) { - if (this._sceneReflectionProbes.has(root)) { - let list = this._sceneReflectionProbes.get(root); - let index = list.indexOf(probe); - if (index != -1) { - list.splice(index, 1); - } - } - } - public getLights(root: Scene3D): LightBase[] { let list = this._sceneLights.get(root); return list ? list : []; } - public getProbes(root: Scene3D) { - let list = this._sceneGIProbes.get(root); - return list ? list : []; - } - - public getReflectionProbes(root: Scene3D) { - let list = this._sceneReflectionProbes.get(root); - return list ? list : []; - } - - public getRenderNodes(scene: Scene3D): CollectInfo { this._collectInfo.clean(); this._collectInfo.sky = this.sky; diff --git a/src/engine/gfx/renderJob/collect/ShadowLightsCollect.ts b/src/engine/gfx/renderJob/collect/ShadowLightsCollect.ts index 6b8d40a0..4da99259 100644 --- a/src/engine/gfx/renderJob/collect/ShadowLightsCollect.ts +++ b/src/engine/gfx/renderJob/collect/ShadowLightsCollect.ts @@ -1,9 +1,11 @@ -import { CameraUtil, Engine3D, UUID } from '../../../..'; +import { Engine3D } from '../../../Engine3D'; import { DirectLight } from '../../../components/lights/DirectLight'; import { LightBase } from '../../../components/lights/LightBase'; import { LightType } from '../../../components/lights/LightData'; import { Scene3D } from '../../../core/Scene3D'; import { View3D } from '../../../core/View3D'; +import { CameraUtil } from '../../../util/CameraUtil'; +import { UUID } from '../../../util/Global'; /** * @internal * @group Lights diff --git a/src/engine/gfx/renderJob/color/ColorPassRenderer.ts b/src/engine/gfx/renderJob/color/ColorPassRenderer.ts index 2bc130ec..89ac1341 100644 --- a/src/engine/gfx/renderJob/color/ColorPassRenderer.ts +++ b/src/engine/gfx/renderJob/color/ColorPassRenderer.ts @@ -1,9 +1,14 @@ -import { Engine3D } from '../../../../Engine3D'; -import { RendererBase } from '../RendererBase'; -import { RendererType } from '../state/RendererType'; -import { OcclusionSystem } from '../../occlusion/OcclusionSystem'; -import { EntityCollect, GPUContext, RenderContext, RenderNode, RTResourceMap, View3D } from '../../../../..'; -import { ProfilerUtil } from '../../../../util/ProfilerUtil'; +import { Engine3D } from "../../../Engine3D"; +import { RenderNode } from "../../../components/renderer/RenderNode"; +import { View3D } from "../../../core/View3D"; +import { ProfilerUtil } from "../../../util/ProfilerUtil"; +import { GPUContext } from "../GPUContext"; +import { EntityCollect } from "../collect/EntityCollect"; +import { OcclusionSystem } from "../occlusion/OcclusionSystem"; +import { RenderContext } from "../passRenderer/RenderContext"; +import { RendererBase } from "../passRenderer/RendererBase"; +import { RendererType } from "../passRenderer/state/RendererType"; + /** * @internal diff --git a/src/engine/gfx/renderJob/frame/ProbeGBufferFrame.ts b/src/engine/gfx/renderJob/frame/ProbeGBufferFrame.ts index 5b635823..7dd09e01 100644 --- a/src/engine/gfx/renderJob/frame/ProbeGBufferFrame.ts +++ b/src/engine/gfx/renderJob/frame/ProbeGBufferFrame.ts @@ -1,6 +1,8 @@ -import { RTDescriptor, RTFrame, VirtualTexture } from "../../../.."; +import { VirtualTexture } from "../../../textures/VirtualTexture"; import { GPUTextureFormat } from "../../graphics/webGpu/WebGPUConst"; +import { RTDescriptor } from "../../graphics/webGpu/descriptor/RTDescriptor"; import { RTResourceConfig } from "../config/RTResourceConfig"; +import { RTFrame } from "./RTFrame"; import { RTResourceMap } from "./RTResourceMap"; export class ProbeGBufferFrame extends RTFrame { diff --git a/src/engine/gfx/renderJob/jobs/ForwardRenderJob.ts b/src/engine/gfx/renderJob/jobs/ForwardRenderJob.ts index 9766cb40..9a04cf75 100644 --- a/src/engine/gfx/renderJob/jobs/ForwardRenderJob.ts +++ b/src/engine/gfx/renderJob/jobs/ForwardRenderJob.ts @@ -1,9 +1,8 @@ -import { defaultRes, GBufferFrame, View3D } from '../../../..'; -import { Scene3D } from '../../../core/Scene3D'; import { Engine3D } from '../../../Engine3D'; +import { View3D } from '../../../core/View3D'; import { GlobalBindGroup } from '../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; -import { ColorPassRenderer } from '../passRenderer/color/ColorPassRenderer'; -import { DDGIProbeRenderer } from '../passRenderer/ddgi/DDGIProbeRenderer'; +import { ColorPassRenderer } from '../color/ColorPassRenderer'; +import { GBufferFrame } from '../frame/GBufferFrame'; import { RendererJob } from './RendererJob'; /** * Forward+ @@ -33,25 +32,25 @@ export class ForwardRenderJob extends RendererJob { colorPassRenderer.setRenderStates(rtFrame); if (Engine3D.setting.gi.enable) { - this.ddgiProbeRenderer = new DDGIProbeRenderer(GlobalBindGroup.getLightEntries(this.view.scene).irradianceVolume); - this.ddgiProbeRenderer.clusterLightingRender = this.clusterLightingRender; - this.ddgiProbeRenderer.setInputTexture([ - this.shadowMapPassRenderer.depth2DTextureArray, - this.pointLightShadowRenderer.cubeTextureArray - ]); + // this.ddgiProbeRenderer = new DDGIProbeRenderer(GlobalBindGroup.getLightEntries(this.view.scene).irradianceVolume); + // this.ddgiProbeRenderer.clusterLightingRender = this.clusterLightingRender; + // this.ddgiProbeRenderer.setInputTexture([ + // this.shadowMapPassRenderer.depth2DTextureArray, + // this.pointLightShadowRenderer.cubeTextureArray + // ]); - colorPassRenderer.setIrradiance(this.ddgiProbeRenderer.irradianceColorMap, this.ddgiProbeRenderer.irradianceDepthMap); + // colorPassRenderer.setIrradiance(this.ddgiProbeRenderer.irradianceColorMap, this.ddgiProbeRenderer.irradianceDepthMap); - this.rendererMap.addRenderer(this.ddgiProbeRenderer); + // this.rendererMap.addRenderer(this.ddgiProbeRenderer); - debugTextures.push( - this.ddgiProbeRenderer.positionMap, - this.ddgiProbeRenderer.normalMap, - this.ddgiProbeRenderer.colorMap, - this.ddgiProbeRenderer.lightingPass.lightingTexture, - this.ddgiProbeRenderer.irradianceColorMap, - this.ddgiProbeRenderer.irradianceDepthMap, - ); + // debugTextures.push( + // this.ddgiProbeRenderer.positionMap, + // this.ddgiProbeRenderer.normalMap, + // this.ddgiProbeRenderer.colorMap, + // this.ddgiProbeRenderer.lightingPass.lightingTexture, + // this.ddgiProbeRenderer.irradianceColorMap, + // this.ddgiProbeRenderer.irradianceDepthMap, + // ); } if (this.postRenderer) { diff --git a/src/engine/gfx/renderJob/jobs/RendererJob.ts b/src/engine/gfx/renderJob/jobs/RendererJob.ts index bb032e4e..0b9e470a 100644 --- a/src/engine/gfx/renderJob/jobs/RendererJob.ts +++ b/src/engine/gfx/renderJob/jobs/RendererJob.ts @@ -1,29 +1,22 @@ import { ComponentBase } from '../../../components/ComponentBase'; -import { Camera3D } from '../../../core/Camera3D'; import { Scene3D } from '../../../core/Scene3D'; +import { View3D } from '../../../core/View3D'; import { Engine3D } from '../../../Engine3D'; -import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { PickFire } from '../../../io/PickFire'; import { GlobalBindGroup } from '../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; -import { EntityCollect } from '../collect/EntityCollect'; +import { ShadowLightsCollect } from '../collect/ShadowLightsCollect'; +import { ColorPassRenderer } from '../color/ColorPassRenderer'; +import { GBufferFrame } from '../frame/GBufferFrame'; import { GPUContext } from '../GPUContext'; import { OcclusionSystem } from '../occlusion/OcclusionSystem'; import { ClusterLightingRender } from '../passRenderer/cluster/ClusterLightingRender'; -import { RendererBase } from '../passRenderer/RendererBase'; -import { PostRenderer } from '../passRenderer/post/PostRenderer'; -import { DDGIProbeRenderer } from '../passRenderer/ddgi/DDGIProbeRenderer'; +import { Graphic3D } from '../passRenderer/graphic/Graphic3DRender'; +import { PointLightShadowRenderer } from '../passRenderer/shadow/PointLightShadowRenderer'; import { ShadowMapPassRenderer } from '../passRenderer/shadow/ShadowMapPassRenderer'; import { PreDepthPassRenderer } from '../passRenderer/preDepth/PreDepthPassRenderer'; -import { PostBase } from '../post/PostBase'; -import { PointLightShadowRenderer } from '../passRenderer/shadow/PointLightShadowRenderer'; -import { UICanvas } from '../../../components/gui/core/UICanvas'; -import { View3D } from '../../../core/View3D'; -import { PickFire } from '../../../io/PickFire'; -import { ShadowLightsCollect } from '../collect/ShadowLightsCollect'; -import { GBufferFrame } from '../frame/GBufferFrame'; import { RendererMap } from './RenderMap'; -import { ColorPassRenderer } from '../passRenderer/color/ColorPassRenderer'; -import { Graphic3D } from '../passRenderer/graphic/Graphic3DRender'; -import { ReflectionProbeRenderer } from '../passRenderer/probe/ReflectionProbeRenderer'; +import { PostRenderer } from '../passRenderer/post/PostRenderer'; +import { PostBase } from '../post/PostBase'; /** * render jobs @@ -32,8 +25,6 @@ import { ReflectionProbeRenderer } from '../passRenderer/probe/ReflectionProbeRe */ export class RendererJob { - private _canvas: UICanvas; - /** * @internal */ @@ -49,11 +40,6 @@ export class RendererJob { */ public pointLightShadowRenderer: PointLightShadowRenderer; - /** - * @internal - */ - public ddgiProbeRenderer: DDGIProbeRenderer; - /** * @internal */ @@ -79,11 +65,6 @@ export class RendererJob { */ public colorPassRenderer: ColorPassRenderer; - /** - * @internal - */ - public reflectionProbeRenderer: ReflectionProbeRenderer; - /** * @internal */ @@ -125,8 +106,6 @@ export class RendererJob { this.shadowMapPassRenderer = new ShadowMapPassRenderer(); this.pointLightShadowRenderer = new PointLightShadowRenderer(); - this.reflectionProbeRenderer = new ReflectionProbeRenderer(); - this.reflectionProbeRenderer.clusterLightingRender = this.clusterLightingRender; } @@ -275,18 +254,6 @@ export class RendererJob { this.depthPassRenderer.lateCompute(view, this.occlusionSystem); } - if (Engine3D.setting.gi.enable && this.ddgiProbeRenderer) { - this.ddgiProbeRenderer.beforeCompute(view, this.occlusionSystem); - this.ddgiProbeRenderer.render(view, this.occlusionSystem); - this.ddgiProbeRenderer.lateCompute(view, this.occlusionSystem); - } - - if (this.reflectionProbeRenderer) { - this.reflectionProbeRenderer.beforeCompute(view, this.occlusionSystem); - this.reflectionProbeRenderer.render(view, this.occlusionSystem); - this.reflectionProbeRenderer.lateCompute(view, this.occlusionSystem); - } - let passList = this.rendererMap.getAllPassRenderer(); for (let i = 0; i < passList.length; i++) { const renderer = passList[i]; diff --git a/src/engine/gfx/renderJob/passRenderer/RendererBase.ts b/src/engine/gfx/renderJob/passRenderer/RendererBase.ts index 63a16781..63329edd 100644 --- a/src/engine/gfx/renderJob/passRenderer/RendererBase.ts +++ b/src/engine/gfx/renderJob/passRenderer/RendererBase.ts @@ -1,21 +1,23 @@ -import { RenderNode } from '../../../components/renderer/RenderNode'; -import { Camera3D } from '../../../core/Camera3D'; -import { Scene3D } from '../../../core/Scene3D'; -import { ViewQuad } from '../../../core/ViewQuad'; -import { Engine3D } from '../../../Engine3D'; -import { VirtualTexture } from '../../../textures/VirtualTexture'; -import { Texture } from '../../graphics/webGpu/core/texture/Texture'; -import { WebGPUDescriptorCreator } from '../../graphics/webGpu/descriptor/WebGPUDescriptorCreator'; -import { CollectInfo } from '../collect/CollectInfo'; -import { EntityCollect } from '../collect/EntityCollect'; -import { GPUContext } from '../GPUContext'; -import { OcclusionSystem } from '../occlusion/OcclusionSystem'; -import { ClusterLightingRender } from './cluster/ClusterLightingRender'; -import { RendererType } from './state/RendererType'; -import { RendererPassState } from './state/RendererPassState'; -import { RTFrame } from '../frame/RTFrame'; -import { CEventDispatcher, GPUTextureFormat, View3D } from '../../../..'; -import { RenderContext } from './RenderContext'; +import { Engine3D } from "../../../Engine3D"; +import { RenderNode } from "../../../components/renderer/RenderNode"; +import { Scene3D } from "../../../core/Scene3D"; +import { View3D } from "../../../core/View3D"; +import { ViewQuad } from "../../../core/ViewQuad"; +import { CEventDispatcher } from "../../../event/CEventDispatcher"; +import { VirtualTexture } from "../../../textures/VirtualTexture"; +import { GPUTextureFormat } from "../../graphics/webGpu/WebGPUConst"; +import { Texture } from "../../graphics/webGpu/core/texture/Texture"; +import { WebGPUDescriptorCreator } from "../../graphics/webGpu/descriptor/WebGPUDescriptorCreator"; +import { GPUContext } from "../GPUContext"; +import { CollectInfo } from "../collect/CollectInfo"; +import { EntityCollect } from "../collect/EntityCollect"; +import { RTFrame } from "../frame/RTFrame"; +import { OcclusionSystem } from "../occlusion/OcclusionSystem"; +import { RendererPassState } from "./state/RendererPassState"; +import { RendererType } from "./state/RendererType"; +import { RenderContext } from "./RenderContext"; +import { ClusterLightingRender } from "./cluster/ClusterLightingRender"; + /** * @internal diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts index ace71f0c..2944b3ee 100644 --- a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts +++ b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts @@ -3,10 +3,10 @@ import { BoundingBox } from "../../../../core/bound/BoundingBox"; import { View3D } from "../../../../core/View3D"; import { Color } from "../../../../math/Color"; import { Vector3 } from "../../../../math/Vector3"; -import { ClusterLightingRender } from "../cluster/ClusterLightingRender"; import { RendererMask } from "../state/RendererMask"; import { RendererPassState } from "../state/RendererPassState"; import { RendererType } from "../state/RendererType"; +import { ClusterLightingRender } from "../cluster/ClusterLightingRender"; import { Graphic3DFixedRenderPipeline } from "./Graphic3DFixedRenderPipeline"; import { GraphicConfig } from "./GraphicConfig"; import { Graphics3DShape } from "./Graphics3DShape"; diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts index 6f61a330..854ca759 100644 --- a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts +++ b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts @@ -1,4 +1,4 @@ -import { GPUPrimitiveTopology } from "../../../../.."; +import { GPUPrimitiveTopology } from "../../../graphics/webGpu/WebGPUConst"; import { Graphic3DBatchRenderer } from "./Graphic3DBatchRenderer"; /** diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts index fbbbb448..28b75fcb 100644 --- a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts +++ b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts @@ -1,12 +1,13 @@ -import { GPUContext, Preprocessor } from "../../../../.."; import { BlendFactor, BlendMode } from "../../../../materials/BlendMode"; import { GlobalBindGroupLayout } from "../../../graphics/webGpu/core/bindGroups/GlobalBindGroupLayout"; import { GPUCullMode, GPUCompareFunction } from "../../../graphics/webGpu/WebGPUConst"; import { webGPUContext } from "../../../graphics/webGpu/Context3D"; -import { RendererPassState } from "../state/RendererPassState"; import { Graphics3DShape } from "./Graphics3DShape"; import Graphic3DShader_vs from "../../../../assets/shader/graphic/Graphic3DShader_vs.wgsl?raw" import Graphic3DShader_fs from "../../../../assets/shader/graphic/Graphic3DShader_fs.wgsl?raw" +import { Preprocessor } from "../../../graphics/webGpu/shader/util/Preprocessor"; +import { GPUContext } from "../../GPUContext"; +import { RendererPassState } from "../state/RendererPassState"; /** * @internal diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts index 5b9ccc5e..4ec76033 100644 --- a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts +++ b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts @@ -1,4 +1,4 @@ -import { GPUPrimitiveTopology } from "../../../../.."; +import { GPUPrimitiveTopology } from "../../../graphics/webGpu/WebGPUConst"; import { Graphic3DBatchRenderer } from "./Graphic3DBatchRenderer"; /** diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DRender.ts b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DRender.ts index d1751647..76b2623c 100644 --- a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DRender.ts +++ b/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DRender.ts @@ -20,7 +20,6 @@ export class Graphic3D extends Object3D { constructor() { super(); - this.serializeTag = "dont-serialize"; this.mLineRender = this.addComponent(Graphic3DLineBatchRenderer); this.mFillRender = this.addComponent(Graphic3DFillRenderer); } diff --git a/src/engine/gfx/renderJob/passRenderer/post/PostRenderer.ts b/src/engine/gfx/renderJob/passRenderer/post/PostRenderer.ts new file mode 100644 index 00000000..ac310c98 --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/post/PostRenderer.ts @@ -0,0 +1,72 @@ +import { Engine3D } from "../../../../Engine3D"; +import { ShaderLib } from "../../../../assets/shader/ShaderLib"; +import { Quad_shader } from "../../../../assets/shader/quad/Quad_shader"; +import { View3D } from "../../../../core/View3D"; +import { ViewQuad } from "../../../../core/ViewQuad"; +import { GPUContext } from "../../GPUContext"; +import { RTFrame } from "../../frame/RTFrame"; +import { PostBase } from "../../post/PostBase"; +import { RendererBase } from "../RendererBase"; +import { RendererType } from "../state/RendererType"; + + +/** + * @internal + * @group Post + */ +export class PostRenderer extends RendererBase { + public finalQuadView: ViewQuad; + public postList: PostBase[]; + constructor() { + super(); + + this._rendererType = RendererType.POST; + + this.postList = []; + + this.initRenderer(); + } + + public initRenderer() { + ShaderLib.register("FullQuad_vert_wgsl", Quad_shader.FullQuad_vert_wgsl); + this.finalQuadView = new ViewQuad(`Quad_vert_wgsl`, `Quad_frag_wgsl`, new RTFrame([], []), null, null, false); + } + + public attachPost(view: View3D, post: PostBase) { + post.postRenderer = this; + let has = this.postList.indexOf(post) != -1; + if (!has) { + this.postList.push(post); + post.onAttach(view); + } + } + + public detachPost(view: View3D, post: PostBase): boolean { + let index = this.postList.indexOf(post); + if (index >= 0) { + this.postList.splice(index, 1); + post.onDetach(view); + post.postRenderer = null; + } + return index >= 0; + } + + public render(view: View3D) { + let command = GPUContext.beginCommandEncoder(); + for (let i = 0; i < this.postList.length; i++) { + const post = this.postList[i]; + if (!post.enable) continue; + post.render(view, command); + } + + let lastTexture = GPUContext.lastRenderPassState.getLastRenderTexture(); + GPUContext.renderToViewQuad(view, this.finalQuadView, command, lastTexture); + { + if (this.debugViewQuads.length) { + let debugIndex = Engine3D.setting.render.debugQuad; + if (debugIndex >= 0) GPUContext.renderToViewQuad(view, this.debugViewQuads[debugIndex], command, this.debugTextures[debugIndex]); + } + } + GPUContext.endCommandEncoder(command); + } +} diff --git a/src/engine/gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer.ts b/src/engine/gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer.ts new file mode 100644 index 00000000..b5843574 --- /dev/null +++ b/src/engine/gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer.ts @@ -0,0 +1,59 @@ +import { View3D } from "../../../../core/View3D"; +import { VirtualTexture } from "../../../../textures/VirtualTexture"; +import { ProfilerUtil } from "../../../../util/ProfilerUtil"; +import { webGPUContext } from "../../../graphics/webGpu/Context3D"; +import { GPUTextureFormat } from "../../../graphics/webGpu/WebGPUConst"; +import { RTDescriptor } from "../../../graphics/webGpu/descriptor/RTDescriptor"; +import { GPUContext } from "../../GPUContext"; +import { EntityCollect } from "../../collect/EntityCollect"; +import { RTResourceConfig } from "../../config/RTResourceConfig"; +import { RTFrame } from "../../frame/RTFrame"; +import { RTResourceMap } from "../../frame/RTResourceMap"; +import { OcclusionSystem } from "../../occlusion/OcclusionSystem"; +import { RendererBase } from "../RendererBase"; +import { RendererType } from "../state/RendererType"; +import { ZCullingCompute } from "./ZCullingCompute"; + +/** + * @internal + * @group Post + */ +export class PreDepthPassRenderer extends RendererBase { + public zBufferTexture: VirtualTexture; + public useRenderBundle: boolean = false; + shadowPassCount: number; + zCullingCompute: ZCullingCompute; + constructor() { + super(); + this.passType = RendererType.DEPTH; + + let size = webGPUContext.presentationSize; + let scale = 1; + this.zBufferTexture = RTResourceMap.createRTTexture(RTResourceConfig.zBufferTexture_NAME, Math.floor(size[0] * scale), Math.floor(size[1] * scale), GPUTextureFormat.rgba16float, false); + let rtDec = new RTDescriptor() + rtDec.clearValue = [0, 0, 0, 0]; + rtDec.loadOp = `clear`; + let rtFrame = new RTFrame([ + this.zBufferTexture + ], [ + new RTDescriptor() + ], + RTResourceMap.createRTTexture(RTResourceConfig.zPreDepthTexture_NAME, Math.floor(size[0]), Math.floor(size[1]), GPUTextureFormat.depth32float, false), + null, + true + ); + this.setRenderStates(rtFrame); + } + + public lateCompute(view: View3D, occlusionSystem: OcclusionSystem) { + // this.zCullingCompute.compute(scene, occlusionSystem); + } + + render(view: View3D, occlusionSystem: OcclusionSystem) { + return; + + // ProfilerUtil.print( "DepthPass Renderer" ); + } + + +} diff --git a/src/engine/gfx/renderJob/preDepth/ZCullingCompute.ts b/src/engine/gfx/renderJob/passRenderer/preDepth/ZCullingCompute.ts similarity index 99% rename from src/engine/gfx/renderJob/preDepth/ZCullingCompute.ts rename to src/engine/gfx/renderJob/passRenderer/preDepth/ZCullingCompute.ts index e2d147da..978ed9cf 100644 --- a/src/engine/gfx/renderJob/preDepth/ZCullingCompute.ts +++ b/src/engine/gfx/renderJob/passRenderer/preDepth/ZCullingCompute.ts @@ -1,12 +1,13 @@ + +import ZPassShader_cs from '../../../../assets/shader/core/pass/ZPassShader_cs.wgsl?raw'; import { Scene3D } from '../../../../core/Scene3D'; import { ComputeGPUBuffer } from '../../../graphics/webGpu/core/buffer/ComputeGPUBuffer'; +import { Texture } from '../../../graphics/webGpu/core/texture/Texture'; import { ComputeShader } from '../../../graphics/webGpu/shader/ComputeShader'; import { GPUContext } from '../../GPUContext'; +import { RTResourceConfig } from '../../config/RTResourceConfig'; import { RTResourceMap } from '../../frame/RTResourceMap'; import { OcclusionSystem } from '../../occlusion/OcclusionSystem'; -import { Texture } from '../../../graphics/webGpu/core/texture/Texture'; -import { RTResourceConfig } from '../../config/RTResourceConfig'; -import ZPassShader_cs from '../../../../assets/shader/core/pass/ZPassShader_cs.wgsl?raw'; /** * @internal diff --git a/src/engine/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts b/src/engine/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts index 5b2a9fd7..93732fb2 100644 --- a/src/engine/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts +++ b/src/engine/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts @@ -1,4 +1,3 @@ -import { CameraUtil, PointShadowCubeCamera, RendererPassState, RenderNode, RenderShader, RTDescriptor as RTDescriptor, Vector3, WebGPUDescriptorCreator, DepthCubeArrayTexture, Time, View3D } from '../../../../..'; import { LightBase } from '../../../../components/lights/LightBase'; import { LightType } from '../../../../components/lights/LightData'; import { ShadowLightsCollect } from '../../collect/ShadowLightsCollect'; @@ -14,6 +13,14 @@ import { GPUContext } from '../../GPUContext'; import { RTFrame } from '../../frame/RTFrame'; import { OcclusionSystem } from '../../occlusion/OcclusionSystem'; import { RendererBase } from '../RendererBase'; +import { RenderNode } from '../../../../components/renderer/RenderNode'; +import { PointShadowCubeCamera } from '../../../../core/PointShadowCubeCamera'; +import { View3D } from '../../../../core/View3D'; +import { DepthCubeArrayTexture } from '../../../../textures/DepthCubeArrayTexture'; +import { Time } from '../../../../util/Time'; +import { RTDescriptor } from '../../../graphics/webGpu/descriptor/RTDescriptor'; +import { WebGPUDescriptorCreator } from '../../../graphics/webGpu/descriptor/WebGPUDescriptorCreator'; +import { RendererPassState } from '../state/RendererPassState'; import { RendererType } from '../state/RendererType'; type CubeShadowMapInfo = { diff --git a/src/engine/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts b/src/engine/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts index 655202a7..383868f3 100644 --- a/src/engine/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts +++ b/src/engine/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts @@ -1,26 +1,25 @@ -import { LightType } from '../../../../components/lights/LightData'; -import { ShadowLightsCollect } from '../../collect/ShadowLightsCollect'; -import { RenderNode } from '../../../../components/renderer/RenderNode'; -import { BoundingBox } from '../../../../core/bound/BoundingBox'; -import { Camera3D } from '../../../../core/Camera3D'; -import { Engine3D } from '../../../../Engine3D'; -import { clamp } from '../../../../math/MathUtil'; -import { Ray } from '../../../../math/Ray'; -import { Vector3 } from '../../../../math/Vector3'; -import { Depth2DTextureArray } from '../../../../textures/Depth2DTextureArray'; -import { VirtualTexture } from '../../../../textures/VirtualTexture'; -import { Time } from '../../../../util/Time'; -import { WebGPUDescriptorCreator } from '../../../graphics/webGpu/descriptor/WebGPUDescriptorCreator'; -import { GPUTextureFormat } from '../../../graphics/webGpu/WebGPUConst'; -import { EntityCollect } from '../../collect/EntityCollect'; -import { GPUContext } from '../../GPUContext'; -import { RTFrame } from '../../frame/RTFrame'; -import { OcclusionSystem } from '../../occlusion/OcclusionSystem'; -import { RendererBase } from '../RendererBase'; -import { RendererPassState } from '../state/RendererPassState'; -import { RendererType } from '../state/RendererType'; -import { View3D } from '../../../../core/View3D'; -import { DirectLight } from '../../../../components/lights/DirectLight'; +import { Engine3D } from "../../../../Engine3D"; +import { DirectLight } from "../../../../components/lights/DirectLight"; +import { LightType } from "../../../../components/lights/LightData"; +import { RenderNode } from "../../../../components/renderer/RenderNode"; +import { Camera3D } from "../../../../core/Camera3D"; +import { View3D } from "../../../../core/View3D"; +import { clamp } from "../../../../math/MathUtil"; +import { Vector3 } from "../../../../math/Vector3"; +import { Depth2DTextureArray } from "../../../../textures/Depth2DTextureArray"; +import { VirtualTexture } from "../../../../textures/VirtualTexture"; +import { Time } from "../../../../util/Time"; +import { GPUTextureFormat } from "../../../graphics/webGpu/WebGPUConst"; +import { WebGPUDescriptorCreator } from "../../../graphics/webGpu/descriptor/WebGPUDescriptorCreator"; +import { GPUContext } from "../../GPUContext"; +import { EntityCollect } from "../../collect/EntityCollect"; +import { ShadowLightsCollect } from "../../collect/ShadowLightsCollect"; +import { RTFrame } from "../../frame/RTFrame"; +import { OcclusionSystem } from "../../occlusion/OcclusionSystem"; +import { RendererPassState } from "../state/RendererPassState"; +import { RendererType } from "../state/RendererType"; +import { RendererBase } from "../RendererBase"; + /** * @internal * @group Post diff --git a/src/engine/gfx/renderJob/state/RendererMask.ts b/src/engine/gfx/renderJob/passRenderer/state/RendererMask.ts similarity index 100% rename from src/engine/gfx/renderJob/state/RendererMask.ts rename to src/engine/gfx/renderJob/passRenderer/state/RendererMask.ts diff --git a/src/engine/gfx/renderJob/state/RendererPassState.ts b/src/engine/gfx/renderJob/passRenderer/state/RendererPassState.ts similarity index 76% rename from src/engine/gfx/renderJob/state/RendererPassState.ts rename to src/engine/gfx/renderJob/passRenderer/state/RendererPassState.ts index f252f8de..ea80fae5 100644 --- a/src/engine/gfx/renderJob/state/RendererPassState.ts +++ b/src/engine/gfx/renderJob/passRenderer/state/RendererPassState.ts @@ -1,6 +1,10 @@ -import { defaultRes, RTDescriptor, RTFrame, VirtualTexture } from '../../../../..'; -import { Camera3D } from '../../../../core/Camera3D'; -import { Texture } from '../../../graphics/webGpu/core/texture/Texture'; +import { Camera3D } from "../../../../core/Camera3D"; +import { defaultRes } from "../../../../textures/DefaultRes"; +import { VirtualTexture } from "../../../../textures/VirtualTexture"; +import { Texture } from "../../../graphics/webGpu/core/texture/Texture"; +import { RTDescriptor } from "../../../graphics/webGpu/descriptor/RTDescriptor"; +import { RTFrame } from "../../frame/RTFrame"; + /** * @internal */ diff --git a/src/engine/gfx/renderJob/state/RendererType.ts b/src/engine/gfx/renderJob/passRenderer/state/RendererType.ts similarity index 100% rename from src/engine/gfx/renderJob/state/RendererType.ts rename to src/engine/gfx/renderJob/passRenderer/state/RendererType.ts diff --git a/src/engine/gfx/renderJob/post/DepthOfFieldPost.ts b/src/engine/gfx/renderJob/post/DepthOfFieldPost.ts new file mode 100644 index 00000000..111d37a2 --- /dev/null +++ b/src/engine/gfx/renderJob/post/DepthOfFieldPost.ts @@ -0,0 +1,209 @@ +import DepthOfView_CsShader from '../../../assets/shader/compute/DepthOfView_CsShader.wgsl?raw'; +import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { GlobalBindGroup } from '../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { StorageGPUBuffer } from '../../graphics/webGpu/core/buffer/StorageGPUBuffer'; +import { UniformGPUBuffer } from '../../graphics/webGpu/core/buffer/UniformGPUBuffer'; +import { WebGPUDescriptorCreator } from '../../graphics/webGpu/descriptor/WebGPUDescriptorCreator'; +import { ComputeShader } from '../../graphics/webGpu/shader/ComputeShader'; +import { GPUTextureFormat } from '../../graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../../graphics/webGpu/Context3D'; +import { GPUContext } from '../GPUContext'; +import { RTResourceMap } from '../frame/RTResourceMap'; +import { RendererPassState } from '../passRenderer/state/RendererPassState'; +import { PostBase } from './PostBase'; +import { Engine3D } from '../../../Engine3D'; +import { View3D } from '../../../core/View3D'; +import { RTDescriptor } from '../../graphics/webGpu/descriptor/RTDescriptor'; +import { RTResourceConfig } from '../config/RTResourceConfig'; +import { GBufferFrame } from '../frame/GBufferFrame'; +import { RTFrame } from '../frame/RTFrame'; +/** + * depth of field effect。 + * A common post-processing effect that simulates the focusing characteristics of a camera lens. + * ``` + * //Configure parameters related to depth of field + * let cfg = {@link Engine3D.setting.render.postProcessing.depthOfView}; + * cfg.near = 150; + * cfg.far = 300; + * cfg.pixelOffset = 1.0; + * let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + * + * Engine3D.startRender(renderJob); + *``` + * @group Post Effects + */ +export class DepthOfFieldPost extends PostBase { + /** + * @internal + */ + blurTexture1: VirtualTexture; + /** + * @internal + */ + blurTexture2: VirtualTexture; + /** + * @internal + */ + rendererPassState: RendererPassState; + /** + * @internal + */ + blurComputes: ComputeShader[]; + /** + * @internal + */ + blurSettings: StorageGPUBuffer[]; + /** + * @internal + */ + outTexture: VirtualTexture; + rtFrame: RTFrame; + + constructor() { + super(); + } + /** + * @internal + */ + onAttach(view: View3D,) { + Engine3D.setting.render.postProcessing.depthOfView.enable = true; + } + /** + * @internal + */ + onDetach(view: View3D,) { + Engine3D.setting.render.postProcessing.depthOfView.enable = false; + } + + private createGUI() { + + } + + public get pixelOffset() { + let setting = Engine3D.setting.render.postProcessing.depthOfView; + return setting.pixelOffset; + } + + public set pixelOffset(value: number) { + value = Math.max(0, value); + let setting = Engine3D.setting.render.postProcessing.depthOfView; + setting.pixelOffset = value; + } + + public get near() { + let setting = Engine3D.setting.render.postProcessing.depthOfView; + return setting.near; + } + + public set near(value: number) { + value = Math.max(0, value); + let setting = Engine3D.setting.render.postProcessing.depthOfView; + setting.near = value; + } + + public get far() { + let setting = Engine3D.setting.render.postProcessing.depthOfView; + return setting.far; + } + + public set far(value: number) { + value = Math.max(0, value); + let setting = Engine3D.setting.render.postProcessing.depthOfView; + setting.far = value; + } + + private createBlurCompute() { + this.blurSettings = []; + this.blurComputes = []; + let cfg = Engine3D.setting.render.postProcessing.depthOfView; + + for (let i = 0; i < cfg.iterationCount; i++) { + let blurSetting: UniformGPUBuffer = new UniformGPUBuffer(4); + let blurCompute = new ComputeShader(DepthOfView_CsShader); + this.blurComputes.push(blurCompute); + this.blurSettings.push(blurSetting); + + blurCompute.setUniformBuffer('blurSetting', blurSetting); + let rtFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer"); + + blurCompute.setSamplerTexture(RTResourceConfig.positionBufferTex_NAME, rtFrame.attachments[1]); + blurCompute.setSamplerTexture(RTResourceConfig.normalBufferTex_NAME, rtFrame.attachments[2]); + + let input = i % 2 == 0 ? this.blurTexture1 : this.blurTexture2; + let output = i % 2 == 1 ? this.blurTexture1 : this.blurTexture2; + blurCompute.setSamplerTexture('inTex', input); + blurCompute.setStorageTexture(`outTex`, output); + + blurCompute.workerSizeX = Math.ceil(this.blurTexture1.width / 8); + blurCompute.workerSizeY = Math.ceil(this.blurTexture1.height / 8); + blurCompute.workerSizeZ = 1; + + this.outTexture = output; + } + } + + private createResource() { + let presentationSize = webGPUContext.presentationSize; + let w = presentationSize[0]; + let h = presentationSize[1]; + + this.blurTexture1 = new VirtualTexture(w, h, GPUTextureFormat.rgba16float, false, GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.TEXTURE_BINDING); + this.blurTexture1.name = 'dof1'; + let blur1Dec = new RTDescriptor(); + blur1Dec.clearValue = [0, 0, 0, 1]; + blur1Dec.loadOp = `clear`; + + this.blurTexture2 = new VirtualTexture(w, h, GPUTextureFormat.rgba16float, false, GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.TEXTURE_BINDING); + this.blurTexture2.name = 'dof2'; + let blur2Dec = new RTDescriptor(); + blur2Dec.clearValue = [0, 0, 0, 1]; + blur2Dec.loadOp = `clear`; + + this.rtFrame = new RTFrame([ + this.blurTexture1, + this.blurTexture2 + ], [ + blur1Dec, + blur2Dec + ]); + } + /** + * @internal + */ + render(view: View3D, command: GPUCommandEncoder) { + if (!this.blurComputes) { + this.createResource(); + this.createBlurCompute(); + this.createGUI(); + + let standUniform = GlobalBindGroup.getCameraGroup(view.camera); + for (let i = 0; i < this.blurComputes.length; i++) { + const blurCompute = this.blurComputes[i]; + blurCompute.setUniformBuffer('standUniform', standUniform.uniformGPUBuffer); + } + this.rendererPassState = WebGPUDescriptorCreator.createRendererPassState(this.rtFrame, null); + } + + this.autoSetColorTexture('inTex', this.blurComputes[0]); + + let cfg = Engine3D.setting.render.postProcessing.depthOfView; + cfg.far = Math.max(cfg.near, cfg.far) + 0.0001; + + for (let i = 0; i < cfg.iterationCount; i++) { + let blurCompute = this.blurComputes[i]; + let blurSetting = this.blurSettings[i]; + blurSetting.setFloat('near', cfg.near); + blurSetting.setFloat('far', cfg.far); + blurSetting.setFloat('pixelOffset', (i + 1) * cfg.pixelOffset); + blurSetting.apply(); + blurCompute.setStorageBuffer('blurSetting', blurSetting); + } + + GPUContext.computeCommand(command, this.blurComputes); + + GPUContext.lastRenderPassState = this.rendererPassState; + } +} diff --git a/src/engine/gfx/renderJob/post/FXAAPost.ts b/src/engine/gfx/renderJob/post/FXAAPost.ts new file mode 100644 index 00000000..56cfb16a --- /dev/null +++ b/src/engine/gfx/renderJob/post/FXAAPost.ts @@ -0,0 +1,56 @@ +import FSAA_Shader from '../../../assets/shader/post/FSAAShader.wgsl?raw'; +import { ShaderLib } from '../../../assets/shader/ShaderLib'; +import { Engine3D } from '../../../Engine3D'; +import { Vector2 } from '../../../math/Vector2'; +import { UniformNode } from '../../graphics/webGpu/core/uniforms/UniformNode'; +import { GPUTextureFormat } from '../../graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../../graphics/webGpu/Context3D'; +import { RTResourceConfig } from '../config/RTResourceConfig'; +import { RTResourceMap } from '../frame/RTResourceMap'; +import { PostBase } from './PostBase'; +import { View3D } from '../../../core/View3D'; +/** + * FXAA(fast approximate antialiasing) + * A deformation anti-aliasing method that pays more attention to performance. + * It only needs one pass to get the result. FXAA focuses on fast visual anti-aliasing effect, + * rather than pursuing perfect real anti-aliasing effect. + * ``` + * let cfg = {@link Engine3D.setting.render.postProcessing.fxaa}; + * let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + * Engine3D.startRender(renderJob); + *``` + * @group Post Effects + */ +export class FXAAPost extends PostBase { + + constructor() { + super(); + let presentationSize = webGPUContext.presentationSize; + RTResourceMap.createRTTexture(RTResourceConfig.colorBufferTex_NAME, presentationSize[0], presentationSize[1], GPUTextureFormat.rgba16float, false); + + ShaderLib.register("FXAA_Shader", FSAA_Shader); + + let shaderUniforms = { + u_texel: new UniformNode(new Vector2(1.0 / presentationSize[0], 1.0 / presentationSize[1])), + u_strength: new UniformNode(4), + }; + + let rt = this.createRTTexture(`FXAAPost`, presentationSize[0], presentationSize[1], GPUTextureFormat.rgba16float); + this.createViewQuad(`fxaa`, 'FXAA_Shader', rt, shaderUniforms); + } + /** + * @internal + */ + onAttach(view: View3D,) { + Engine3D.setting.render.postProcessing.fxaa.enable = true; + } + /** + * @internal + */ + onDetach(view: View3D,) { + Engine3D.setting.render.postProcessing.fxaa.enable = false; + } +} diff --git a/src/engine/gfx/renderJob/post/GTAOPost.ts b/src/engine/gfx/renderJob/post/GTAOPost.ts new file mode 100644 index 00000000..cf995f35 --- /dev/null +++ b/src/engine/gfx/renderJob/post/GTAOPost.ts @@ -0,0 +1,277 @@ +import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { GlobalBindGroup } from '../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { StorageGPUBuffer } from '../../graphics/webGpu/core/buffer/StorageGPUBuffer'; +import { UniformGPUBuffer } from '../../graphics/webGpu/core/buffer/UniformGPUBuffer'; +import { WebGPUDescriptorCreator } from '../../graphics/webGpu/descriptor/WebGPUDescriptorCreator'; +import { ComputeShader } from '../../graphics/webGpu/shader/ComputeShader'; +import { GPUTextureFormat } from '../../graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../../graphics/webGpu/Context3D'; +import { GPUContext } from '../GPUContext'; +import { RendererPassState } from '../passRenderer/state/RendererPassState'; +import { PostBase } from './PostBase'; +import { Engine3D } from '../../../Engine3D'; +import GTAOCs from '../../../assets/shader/compute/GTAOCs.wgsl?raw'; +import { Time } from '../../../util/Time'; +import { clamp } from '../../../math/MathUtil'; +import { View3D } from '../../../core/View3D'; +import { RTDescriptor } from '../../graphics/webGpu/descriptor/RTDescriptor'; +import { GBufferFrame } from '../frame/GBufferFrame'; +import { RTFrame } from '../frame/RTFrame'; + +/** + * Ground base Ambient Occlusion + * Let the intersection of the object and the object imitate the effect of the light being cross-occluded + * ``` + * //gtao setting + * let cfg = {@link Engine3D.setting.render.postProcessing.gtao}; + * let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + * + * Engine3D.startRender(renderJob); + *``` + * @group Post Effects + */ +export class GTAOPost extends PostBase { + /** + * @internal + */ + gtaoTexture: VirtualTexture; + /** + * @internal + */ + rendererPassState: RendererPassState; + /** + * @internal + */ + gtaoCompute: ComputeShader; + /** + * @internal + */ + gtaoSetting: StorageGPUBuffer; + /** + * @internal + */ + aoBuffer: StorageGPUBuffer; + + /** + * @internal + */ + directionsBuffer: StorageGPUBuffer; + /** + * @internal + */ + directionsArray: Float32Array; + rtFrame: RTFrame; + + constructor() { + super(); + } + + /** + * @internal + */ + onAttach(view: View3D,) { + Engine3D.setting.render.postProcessing.gtao.enable = true; + this.createGUI(); + } + /** + * @internal + */Render + onDetach(view: View3D,) { + Engine3D.setting.render.postProcessing.gtao.enable = false; + this.removeGUI(); + } + + public get maxDistance() { + let setting = Engine3D.setting.render.postProcessing.gtao; + return setting.maxDistance; + } + + public set maxDistance(value: number) { + value = clamp(value, 0.1, 50); + let setting = Engine3D.setting.render.postProcessing.gtao; + setting.maxDistance = value; + } + + public get maxPixel() { + let setting = Engine3D.setting.render.postProcessing.gtao; + return setting.maxPixel; + } + + public set maxPixel(value: number) { + value = clamp(value, 5, 100); + let setting = Engine3D.setting.render.postProcessing.gtao; + setting.maxPixel = value; + } + + public get darkFactor() { + let setting = Engine3D.setting.render.postProcessing.gtao; + return setting.darkFactor; + } + + public set darkFactor(value: number) { + value = clamp(value, 0.01, 1); + let setting = Engine3D.setting.render.postProcessing.gtao; + setting.darkFactor = value; + } + + + public get rayMarchSegment() { + let setting = Engine3D.setting.render.postProcessing.gtao; + return setting.rayMarchSegment; + } + + public set rayMarchSegment(value: number) { + value = clamp(value, 4, 10); + let setting = Engine3D.setting.render.postProcessing.gtao; + setting.rayMarchSegment = value; + } + + public get multiBounce() { + let setting = Engine3D.setting.render.postProcessing.gtao; + return setting.multiBounce; + } + + public set multiBounce(value: boolean) { + let setting = Engine3D.setting.render.postProcessing.gtao; + setting.multiBounce = value; + } + + public get blendColor() { + let setting = Engine3D.setting.render.postProcessing.gtao; + return setting.blendColor; + } + + public set blendColor(value: boolean) { + let setting = Engine3D.setting.render.postProcessing.gtao; + setting.blendColor = value; + } + + public get usePosFloat32() { + let setting = Engine3D.setting.render.postProcessing.gtao; + return setting.usePosFloat32; + } + + public set usePosFloat32(value: boolean) { + let setting = Engine3D.setting.render.postProcessing.gtao; + setting.usePosFloat32 = value; + } + + private createGUI() { + + } + + private removeGUI() { + } + + + private createCompute() { + let setting = Engine3D.setting.render.postProcessing.gtao; + + this.gtaoCompute = new ComputeShader(GTAOCs); + + let gtaoSetting: UniformGPUBuffer = new UniformGPUBuffer(4 * 3); //vector4 * 2 + this.gtaoCompute.setUniformBuffer('gtaoData', gtaoSetting); + + this.directionsArray = new Float32Array(8 * 2); + this.directionsBuffer = new StorageGPUBuffer(8 * 2); + + this.directionsBuffer.setFloat32Array('array', this.randomDirection()); + this.directionsBuffer.apply(); + this.gtaoCompute.setStorageBuffer('directions', this.directionsBuffer); + + this.aoBuffer = new StorageGPUBuffer(this.gtaoTexture.width * this.gtaoTexture.height); + this.gtaoCompute.setStorageBuffer('aoBuffer', this.aoBuffer); + let rtFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer"); + //setting.usePosFloat32 ? RTResourceMap.getTexture(RTResourceConfig.positionBufferTex_NAME): + let posTexture = rtFrame.attachments[1]; + this.gtaoCompute.setSamplerTexture(`posTex`, posTexture); + this.gtaoCompute.setSamplerTexture(`normalTex`, rtFrame.attachments[2]); + this.autoSetColorTexture('inTex', this.gtaoCompute); + this.gtaoCompute.setStorageTexture(`outTex`, this.gtaoTexture); + + this.gtaoCompute.workerSizeX = Math.ceil(this.gtaoTexture.width / 8); + this.gtaoCompute.workerSizeY = Math.ceil(this.gtaoTexture.height / 8); + this.gtaoCompute.workerSizeZ = 1; + + this.gtaoSetting = gtaoSetting; + } + + private createResource() { + let presentationSize = webGPUContext.presentationSize; + let w = presentationSize[0]; + let h = presentationSize[1]; + + // RTResourceMap.createRTTextures( + // [RTResourceConfig.colorBufferTex_NAME, RTResourceConfig.positionBufferTex_NAME, RTResourceConfig.normalBufferTex_NAME, RTResourceConfig.materialBufferTex_NAME], + // [GPUTextureFormat.rgba16float, GPUTextureFormat.rgba16float, GPUTextureFormat.rgba8unorm, GPUTextureFormat.rgba8unorm], + // ); + + this.gtaoTexture = new VirtualTexture(w, h, GPUTextureFormat.rgba16float, false, GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.TEXTURE_BINDING); + this.gtaoTexture.name = 'gtaoTex'; + let gtaoDec = new RTDescriptor(); + // gtaoDec.clearValue = [1, 1, 1, 1]; + gtaoDec.loadOp = `load`; + this.rtFrame = new RTFrame([ + this.gtaoTexture + ], [ + gtaoDec + ]); + } + + private randomCount: number = 0; + private randomDirection(): Float32Array { + this.randomCount++; + if (this.randomCount > 1) this.randomCount = 0; + let offsetAngle = (Math.PI * 2 * this.randomCount) / 16; + let angleSegment = (Math.PI * 2) / 8; + for (let i = 0; i < 8; i++) { + let angle = offsetAngle + i * angleSegment; + this.directionsArray[i * 2] = Math.sin(angle); + this.directionsArray[i * 2 + 1] = Math.cos(angle); + } + return this.directionsArray; + } + /** + * @internal + */ + render(view: View3D, command: GPUCommandEncoder) { + if (!this.gtaoCompute) { + this.createResource(); + this.createCompute(); + + this.rendererPassState = WebGPUDescriptorCreator.createRendererPassState(this.rtFrame, null); + this.rendererPassState.label = "GTAO"; + + let standUniform = GlobalBindGroup.getCameraGroup(view.camera); + this.gtaoCompute.setUniformBuffer('standUniform', standUniform.uniformGPUBuffer); + } + let cfg = Engine3D.setting.render.postProcessing.gtao; + + this.directionsBuffer.setFloat32Array('array', this.randomDirection()); + this.directionsBuffer.apply(); + let scaleFactor = 1 - 0.2 * (Time.frame % 2); + let maxDistance = cfg.maxDistance * scaleFactor; + let maxPixel = cfg.maxPixel * scaleFactor; + this.gtaoSetting.setFloat('maxDistance', maxDistance); + this.gtaoSetting.setFloat('maxPixel', maxPixel); + this.gtaoSetting.setFloat('darkFactor', cfg.darkFactor); + this.gtaoSetting.setFloat('rayMarchSegment', cfg.rayMarchSegment); + + let camera = view.camera; + this.gtaoSetting.setFloat('cameraNear', camera.near); + this.gtaoSetting.setFloat('cameraFar', camera.far); + this.gtaoSetting.setFloat('viewPortWidth', camera.viewPort.width); + this.gtaoSetting.setFloat('viewPortHeight', camera.viewPort.height); + + this.gtaoSetting.setFloat('multiBounce', cfg.multiBounce ? 1 : 0); + this.gtaoSetting.setFloat('blendColor', cfg.blendColor ? 1 : 0); + + this.gtaoSetting.apply(); + + GPUContext.computeCommand(command, [this.gtaoCompute]); + GPUContext.lastRenderPassState = this.rendererPassState; + } +} diff --git a/src/engine/gfx/renderJob/post/GlobalFog.ts b/src/engine/gfx/renderJob/post/GlobalFog.ts new file mode 100644 index 00000000..99422b83 --- /dev/null +++ b/src/engine/gfx/renderJob/post/GlobalFog.ts @@ -0,0 +1,149 @@ +import { GlobalFog_shader } from '../../../assets/shader/post/GlobalFog_shader'; +import { ShaderLib } from '../../../assets/shader/ShaderLib'; +import { ViewQuad } from '../../../core/ViewQuad'; +import { Engine3D } from '../../../Engine3D'; +import { Color } from '../../../math/Color'; +import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { UniformNode } from '../../graphics/webGpu/core/uniforms/UniformNode'; +import { GPUTextureFormat } from '../../graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../../graphics/webGpu/Context3D'; +import { GPUContext } from '../GPUContext'; +import { PostBase } from './PostBase'; +import { View3D } from '../../../core/View3D'; +import { GBufferFrame } from '../frame/GBufferFrame'; +/** + * screen space fog + * ``` + * //setting + * let cfg = {@link Engine3D.setting.render.postProcessing.globalFog}; + * let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + * + * Engine3D.startRender(renderJob); + *``` + * @group Post Effects + */ +export class GlobalFog extends PostBase { + /** + * @internal + */ + viewQuad: ViewQuad; + /** + * @internal + */ + rtTexture: VirtualTexture; + constructor() { + super(); + let globalFog = Engine3D.setting.render.postProcessing.globalFog; + + let rtFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer"); + + let presentationSize = webGPUContext.presentationSize; + + ShaderLib.register("GlobalFog_shader", GlobalFog_shader); + let shaderUniforms = { + fogColor: new UniformNode(new Color(globalFog.fogColor.r, globalFog.fogColor.g, globalFog.fogColor.b, globalFog.fogColor.a)), + fogType: new UniformNode(globalFog.fogType), + height: new UniformNode(globalFog.height), + start: new UniformNode(globalFog.start), + end: new UniformNode(globalFog.end), + density: new UniformNode(globalFog.density), + ins: new UniformNode(globalFog.ins), + }; + + this.rtTexture = this.createRTTexture(`GlobalFog`, presentationSize[0], presentationSize[1], GPUTextureFormat.rgba16float); + this.viewQuad = this.createViewQuad(`GlobalFog`, 'GlobalFog_shader', this.rtTexture, shaderUniforms); + + let ptex = rtFrame.getPositionMap(); + let ntex = rtFrame.getNormalMap(); + this.setInputTexture(ptex, ntex); + } + + /** + * @internal + */ + public onAttach(view: View3D,) { + Engine3D.setting.render.postProcessing.globalFog.enable = true; + if (Engine3D.setting.render.postProcessing.globalFog.debug) { + this.debug(); + } + } + /** + * @internal + */ + public onDetach(view: View3D,) { + Engine3D.setting.render.postProcessing.globalFog.enable = false; + } + + public debug() { + } + public set fogType(v: number) { + this.viewQuad.uniforms['fogType'].value = v; + } + public get fogType() { + return this.viewQuad.uniforms['fogType'].value; + } + public set height(v: number) { + this.viewQuad.uniforms['height'].value = v; + } + public get height() { + return this.viewQuad.uniforms['height'].value; + } + public set start(v: number) { + this.viewQuad.uniforms['start'].value = v; + } + public get start() { + return this.viewQuad.uniforms['start'].value; + } + public set end(v: number) { + this.viewQuad.uniforms['end'].value = v; + } + public get end() { + return this.viewQuad.uniforms['end'].value; + } + public set ins(v: number) { + this.viewQuad.uniforms['ins'].value = v; + } + public get ins() { + return this.viewQuad.uniforms['ins'].value; + } + public set density(v: number) { + this.viewQuad.uniforms['density'].value = v; + } + public get density() { + return this.viewQuad.uniforms['density'].value; + } + /** + * @internal + */ + public get fogColor(): Color { + return this.viewQuad.uniforms['fogColor'].color; + } + /** + * @internal + */ + public set fogColor(value: Color) { + this.viewQuad.uniforms['fogColor'].color = value; + this.viewQuad.uniforms['fogColor'].onChange(); + } + + /** + * @internal + */ + public setInputTexture(positionMap: VirtualTexture, normalMap: VirtualTexture) { + const renderShader = this.viewQuad.material.renderShader; + renderShader.setTexture('positionMap', positionMap); + renderShader.setTexture('normalMap', normalMap); + } + /** + * @internal + */ + render(view: View3D, command: GPUCommandEncoder) { + const renderShader = this.viewQuad.material.renderShader; + renderShader.setTexture('colorMap', this.getOutTexture()); + GPUContext.renderTarget(view, this.viewQuad, command); + } + +} diff --git a/src/engine/gfx/renderJob/post/HDRBloomPost.ts b/src/engine/gfx/renderJob/post/HDRBloomPost.ts new file mode 100644 index 00000000..9a8621af --- /dev/null +++ b/src/engine/gfx/renderJob/post/HDRBloomPost.ts @@ -0,0 +1,178 @@ +import { ViewQuad } from '../../../core/ViewQuad'; +import { Engine3D } from '../../../Engine3D'; +import { Vector2 } from '../../../math/Vector2'; +import { UniformNode } from '../../graphics/webGpu/core/uniforms/UniformNode'; +import { GPUTextureFormat } from '../../graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../../graphics/webGpu/Context3D'; +import { GPUContext } from '../GPUContext'; +import { RTResourceConfig } from '../config/RTResourceConfig'; +import { RTResourceMap } from '../frame/RTResourceMap'; +import { PostBase } from './PostBase'; +import { View3D } from '../../../core/View3D'; +/** + * HDR Bloom effect + * ``` + * //setting + * let cfg = {@link Engine3D.setting.render.postProcessing.bloom}; + * let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + * + * Engine3D.startRender(renderJob); + *``` + * @group Post Effects + */ +export class HDRBloomPost extends PostBase { + private brightnessView: ViewQuad; + private compositeView: ViewQuad; + private blurList: { ql: ViewQuad; qr: ViewQuad }[]; + /** + * @internal + */ + public blurX: number = 1; + /** + * @internal + */ + public blurY: number = 1; + constructor() { + super(); + Engine3D.setting.render.postProcessing.bloom.enable = true; + + this.blurX = Engine3D.setting.render.postProcessing.bloom.blurX; + this.blurY = Engine3D.setting.render.postProcessing.bloom.blurY; + + let presentationSize = webGPUContext.presentationSize; + let outTextures = this.createRTTexture('HDRBloomPost-outTextures', presentationSize[0], presentationSize[1], GPUTextureFormat.rgba16float, false); + RTResourceMap.createRTTexture(RTResourceConfig.colorBufferTex_NAME, presentationSize[0], presentationSize[1], GPUTextureFormat.rgba16float, false); + + { + let brightnessTextures = this.createRTTexture('brightnessTextures', presentationSize[0], presentationSize[1], GPUTextureFormat.rgba16float, false); + + this.brightnessView = this.createViewQuad(`brightnessView`, `Bloom_Brightness_frag_wgsl`, brightnessTextures, { + luminosityThreshold: new UniformNode(Engine3D.setting.render.postProcessing.bloom.brightness), + }); + } + + let blurMip = 5; + let sizeW = presentationSize[0]; + let sizeH = presentationSize[1]; + this.blurList = []; + for (let i = 0; i < blurMip; i++) { + let tex_l = this.createRTTexture(`tex_l${i}`, sizeW, sizeH, GPUTextureFormat.rgba16float); + let tex_r = this.createRTTexture(`tex_r${i}`, sizeW, sizeH, GPUTextureFormat.rgba16float); + + let ql = this.createViewQuad(`ql${i}`, `Bloom_blur_frag_wgsl`, tex_l, { + texSize: new UniformNode(new Vector2(sizeW * 2, sizeH * 2)), + hScale: new UniformNode(i), + vScale: new UniformNode(i), + horizontal: new UniformNode(0.5), + }); + + let qr = this.createViewQuad(`qr${i}`, `Bloom_blur_frag_wgsl`, tex_r, { + texSize: new UniformNode(new Vector2(sizeW * 2, sizeH * 2)), + hScale: new UniformNode(i), + vScale: new UniformNode(i), + horizontal: new UniformNode(1.0), + }); + + this.blurList.push({ + ql: ql, + qr: qr, + }); + + sizeW /= 2; + sizeH /= 2; + } + + { + this.compositeView = this.createViewQuad(`compositeView`, `Bloom_composite_frag_wgsl`, outTextures, { + bloomStrength: new UniformNode(Engine3D.setting.render.postProcessing.bloom.intensity), + bloomRadius: new UniformNode(1), + }); + } + } + + onAttach(view: View3D): void { + this.debug(); + } + + onDetach(view: View3D): void { + } + + public debug() { + } + + public get bloomStrength() { + return this.compositeView.uniforms['bloomStrength'].value; + } + + public set bloomStrength(value: number) { + this.compositeView.uniforms['bloomStrength'].value = value; + } + + public get bloomRadius() { + return this.compositeView.uniforms['bloomRadius'].value; + } + + public set bloomRadius(value: number) { + this.compositeView.uniforms['bloomRadius'].value = value; + } + + public get luminosityThreshold() { + return this.brightnessView.uniforms['luminosityThreshold'].value; + } + + public set luminosityThreshold(value: number) { + this.brightnessView.uniforms['luminosityThreshold'].value = value; + } + + /** + * @internal + */ + render(view: View3D, command: GPUCommandEncoder) { + // let command = GPUContext.beginCommandEncoder(); + { + let colorTexture = this.getOutTexture(); + { + GPUContext.renderToViewQuad(view, this.brightnessView, command, colorTexture); + } + { + let tex = this.brightnessView.rendererPassState.renderTargets[0]; + for (let i = 0; i < this.blurList.length; i++) { + let ql = this.blurList[i].ql; + let qr = this.blurList[i].qr; + + ql.material.renderShader.setUniformFloat(`horizontal`, 0.5); + ql.material.renderShader.setUniformFloat(`vScale`, i * this.blurX); + + GPUContext.renderToViewQuad(view, ql, command, tex); + tex = ql.rendererPassState.renderTargets[0]; + + qr.material.renderShader.setUniformFloat(`horizontal`, 2.0); + qr.material.renderShader.setUniformFloat(`hScale`, i * this.blurY); + + GPUContext.renderToViewQuad(view, qr, command, tex); + tex = qr.rendererPassState.renderTargets[0]; + } + } + + { + let shader = this.compositeView.material.renderShader; + shader.setTexture(`blurTex1`, this.blurList[0].qr.rendererPassState.renderTargets[0]); + shader.setTexture(`blurTex2`, this.blurList[1].qr.rendererPassState.renderTargets[0]); + shader.setTexture(`blurTex3`, this.blurList[2].qr.rendererPassState.renderTargets[0]); + shader.setTexture(`blurTex4`, this.blurList[3].qr.rendererPassState.renderTargets[0]); + shader.setTexture(`blurTex5`, this.blurList[4].qr.rendererPassState.renderTargets[0]); + + // this.compositeView.material.blurTex5[1] = this.blurList[0].qr.rendererPassState.renderTargets[0]; + // this.compositeView.material.textures[2] = this.blurList[1].qr.rendererPassState.renderTargets[0]; + // this.compositeView.material.textures[3] = this.blurList[2].qr.rendererPassState.renderTargets[0]; + // this.compositeView.material.textures[4] = this.blurList[3].qr.rendererPassState.renderTargets[0]; + // this.compositeView.material.textures[5] = this.blurList[4].qr.rendererPassState.renderTargets[0]; + GPUContext.renderToViewQuad(view, this.compositeView, command, colorTexture); + } + } + // GPUContext.endCommandEncoder(command); + } +} diff --git a/src/engine/gfx/renderJob/post/OutlinePost.ts b/src/engine/gfx/renderJob/post/OutlinePost.ts new file mode 100644 index 00000000..5a914537 --- /dev/null +++ b/src/engine/gfx/renderJob/post/OutlinePost.ts @@ -0,0 +1,347 @@ + +import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { StorageGPUBuffer } from '../../graphics/webGpu/core/buffer/StorageGPUBuffer'; +import { UniformGPUBuffer } from '../../graphics/webGpu/core/buffer/UniformGPUBuffer'; +import { WebGPUDescriptorCreator } from '../../graphics/webGpu/descriptor/WebGPUDescriptorCreator'; +import { ComputeShader } from '../../graphics/webGpu/shader/ComputeShader'; +import { GPUTextureFormat } from '../../graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../../graphics/webGpu/Context3D'; +import { GPUContext } from '../GPUContext'; +import { RendererPassState } from '../passRenderer/state/RendererPassState'; +import { PostBase } from './PostBase'; +import { Engine3D } from '../../../Engine3D'; +import { clamp } from '../../../math/MathUtil'; +import { Color } from '../../../math/Color'; +import OutLineBlendColor from '../../../assets/shader/compute/OutLineBlendColor.wgsl?raw'; +import OutlineCalcOutline from '../../../assets/shader/compute/OutlineCalcOutline.wgsl?raw'; +import OutlineCs from '../../../assets/shader/compute/OutlineCs.wgsl?raw'; +import { Vector2 } from '../../../math/Vector2'; +import { RTDescriptor } from '../../graphics/webGpu/descriptor/RTDescriptor'; +import { GBufferFrame } from '../frame/GBufferFrame'; +import { RTFrame } from '../frame/RTFrame'; +import { OutlineSetting } from '../../../setting/post/OutlineSetting'; +import { View3D } from '../../../core/View3D'; + +export class OutlinePostSlot { + public indexList: Float32Array; + public color: Color; + public count: number; +} + +export class OutlinePostData { + //max to 8 groups of different colors can be selected + public readonly SlotCount: number = 8; + public readonly MaxEntities: number = 16; + public readonly defaultColor: Color = new Color(0.2, 1, 1, 1); + private readonly slots: OutlinePostSlot[] = []; + + private dataDirty: boolean = true; + + constructor() { + let groupCount = Engine3D.setting.render.postProcessing.outline.groupCount; + this.SlotCount = Math.max(1, Math.min(groupCount, this.SlotCount)); + for (let i = 0; i < this.SlotCount; i++) { + let slot: OutlinePostSlot = (this.slots[i] = new OutlinePostSlot()); + slot.indexList = new Float32Array(this.MaxEntities); + slot.color = this.defaultColor.clone(); + slot.count = 0; + } + } + + public clear(): void { + for (let i = 0; i < this.SlotCount; i++) { + this.clearAt(i); + } + } + + public clearAt(slotIndex: number): this { + this.dataDirty = true; + let slot: OutlinePostSlot = this.slots[slotIndex]; + slot.color.copyForm(this.defaultColor); + slot.indexList.fill(-1); + slot.count = 0; + return this; + } + + public fillDataAt(slot: number, indexList: number[], color: Color): this { + this.dataDirty = true; + let data = this.slots[slot]; + if (data) { + data.indexList.fill(-1); + for (let i = 0, c = indexList.length; i < c; i++) { + data.indexList[i] = indexList[i]; + } + data.count = indexList.length; + data.color.copyForm(color); + } + return this; + } + + public fetchData(target: { dirty: boolean; slots: OutlinePostSlot[] }): this { + target.dirty = this.dataDirty; + target.slots = this.slots; + this.dataDirty = false; + return this; + } +} + +export let outlinePostData: OutlinePostData = new OutlinePostData(); + +/** + * post effect out line + * OutlinePostManager, + * ``` + * //setting + * let cfg = {@link Engine3D.setting.render.postProcessing.outline}; + * let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + * + * Engine3D.startRender(renderJob); + *``` + * @group Post Effects + */ +export class OutlinePost extends PostBase { + /** + * @internal + */ + outlineTex: VirtualTexture; + + lowTex: VirtualTexture; + + /** + * @internal + */ + rendererPassState: RendererPassState; + /** + * @internal + */ + calcWeightCompute: ComputeShader; + outlineCompute: ComputeShader; + blendCompute: ComputeShader; + /** + * @internal + */ + outlineSetting: StorageGPUBuffer; + + /** + * @internal + */ + slotsBuffer: StorageGPUBuffer; + slotsArray: Float32Array; + + + entitiesArray: Float32Array; + entitiesBuffer: StorageGPUBuffer; + + weightBuffer: StorageGPUBuffer; + lowTexSize: Vector2; + + oldOutlineColor: StorageGPUBuffer; + rtFrame: RTFrame; + + constructor() { + super(); + } + + /** + * @internal + */ + onAttach(view: View3D,) { + Engine3D.setting.render.postProcessing.outline.enable = true; + } + + /** + * @internal + */ + onDetach(view: View3D,) { + Engine3D.setting.render.postProcessing.outline.enable = false; + } + + public set outlinePixel(value: number) { + value = clamp(value, 0, 8); + let cfg = Engine3D.setting.render.postProcessing.outline; + if (cfg.outlinePixel != value) { + cfg.outlinePixel = value; + } + } + + public get outlinePixel() { + return Engine3D.setting.render.postProcessing.outline.outlinePixel; + } + + public set fadeOutlinePixel(value: number) { + let cfg = Engine3D.setting.render.postProcessing.outline; + value = clamp(value, 0, 8); + if (cfg.fadeOutlinePixel != value) { + cfg.fadeOutlinePixel = value; + } + } + + public get fadeOutlinePixel() { + return Engine3D.setting.render.postProcessing.outline.fadeOutlinePixel; + } + + public set strength(value: number) { + value = clamp(value, 0, 1); + let cfg = Engine3D.setting.render.postProcessing.outline; + if (cfg.strength != value) { + cfg.strength = value; + } + } + + public get strength() { + return Engine3D.setting.render.postProcessing.outline.strength; + } + + public set useAddMode(value: boolean) { + Engine3D.setting.render.postProcessing.outline.useAddMode = value; + } + + public get useAddMode() { + return Engine3D.setting.render.postProcessing.outline.useAddMode; + } + + private createGUI() { + } + + private createCompute() { + let rtFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer"); + let visibleMap = rtFrame.getPositionMap();// RTResourceMap.getTexture(RTResourceConfig.zBufferTexture_NAME); + + this.calcWeightCompute = new ComputeShader(OutlineCalcOutline); + this.calcWeightCompute.setStorageBuffer('outlineSetting', this.outlineSetting); + this.calcWeightCompute.setStorageBuffer('slotsBuffer', this.slotsBuffer); + this.calcWeightCompute.setStorageBuffer(`weightBuffer`, this.weightBuffer); + this.calcWeightCompute.setStorageBuffer(`entitiesBuffer`, this.entitiesBuffer); + this.calcWeightCompute.setSamplerTexture(`indexTexture`, visibleMap); + + this.calcWeightCompute.workerSizeX = Math.ceil(this.lowTex.width / 8); + this.calcWeightCompute.workerSizeY = Math.ceil(this.lowTex.height / 8); + this.calcWeightCompute.workerSizeZ = 1; + + //outline + this.outlineCompute = new ComputeShader(OutlineCs); + this.outlineCompute.setStorageBuffer('outlineSetting', this.outlineSetting); + this.outlineCompute.setStorageBuffer('slotsBuffer', this.slotsBuffer); + this.outlineCompute.setStorageBuffer(`weightBuffer`, this.weightBuffer); + this.outlineCompute.setStorageBuffer(`oldOutlineColor`, this.oldOutlineColor); + this.outlineCompute.setStorageTexture(`lowTex`, this.lowTex); + + this.outlineCompute.workerSizeX = Math.ceil(this.lowTex.width / 8); + this.outlineCompute.workerSizeY = Math.ceil(this.lowTex.height / 8); + this.outlineCompute.workerSizeZ = 1; + + //blend + this.blendCompute = new ComputeShader(OutLineBlendColor); + this.blendCompute.setStorageBuffer('outlineSetting', this.outlineSetting); + this.autoSetColorTexture('inTex', this.blendCompute); + this.blendCompute.setSamplerTexture(`lowTex`, this.lowTex); + this.blendCompute.setStorageTexture(`outlineTex`, this.outlineTex); + + this.blendCompute.workerSizeX = Math.ceil(this.outlineTex.width / 8); + this.blendCompute.workerSizeY = Math.ceil(this.outlineTex.height / 8); + this.blendCompute.workerSizeZ = 1; + } + + private createResource() { + let presentationSize = webGPUContext.presentationSize; + let w = presentationSize[0]; + let h = presentationSize[1]; + this.lowTexSize = new Vector2(Math.floor(w * 0.5), Math.floor(h * 0.5)); + + this.lowTex = new VirtualTexture(this.lowTexSize.x, this.lowTexSize.y, GPUTextureFormat.rgba16float, false, GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.TEXTURE_BINDING); + this.lowTex.name = 'lowTex'; + let lowDec = new RTDescriptor(); + lowDec.clearValue = [0, 0, 0, 1]; + lowDec.loadOp = `clear`; + + this.outlineTex = new VirtualTexture(w, h, GPUTextureFormat.rgba16float, false, GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.TEXTURE_BINDING); + this.outlineTex.name = 'outlineTex'; + let outDec = new RTDescriptor(); + outDec.clearValue = [0, 0, 0, 1]; + outDec.loadOp = `clear`; + + this.rtFrame = new RTFrame([ + this.outlineTex + ], [ + outDec + ]); + + let rtFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer"); + + // RTResourceMap.createRTTextures( + // [RTResourceConfig.colorBufferTex_NAME, RTResourceConfig.positionBufferTex_NAME, RTResourceConfig.normalBufferTex_NAME, RTResourceConfig.materialBufferTex_NAME], + // [GPUTextureFormat.rgba16float, GPUTextureFormat.rgba16float, GPUTextureFormat.rgba8unorm, GPUTextureFormat.rgba8unorm], + // ); + + this.outlineSetting = new UniformGPUBuffer(8); + this.weightBuffer = new StorageGPUBuffer(this.lowTexSize.x * this.lowTexSize.y * 4, GPUBufferUsage.COPY_SRC); + this.oldOutlineColor = new StorageGPUBuffer(this.lowTexSize.x * this.lowTexSize.y * 4, GPUBufferUsage.COPY_SRC); + + this.slotsArray = new Float32Array(outlinePostData.SlotCount * 4); + this.slotsBuffer = new StorageGPUBuffer(this.slotsArray.length); + this.slotsBuffer.setFloat32Array('slotsArray', this.slotsArray); + this.slotsBuffer.apply(); + + this.entitiesArray = new Float32Array(outlinePostData.SlotCount * outlinePostData.MaxEntities); + this.entitiesBuffer = new StorageGPUBuffer(this.entitiesArray.length); + this.entitiesBuffer.setFloat32Array('entitiesArray', this.entitiesArray); + this.slotsBuffer.apply(); + + this.fetchData ||= {} as any; + } + + private fetchData: { dirty: boolean; slots: OutlinePostSlot[] }; + + private fetchOutlineData(): void { + outlinePostData.fetchData(this.fetchData); + if (this.fetchData.dirty) { + let slotCount = outlinePostData.SlotCount; + let maxEntities = outlinePostData.MaxEntities; + for (let i = 0; i < slotCount; i++) { + let offset = 4 * i; + let slot = this.fetchData.slots[i]; + this.slotsArray[offset + 0] = slot.color.r; + this.slotsArray[offset + 1] = slot.color.g; + this.slotsArray[offset + 2] = slot.color.b; + this.slotsArray[offset + 3] = slot.count; + + offset = maxEntities * i; + this.entitiesArray.set(slot.indexList, offset); + } + this.slotsBuffer.setFloat32Array('slotsArray', this.slotsArray); + this.slotsBuffer.apply(); + this.entitiesBuffer.setFloat32Array('entitiesArray', this.entitiesArray); + this.entitiesBuffer.apply(); + } + } + + private computeList: ComputeShader[]; + + /** + * @internal + */ + render(view: View3D, command: GPUCommandEncoder) { + if (!this.calcWeightCompute) { + this.createResource(); + this.createCompute(); + this.createGUI(); + this.rendererPassState = WebGPUDescriptorCreator.createRendererPassState(this.rtFrame, null); + } + this.computeList ||= [this.calcWeightCompute, this.outlineCompute, this.blendCompute]; + let cfg = Engine3D.setting.render.postProcessing.outline; + this.outlineSetting.setFloat('strength', cfg.strength); + this.outlineSetting.setFloat('useAddMode', cfg.useAddMode ? 1 : 0); + this.outlineSetting.setFloat('outlinePixel', cfg.outlinePixel); + this.outlineSetting.setFloat('fadeOutlinePixel', cfg.fadeOutlinePixel); + this.outlineSetting.setFloat('lowTexWidth', this.lowTexSize.x); + this.outlineSetting.setFloat('lowTexHeight', this.lowTexSize.y); + this.outlineSetting.apply(); + + this.fetchOutlineData(); + GPUContext.computeCommand(command, this.computeList); + GPUContext.lastRenderPassState = this.rendererPassState; + } +} diff --git a/src/engine/gfx/renderJob/post/PostBase.ts b/src/engine/gfx/renderJob/post/PostBase.ts new file mode 100644 index 00000000..7b66d20c --- /dev/null +++ b/src/engine/gfx/renderJob/post/PostBase.ts @@ -0,0 +1,93 @@ +import { Scene3D } from '../../../core/Scene3D'; +import { ViewQuad } from '../../../core/ViewQuad'; +import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { Texture } from '../../graphics/webGpu/core/texture/Texture'; +import { UniformNode } from '../../graphics/webGpu/core/uniforms/UniformNode'; +import { GPUContext } from '../GPUContext'; +import { RTResourceMap } from '../frame/RTResourceMap'; +import { ComputeShader } from '../../../gfx/graphics/webGpu/shader/ComputeShader'; +import { RTResourceConfig } from '../config/RTResourceConfig'; +import { PostRenderer } from '../passRenderer/post/PostRenderer'; +import { View3D } from '../../../core/View3D'; +/** + * @internal + * Base class for post-processing effects + * @group Post Effects + */ +export class PostBase { + public enable: boolean = true; + public postRenderer: PostRenderer; + protected rtViewQuad: Map; + protected virtualTexture: Map; + + constructor() { + this.rtViewQuad = new Map(); + this.virtualTexture = new Map(); + } + + protected createRTTexture(name: string, rtWidth: number, rtHeight: number, format: GPUTextureFormat, useMipmap: boolean = false, sampleCount: number = 0) { + let rt = RTResourceMap.createRTTexture(name, rtWidth, rtHeight, format, useMipmap, sampleCount); + rt.name = name; + this.virtualTexture.set(name, rt); + return rt; + } + + protected createViewQuad(name: string, shaderName: string, outRtTexture: VirtualTexture, shaderUniforms?: { [uniName: string]: UniformNode }, msaa: number = 0) { + let viewQuad = RTResourceMap.createViewQuad(name, 'Quad_vert_wgsl', shaderName, outRtTexture, shaderUniforms, msaa); + this.rtViewQuad.set(name, viewQuad); + return viewQuad; + } + + protected getOutTexture(): Texture { + let colorTexture: Texture; + let renderTargets = GPUContext.lastRenderPassState.renderTargets; + if (renderTargets.length > 0) { + colorTexture = renderTargets[0]; + } else { + colorTexture = RTResourceMap.getTexture(RTResourceConfig.colorBufferTex_NAME); + } + return colorTexture; + } + + protected autoSetColorTexture(name: string, compute: ComputeShader): void { + let input = this.getOutTexture() as VirtualTexture; + compute.setSamplerTexture(name, input); + } + /** + * @internal + */ + public compute(view: View3D,) { } + /** + * @internal + */ + public onAttach(view: View3D,) { } + /** + * @internal + */ + public onDetach(view: View3D,) { } + /** + * @internal + */ + public render(view: View3D, command: GPUCommandEncoder) { + this.compute(view); + this.rtViewQuad.forEach((v, k) => { + let lastTexture = GPUContext.lastRenderPassState.getLastRenderTexture(); + GPUContext.renderToViewQuad(view, v, command, lastTexture); + }); + } + + public destroy() { + this.postRenderer = null; + for (let i = 0; i < this.rtViewQuad.size; i++) { + const quad = this.rtViewQuad.values[i] as ViewQuad; + quad.destroy(); + } + this.rtViewQuad.clear(); + this.rtViewQuad = null; + + for (let i = 0; i < this.virtualTexture.size; i++) { + const tex = this.virtualTexture.values[i] as VirtualTexture; + tex.destroy(); + } + } +} diff --git a/src/engine/gfx/renderJob/post/SSRPost.ts b/src/engine/gfx/renderJob/post/SSRPost.ts new file mode 100644 index 00000000..1cda19e1 --- /dev/null +++ b/src/engine/gfx/renderJob/post/SSRPost.ts @@ -0,0 +1,314 @@ +import SSR_BlendColor_Shader from '../../../assets/shader/compute/SSR_BlendColor_Shader.wgsl?raw'; +import SSR_IS_Shader from '../../../assets/shader/compute/SSR_IS_Shader.wgsl?raw'; +import SSR_RayTrace_Shader from '../../../assets/shader/compute/SSR_RayTrace_Shader.wgsl?raw'; +import { Engine3D } from '../../../Engine3D'; +import { Vector3 } from '../../../math/Vector3'; +import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { GlobalBindGroup } from '../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { StorageGPUBuffer } from '../../graphics/webGpu/core/buffer/StorageGPUBuffer'; +import { UniformGPUBuffer } from '../../graphics/webGpu/core/buffer/UniformGPUBuffer'; +import { WebGPUDescriptorCreator } from '../../graphics/webGpu/descriptor/WebGPUDescriptorCreator'; +import { ComputeShader } from '../../graphics/webGpu/shader/ComputeShader'; +import { GPUTextureFormat } from '../../graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../../graphics/webGpu/Context3D'; +import { GPUContext } from '../GPUContext'; +import { RTResourceMap } from '../frame/RTResourceMap'; +import { RendererPassState } from '../passRenderer/state/RendererPassState'; +import { PostBase } from './PostBase'; +import { clamp } from '../../../math/MathUtil'; +import { EntityCollect } from '../collect/EntityCollect'; +import { RTResourceConfig } from '../config/RTResourceConfig'; +import { RTDescriptor } from '../../graphics/webGpu/descriptor/RTDescriptor'; +import { RTFrame } from '../frame/RTFrame'; +import { GBufferFrame } from '../frame/GBufferFrame'; +import { SSRSetting } from '../../../setting/post/SSRSetting'; +import { View3D } from '../../../core/View3D'; +/** + * Screen space reflection + * ``` + * //setting + * let cfg = {@link Engine3D.setting.render.postProcessing.ssr}; + * let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + * + * Engine3D.startRender(renderJob); + *``` + * @group Post Effects + */ +export class SSRPost extends PostBase { + private SSR_RayTraceCompute: ComputeShader; + private SSR_IS_Compute: ComputeShader; + private SSR_Blend_Compute: ComputeShader; + /** + * @internal + */ + isRetTexture: VirtualTexture; + /** + * @internal + */ + finalTexture: VirtualTexture; + /** + * @internal + */ + rendererPassState: RendererPassState; + /** + * @internal + */ + ssrUniformBuffer: StorageGPUBuffer; + /** + * @internal + */ + rayTraceData: StorageGPUBuffer; + /** + * @internal + */ + ssrColorData: StorageGPUBuffer; + /** + * @internal + */ + isKernelFloat32Array: Float32Array; + rtFrame: RTFrame; + historyPosition: StorageGPUBuffer; + + constructor() { + super(); + } + /** + * @internal + */ + public onAttach(view: View3D,) { + Engine3D.setting.render.postProcessing.ssr.enable = true; + this.debug(); + } + /** + * @internal + */ + public onDetach(view: View3D,) { + Engine3D.setting.render.postProcessing.ssr.enable = false; + } + + private reflectionRatio: number = 0.5;//sqrt + + public get fadeEdgeRatio() { + let setting = Engine3D.setting.render.postProcessing.ssr; + return setting.fadeEdgeRatio; + } + + public set fadeEdgeRatio(value: number) { + value = clamp(value, 0, 1); + let setting = Engine3D.setting.render.postProcessing.ssr; + setting.fadeEdgeRatio = value; + } + + public get rayMarchRatio() { + let setting = Engine3D.setting.render.postProcessing.ssr; + return setting.rayMarchRatio; + } + + public set rayMarchRatio(value: number) { + value = clamp(value, 0, 1); + let setting = Engine3D.setting.render.postProcessing.ssr; + setting.rayMarchRatio = value; + } + + public get roughnessThreshold() { + let setting = Engine3D.setting.render.postProcessing.ssr; + return setting.roughnessThreshold; + } + + public set roughnessThreshold(value: number) { + value = clamp(value, 0, 1); + let setting = Engine3D.setting.render.postProcessing.ssr; + setting.roughnessThreshold = value; + } + + public get fadeDistanceMin() { + let setting = Engine3D.setting.render.postProcessing.ssr; + return setting.fadeDistanceMin; + } + + public set fadeDistanceMin(value: number) { + value = clamp(value, 0, 10000); + let setting = Engine3D.setting.render.postProcessing.ssr; + setting.fadeDistanceMin = value; + } + + public get fadeDistanceMax() { + let setting = Engine3D.setting.render.postProcessing.ssr; + return setting.fadeDistanceMax; + } + + public set fadeDistanceMax(value: number) { + value = clamp(value, 0, 10000); + let setting = Engine3D.setting.render.postProcessing.ssr; + setting.fadeDistanceMax = value; + } + + public get powDotRN() { + let setting = Engine3D.setting.render.postProcessing.ssr; + return setting.powDotRN; + } + + public set powDotRN(value: number) { + value = clamp(value, 0, 1); + let setting = Engine3D.setting.render.postProcessing.ssr; + setting.powDotRN = value; + } + + private debug() { + } + + private createRayTraceShader() { + this.SSR_RayTraceCompute = new ComputeShader(SSR_RayTrace_Shader); + this.SSR_RayTraceCompute.setStorageBuffer('ssrUniform', this.ssrUniformBuffer); + this.SSR_RayTraceCompute.setStorageBuffer(`rayTraceBuffer`, this.rayTraceData); + this.SSR_RayTraceCompute.setStorageBuffer(`historyPosition`, this.historyPosition); + + let rtFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer"); + this.SSR_RayTraceCompute.setSamplerTexture("zBufferTexture", rtFrame.getPositionMap()); + this.SSR_RayTraceCompute.setSamplerTexture(RTResourceConfig.normalBufferTex_NAME, rtFrame.attachments[2]); + this.SSR_RayTraceCompute.setSamplerTexture(RTResourceConfig.materialBufferTex_NAME, rtFrame.attachments[3]); + this.SSR_RayTraceCompute.setSamplerTexture(`prefilterMap`, EntityCollect.instance.sky.map); + + this.SSR_RayTraceCompute.workerSizeX = Math.ceil(this.isRetTexture.width / 8); + this.SSR_RayTraceCompute.workerSizeY = Math.ceil(this.isRetTexture.height / 8); + this.SSR_RayTraceCompute.workerSizeZ = 1; + } + + private createISShader() { + this.SSR_IS_Compute = new ComputeShader(SSR_IS_Shader); + + this.SSR_IS_Compute.setStorageBuffer('ssrUniform', this.ssrUniformBuffer); + this.SSR_IS_Compute.setStorageBuffer(`rayTraceBuffer`, this.rayTraceData); + this.SSR_IS_Compute.setStorageBuffer(`ssrColorData`, this.ssrColorData); + this.SSR_IS_Compute.setStorageBuffer(`historyPosition`, this.historyPosition); + + this.autoSetColorTexture('colorMap', this.SSR_IS_Compute); + this.SSR_IS_Compute.setStorageTexture(`outTex`, this.isRetTexture); + + this.SSR_IS_Compute.workerSizeX = Math.ceil(this.isRetTexture.width / 8); + this.SSR_IS_Compute.workerSizeY = Math.ceil(this.isRetTexture.height / 8); + this.SSR_IS_Compute.workerSizeZ = 1; + } + + private createBlendShader(input: VirtualTexture): void { + this.SSR_Blend_Compute = new ComputeShader(SSR_BlendColor_Shader); + + this.SSR_Blend_Compute.setStorageBuffer(`rayTraceBuffer`, this.rayTraceData); + this.autoSetColorTexture('colorMap', this.SSR_Blend_Compute); + this.SSR_Blend_Compute.setSamplerTexture(`ssrMap`, input); + this.SSR_Blend_Compute.setStorageTexture(`outTex`, this.finalTexture); + + this.SSR_Blend_Compute.workerSizeX = Math.ceil(this.finalTexture.width / 8); + this.SSR_Blend_Compute.workerSizeY = Math.ceil(this.finalTexture.height / 8); + this.SSR_Blend_Compute.workerSizeZ = 1; + } + + private createResource() { + let presentationSize = webGPUContext.presentationSize; + let w = presentationSize[0]; + let h = presentationSize[1]; + // RTResourceMap.createRTTextures( + // [RTResourceConfig.colorBufferTex_NAME, RTResourceConfig.positionBufferTex_NAME, RTResourceConfig.normalBufferTex_NAME, RTResourceConfig.materialBufferTex_NAME], + // [GPUTextureFormat.rgba16float, GPUTextureFormat.rgba16float, GPUTextureFormat.rgba8unorm, GPUTextureFormat.rgba8unorm], + // ); + this.finalTexture = new VirtualTexture(w, h, GPUTextureFormat.rgba16float, false, GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING); + this.finalTexture.name = 'ssrOutTex'; + let rtDec = new RTDescriptor(); + rtDec.clearValue = [0, 0, 0, 0]; + rtDec.loadOp = `clear`; + + let ssrWidth = Math.ceil(w * Engine3D.setting.render.postProcessing.ssr.pixelRatio); + let ssrHeight = Math.ceil(h * Engine3D.setting.render.postProcessing.ssr.pixelRatio); + + this.isRetTexture = new VirtualTexture(ssrWidth, ssrHeight, GPUTextureFormat.rgba16float, false, GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING); + this.isRetTexture.name = 'ssrTextureIn'; + let isRetDec = new RTDescriptor(); + isRetDec.clearValue = [0, 0, 0, 0]; + isRetDec.loadOp = `clear`; + + this.rtFrame = new RTFrame([ + this.finalTexture, + this.isRetTexture + ], [ + rtDec, + isRetDec + ]); + + this.rayTraceData = new StorageGPUBuffer(ssrWidth * ssrHeight * 8, GPUBufferUsage.COPY_SRC); + this.ssrColorData = new StorageGPUBuffer(ssrWidth * ssrHeight * 4, GPUBufferUsage.COPY_SRC); + this.historyPosition = new StorageGPUBuffer(ssrWidth * ssrHeight * 4, GPUBufferUsage.COPY_SRC); + + //ssr uniform + this.ssrUniformBuffer = new UniformGPUBuffer(4 * 8); + this.ssrUniformBuffer.setFloat('ssrBufferSizeX', this.isRetTexture.width); + this.ssrUniformBuffer.setFloat('ssrBufferSizeY', this.isRetTexture.height); + this.ssrUniformBuffer.setFloat('colorMapSizeX', this.finalTexture.width); + this.ssrUniformBuffer.setFloat('colorMapSizeY', this.finalTexture.height); + + this.ssrUniformBuffer.apply(); + } + /** + * @internal + */ + render(view: View3D, command: GPUCommandEncoder) { + if (!this.SSR_RayTraceCompute) { + this.createResource(); + this.createISShader(); + this.createRayTraceShader(); + this.createBlendShader(this.isRetTexture); + let presentTexture = this.finalTexture; + this.rendererPassState = WebGPUDescriptorCreator.createRendererPassState(this.rtFrame, null); + + let standUniform = GlobalBindGroup.getCameraGroup(view.camera); + this.SSR_RayTraceCompute.setUniformBuffer('standUniform', standUniform.uniformGPUBuffer); + } + + let setting: SSRSetting = Engine3D.setting.render.postProcessing.ssr; + this.ssrUniformBuffer.setFloat('fadeEdgeRatio', setting.fadeEdgeRatio); + this.ssrUniformBuffer.setFloat('rayMarchRatio', setting.rayMarchRatio); + this.ssrUniformBuffer.setFloat('fadeDistanceMin', setting.fadeDistanceMin); + this.ssrUniformBuffer.setFloat('fadeDistanceMax', setting.fadeDistanceMax); + + this.ssrUniformBuffer.setFloat('mixThreshold', setting.mixThreshold); + this.ssrUniformBuffer.setFloat('roughnessThreshold', setting.roughnessThreshold); + this.ssrUniformBuffer.setFloat('reflectionRatio', this.reflectionRatio); + this.ssrUniformBuffer.setFloat('powDotRN', setting.powDotRN); + + this.ssrUniformBuffer.setFloat('randomSeedX', Math.random()); + this.ssrUniformBuffer.setFloat('randomSeedY', Math.random()); + + this.ssrUniformBuffer.apply(); + + let computes = [this.SSR_RayTraceCompute, this.SSR_IS_Compute, this.SSR_Blend_Compute]; + GPUContext.computeCommand(command, computes); + GPUContext.lastRenderPassState = this.rendererPassState; + } +} + +/** + * @internal + * @group Post Effects + */ +export class SSR_IS_Kernel { + public static createSeeds(): Vector3[] { + let scaler = 20; + let count = 32; + let list = [new Vector3(0, 0, scaler)]; + let angle = 0; + let radius = 0.02; + for (let i = 1; i < count; i++) { + let pt = new Vector3(); + list.push(pt); + angle += 1 - ((1 - 0.618) * i) / count; + radius += i * 0.01; + pt.x = Math.sin(angle) * radius; + pt.y = Math.cos(angle) * radius; + pt.z = 1 - i / count; + pt.multiplyScalar(scaler); + } + return list; + } +} diff --git a/src/engine/gfx/renderJob/post/TAAPost.ts b/src/engine/gfx/renderJob/post/TAAPost.ts new file mode 100644 index 00000000..87f69970 --- /dev/null +++ b/src/engine/gfx/renderJob/post/TAAPost.ts @@ -0,0 +1,260 @@ +import { VirtualTexture } from '../../../textures/VirtualTexture'; +import { GlobalBindGroup } from '../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { StorageGPUBuffer } from '../../graphics/webGpu/core/buffer/StorageGPUBuffer'; +import { UniformGPUBuffer } from '../../graphics/webGpu/core/buffer/UniformGPUBuffer'; +import { WebGPUDescriptorCreator } from '../../graphics/webGpu/descriptor/WebGPUDescriptorCreator'; +import { ComputeShader } from '../../graphics/webGpu/shader/ComputeShader'; +import { GPUTextureFormat } from '../../graphics/webGpu/WebGPUConst'; +import { webGPUContext } from '../../graphics/webGpu/Context3D'; +import { GPUContext } from '../GPUContext'; +import { RendererPassState } from '../passRenderer/state/RendererPassState'; +import { PostBase } from './PostBase'; +import { Engine3D } from '../../../Engine3D'; +import { Matrix4 } from '../../../math/Matrix4'; +import { clamp } from '../../../math/MathUtil'; +import { RTDescriptor } from '../../graphics/webGpu/descriptor/RTDescriptor'; +import { RTFrame } from '../frame/RTFrame'; +import TAAcs from '../../../assets/shader/compute/TAAcs.wgsl?raw'; +import TAACopyTex from '../../../assets/shader/compute/TAACopyTex.wgsl?raw'; +import TAASharpTex from '../../../assets/shader/compute/TAASharpTex.wgsl?raw'; +import { GBufferFrame } from '../frame/GBufferFrame'; +import { View3D } from '../../../core/View3D'; + +/** + * Temporal AA + * ``` + * //setting + * let cfg = {@link Engine3D.setting.render.postProcessing.taa}; + * let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + * + * Engine3D.startRender(renderJob); + *``` + * @group Post Effects + */ +export class TAAPost extends PostBase { + /** + * @internal + */ + taaTexture: VirtualTexture; + outTexture: VirtualTexture; + /** + * @internal + */ + rendererPassState: RendererPassState; + /** + * @internal + */ + taaCompute: ComputeShader; + copyTexCompute: ComputeShader; + sharpCompute: ComputeShader; + /** + * @internal + */ + taaSetting: StorageGPUBuffer; + + /** + * @internal + */ + preColorBuffer: StorageGPUBuffer; + preColorTex: VirtualTexture; + + /** + * @internal + */ + preProjMatrix: Matrix4; + preViewMatrix: Matrix4; + rtFrame: RTFrame; + + constructor() { + super(); + } + /** + * @internal + */ + onAttach(view: View3D) { + Engine3D.setting.render.postProcessing.taa.enable = true; + view.camera.enableJitterProjection(true); + + this.createGUI(); + } + /** + * @internal + */ + onDetach(view: View3D) { + Engine3D.setting.render.postProcessing.taa.enable = false; + view.camera.enableJitterProjection(false); + } + + public get jitterSeedCount() { + let setting = Engine3D.setting.render.postProcessing.taa; + return setting.jitterSeedCount; + } + + public set jitterSeedCount(value: number) { + value = clamp(value, 2, 8); + value = Math.round(value); + let setting = Engine3D.setting.render.postProcessing.taa; + setting.jitterSeedCount = value; + } + + public get blendFactor() { + let setting = Engine3D.setting.render.postProcessing.taa; + return setting.blendFactor; + } + + public set blendFactor(value: number) { + value = clamp(value, 0, 1); + let setting = Engine3D.setting.render.postProcessing.taa; + setting.blendFactor = value; + } + + public get sharpFactor() { + let setting = Engine3D.setting.render.postProcessing.taa; + return setting.sharpFactor; + } + + public set sharpFactor(value: number) { + value = clamp(value, 0.1, 0.9); + let setting = Engine3D.setting.render.postProcessing.taa; + setting.sharpFactor = value; + } + + public get sharpPreBlurFactor() { + let setting = Engine3D.setting.render.postProcessing.taa; + return setting.sharpPreBlurFactor; + } + + public set sharpPreBlurFactor(value: number) { + value = clamp(value, 0.1, 0.9); + let setting = Engine3D.setting.render.postProcessing.taa; + setting.sharpPreBlurFactor = value; + } + + public get temporalJitterScale() { + let setting = Engine3D.setting.render.postProcessing.taa; + return setting.temporalJitterScale; + } + + public set temporalJitterScale(value: number) { + value = clamp(value, 0, 1); + let setting = Engine3D.setting.render.postProcessing.taa; + setting.temporalJitterScale = value; + } + + private createGUI() { + } + + private createCompute(view: View3D) { + let computeShader = new ComputeShader(TAAcs); + let cfg = Engine3D.setting.render.postProcessing.taa; + + let taaSetting: UniformGPUBuffer = new UniformGPUBuffer(16 * 2 + 4 * 3); //matrix + 3 * vector4 + + let standUniform = GlobalBindGroup.getCameraGroup(view.camera); + computeShader.setUniformBuffer('standUniform', standUniform.uniformGPUBuffer); + computeShader.setUniformBuffer('taaData', taaSetting); + computeShader.setStorageBuffer(`preColorBuffer`, this.preColorBuffer); + + let rtFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer"); + computeShader.setSamplerTexture(`preColorTex`, this.preColorTex); + computeShader.setSamplerTexture(`posTex`, rtFrame.getPositionMap()); + this.autoSetColorTexture('inTex', computeShader); + computeShader.setStorageTexture(`outTex`, this.taaTexture); + + computeShader.workerSizeX = Math.ceil(this.taaTexture.width / 8); + computeShader.workerSizeY = Math.ceil(this.taaTexture.height / 8); + computeShader.workerSizeZ = 1; + + this.taaCompute = computeShader; + this.taaSetting = taaSetting; + + //copy + this.copyTexCompute = new ComputeShader(TAACopyTex); + this.copyTexCompute.setStorageBuffer(`preColor`, this.preColorBuffer); + this.copyTexCompute.setStorageTexture(`preColorTex`, this.preColorTex); + this.copyTexCompute.workerSizeX = Math.ceil(this.taaTexture.width / 8); + this.copyTexCompute.workerSizeY = Math.ceil(this.taaTexture.height / 8); + this.copyTexCompute.workerSizeZ = 1; + + //sharp + this.sharpCompute = new ComputeShader(TAASharpTex); + this.sharpCompute.setUniformBuffer('taaData', taaSetting); + this.sharpCompute.setSamplerTexture(`inTex`, this.taaTexture); + this.sharpCompute.setStorageTexture(`outTex`, this.outTexture); + this.sharpCompute.workerSizeX = Math.ceil(this.outTexture.width / 8); + this.sharpCompute.workerSizeY = Math.ceil(this.outTexture.height / 8); + this.sharpCompute.workerSizeZ = 1; + } + + private createResource() { + this.preProjMatrix = new Matrix4().identity(); + this.preViewMatrix = new Matrix4().identity(); + + let presentationSize = webGPUContext.presentationSize; + let w = presentationSize[0]; + let h = presentationSize[1]; + + this.preColorBuffer = new StorageGPUBuffer(w * h * 4, GPUBufferUsage.COPY_SRC); + + this.preColorTex = new VirtualTexture(w, h, GPUTextureFormat.rgba16float, false, GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.TEXTURE_BINDING); + this.preColorTex.name = 'taaTex'; + let preColorDec = new RTDescriptor(); + preColorDec.clearValue = [0, 0, 0, 1]; + preColorDec.loadOp = `clear`; + + this.taaTexture = new VirtualTexture(w, h, GPUTextureFormat.rgba16float, false, GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.TEXTURE_BINDING); + this.taaTexture.name = 'taaTex'; + let taaDec = new RTDescriptor(); + taaDec.clearValue = [0, 0, 0, 1]; + taaDec.loadOp = `clear`; + + this.outTexture = new VirtualTexture(w, h, GPUTextureFormat.rgba16float, false, GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.TEXTURE_BINDING); + this.outTexture.name = 'sharpTaaTex'; + let outDec = new RTDescriptor(); + outDec.clearValue = [0, 0, 0, 1]; + outDec.loadOp = `clear`; + + this.rtFrame = new RTFrame([ + this.preColorTex, + this.taaTexture, + this.outTexture + ], [ + preColorDec, + taaDec, + outDec + ]); + } + /** + * @internal + */ + render(view: View3D, command: GPUCommandEncoder) { + if (!this.taaCompute) { + this.createResource(); + this.createCompute(view); + this.rendererPassState = WebGPUDescriptorCreator.createRendererPassState(this.rtFrame, null); + } + + let cfg = Engine3D.setting.render.postProcessing.taa; + this.taaSetting.setMatrix('preProjMatrix', this.preProjMatrix); + this.taaSetting.setMatrix('preViewMatrix', this.preViewMatrix); + this.taaSetting.setFloat('jitterFrameIndex', view.camera.jitterFrameIndex); + this.taaSetting.setFloat('blendFactor', cfg.blendFactor); + this.taaSetting.setFloat('sharpFactor', cfg.sharpFactor); + this.taaSetting.setFloat('sharpPreBlurFactor', cfg.sharpPreBlurFactor); + this.taaSetting.setFloat('jitterX', view.camera.jitterX); + this.taaSetting.setFloat('jitterY', view.camera.jitterY); + this.taaSetting.apply(); + + GPUContext.computeCommand(command, [this.copyTexCompute, this.taaCompute, this.sharpCompute]); + + GPUContext.lastRenderPassState = this.rendererPassState; + + this.preProjMatrix.copyFrom(view.camera.projectionMatrix); + this.preViewMatrix.copyFrom(view.camera.viewMatrix); + + // view.camera.getViewMatrix(this.preViewMatrix); + } +} diff --git a/src/engine/gfx/renderJob/preDepth/PreDepthPassRenderer.ts b/src/engine/gfx/renderJob/preDepth/PreDepthPassRenderer.ts deleted file mode 100644 index 58caa91b..00000000 --- a/src/engine/gfx/renderJob/preDepth/PreDepthPassRenderer.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { RenderNode } from '../../../../components/renderer/RenderNode'; -import { Camera3D } from '../../../../core/Camera3D'; -import { Scene3D } from '../../../../core/Scene3D'; -import { Engine3D } from '../../../../Engine3D'; -import { VirtualTexture } from '../../../../textures/VirtualTexture'; -import { ProfilerUtil } from '../../../../util/ProfilerUtil'; -import { GlobalBindGroup } from '../../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; -import { StorageGPUBuffer } from '../../../graphics/webGpu/core/buffer/StorageGPUBuffer'; -import { RTDescriptor } from '../../../graphics/webGpu/descriptor/RTDescriptor'; -import { GPUTextureFormat } from '../../../graphics/webGpu/WebGPUConst'; -import { webGPUContext } from '../../../graphics/webGpu/Context3D'; -import { CollectInfo } from '../../collect/CollectInfo'; -import { EntityCollect } from '../../collect/EntityCollect'; -import { GPUContext } from '../../GPUContext'; -import { RTFrame } from '../../frame/RTFrame'; -import { RTResourceConfig } from '../../config/RTResourceConfig'; -import { RTResourceMap } from '../../frame/RTResourceMap'; -import { OcclusionSystem } from '../../occlusion/OcclusionSystem'; -import { RendererBase } from '../RendererBase'; -import { RendererType } from '../state/RendererType'; -import { ZCullingCompute } from './ZCullingCompute'; -import { View3D } from '../../../../core/View3D'; -/** - * @internal - * @group Post - */ -export class PreDepthPassRenderer extends RendererBase { - public zBufferTexture: VirtualTexture; - public useRenderBundle: boolean = false; - shadowPassCount: number; - zCullingCompute: ZCullingCompute; - constructor() { - super(); - this.passType = RendererType.DEPTH; - - let size = webGPUContext.presentationSize; - let scale = 1; - this.zBufferTexture = RTResourceMap.createRTTexture(RTResourceConfig.zBufferTexture_NAME, Math.floor(size[0] * scale), Math.floor(size[1] * scale), GPUTextureFormat.rgba16float, false); - let rtDec = new RTDescriptor() - rtDec.clearValue = [0, 0, 0, 0]; - rtDec.loadOp = `clear`; - let rtFrame = new RTFrame([ - this.zBufferTexture - ], [ - new RTDescriptor() - ], - RTResourceMap.createRTTexture(RTResourceConfig.zPreDepthTexture_NAME, Math.floor(size[0]), Math.floor(size[1]), GPUTextureFormat.depth32float, false), - null, - true - ); - this.setRenderStates(rtFrame); - } - - public lateCompute(view: View3D, occlusionSystem: OcclusionSystem) { - // this.zCullingCompute.compute(scene, occlusionSystem); - } - - render(view: View3D, occlusionSystem: OcclusionSystem) { - return; - let camera = view.camera; - let scene = view.scene; - GPUContext.cleanCache(); - - ProfilerUtil.start("DepthPass Renderer"); - - let scene3D = scene; - - this.rendererPassState.camera3D = camera; - let collectInfo = EntityCollect.instance.getRenderNodes(scene3D); - // this.compute(collectInfo, scene, occlusionSystem); - - // let op_bundleList = this.renderBundleOp(camera, collectInfo, scene, occlusionSystem); - // let tr_bundleList = true ? [] : this.renderBundleTr(camera, collectInfo, scene, occlusionSystem); - - let command = GPUContext.beginCommandEncoder(); - let encoder = GPUContext.beginRenderPass(command, this.rendererPassState); - - // if (op_bundleList.length > 0) { - // encoder.executeBundles(op_bundleList); - // } - - // if(!true&&EntityCollect.instance.sky){ - // GPUContext.bindCamera( encoder , camera); - // EntityCollect.instance.sky.renderPass2(this._rendererType,this.rendererPassState,scene,this.clusterLightingRender, encoder ); - // } - - // this.drawRenderNodes(camera, scene, encoder, command, collectInfo.opaqueList, occlusionSystem); - - // if (tr_bundleList.length > 0) { - // encoder.executeBundles(tr_bundleList); - // } - - // if (false) { - // this.drawRenderNodes(camera, scene, encoder, command, collectInfo.transparentList, occlusionSystem); - // } - - GPUContext.endPass(encoder); - GPUContext.endCommandEncoder(command); - - ProfilerUtil.end("DepthPass Renderer"); - // ProfilerUtil.print( "DepthPass Renderer" ); - } - - -} diff --git a/src/engine/io/InputSystem.ts b/src/engine/io/InputSystem.ts index 5eb5d8e9..858559ad 100644 --- a/src/engine/io/InputSystem.ts +++ b/src/engine/io/InputSystem.ts @@ -1,8 +1,8 @@ -import { PointerEvent3D } from '../..'; import { CEvent } from '../event/CEvent'; import { CEventDispatcher } from '../event/CEventDispatcher'; import { CResizeEvent } from '../event/CResizeEvent'; import { KeyEvent } from '../event/eventConst/KeyEvent'; +import { PointerEvent3D } from '../event/eventConst/PointerEvent3D'; import { KeyCode } from '../event/KeyCode'; import { MouseCode } from '../event/MouseCode'; import { Vector3 } from '../math/Vector3'; @@ -86,18 +86,8 @@ export class InputSystem extends CEventDispatcher { protected _pointerEvent3D: PointerEvent3D; protected _windowsEvent3d: CEvent; - /** - * - * 游戏手柄Stick1事件侦听函数。 - * - */ private _onGamepadStick1: Function = null; - /** - * - * 游戏手柄Stick2事件侦听函数。 - * - */ private _onGamepadStick2: Function = null; /** @@ -186,8 +176,7 @@ export class InputSystem extends CEventDispatcher { /** * @private * - * 获取按键是否压下 - * @param code 按键码 {@link KeyCode} + * @param code {@link KeyCode} * */ private getKeyPress(code: KeyCode): boolean { @@ -196,9 +185,7 @@ export class InputSystem extends CEventDispatcher { /** * @private - * - * 获取鼠标是否压下 - * @param code 鼠标按钮码 {@link MouseCode} + * @param code {@link MouseCode} * */ private getMousePress(code: MouseCode): boolean { @@ -216,9 +203,6 @@ export class InputSystem extends CEventDispatcher { } /** - * - * 游戏手柄按钮是否按下。 - * * @param index {number} * @returns {boolean} */ @@ -227,9 +211,6 @@ export class InputSystem extends CEventDispatcher { } /** - * - * 游戏手柄摇杆方向 Stick1 。 - * * @returns {Vector3D} */ private getGamepadStick1(): Vector3 { @@ -237,9 +218,6 @@ export class InputSystem extends CEventDispatcher { } /** - * - * 游戏手柄摇杆方向 Stick2 。 - * * @returns {Vector3D} */ private getGamepadStick2(): Vector3 { @@ -264,7 +242,6 @@ export class InputSystem extends CEventDispatcher { private touchStart(e: TouchEvent) { this.isMouseDown = true; if (e && e.changedTouches && e.changedTouches.length > 0) { - // x1 y1 最新的触摸点 var newX: number = e.changedTouches[0].clientX - this.canvasX; //- Input.canvas.x + Input.canvas.offsetX; var newY: number = e.changedTouches[0].clientY - this.canvasY; // Input.canvas.y + Input.canvas.offsetY; } @@ -624,26 +601,23 @@ export class InputSystem extends CEventDispatcher { this.dispatchEvent(this._windowsEvent3d); } - //返回角度 private GetSlideAngle(dx: number, dy: number) { return (Math.atan2(dy, dx) * 180) / Math.PI; } /** * - * 根据起点和终点返回方向 - * @param startX {Number} 起点X坐标 - * @param startY {Number} 起点Y坐标 - * @param endX {Number} 终点X坐标 - * @param endY {Number} 终点Y坐标 - * @returns result {number} 1:向上,2:向下,3:向左,4:向右,0:未滑动 + * @param startX {Number} + * @param startY {Number} + * @param endX {Number} + * @param endY {Number} + * @returns result {number} 1:up,2:down,3:left,4:right,0:not move */ public GetSlideDirection(startX: number, startY: number, endX: number, endY: number): number { var dy = startY - endY; var dx = endX - startX; var result = 0; - //如果滑动距离太短 if (Math.abs(dx) < 2 && Math.abs(dy) < 2) { return result; } @@ -663,15 +637,12 @@ export class InputSystem extends CEventDispatcher { } private isEnlarge(op1: Vector3, op2: Vector3, np1: Vector3, np2: Vector3): boolean { - //函数传入上一次触摸两点的位置与本次触摸两点的位置计算出用户的手势 var leng1 = Math.sqrt((op1.x - op2.x) * (op1.x - op2.x) + (op1.y - op2.y) * (op1.y - op2.y)); var leng2 = Math.sqrt((np1.x - np2.x) * (np1.x - np2.x) + (np1.y - np2.y) * (np1.y - np2.y)); if (leng1 < leng2) { - //放大手势 return true; } else { - //缩小手势 return false; } } diff --git a/src/engine/io/PickFire.ts b/src/engine/io/PickFire.ts index e39aa915..84b6f708 100644 --- a/src/engine/io/PickFire.ts +++ b/src/engine/io/PickFire.ts @@ -1,5 +1,3 @@ -import { PointerEvent3D, View3D } from '../..'; -import { ColliderComponent } from '../components/colliders/ColliderComponent'; import { Camera3D } from '../core/Camera3D'; import { Engine3D } from '../Engine3D'; import { MouseCode } from '../event/MouseCode'; @@ -7,6 +5,9 @@ import { CEventDispatcher } from '../event/CEventDispatcher'; import { Ray } from '../math/Ray'; import { Vector3 } from '../math/Vector3'; import { PickCompute } from './picker/PickCompute'; +import { ColliderComponent } from '../components/ColliderComponent'; +import { View3D } from '../core/View3D'; +import { PointerEvent3D } from '../event/eventConst/PointerEvent3D'; /** * Management and triggering for picking 3D objects * @group IO diff --git a/src/engine/io/PickResult.ts b/src/engine/io/PickResult.ts index 6573216d..150991f7 100644 --- a/src/engine/io/PickResult.ts +++ b/src/engine/io/PickResult.ts @@ -54,7 +54,6 @@ export class PickResult { /** * @internal - * 相交面顶点2索引 */ public v2: number; diff --git a/src/engine/io/picker/PickCompute.ts b/src/engine/io/picker/PickCompute.ts index d56e65f0..cf489fc2 100644 --- a/src/engine/io/picker/PickCompute.ts +++ b/src/engine/io/picker/PickCompute.ts @@ -1,10 +1,11 @@ -import { GBufferFrame, GPUTextureFormat, RTResourceConfig, View3D } from '../../..'; import Picker_CsShader from '../../assets/shader/compute/Picker_CsShader.wgsl?raw'; import { Camera3D } from '../../core/Camera3D'; +import { View3D } from '../../core/View3D'; import { GlobalBindGroup } from '../../gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup'; import { ComputeGPUBuffer } from '../../gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer'; import { ComputeShader } from '../../gfx/graphics/webGpu/shader/ComputeShader'; import { GPUContext } from '../../gfx/renderJob/GPUContext'; +import { GBufferFrame } from '../../gfx/renderJob/frame/GBufferFrame'; import { Vector2 } from '../../math/Vector2'; import { Vector3 } from '../../math/Vector3'; /** diff --git a/src/engine/loader/parser/AtlasParser.ts b/src/engine/loader/parser/AtlasParser.ts deleted file mode 100644 index 9031b5d4..00000000 --- a/src/engine/loader/parser/AtlasParser.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { GUIAtlasTexture } from "../../components/gui/core/GUIAtlasTexture"; -import { GUITextureSource } from "../../components/gui/core/GUISubTexture"; -import { Engine3D } from "../../Engine3D"; -import { Texture } from "../../gfx/graphics/webGpu/core/texture/Texture"; -import { ParserBase } from "../../loader/parser/ParserBase"; - -export class AtlasParser extends ParserBase { - static format: string = 'text'; - - private _json: any; - private _texture: Texture; - - public async parserString(data: string) { - this._json = JSON.parse(data); - let textureUrl = this.userData.replace('.json', '.png'); - this._texture = await Engine3D.res.loadTexture(textureUrl, null, true); - - this.data = { json: this._json, texture: this._texture }; - this.parseAtlas(); - } - - /** - * Verify parsing validity - * @param ret - * @returns - */ - public verification(): boolean { - if (this.data) { - return true; - } - throw new Error('Method not implemented.'); - } - - private parseAtlas() { - let atlas: GUIAtlasTexture = new GUIAtlasTexture(); - let source: GUITextureSource = new GUITextureSource(this._texture); - atlas.textureSize.set(this._json.size.x, this._json.size.y); - - let atlasInfo = this._json.atlas; - for (const key in atlasInfo) { - atlas.setTexture(source, key, atlasInfo[key]); - } - Engine3D.res.addAtlas(this.baseUrl, atlas); - this.data = atlas; - } -} diff --git a/src/engine/loader/parser/B3DMParser.ts b/src/engine/loader/parser/B3DMParser.ts index 8db9b531..2a23e9db 100644 --- a/src/engine/loader/parser/B3DMParser.ts +++ b/src/engine/loader/parser/B3DMParser.ts @@ -1,4 +1,5 @@ -import { ParserBase } from './ParserBase'; +import { Object3D } from '../../core/entities/Object3D'; +import { ParserBase } from './ParserBase'; export class B3DMParser extends ParserBase { static format: string = 'bin'; @@ -23,7 +24,7 @@ export class B3DMParser extends ParserBase { } import { B3DMLoader } from './b3dm/B3DMLoader'; -import { GLBParser, Object3D } from '../../..'; +import { GLBParser } from './gltf/GLBParser'; const BINARY_EXTENSION_HEADER_MAGIC = 'glTF'; const BINARY_EXTENSION_HEADER_LENGTH = 12; diff --git a/src/engine/loader/parser/FntParser.ts b/src/engine/loader/parser/FntParser.ts deleted file mode 100644 index 059e6654..00000000 --- a/src/engine/loader/parser/FntParser.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { GUISubTexture, GUITextureSource } from '../../components/gui/core/GUISubTexture'; -import { fonts } from '../../../engine/assets/Fonts'; -import { ParserBase } from '../../../engine/loader/parser/ParserBase'; -import { Engine3D } from '../../Engine3D'; - -export class FontInfo { - public face: string = ''; - public size: number = 0; - public bold: boolean = false; - public italic: boolean = false; - public stretchH: number = 0; - public spacing: string = ''; - public outline: number = 0; - public lineHeight: number = 0; - public base: number = 0; - public scaleW: number = 0; - public scaleH: number = 0; - public pages: number = 0; - public packed: number = 0; - public alphaChnl: number = 0; - public redChnl: number = 0; - public greenChnl: number = 0; - public blueChnl: number = 0; - public count: number = 0; - - public fontPage: FontPage[] = []; - public fontChar: { [key: string]: FontChar } = {}; - - constructor() { } -} - -export class FontPage { - public id: number = 0; - public file: string = ''; -} - -export class FontChar { - public id: number = -1; - public x: number = 0; - public y: number = 0; - public width: number = 0; - public height: number = 0; - public xoffset: number = 0; - public yoffset: number = 0; - public xadvance: number = 0; - public page: number = 0; - public chnl: number = 0; -} - -export class FntParser extends ParserBase { - static format: string = 'text'; - - public static parserSubTexture(sources: GUITextureSource[], fontData: FontInfo) { - for (const key in fontData.fontChar) { - if (Object.prototype.hasOwnProperty.call(fontData.fontChar, key)) { - const charInfo = fontData.fontChar[key]; - let subTexture = new GUISubTexture(); - subTexture.id = charInfo.id.toString(); - subTexture.offsetSize.set(0, 0, charInfo.width, charInfo.height); - subTexture.trimSize.set(charInfo.width, charInfo.height); - subTexture.width = charInfo.width; - subTexture.height = charInfo.height; - subTexture.xadvance = charInfo.xadvance; - subTexture.xoffset = charInfo.xoffset; - subTexture.yoffset = charInfo.yoffset; - subTexture.sourceTexture = sources[charInfo.page]; - subTexture.uvRec.set(charInfo.x / fontData.scaleW, (fontData.scaleH - (charInfo.y + charInfo.height)) / fontData.scaleH, charInfo.width / fontData.scaleW, charInfo.height / fontData.scaleH); - fonts.addFnt(fontData.face, fontData.size, subTexture.id, subTexture); - } - } - } - - /** - * Verify parsing validity - * @param ret - * @returns - */ - public verification(): boolean { - if (this.data) { - return true; - } - throw new Error('Method not implemented.'); - } - - public async parserString(data: string) { - let newLine = this.getNewLine(data); - let fnt: string = data; - let fontData: FontInfo = new FontInfo(); - fnt.trim() - .split(newLine) - .forEach((v, i) => { - if (i < 2) { - FntParser.readLineProperty(v, fontData); - } else { - if (i < fontData.pages + 2) { - let page = new FontPage(); - FntParser.readLineProperty(v, page); - fontData.fontPage.push(page); - } else if (i < fontData.pages + 3) { - FntParser.readLineProperty(v, fontData); - } else { - if (fontData.count > 0) { - let char = new FontChar(); - FntParser.readLineProperty(v, char); - fontData.fontChar[char.id] = char; - fontData.count--; - } - } - } - }); - fnt = ''; - this.data = fontData; - - await this.loadFontTextures(); - } - - private getNewLine(value: string): string { - if (value.indexOf('\r\n') != -1) return '\r\n'; - else if (value.indexOf('\r') != -1) return '\r'; - else return '\n'; - } - - private async loadFontTextures() { - let images: GUITextureSource[] = []; - let fontData: FontInfo = this.data; - for (const fontPage of fontData.fontPage) { - let texturePath = this.baseUrl + fontPage.file; - await Engine3D.res.loadTexture(texturePath, null, true); - let texture = Engine3D.res.getTexture(texturePath); - let source: GUITextureSource = new GUITextureSource(texture); - images.push(source); - } - FntParser.parserSubTexture(images, fontData); - //check empty - if (!fontData.fontChar[' ']) { - FntParser.insertSpaceChar(fontData, images[0]); - } - } - - private static insertSpaceChar(fontData: FontInfo, texture: GUITextureSource): void { - let subTexture = new GUISubTexture(); - let width = fontData.size * 0.5; - let height = fontData.lineHeight * 0.5; - subTexture.id = ' '; - subTexture.offsetSize.set(0, 0, fontData.size, fontData.size); - subTexture.trimSize.set(width, height); - subTexture.width = width; - subTexture.height = height; - subTexture.xadvance = 0; - subTexture.xoffset = 0; - subTexture.yoffset = 0; - subTexture.sourceTexture = texture; - subTexture.uvRec.set(0, 0, 0.000001, 0.000001); - fonts.addFnt(fontData.face, fontData.size, subTexture.id, subTexture); - } - - private static readLineProperty(line: string, data: any) { - line.trim() - .split(' ') - .forEach((v, i) => { - let strArr = v.split('='); - if (strArr.length > 1) { - let key = strArr[0]; - let value = strArr[1]; - if (Object.prototype.hasOwnProperty.call(data, key)) { - if (value.indexOf('"') == -1) { - data[key] = parseFloat(strArr[1]); - } else { - data[key] = value.replace('"', '').replace('"', ''); - } - } - } - }); - } -} diff --git a/src/engine/loader/parser/OBJParser.ts b/src/engine/loader/parser/OBJParser.ts index 9604de1a..c5241277 100644 --- a/src/engine/loader/parser/OBJParser.ts +++ b/src/engine/loader/parser/OBJParser.ts @@ -1,14 +1,12 @@ +import { Engine3D } from '../../Engine3D'; +import { MeshRenderer } from '../../components/renderer/MeshRenderer'; +import { Object3D } from '../../core/entities/Object3D'; +import { GeometryBase } from '../../core/geometry/GeometryBase'; +import { VertexAttributeName } from '../../core/geometry/VertexAttributeName'; +import { LitMaterial } from '../../materials/LitMaterial'; import { StringUtil } from '../../util/StringUtil'; import { FileLoader } from '../FileLoader'; import { ParserBase } from './ParserBase'; -import { - Engine3D, - GeometryBase, - LitMaterial, - MeshRenderer, - Object3D, - VertexAttributeName -} from '../../..'; type MatData = { name?: string, diff --git a/src/engine/loader/parser/b3dm/B3DMLoader.ts b/src/engine/loader/parser/b3dm/B3DMLoader.ts index 1ed98e69..3ccdff43 100644 --- a/src/engine/loader/parser/b3dm/B3DMLoader.ts +++ b/src/engine/loader/parser/b3dm/B3DMLoader.ts @@ -1,6 +1,9 @@ -import {B3DMLoaderBase} from "./B3DMLoaderBase"; -import {B3DMParseUtil} from "../B3DMParser"; -import { Matrix4, Orientation3D, Transform, Vector3 } from "../../../.."; +import { B3DMLoaderBase } from "./B3DMLoaderBase"; +import { B3DMParseUtil } from "../B3DMParser"; +import { Transform } from "../../../components/Transform"; +import { Matrix4 } from "../../../math/Matrix4"; +import { Orientation3D } from "../../../math/Orientation3D"; +import { Vector3 } from "../../../math/Vector3"; export class B3DMLoader extends B3DMLoaderBase { @@ -21,7 +24,7 @@ export class B3DMLoader extends B3DMLoaderBase { let model = await glbLoader.parseBinary(this.gltfBuffer); - let {batchTable, featureTable} = b3dm; + let { batchTable, featureTable } = b3dm; const rtcCenter = featureTable.getData('RTC_CENTER'); if (rtcCenter) { diff --git a/src/engine/loader/parser/gltf/GLBParser.ts b/src/engine/loader/parser/gltf/GLBParser.ts index 0848da4b..5de78620 100644 --- a/src/engine/loader/parser/gltf/GLBParser.ts +++ b/src/engine/loader/parser/gltf/GLBParser.ts @@ -94,7 +94,6 @@ export class GLBParser extends ParserBase { let dtexture = new BitmapTexture2D(); await dtexture.loadFromBlob(imgData); dtexture.name = image.name; - dtexture.textureSource.setGLBImage(this.initUrl, i); this._gltf.resources[image.name] = dtexture; } } @@ -125,7 +124,6 @@ export class GLBParser extends ParserBase { let dataBuffer = new Uint8Array(buffer.dbuffer, bufferView.byteOffset, bufferView.byteLength); let imgData = new Blob([dataBuffer], { type: image.mimeType }); let dtexture = new BitmapTexture2D(); - dtexture.textureSource.setGLBImage(this.initUrl, i); await dtexture.loadFromBlob(imgData); dtexture.name = image.name; this._gltf.resources[image.name] = dtexture; diff --git a/src/engine/loader/parser/gltf/GLTFParser.ts b/src/engine/loader/parser/gltf/GLTFParser.ts index bf09f225..b74e43bb 100644 --- a/src/engine/loader/parser/gltf/GLTFParser.ts +++ b/src/engine/loader/parser/gltf/GLTFParser.ts @@ -222,7 +222,6 @@ export class GLTFParser extends ParserBase { let promise = new FileLoader().loadAsyncBitmapTexture(url, this.loaderFunctions).then(texture => { texture.name = StringUtil.getURLName(element.uri); this._gltf.resources[texture.name] = texture; - texture.textureSource.setGLTFImage(this.initUrl, i, url); }) textureArray.push(promise) } diff --git a/src/engine/loader/parser/gltf/GLTFSubParserConverter.ts b/src/engine/loader/parser/gltf/GLTFSubParserConverter.ts index 75fc31a3..1cc0a4d8 100644 --- a/src/engine/loader/parser/gltf/GLTFSubParserConverter.ts +++ b/src/engine/loader/parser/gltf/GLTFSubParserConverter.ts @@ -1,6 +1,28 @@ -import { BlendMode, Color, DirectLight, Engine3D, GLTFParser, GeometryBase, KHR_materials_clearcoat, KHR_materials_emissive_strength, KHR_materials_unlit, LitMaterial, MaterialBase, MeshRenderer, Object3D, PhysicMaterial, PointLight, Quaternion, RADIANS_TO_DEGREES, SkeletonAnimationComponent, SkinnedMeshRenderer, SpotLight, UUID, VertexAttributeName, defaultRes } from "../../../.."; +import { Engine3D } from "../../../Engine3D"; +import { SkeletonAnimationComponent } from "../../../components/SkeletonAnimationComponent"; +import { DirectLight } from "../../../components/lights/DirectLight"; +import { PointLight } from "../../../components/lights/PointLight"; +import { SpotLight } from "../../../components/lights/SpotLight"; +import { MeshRenderer } from "../../../components/renderer/MeshRenderer"; +import { SkinnedMeshRenderer } from "../../../components/renderer/SkinnedMeshRenderer"; +import { Object3D } from "../../../core/entities/Object3D"; +import { GeometryBase } from "../../../core/geometry/GeometryBase"; +import { VertexAttributeName } from "../../../core/geometry/VertexAttributeName"; +import { BlendMode } from "../../../materials/BlendMode"; +import { LitMaterial } from "../../../materials/LitMaterial"; +import { MaterialBase } from "../../../materials/MaterialBase"; +import { PhysicMaterial } from "../../../materials/PhysicMaterial"; +import { Color } from "../../../math/Color"; +import { RADIANS_TO_DEGREES } from "../../../math/MathUtil"; +import { Quaternion } from "../../../math/Quaternion"; +import { defaultRes } from "../../../textures/DefaultRes"; +import { UUID } from "../../../util/Global"; import { GLTF_Info, GLTF_Node } from "./GLTFInfo"; +import { GLTFParser } from "./GLTFParser"; import { GLTFSubParser } from "./GLTFSubParser"; +import { KHR_materials_clearcoat } from "./extends/KHR_materials_clearcoat"; +import { KHR_materials_emissive_strength } from "./extends/KHR_materials_emissive_strength"; +import { KHR_materials_unlit } from "./extends/KHR_materials_unlit"; export class GLTFSubParserConverter { protected gltf: GLTF_Info; diff --git a/src/engine/materials/GIProbeMaterial.ts b/src/engine/materials/GIProbeMaterial.ts deleted file mode 100644 index 14122bd1..00000000 --- a/src/engine/materials/GIProbeMaterial.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { GIProbeShader } from '../..'; -import { ShaderLib } from '../assets/shader/ShaderLib'; -import { Engine3D } from '../Engine3D'; -import { Vector4 } from '../math/Vector4'; -import { defaultRes } from '../textures/DefaultRes'; -import { PhysicMaterial } from './PhysicMaterial'; - -/** - * @internal - * @group Material - */ -export enum GIProbeMaterialType { - CastGI = 0, - ReceiveGI = 1, - CastDepth = 2, - Other = 3, -} - -export class GIProbeMaterial extends PhysicMaterial { - static count = 0; - - constructor(type: GIProbeMaterialType = GIProbeMaterialType.CastGI, index: number = 0) { - super(); - - ShaderLib.register("GIProbeShader", GIProbeShader); - this.setShader('GIProbeShader', 'GIProbeShader'); - - let shader = this.getShader(); - shader.setDefine('USE_BRDF', true); - shader.setShaderEntry(`VertMain`, `FragMain`); - shader.setUniformVector4('probeUniform', new Vector4(index, type, 0, 0)); - let shaderState = shader.shaderState; - shaderState.acceptShadow = false; - shaderState.castShadow = false; - shaderState.receiveEnv = false; - shaderState.acceptGI = false; - shaderState.useLight = false; - - let bdrflutTex = Engine3D.res.getTexture(`BRDFLUT`); - this.brdfLUT = bdrflutTex; - - this.baseMap = defaultRes.whiteTexture; - this.normalMap = defaultRes.normalTexture; - // this.aoMap = defaultTexture.whiteTexture; - // this.maskMap = defaultTexture.maskTexture; - // this.maskMap = defaultTexture.grayTexture; - // shader.setDefine(`USE_ARMC`, false); - this.emissiveMap = defaultRes.blackTexture; - } - - debug() { } -} diff --git a/src/engine/materials/GlassMaterial.ts b/src/engine/materials/GlassMaterial.ts index d43d96e2..fcb0d4a8 100644 --- a/src/engine/materials/GlassMaterial.ts +++ b/src/engine/materials/GlassMaterial.ts @@ -1,10 +1,10 @@ -import { registerMaterial } from '../..'; import { ShaderLib } from '../assets/shader/ShaderLib'; import GlassShader from '../assets/shader/materials/GlassShader.wgsl?raw'; import { Engine3D } from '../Engine3D'; import { Vector4 } from '../math/Vector4'; import { defaultRes } from '../textures/DefaultRes'; import { PhysicMaterial } from './PhysicMaterial'; +import { registerMaterial } from './MaterialRegister'; /** * GlassMaterial * an rendering material implemented by simulating glass surfaces diff --git a/src/engine/materials/LitMaterial.ts b/src/engine/materials/LitMaterial.ts index f1eed728..be8a37f1 100644 --- a/src/engine/materials/LitMaterial.ts +++ b/src/engine/materials/LitMaterial.ts @@ -1,7 +1,7 @@ -import { registerMaterial } from '../..'; import { Engine3D } from '../Engine3D'; import { Vector4 } from '../math/Vector4'; import { defaultRes } from '../textures/DefaultRes'; +import { registerMaterial } from './MaterialRegister'; import { PhysicMaterial } from './PhysicMaterial'; /** * a type of material, based on physical lighting model diff --git a/src/engine/materials/MaterialPass.ts b/src/engine/materials/MaterialPass.ts index a2dde7c9..fad9bb37 100644 --- a/src/engine/materials/MaterialPass.ts +++ b/src/engine/materials/MaterialPass.ts @@ -1,5 +1,6 @@ -import { GPUCullMode, RendererType } from "../.."; +import { GPUCullMode } from "../gfx/graphics/webGpu/WebGPUConst"; import { RenderShader } from "../gfx/graphics/webGpu/shader/RenderShader"; +import { RendererType } from "../gfx/renderJob/passRenderer/state/RendererType"; import { BlendMode } from "./BlendMode"; export class MaterialPass { diff --git a/src/engine/materials/PointMaterial.ts b/src/engine/materials/PointMaterial.ts index 7ba88a07..b66c0018 100644 --- a/src/engine/materials/PointMaterial.ts +++ b/src/engine/materials/PointMaterial.ts @@ -1,5 +1,5 @@ -import { PointShadowDebug } from '../..'; import { ShaderLib } from '../assets/shader/ShaderLib'; +import { PointShadowDebug } from '../assets/shader/materials/PointShadowDebug'; import UnLit from '../assets/shader/materials/UnLit.wgsl?raw'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { Color } from '../math/Color'; diff --git a/src/engine/materials/effectPass/OutLinePass.ts b/src/engine/materials/effectPass/OutLinePass.ts index 1d322b74..5ff2c8d3 100644 --- a/src/engine/materials/effectPass/OutLinePass.ts +++ b/src/engine/materials/effectPass/OutLinePass.ts @@ -1,7 +1,10 @@ -import { BlendMode, Color, ColorLitShader, defaultRes, GPUCompareFunction, ShaderLib } from "../../.."; import { MaterialPass } from "../MaterialPass"; import OutlineShaderPass from "../../assets/shader/materials/OutlinePass.wgsl?raw" +import { GPUCompareFunction } from "../../gfx/graphics/webGpu/WebGPUConst"; +import { defaultRes } from "../../textures/DefaultRes"; +import { Color } from "../../math/Color"; +import { ShaderLib } from "../../assets/shader/ShaderLib"; export class OutLinePass extends MaterialPass { constructor(lineWeight: number = 10) { diff --git a/src/engine/materials/multiPass/CastShadowMaterialPass.ts b/src/engine/materials/multiPass/CastShadowMaterialPass.ts index 930c75aa..216672e8 100644 --- a/src/engine/materials/multiPass/CastShadowMaterialPass.ts +++ b/src/engine/materials/multiPass/CastShadowMaterialPass.ts @@ -1,6 +1,6 @@ -import { Vector3 } from '../../..'; import { CastShadow } from '../../assets/shader/core/pass/CastShadowPass_wgsl'; import { ShaderLib } from '../../assets/shader/ShaderLib'; +import { Vector3 } from '../../math/Vector3'; import { MaterialBase } from '../MaterialBase'; import { registerMaterial } from "../MaterialRegister"; diff --git a/src/engine/math/MathUtil.ts b/src/engine/math/MathUtil.ts index 457b3f05..9c46fa01 100644 --- a/src/engine/math/MathUtil.ts +++ b/src/engine/math/MathUtil.ts @@ -1,3 +1,4 @@ +import { Color } from './Color'; import { Matrix4 } from './Matrix4'; import { Quaternion } from './Quaternion'; import { Rand } from './Rand'; @@ -24,9 +25,6 @@ export let MAX_VALUE: number = 0x7fffffff; */ export let MIN_VALUE: number = -0x7fffffff; -export let PI: number = 3.1415926; - - /** * value min max bound * @internal @@ -287,6 +285,55 @@ export class MathUtil { result.w = m * x + n * y + o * z + p; return result; } + +} + +/** + * @internal + */ +export let lerp = function (v0: number, v1: number, t: number) { + //return v0 * t + v1 * (1-t) ; + return v0 * (1 - t) + v1 * t; +} + +/** + * @internal + */ +export function lerpVector3(v0: Vector3, v1: Vector3, t: number) { + let newV = new Vector3(); + let v0x: number = v0.x; + let v0y: number = v0.y; + let v0z: number = v0.z; + let v0w: number = v0.w; + let v1x: number = v1.x; + let v1y: number = v1.y; + let v1z: number = v1.z; + let v1w: number = v1.w; + + newV.x = (v1x - v0x) * t + v0x; + newV.y = (v1y - v0y) * t + v0y; + newV.z = (v1z - v0z) * t + v0z; + newV.w = (v1w - v0w) * t + v0w; + return newV; +} + +/** + * @internal + */ +export function lerpColor(c0: Color, c1: Color, t) { + let newColor = new Color(); + newColor.r = (1.0 - t) * c0.r + t * c1.r; + newColor.g = (1.0 - t) * c0.g + t * c1.g; + newColor.b = (1.0 - t) * c0.b + t * c1.b; + newColor.a = (1.0 - t) * c0.a + t * c1.a; + return newColor; +} + +/** + * @internal + */ +export function lerpByte(u0, u1, scale) { + return (u0 + (((u1 - u0) * scale) >> 8)) & 0xff; } /** @@ -465,7 +512,7 @@ export function rangedRandomInt(r: Rand, min: number, max: number) { */ export function randomUnitVector(rand: Rand) { let z = rangedRandomFloat(rand, -1.0, 1.0); - let a = rangedRandomFloat(rand, 0.0, 2.0 * PI); + let a = rangedRandomFloat(rand, 0.0, 2.0 * Math.PI); let r = Math.sqrt(1.0 - z * z); @@ -479,7 +526,7 @@ export function randomUnitVector(rand: Rand) { * @internal */ export function randomUnitVector2(rand: Rand) { - let a = rangedRandomFloat(rand, 0.0, 2.0 * PI); + let a = rangedRandomFloat(rand, 0.0, 2.0 * Math.PI); let x = Math.cos(a); let y = Math.sin(a); @@ -509,7 +556,7 @@ export function randomQuaternion(rand: Rand) { * @internal */ export function randomQuaternionUniformDistribution(rand: Rand) { - const two_pi = 2.0 * PI; + const two_pi = 2.0 * Math.PI; // Employs Hopf fibration to uniformly distribute quaternions let u1 = rangedRandomFloat(rand, 0.0, 1.0); @@ -624,7 +671,7 @@ export function randomBarycentricCoord(rand: Rand) { export function deg2Rad(deg) { // TODO : should be deg * kDeg2Rad, but can't be changed, // because it changes the order of operations and that affects a replay in some RegressionTests - return (deg / 360.0) * 2.0 * PI; + return (deg / 360.0) * 2.0 * Math.PI; } /** @@ -633,7 +680,7 @@ export function deg2Rad(deg) { export function rad2Deg(deg) { // TODO : should be deg * kDeg2Rad, but can't be changed, // because it changes the order of operations and that affects a replay in some RegressionTests - return (180 * deg) / PI; + return (180 * deg) / Math.PI; } /** diff --git a/src/engine/math/Matrix4.ts b/src/engine/math/Matrix4.ts index c0b51837..4fc3dd6b 100644 --- a/src/engine/math/Matrix4.ts +++ b/src/engine/math/Matrix4.ts @@ -1,4 +1,4 @@ -import { PI, clamp, DEGREES_TO_RADIANS, RADIANS_TO_DEGREES } from './MathUtil'; +import { DEGREES_TO_RADIANS, clamp, RADIANS_TO_DEGREES } from './MathUtil'; import { Orientation3D } from './Orientation3D'; import { Quaternion } from './Quaternion'; import { Vector3 } from './Vector3'; @@ -211,27 +211,27 @@ export class Matrix4 { */ public static makePositive(euler: Vector3): void { let negativeFlip = -0.0001; - let positiveFlip = PI * 2.0 - 0.0001; + let positiveFlip = Math.PI * 2.0 - 0.0001; if (euler.x < negativeFlip) { - euler.x += 2.0 * PI; + euler.x += 2.0 * Math.PI; } else if (euler.x > positiveFlip) { - euler.x -= 2.0 * PI; + euler.x -= 2.0 * Math.PI; } if (euler.y < negativeFlip) { - euler.y += 2.0 * PI; + euler.y += 2.0 * Math.PI; } else if (euler.y > positiveFlip) { - euler.y -= 2.0 * PI; + euler.y -= 2.0 * Math.PI; } if (euler.z < negativeFlip) { - euler.z += 2.0 * PI; + euler.z += 2.0 * Math.PI; } else if (euler.z > positiveFlip) { - euler.z -= 2.0 * PI; + euler.z -= 2.0 * Math.PI; } } @@ -255,7 +255,7 @@ export class Matrix4 { return true; } else { // WARNING. Not unique. YA - ZA = atan2(r01,r00) - v.x = PI * 0.5; + v.x = Math.PI * 0.5; v.y = Math.atan2(matrix.get(0, 1), matrix.get(0, 0)); v.z = 0.0; Matrix4.sanitizeEuler(v); @@ -263,7 +263,7 @@ export class Matrix4 { } } else { // WARNING. Not unique. YA + ZA = atan2(-r01,r00) - v.x = -PI * 0.5; + v.x = -Math.PI * 0.5; v.y = Math.atan2(-matrix.get(0, 1), matrix.get(0, 0)); v.z = 0.0; Matrix4.sanitizeEuler(v); @@ -588,7 +588,7 @@ export class Matrix4 { */ public perspective(fov: number, aspect: number, zn: number, zf: number) { let data = this.rawData; - // let angle: number = (Math.PI - fov * DEGREES_TO_RADIANS) / 2.0; + // let angle: number = (Math.Math.PI - fov * DEGREES_TO_RADIANS) / 2.0; // let yScale: number = Math.tan(angle); // let xScale: number = yScale / aspect; @@ -1307,7 +1307,7 @@ export class Matrix4 { } /** - * Copies the value of the current matrix to a float array. + * CoMath.PIes the value of the current matrix to a float array. * @param vector The target array. * @param index copy from the index of the array. * @param transpose Whether to transpose the current matrix. @@ -2041,7 +2041,7 @@ export class Matrix4 { } /** - * form unity API + * form unity AMath.PI */ public setTRInverse(pos: Vector3, q: Quaternion) { q = q.inverse(); diff --git a/src/engine/math/Random.ts b/src/engine/math/Random.ts index 55f5e1a0..76506cbe 100644 --- a/src/engine/math/Random.ts +++ b/src/engine/math/Random.ts @@ -486,7 +486,7 @@ export function snoise4(x, y, z, w) { // To find out which of the 24 possible simplices we're in, we need to // determine the magnitude ordering of x0, y0, z0 and w0. // The method below is a good way of finding the ordering of x,y,z,w and - // then find the correct traversal order for the simplex we抮e in. + // then find the correct traversal order for the simplex were in. // First, six pair-wise comparisons are performed between each possible pair // of the four coordinates, and the results are used to add up binary bits // for an integer index. diff --git a/src/engine/setting/SkySetting.ts b/src/engine/setting/SkySetting.ts index 4c225212..0bfc5b08 100644 --- a/src/engine/setting/SkySetting.ts +++ b/src/engine/setting/SkySetting.ts @@ -1,4 +1,4 @@ -import { HDRTextureCube } from "../.."; +import { HDRTextureCube } from "../textures/HDRTextureCube"; /** * Sky setting diff --git a/src/engine/setting/post/GlobalFogSetting.ts b/src/engine/setting/post/GlobalFogSetting.ts index d9703079..9031b10a 100644 --- a/src/engine/setting/post/GlobalFogSetting.ts +++ b/src/engine/setting/post/GlobalFogSetting.ts @@ -1,4 +1,4 @@ -import { Color } from "../../.."; +import { Color } from "../../math/Color"; /** * Global fog effect setting diff --git a/src/engine/textures/AtmosphericScatteringSky.ts b/src/engine/textures/AtmosphericScatteringSky.ts index e9294c11..93784bbd 100644 --- a/src/engine/textures/AtmosphericScatteringSky.ts +++ b/src/engine/textures/AtmosphericScatteringSky.ts @@ -1,4 +1,4 @@ -import { AtmosphericScatteringSky_shader } from '../assets/shader/materials/sky/AtmosphericScatteringSky_shader'; +import { AtmosphericScatteringSky_shader } from '../assets/shader/sky/AtmosphericScatteringSky_shader'; import { UniformGPUBuffer } from '../gfx/graphics/webGpu/core/buffer/UniformGPUBuffer'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { ComputeShader } from '../gfx/graphics/webGpu/shader/ComputeShader'; @@ -45,7 +45,6 @@ export class AtmosphericScatteringSky extends HDRTextureCube { this._internalTexture = new AtmosphericTexture2D(setting.defaultTexture2DSize, setting.defaultTexture2DSize * 0.5); this._internalTexture.update(this.setting); this.createFromTexture(this._cubeSize, this._internalTexture); - this.textureSource.setCubeAtmosphericScattering(); return this; } diff --git a/src/engine/textures/BitmapTexture2D.ts b/src/engine/textures/BitmapTexture2D.ts index 6f80acbf..93814633 100644 --- a/src/engine/textures/BitmapTexture2D.ts +++ b/src/engine/textures/BitmapTexture2D.ts @@ -55,7 +55,6 @@ export class BitmapTexture2D extends Texture { */ public async load(url: string, loaderFunctions?: LoaderFunctions) { if (url.indexOf(';base64') != -1) { - this.textureSource.setNetImageBase64(url); const img = document.createElement('img'); let start = url.indexOf('data:image'); let uri = url.substring(start, url.length); @@ -71,7 +70,6 @@ export class BitmapTexture2D extends Texture { this.format = GPUTextureFormat.rgba8unorm; this.generate(imageBitmap); } else { - this.textureSource.setNetImage(url); const r = await fetch(url, { headers: Object.assign({ 'Accept': 'image/avif,image/webp,*/*' diff --git a/src/engine/textures/BitmapTexture2DArray.ts b/src/engine/textures/BitmapTexture2DArray.ts index 3abe4d09..fb9d4773 100644 --- a/src/engine/textures/BitmapTexture2DArray.ts +++ b/src/engine/textures/BitmapTexture2DArray.ts @@ -3,7 +3,7 @@ import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; import { ITexture } from '../gfx/graphics/webGpu/core/texture/ITexture'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { BitmapTexture2D } from './BitmapTexture2D'; -import { GPUContext } from '../..'; +import { GPUContext } from '../gfx/renderJob/GPUContext'; /** * Type BitmapTexture 2D Array , Use in GPU diff --git a/src/engine/textures/BitmapTextureCube.ts b/src/engine/textures/BitmapTextureCube.ts index cf30476f..c4558d19 100644 --- a/src/engine/textures/BitmapTextureCube.ts +++ b/src/engine/textures/BitmapTextureCube.ts @@ -1,9 +1,13 @@ -import { BitmapTexture2D, GPUContext, StringUtil, Texture, VirtualTexture } from '../..'; import { BlurTexture2DBufferCreator } from '../gfx/generate/convert/BlurEffectCreator'; import { TextureCube } from '../gfx/graphics/webGpu/core/texture/TextureCube'; import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; import { TextureCubeStdCreator } from "../gfx/generate/convert/TextureCubeStdCreator"; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { GPUContext } from '../gfx/renderJob/GPUContext'; +import { StringUtil } from '../util/StringUtil'; +import { BitmapTexture2D } from './BitmapTexture2D'; +import { VirtualTexture } from './VirtualTexture'; /** * @group Texture diff --git a/src/engine/textures/DefaultRes.ts b/src/engine/textures/DefaultRes.ts index 4bd938df..69de0a77 100644 --- a/src/engine/textures/DefaultRes.ts +++ b/src/engine/textures/DefaultRes.ts @@ -1,7 +1,6 @@ import { Engine3D } from '../Engine3D'; import { BRDFLUTGenerate } from '../gfx/generate/BrdfLUTGenerate'; import { Uint8ArrayTexture } from './Uint8ArrayTexture'; -import { GUISubTexture, GUITextureSource } from "../components/gui/core/GUISubTexture"; import { Texture } from "../gfx/graphics/webGpu/core/texture/Texture"; import { HDRTextureCube } from './HDRTextureCube'; @@ -23,12 +22,8 @@ class _DefaultRes { public greenTexture: Uint8ArrayTexture; public yellowTexture: Uint8ArrayTexture; public grayTexture: Uint8ArrayTexture; - public defaultTextureKVMap: { [name: string]: Texture } = {}; public defaultTextureVKMap: Map = new Map(); - - public defaultTextureSource: GUITextureSource;// = new GUITextureSource(defaultTexture.whiteTexture); - public defaultSubTexture: GUISubTexture;// = new GUISubTexture(); public defaultSky: HDRTextureCube; /** * create a texture @@ -96,10 +91,6 @@ class _DefaultRes { defaultRes.yellowTexture = defaultRes.createTexture(32, 32, 0, 255, 255, 255.0, 'default-yellowTexture'); defaultRes.grayTexture = defaultRes.createTexture(32, 32, 128, 128, 128, 255.0, 'default-grayTexture'); - defaultRes.defaultTextureSource = new GUITextureSource(defaultRes.whiteTexture); - defaultRes.defaultSubTexture = new GUISubTexture(); - defaultRes.defaultSubTexture.trimSize.set(4, 4) - let brdf = new BRDFLUTGenerate(); let texture = brdf.generateBRDFLUTTexture(); let BRDFLUT = texture.name = 'BRDFLUT'; diff --git a/src/engine/textures/Float16ArrayTexture.ts b/src/engine/textures/Float16ArrayTexture.ts index 7844bc8e..5291bdc5 100644 --- a/src/engine/textures/Float16ArrayTexture.ts +++ b/src/engine/textures/Float16ArrayTexture.ts @@ -1,9 +1,9 @@ -import { GPUContext } from '../..'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { TextureMipmapGenerator } from '../gfx/graphics/webGpu/core/texture/TextureMipmapGenerator'; import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; import { toHalfFloat } from '../util/Convert'; +import { GPUContext } from '../gfx/renderJob/GPUContext'; /** * @internal * Float16Array texture diff --git a/src/engine/textures/Float32ArrayTexture.ts b/src/engine/textures/Float32ArrayTexture.ts index 30cf5609..178f611d 100644 --- a/src/engine/textures/Float32ArrayTexture.ts +++ b/src/engine/textures/Float32ArrayTexture.ts @@ -1,8 +1,8 @@ -import { GPUContext } from '../..'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { TextureMipmapGenerator } from '../gfx/graphics/webGpu/core/texture/TextureMipmapGenerator'; import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +import { GPUContext } from '../gfx/renderJob/GPUContext'; /** * @internal * Float32Array texture diff --git a/src/engine/textures/HDRTexture.ts b/src/engine/textures/HDRTexture.ts index fd82bae3..19d1a757 100644 --- a/src/engine/textures/HDRTexture.ts +++ b/src/engine/textures/HDRTexture.ts @@ -1,7 +1,10 @@ -import { FileLoader, GPUContext, LoaderFunctions, RGBEParser } from '../..'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +import { GPUContext } from '../gfx/renderJob/GPUContext'; +import { FileLoader } from '../loader/FileLoader'; +import { LoaderFunctions } from '../loader/LoaderFunctions'; +import { RGBEParser } from '../loader/parser/RGBEParser'; /** * HDR Texture * @group Texture diff --git a/src/engine/textures/HDRTextureCube.ts b/src/engine/textures/HDRTextureCube.ts index 57f7859c..dae21a01 100644 --- a/src/engine/textures/HDRTextureCube.ts +++ b/src/engine/textures/HDRTextureCube.ts @@ -1,4 +1,3 @@ -import { FileLoader, LoaderFunctions, RGBEParser } from '../..'; import { ErpImage2CubeMap } from '../gfx/generate/convert/ErpImage2CubeMap'; import { IBLEnvMapCreator } from '../gfx/generate/convert/IBLEnvMapCreator'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; @@ -6,6 +5,9 @@ import { TextureCube } from '../gfx/graphics/webGpu/core/texture/TextureCube'; import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; import { VirtualTexture } from './VirtualTexture'; +import { FileLoader } from '../loader/FileLoader'; +import { LoaderFunctions } from '../loader/LoaderFunctions'; +import { RGBEParser } from '../loader/parser/RGBEParser'; /** * HDR TextureCube diff --git a/src/engine/textures/Uint16Texture.ts b/src/engine/textures/Uint16Texture.ts index 128e58e6..c00ce603 100644 --- a/src/engine/textures/Uint16Texture.ts +++ b/src/engine/textures/Uint16Texture.ts @@ -1,8 +1,8 @@ -import { GPUContext } from '../..'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { TextureMipmapGenerator } from '../gfx/graphics/webGpu/core/texture/TextureMipmapGenerator'; import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +import { GPUContext } from '../gfx/renderJob/GPUContext'; /** * @internal * Uint16 texture diff --git a/src/engine/textures/Uint8ArrayTexture.ts b/src/engine/textures/Uint8ArrayTexture.ts index e72b1b16..c554622a 100644 --- a/src/engine/textures/Uint8ArrayTexture.ts +++ b/src/engine/textures/Uint8ArrayTexture.ts @@ -1,8 +1,8 @@ -import { GPUContext } from '../..'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { TextureMipmapGenerator } from '../gfx/graphics/webGpu/core/texture/TextureMipmapGenerator'; import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; +import { GPUContext } from '../gfx/renderJob/GPUContext'; /** * create texture by number array, which format is uint8 diff --git a/tsconfig.json b/tsconfig.json index 142a36cf..f5e65983 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,9 +18,9 @@ }, "types": ["vite/client", "@webgpu/types"], // for dev - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noImplicitReturns": true, "allowJs": true, "strict": false }, From 6960df22192ecc4130b7b09296b986b25e9eacd7 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Thu, 27 Apr 2023 18:09:42 +0800 Subject: [PATCH 062/100] feat(clusterLighting): add cluster lighting shader (#77) add cluster lighting cs shader --- .../cluster/ClusterBoundsSource_cs.wgsl | 99 +++++++++++++ .../shader/cluster/ClusterLighting_cs.wgsl | 139 ++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 src/engine/assets/shader/cluster/ClusterBoundsSource_cs.wgsl create mode 100644 src/engine/assets/shader/cluster/ClusterLighting_cs.wgsl diff --git a/src/engine/assets/shader/cluster/ClusterBoundsSource_cs.wgsl b/src/engine/assets/shader/cluster/ClusterBoundsSource_cs.wgsl new file mode 100644 index 00000000..ed0ebe5f --- /dev/null +++ b/src/engine/assets/shader/cluster/ClusterBoundsSource_cs.wgsl @@ -0,0 +1,99 @@ + #include "GlobalUniform" + + struct ClusterBox{ + minPoint:vec4, + maxPoint:vec4 + } + + struct ClustersUniform{ + clusterTileX:f32, + clusterTileY:f32, + clusterTileZ:f32, + numLights:f32, + maxNumLightsPerCluster:f32, + near:f32, + far:f32, + screenWidth:f32, + screenHeight:f32, + } + + @group(0) @binding(1) var clustersUniform : ClustersUniform; + @group(0) @binding(2) var clusterBuffer : array; + + + var clusterTileX:f32 ; + var clusterTileY:f32 ; + var clusterTileZ:f32 ; + fn convertNDCToView( v4:vec4 ) -> vec4 { + var v = globalUniform.pvMatrixInv * v4 ; + v = v / v.w ; + return v ; + } + + fn gridToIndex(i:vec3) -> u32{ + return i.z * u32(clusterTileX) * u32(clusterTileY) + i.y * u32(clusterTileX) + i.x ; + } + + fn ScreenToView(screen : vec4) -> vec4 { + let texCoord = screen.xy / vec2(clustersUniform.screenWidth, clustersUniform.screenHeight); + let clip = vec4(vec2(texCoord.x, 1.0 - texCoord.y) * 2.0 - vec2(1.0, 1.0), screen.z, screen.w); + return convertNDCToView(clip); + } + + fn LineIntersectionToZPlane( eye:vec3 , ndcPoint :vec3 , z:f32) -> vec3 + { + var normal = vec3(0.0, 0.0, 1.0); + var dir = ndcPoint - eye; + var t = (z - dot(normal, eye)) / dot(normal, dir); + var result = eye + t * dir; + return result; + } + + // @compute @workgroup_size(2,2,1) + @compute @workgroup_size(16,12,1) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(local_invocation_id) local_invocation_id : vec3 ){ + // let i = local_invocation_id.x ; + // let j = local_invocation_id.y ; + + let i = local_invocation_id.x ; + let j = local_invocation_id.y ; + let k = workgroup_id.x ; + + clusterTileX = clustersUniform.clusterTileX; + clusterTileY = clustersUniform.clusterTileY; + clusterTileZ = clustersUniform.clusterTileZ; + + let clusterGrid = vec3(i,j,k); + let tileIndex = gridToIndex(clusterGrid); + let eyePos = vec3(0.0, 0.0, 0.0); + + let tx = clusterTileX; + let ty = clusterTileY; + let tz = clusterTileZ ; + let near = clustersUniform.near ; + let far = clustersUniform.far ; + + let titleSize = vec2( clustersUniform.screenWidth / tx , clustersUniform.screenHeight / ty ) ; + + var maxPointSs = vec4(vec2(f32(i) + 1.0, f32(j) + 1.0) * titleSize, 0.0, 1.0); + var minPointSs = vec4(vec2(f32(i) , f32(j)) * titleSize, 0.0, 1.0); + + var maxPointVs = ScreenToView(maxPointSs).xyz; + var minPointVs = ScreenToView(minPointSs).xyz; + + var tileNear = clustersUniform.near * pow(clustersUniform.far / clustersUniform.near, f32(k) / clustersUniform.clusterTileZ); + var tileFar = clustersUniform.near * pow(clustersUniform.far / clustersUniform.near, (f32(k) + 1.0) / clustersUniform.clusterTileZ); + + var minPointNear = LineIntersectionToZPlane(eyePos, minPointVs, tileNear); + var minPointFar = LineIntersectionToZPlane(eyePos, minPointVs, tileFar); + var maxPointNear = LineIntersectionToZPlane(eyePos, maxPointVs, tileNear); + var maxPointFar = LineIntersectionToZPlane(eyePos, maxPointVs, tileFar); + + var minPointAABB = min(min(minPointNear, minPointFar), min(maxPointNear, maxPointFar)); + var maxPointAABB = max(max(minPointNear, minPointFar), max(maxPointNear, maxPointFar)); + + var clusterBox : ClusterBox ; + clusterBox.minPoint = vec4(minPointAABB,f32(tileIndex)) ; + clusterBox.maxPoint = vec4(maxPointAABB,f32(tileIndex)) ; + clusterBuffer[tileIndex] = clusterBox; + } \ No newline at end of file diff --git a/src/engine/assets/shader/cluster/ClusterLighting_cs.wgsl b/src/engine/assets/shader/cluster/ClusterLighting_cs.wgsl new file mode 100644 index 00000000..7a6c2e25 --- /dev/null +++ b/src/engine/assets/shader/cluster/ClusterLighting_cs.wgsl @@ -0,0 +1,139 @@ + #include "GlobalUniform" + + struct ClusterBox{ + minPoint:vec4, + maxPoint:vec4 + } + + struct Light { + index:f32, + lightType:i32, + radius:f32, + linear:f32, + + position:vec3, + lightMatrixIndex:f32, + + direction:vec3, + quadratic:f32, + + lightColor:vec3, + intensity:f32, + + innerCutOff :f32, + outerCutOff:f32, + range :f32, + castShadow:f32, + + lightTangent:vec3, + ies:f32, + }; + + struct LightIndex + { + count:f32, + start:f32, + empty0:f32, + empty1:f32, + }; + + struct ClustersUniform{ + clusterTileX:f32, + clusterTileY:f32, + clusterTileZ:f32, + numLights:f32, + maxNumLightsPerCluster:f32, + near:f32, + far:f32, + screenWidth:f32, + screenHeight:f32, + clusterPix:f32, + } + + struct Uniforms { + matrix : array> + }; + + + + var clusterTileX:f32 ; + var clusterTileY:f32 ; + var clusterTileZ:f32 ; + + @group(0) @binding(1) var models : Uniforms; + @group(0) @binding(2) var clustersUniform : ClustersUniform; + @group(0) @binding(3) var clusterBuffer : array; + @group(0) @binding(4) var lightBuffer : array; + @group(0) @binding(5) var lightAssignBuffer : array; + @group(0) @binding(6) var assignTable : array; + + fn gridToIndex(i:vec3) -> u32{ + return i.z * u32(clusterTileX) * u32(clusterTileY) + i.y * u32(clusterTileX) + i.x ; + } + + fn GetSqdisPointAABB( pos:vec3, clusterIndex:u32 ) -> f32 + { + var sqDistance = 0.0; + let cluster = clusterBuffer[clusterIndex]; + for (var i = 0u; i < 3u; i+=1u) + { + var v = pos[i]; + if (v < cluster.minPoint[i]) + { + let diff = cluster.minPoint[i] - v; + sqDistance += diff * diff; + } + + if (v > cluster.maxPoint[i]) + { + let diff = v - cluster.maxPoint[i]; + sqDistance += diff * diff; + } + } + return sqDistance; + } + + fn TestSphereAABB( lightIndex:i32 , clusterIndex : u32 ) -> bool + { + let light = lightBuffer[lightIndex]; + let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; + var radius = light.range * 2.0 ; + let spherePos = globalUniform.viewMat * vec4(lightPos.xyz, 1.0) ; + let sqDistance = GetSqdisPointAABB(spherePos.xyz , clusterIndex); + return sqDistance <= (radius*radius); + } + + + + @compute @workgroup_size(16,12,1) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(local_invocation_id) local_invocation_id : vec3 ){ + clusterTileX = clustersUniform.clusterTileX; + clusterTileY = clustersUniform.clusterTileY; + clusterTileZ = clustersUniform.clusterTileZ; + // cluster ID + let i = local_invocation_id.x ; + let j = local_invocation_id.y ; + let k = workgroup_id.x ; + + var clusterId_3D = vec3(i,j,k); + var clusterId_1D = gridToIndex(clusterId_3D); + + var startIndex = i32(clusterId_1D) * i32(clustersUniform.maxNumLightsPerCluster) ; + var endIndex = startIndex; + + for(var lightID = 0 ; lightID < i32(clustersUniform.numLights) ; lightID+=1) + { + if(!TestSphereAABB(lightID, clusterId_1D)) { + continue; + }; + lightAssignBuffer[endIndex] = f32(lightID); + endIndex += 1 ; + } + + // workgroupBarrier(); + + var idx: LightIndex; + idx.count = f32(endIndex-startIndex); + idx.start = f32(startIndex); + assignTable[clusterId_1D] = idx; + } \ No newline at end of file From 4733b23cbe82e0757b622383deda2ef283afa0f6 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Thu, 27 Apr 2023 18:30:15 +0800 Subject: [PATCH 063/100] docs: update docs (#78) update docs --- src/engine/assets/Res.ts | 4 +- src/engine/io/InputSystem.ts | 179 +------------ src/engine/loader/parser/gltf/GLBParser.ts | 16 +- src/engine/loader/parser/gltf/GLTFInfo.ts | 6 +- src/engine/loader/parser/gltf/GLTFParser.ts | 8 +- .../loader/parser/gltf/GLTFSubParser.ts | 245 +----------------- .../loader/parser/gltf/GLTFSubParserMesh.ts | 6 +- 7 files changed, 33 insertions(+), 431 deletions(-) diff --git a/src/engine/assets/Res.ts b/src/engine/assets/Res.ts index 77f19a8e..afc7c80b 100644 --- a/src/engine/assets/Res.ts +++ b/src/engine/assets/Res.ts @@ -69,7 +69,7 @@ export class Res { /** * get material by name - * @param name mateiral name + * @param name material name * @returns */ public getMat(name: string) { @@ -182,7 +182,7 @@ export class Res { * load texture by url * @param url texture path * @param loaderFunctions callback - * @param flipY use filp y or not + * @param flipY use flip y or not * @returns */ public async loadTexture(url: string, loaderFunctions?: LoaderFunctions, flipY?: boolean) { diff --git a/src/engine/io/InputSystem.ts b/src/engine/io/InputSystem.ts index 858559ad..74518cf6 100644 --- a/src/engine/io/InputSystem.ts +++ b/src/engine/io/InputSystem.ts @@ -36,7 +36,7 @@ export class InputSystem extends CEventDispatcher { public isRightMouseDown: boolean = false; /** - * referrence of canvas + * reference of canvas */ public canvas: HTMLCanvasElement; @@ -86,13 +86,11 @@ export class InputSystem extends CEventDispatcher { protected _pointerEvent3D: PointerEvent3D; protected _windowsEvent3d: CEvent; - private _onGamepadStick1: Function = null; - private _onGamepadStick2: Function = null; /** * init the input system - * @param canvas the referrence of canvas + * @param canvas the reference of canvas */ public initCanvas(canvas: HTMLCanvasElement) { this.canvas = canvas; @@ -173,56 +171,12 @@ export class InputSystem extends CEventDispatcher { this._windowsEvent3d = new CEvent(); } - /** - * @private - * - * @param code {@link KeyCode} - * - */ - private getKeyPress(code: KeyCode): boolean { - return this._keyStatus[code]; - } - /** - * @private - * @param code {@link MouseCode} - * - */ - private getMousePress(code: MouseCode): boolean { - return this._mouseStatus[code]; - } private _gp: boolean = false; - private ongamepaddisconnected(e: GamepadEvent) { - //Debug.instance.trace("Gamepad disconnected!"); - this._gp = false; - } - private ongamepadconnected(e: GamepadEvent) { - //Debug.instance.trace("Gamepad connected!"); - this._gp = true; - } - /** - * @param index {number} - * @returns {boolean} - */ - private getGamepadButtonState(index: number): boolean { - return navigator.getGamepads()[0].buttons[index].pressed; - } - /** - * @returns {Vector3D} - */ - private getGamepadStick1(): Vector3 { - return new Vector3(navigator.getGamepads()[0].axes[0], navigator.getGamepads()[0].axes[1], 0); - } - /** - * @returns {Vector3D} - */ - private getGamepadStick2(): Vector3 { - return new Vector3(navigator.getGamepads()[0].axes[2], navigator.getGamepads()[0].axes[3], 0); - } private onPinch(x1: number, y1: number, x2: number, y2: number) { this._oldPosition1 = new Vector3(x1, y1); @@ -239,115 +193,9 @@ export class InputSystem extends CEventDispatcher { this._time = new Date().getTime(); } - private touchStart(e: TouchEvent) { - this.isMouseDown = true; - if (e && e.changedTouches && e.changedTouches.length > 0) { - var newX: number = e.changedTouches[0].clientX - this.canvasX; //- Input.canvas.x + Input.canvas.offsetX; - var newY: number = e.changedTouches[0].clientY - this.canvasY; // Input.canvas.y + Input.canvas.offsetY; - } - - if (e.targetTouches && e.targetTouches.length == 2) { - var oldX: number = e.targetTouches[0].clientX - this.canvasX; // - Input.canvas.x + Input.canvas.offsetX; - var oldY: number = e.targetTouches[0].clientY - this.canvasY; // - Input.canvas.y + Input.canvas.offsetY; - this.onPinch(oldX, oldY, newX, newY); - } else if (e.targetTouches && e.targetTouches.length == 1) { - this.onSwipe(newX, newY); - this._mouseStatus[MouseCode.MOUSE_LEFT] = true; - } - - this._pointerEvent3D.reset(); - this._pointerEvent3D.targetTouches = this.GetTargetTouches(e.targetTouches); - this._pointerEvent3D.changedTouches = this.GetTargetTouches(e.changedTouches); - this._pointerEvent3D.touches = this.GetTargetTouches(e.touches); - // this._pointerEvent3D.target = this; - this.mouseX = e.targetTouches[0].clientX - this.canvasX; /*- Input.canvas.x + Input.canvas.offsetX*/ - this.mouseY = e.targetTouches[0].clientY - this.canvasY; /*- Input.canvas.y + Input.canvas.offsetY*/ - this._pointerEvent3D.mouseX = this.mouseX; - this._pointerEvent3D.mouseY = this.mouseY; - // if (!this._isTouchStart) { - this._isTouchStart = true; - this._pointerEvent3D.type = PointerEvent3D.POINTER_DOWN; - this.dispatchEvent(this._pointerEvent3D); - // } - this._downTime = Time.time; - } - private _oldPosition1: Vector3 = null; private _oldPosition2: Vector3 = null; - private touchEnd(e: TouchEvent) { - this.isMouseDown = false; - if (e.targetTouches.length > 1) { - var x: number = e.targetTouches[0].clientX - this.canvasX; //- Input.canvas.x + Input.canvas.offsetX; - var y: number = e.targetTouches[0].clientY - this.canvasY; //- Input.canvas.y + Input.canvas.offsetY; - var x1: number = e.targetTouches[1].clientX - this.canvasX; //- Input.canvas.x + Input.canvas.offsetX; - var y1: number = e.targetTouches[1].clientY - this.canvasY; // Input.canvas.y + Input.canvas.offsetY; - this.onPinch(x, y, x1, y1); - } else if (e.targetTouches.length == 1) { - this.onSwipe(e.targetTouches[0].clientX - this.canvasX /*- Input.canvas.x + Input.canvas.offsetX*/, e.targetTouches[0].clientY - this.canvasY /*- Input.canvas.y + Input.canvas.offsetY*/); - this._mouseStatus[MouseCode.MOUSE_LEFT] = false; - } else { - this._oldPosition1 = null; - this._oldPosition2 = null; - this._time = 0; - } - this._pointerEvent3D.reset(); - this._isTouchStart = false; - this._pointerEvent3D.targetTouches = this.GetTargetTouches(e.targetTouches); - this._pointerEvent3D.changedTouches = this.GetTargetTouches(e.changedTouches); - this._pointerEvent3D.touches = this.GetTargetTouches(e.touches); - // this._pointerEvent3D.target = this; - this._pointerEvent3D.type = PointerEvent3D.POINTER_UP; - this._pointerEvent3D.mouseX = this.mouseX; - this._pointerEvent3D.mouseY = this.mouseY; - this.dispatchEvent(this._pointerEvent3D); - if (Time.time - this._downTime < 200) { - this._pointerEvent3D.type = PointerEvent3D.POINTER_CLICK; - this.dispatchEvent(this._pointerEvent3D); - } - } - - private touchMove(e: TouchEvent) { - this.mouseLastX = this.mouseX; - this.mouseLastY = this.mouseY; - - this.mouseX = e.targetTouches[0].clientX - this.canvasX; /*- Input.canvas.x + Input.canvas.offsetX*/ - this.mouseY = e.targetTouches[0].clientY - this.canvasY; /*- Input.canvas.y + Input.canvas.offsetY*/ - - this.mouseOffsetX = this.mouseX - this.mouseLastX; - this.mouseOffsetY = this.mouseY - this.mouseLastY; - - // e.preventDefault(); - // this.mouseClick.apply(this, e); - // this._touchEvent3d.reset(); - //e.preventDefault(); - - if (e.targetTouches.length > 1) { - var newPosition1: Vector3 = new Vector3(this.mouseX, this.mouseY); - var newPosition2: Vector3 = new Vector3(e.targetTouches[1].clientX - this.canvasX /*- Input.canvas.x + Input.canvas.offsetX*/, e.targetTouches[1].clientY - this.canvasY /*- Input.canvas.y + Input.canvas.offsetY*/); - - if (this._oldPosition1 == null) this._oldPosition1 = newPosition1; - if (this._oldPosition2 == null) this._oldPosition2 = newPosition2; - - if (this.isEnlarge(this._oldPosition1, this._oldPosition2, newPosition1, newPosition2)) this.wheelDelta = 120; - else this.wheelDelta = -120; - - this._oldPosition1 = newPosition1; - this._oldPosition2 = newPosition2; - } else { - } - - this._pointerEvent3D.reset(); - this._pointerEvent3D.targetTouches = this.GetTargetTouches(e.targetTouches); - this._pointerEvent3D.changedTouches = this.GetTargetTouches(e.changedTouches); - this._pointerEvent3D.touches = this.GetTargetTouches(e.touches); - this._pointerEvent3D.mouseX = this.mouseX; - this._pointerEvent3D.mouseY = this.mouseY; - // this._pointerEvent3D.target = this; - this._pointerEvent3D.type = PointerEvent3D.POINTER_MOVE; - this.dispatchEvent(this._pointerEvent3D); - } - private GetTargetTouches(targetTouches: TouchList): Array { var array: Array = new Array(); for (var i = 0; i < targetTouches.length; i++) { @@ -448,10 +296,6 @@ export class InputSystem extends CEventDispatcher { this.dispatchEvent(this._pointerEvent3D); } - private isMobile(pointerType: string): boolean { - // return /Mobile/i.test(navigator.userAgent); - return "touch" == pointerType; - } private mouseStart(e: PointerEvent) { this.isMouseDown = true; @@ -592,14 +436,6 @@ export class InputSystem extends CEventDispatcher { this.dispatchEvent(this._keyEvent3d); } - private onWindowsResize(e: UIEvent) { - let rect: DOMRect = this.canvas.getBoundingClientRect(); - - this.canvasX = rect.left; // parseInt( this.canvas.style.left.split("px")[0] ); - this.canvasY = rect.top; //rect parseInt(this.canvas.style.top.split("px")[0]); - this._windowsEvent3d.type = CResizeEvent.RESIZE; - this.dispatchEvent(this._windowsEvent3d); - } private GetSlideAngle(dx: number, dy: number) { return (Math.atan2(dy, dx) * 180) / Math.PI; @@ -635,15 +471,4 @@ export class InputSystem extends CEventDispatcher { return result; } - - private isEnlarge(op1: Vector3, op2: Vector3, np1: Vector3, np2: Vector3): boolean { - var leng1 = Math.sqrt((op1.x - op2.x) * (op1.x - op2.x) + (op1.y - op2.y) * (op1.y - op2.y)); - var leng2 = Math.sqrt((np1.x - np2.x) * (np1.x - np2.x) + (np1.y - np2.y) * (np1.y - np2.y)); - - if (leng1 < leng2) { - return true; - } else { - return false; - } - } } diff --git a/src/engine/loader/parser/gltf/GLBParser.ts b/src/engine/loader/parser/gltf/GLBParser.ts index 5de78620..de629e4e 100644 --- a/src/engine/loader/parser/gltf/GLBParser.ts +++ b/src/engine/loader/parser/gltf/GLBParser.ts @@ -91,10 +91,10 @@ export class GLBParser extends ParserBase { const buffer = this._gltf.buffers[bufferView.buffer]; let dataBuffer = new Uint8Array(buffer.dbuffer, bufferView.byteOffset, bufferView.byteLength); let imgData = new Blob([dataBuffer], { type: image.mimeType }); - let dtexture = new BitmapTexture2D(); - await dtexture.loadFromBlob(imgData); - dtexture.name = image.name; - this._gltf.resources[image.name] = dtexture; + let dTexture = new BitmapTexture2D(); + await dTexture.loadFromBlob(imgData); + dTexture.name = image.name; + this._gltf.resources[image.name] = dTexture; } } @@ -123,10 +123,10 @@ export class GLBParser extends ParserBase { const buffer = this._gltf.buffers[bufferView.buffer]; let dataBuffer = new Uint8Array(buffer.dbuffer, bufferView.byteOffset, bufferView.byteLength); let imgData = new Blob([dataBuffer], { type: image.mimeType }); - let dtexture = new BitmapTexture2D(); - await dtexture.loadFromBlob(imgData); - dtexture.name = image.name; - this._gltf.resources[image.name] = dtexture; + let dTexture = new BitmapTexture2D(); + await dTexture.loadFromBlob(imgData); + dTexture.name = image.name; + this._gltf.resources[image.name] = dTexture; } } diff --git a/src/engine/loader/parser/gltf/GLTFInfo.ts b/src/engine/loader/parser/gltf/GLTFInfo.ts index 72801b98..0006e695 100644 --- a/src/engine/loader/parser/gltf/GLTFInfo.ts +++ b/src/engine/loader/parser/gltf/GLTFInfo.ts @@ -46,7 +46,7 @@ export class GLTF_Info { sampler: number; source: number; name: string; - dtexture: any; + dTexture: any; }[]; cameras: any; skins: any; @@ -55,8 +55,8 @@ export class GLTF_Info { uri: string; name: string; isParsed: any; - dsampler: any; - dimage: any; + dSampler: any; + dImage: any; mimeType: string; bufferView: number; }[]; diff --git a/src/engine/loader/parser/gltf/GLTFParser.ts b/src/engine/loader/parser/gltf/GLTFParser.ts index b74e43bb..49340271 100644 --- a/src/engine/loader/parser/gltf/GLTFParser.ts +++ b/src/engine/loader/parser/gltf/GLTFParser.ts @@ -26,7 +26,7 @@ export class GLTFParser extends ParserBase { //await this.load_gltf_textures(); let subParser = new GLTFSubParser(); let nodes = await subParser.parse(this.initUrl, this._gltf, this._gltf.scene); - subParser.destory(); + subParser.destroy(); subParser = null if (nodes) { this.data = nodes.rootNode; @@ -135,15 +135,15 @@ export class GLTFParser extends ParserBase { return `MORPH_TARGET_NUM ${targetNum}`; } - public static getMorphtargetPositionDefine() { + public static getMorphTargetPositionDefine() { return 'HAS_MORPH_POSITION'; } - public static getMorphtargetNormalDefine() { + public static getMorphTargetNormalDefine() { return 'HAS_MORPH_NORMAL'; } - public static getMorphtargetTangentDefine() { + public static getMorphTargetTangentDefine() { return 'HAS_MORPH_TANGENT'; } diff --git a/src/engine/loader/parser/gltf/GLTFSubParser.ts b/src/engine/loader/parser/gltf/GLTFSubParser.ts index a3ed32f4..9a945f04 100644 --- a/src/engine/loader/parser/gltf/GLTFSubParser.ts +++ b/src/engine/loader/parser/gltf/GLTFSubParser.ts @@ -93,7 +93,7 @@ export class GLTFSubParser { return await this.convertToNode(result); } - public destory() { + public destroy() { KHR_draco_mesh_compression.unload(this.gltf) this.gltf = null } @@ -186,31 +186,31 @@ export class GLTFSubParser { public async parseTexture(index: number) { let textureInfo = this.gltf.textures[index]; - if (textureInfo && !textureInfo.dtexture) { + if (textureInfo && !textureInfo.dTexture) { if (textureInfo && textureInfo.source != null) { let image = this.gltf.images[textureInfo.source]; if (image.uri) { let name = image.uri; name = StringUtil.getURLName(name); - textureInfo.dtexture = this.gltf.resources[name]; + textureInfo.dTexture = this.gltf.resources[name]; } else if (image.bufferView) { let buffer = this.parseBufferView(image.bufferView); let bitmapTexture = new BitmapTexture2D(); let img = new Blob([buffer], { type: image.mimeType }); await bitmapTexture.loadFromBlob(img); - textureInfo.dtexture = bitmapTexture; + textureInfo.dTexture = bitmapTexture; } else { - textureInfo.dtexture = this.gltf.resources[image.name]; + textureInfo.dTexture = this.gltf.resources[image.name]; } } else if (textureInfo.name) { let name = StringUtil.getURLName(textureInfo.name); - textureInfo.dtexture = this.gltf.resources[name]; + textureInfo.dTexture = this.gltf.resources[name]; } } - if (!textureInfo.dtexture) { + if (!textureInfo.dTexture) { console.log("miss texture , please check texture!", index, textureInfo); } - return textureInfo.dtexture; + return textureInfo.dTexture; } public async parseMaterial(materialId) { @@ -222,87 +222,6 @@ export class GLTFSubParser { private parseAnimations() { const result = []; - // const animations = this.gltf.animations; - // if (animations) - // for (let i = 0; i < animations.length; i++) { - // const animation = animations[i]; - // const { name, channels, samplers } = animation; - // const clips = []; - // if (channels && samplers) - // for (let j = 0; j < channels.length; j++) { - // const channel = channels[j]; - // const sampler = samplers[channel.sampler]; - // if (!sampler) { - - // this.errorMiss(`animations[${i}].channels[${j}].sampler`, channel.sampler); - // continue; - - // } - - // const input = this.parseAccessor(sampler.input).data; - // const outputData = this.parseAccessor(sampler.output); - // const output = outputData.data; - // const numComponents = outputData.numComponents; - // const interpolation = sampler.interpolation || 'LINEAR'; - // const gltfNodeIdx = channel.target.node; - // const path = channel.target.path; - - // if (!input || !output) continue; - - // let combinedOutput = output; - // if (numComponents !== 1 || input.length !== output.length) { - - // const numComp = output.length / input.length; - // combinedOutput = []; - // for (let k = 0; k < input.length; k++) - // combinedOutput.push(output.slice(numComp * k, numComp * (k + 1))); - - // } - - // let nodeProperty = path; - // const extras = {}; - // switch (path) { - - // case 'translation': - // nodeProperty = 'position'; - // break; - // case 'rotation': - // nodeProperty = 'quaternion'; - // break; - // case 'scale': - // nodeProperty = 'scale'; - // break; - // case 'weights': - // nodeProperty = 'weights'; - // // extras.uniformName = GLTFParser.MORPH_WEIGHT_UNIFORM; - // break; - // default: - // console.error(`unsupported animation sampler path ${path}`); - // nodeProperty = false; - // } - - // if (!nodeProperty) continue; - - // const clip = { - // times: input, - // values: combinedOutput, - // findFlag: GLTFParser.GLTF_NODE_INDEX_PROPERTY, - // findValue: gltfNodeIdx, - // targetProp: nodeProperty, - // method: interpolation, - // extras, - // }; - - // clips.push(clip); - - // } - - // result.push({ - // name: name || String(i), - // clips, - // }); - - // } return result; } @@ -327,10 +246,10 @@ export class GLTFSubParser { return this._skeletonParser.parseSkeletonAnimation(skeleton, animation); } - private async trivarse(parentNode, nodeInfos) { + private async traverse(parentNode, nodeInfos) { for (let i = 0; i < nodeInfos.length; i++) { const node = await this.parseObject3D(nodeInfos[i], parentNode); - await this.trivarse(node, nodeInfos[i].children); + await this.traverse(node, nodeInfos[i].children); } } @@ -342,151 +261,9 @@ export class GLTFSubParser { const textures = []; const skins = []; const cameras = []; - await this.trivarse(rootNode, nodes); + await this.traverse(rootNode, nodes); let animas; - // apply skins - // if ( skins.length ) { - - // const handlers = []; // help uglify use different name - // for ( let i = 0; i < skins.length; i ++ ) { - - // const { - // joints, skeleton, inverseBindMatrices, models, - // } = skins[ i ]; - - // const jointNum = joints.length; - // const globalJointTransformNodes = []; - // for ( let j = 0; j < jointNum; j ++ ) - // globalJointTransformNodes[ j ] = rootNode.findInChildren( GLTFParser.GLTF_NODE_INDEX_PROPERTY, joints[ j ] ); - - // let skeletonNode; - // if ( skeleton !== GLTFParser.SCENE_ROOT_SKELETON ) - // skeletonNode = rootNode.findInChildren( GLTFParser.GLTF_NODE_INDEX_PROPERTY, skeleton ); - // else - // skeletonNode = rootNode; - // skins[ i ].skeletonNode = skeletonNode; // do not know how to use it - - // const frag = new Array( 16 ); - // const fragWorld = new Array( 16 ); - // handlers[ i ] = function updateJointUniformFunc() { - - // for ( let k = 0; k < models.length; k ++ ) { - - // const model = models[ k ]; - // const globalTransformNode = model.node; - // let jointMats = []; - // Matrix4.invert( fragWorld, globalTransformNode.transform.getWorldMatrix() ); - - // for ( let n = 0; n < jointNum; n ++ ) { - - // Matrix4.mult( frag, fragWorld, globalJointTransformNodes[ n ].transform.getWorldMatrix() ); - // if ( inverseBindMatrices[ n ] !== GLTFParser.IDENTITY_INVERSE_BIND_MATRICES ) - // Matrix4.mult( frag, frag, inverseBindMatrices[ n ] ); - // jointMats = jointMats.concat( frag ); - - // } - - // const uniformObj = {}; - // uniformObj[ GLTFParser.JOINT_MATRICES_UNIFORM ] = jointMats; - // model.setUniformObj( uniformObj ); - - // } - - // }; - - // rootNode.afterUpdateMatrix.push( { - // type: 'skin', skinName: skins[ i ].name, handler: handlers[ i ], trigerNodes: [ skeletonNode, ...globalJointTransformNodes ], - // } ); - - // } - - // } - - // // animations - // for ( let i = 0; i < animations.length; i ++ ) { - - // const { clips } = animations[ i ]; - // let animateMaxTime = Number.NEGATIVE_INFINITY; - // let animateMinTime = Number.POSITIVE_INFINITY; - // for ( let j = 0; j < clips.length; j ++ ) { - - // const { - // findFlag, findValue, targetProp, times, extras, // method, - // } = clips[ j ]; - - // const node = rootNode.findInChildren( findFlag, findValue ); - // let targetNodes = [ node ]; - // if ( ! node.model && node.gltfPrimitives ) - // targetNodes = node.gltfPrimitives; - - // let setTarget; - // let resetTarget; - // if ( targetProp === 'weights' ) { - - // const resetObj = {}; - // resetObj[ GLTFParser.MORPH_WEIGHT_UNIFORM ] = targetNodes[ 0 ].model.uniformObj[ GLTFParser.MORPH_WEIGHT_UNIFORM ]; - // resetTarget = function () { - - // targetNodes.forEach( ( n ) => { - - // n.model.setUniformObj( resetObj ); - - // } ); - - // }; - - // setTarget = function ( v ) { - - // const uniformobj = {}; - // uniformobj[ extras.uniformName ] = v; - - // targetNodes.forEach( ( n ) => { - - // n.model.setUniformObj( uniformobj ); - - // } ); - - // }; - - // } else { - - // const defaultValues = []; - // for ( let m = 0; m < targetNodes.length; m ++ ) - // defaultValues[ m ] = targetNodes[ m ][ targetProp ]; - - // resetTarget = function () { - - // for ( let m = 0; m < targetNodes.length; m ++ ) - // targetNodes[ m ][ targetProp ] = defaultValues[ m ]; - - // }; - - // setTarget = function ( v ) { - - // targetNodes.forEach( ( n ) => { - - // n[ targetProp ] = v; // eslint-disable-line - - // } ); - - // }; - - // } - - // animateMinTime = animateMinTime < times[ 0 ] ? animateMinTime : times[ 0 ]; - // animateMaxTime = animateMaxTime > times[ times.length - 1 ] ? animateMaxTime : times[ times.length - 1 ]; - - // Object.assign( clips[ j ], { setTarget, resetTarget } ); - - // } - - // Object.assign( animations[ i ], { animateMinTime, animateMaxTime } ); - - // } - - // animas = { animations, type: 'gltf' }; - return { rootNode, textures, diff --git a/src/engine/loader/parser/gltf/GLTFSubParserMesh.ts b/src/engine/loader/parser/gltf/GLTFSubParserMesh.ts index 7c5c21b5..02f1133b 100644 --- a/src/engine/loader/parser/gltf/GLTFSubParserMesh.ts +++ b/src/engine/loader/parser/gltf/GLTFSubParserMesh.ts @@ -180,9 +180,9 @@ export class GLTFSubParserMesh { }); } - if (hasPositions) dprimitive.defines.push(GLTFParser.getMorphtargetPositionDefine()); - if (hasNormals) dprimitive.defines.push(GLTFParser.getMorphtargetNormalDefine()); - if (hasTangents) dprimitive.defines.push(GLTFParser.getMorphtargetTangentDefine()); + if (hasPositions) dprimitive.defines.push(GLTFParser.getMorphTargetPositionDefine()); + if (hasNormals) dprimitive.defines.push(GLTFParser.getMorphTargetNormalDefine()); + if (hasTangents) dprimitive.defines.push(GLTFParser.getMorphTargetTangentDefine()); dprimitive.weights = mesh.weights || new Array(targets.length).fill(0); } From 4ac5ba4bd52d40b59ee8c0276b60915f0df1c559 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Thu, 27 Apr 2023 18:48:42 +0800 Subject: [PATCH 064/100] feat(ComputeShader): add cs shader (#79) add cs shader add shader resource update docs --- src/engine/assets/shader/ShaderLib.ts | 2 +- .../assets/shader/compute/BLUR_CsShader.wgsl | 40 +++ .../shader/compute/DepthOfView_CsShader.wgsl | 81 +++++ .../ErpImage2CubeMapCreateCube_compute.wgsl | 65 ++++ .../ErpImage2CubeMapRgbe2rgba_compute.wgsl | 32 ++ src/engine/assets/shader/compute/GTAOCs.wgsl | 133 ++++++++ .../compute/IBLEnvMapCreator_compute.wgsl | 174 ++++++++++ .../assets/shader/compute/MergeRGBA_Cs.wgsl | 29 ++ .../compute/MultiBouncePass_Shader.wgsl | 185 ++++++++++ .../shader/compute/OutLineBlendColor.wgsl | 40 +++ .../shader/compute/OutlineCalcOutline.wgsl | 86 +++++ .../assets/shader/compute/OutlineCs.wgsl | 120 +++++++ .../shader/compute/Picker_CsShader.wgsl | 65 ++++ .../assets/shader/compute/SSAO_CsShader.wgsl | 99 ++++++ .../shader/compute/SSR_BlendColor_Shader.wgsl | 45 +++ .../assets/shader/compute/SSR_IS_Shader.wgsl | 82 +++++ .../shader/compute/SSR_RayTrace_Shader.wgsl | 315 ++++++++++++++++++ .../assets/shader/compute/TAACopyTex.wgsl | 18 + .../assets/shader/compute/TAASharpTex.wgsl | 41 +++ src/engine/assets/shader/compute/TAAcs.wgsl | 155 +++++++++ .../assets/shader/core/base/Common_frag.wgsl | 26 ++ .../assets/shader/core/base/Common_vert.wgsl | 11 + .../shader/core/common/BrdfLut_frag.wgsl | 4 + .../shader/core/common/EnvMap_frag.wgsl | 9 + .../shader/core/common/GlobalUniform.wgsl | 37 ++ .../shader/core/common/InstanceUniform.wgsl | 7 + .../core/common/WorldMatrixUniform.wgsl | 9 + .../shader/core/inline/Inline_vert.wgsl | 49 +++ .../shader/graphic/Graphic3DShader_fs.wgsl | 30 ++ .../shader/graphic/Graphic3DShader_vs.wgsl | 27 ++ .../assets/shader/materials/GlassShader.wgsl | 36 ++ .../assets/shader/materials/LitShader.wgsl | 22 ++ .../assets/shader/materials/OutlinePass.wgsl | 80 +++++ .../assets/shader/materials/PBRLItShader.wgsl | 106 ++++++ src/engine/assets/shader/materials/UnLit.wgsl | 28 ++ .../sky/AtmosphericScatteringSky_shader.ts | 0 .../{ => materials}/sky/CubeSky_Shader.ts | 0 .../assets/shader/math/FastMathShader.wgsl | 31 ++ src/engine/assets/shader/post/FSAAShader.wgsl | 76 +++++ src/engine/assets/shader/utils/BRDFLUT.wgsl | 112 +++++++ src/engine/assets/shader/utils/ColorUtil.wgsl | 99 ++++++ .../assets/shader/utils/GenerayRandomDir.wgsl | 23 ++ .../textures/AtmosphericScatteringSky.ts | 2 +- 43 files changed, 2629 insertions(+), 2 deletions(-) create mode 100644 src/engine/assets/shader/compute/BLUR_CsShader.wgsl create mode 100644 src/engine/assets/shader/compute/DepthOfView_CsShader.wgsl create mode 100644 src/engine/assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl create mode 100644 src/engine/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl create mode 100644 src/engine/assets/shader/compute/GTAOCs.wgsl create mode 100644 src/engine/assets/shader/compute/IBLEnvMapCreator_compute.wgsl create mode 100644 src/engine/assets/shader/compute/MergeRGBA_Cs.wgsl create mode 100644 src/engine/assets/shader/compute/MultiBouncePass_Shader.wgsl create mode 100644 src/engine/assets/shader/compute/OutLineBlendColor.wgsl create mode 100644 src/engine/assets/shader/compute/OutlineCalcOutline.wgsl create mode 100644 src/engine/assets/shader/compute/OutlineCs.wgsl create mode 100644 src/engine/assets/shader/compute/Picker_CsShader.wgsl create mode 100644 src/engine/assets/shader/compute/SSAO_CsShader.wgsl create mode 100644 src/engine/assets/shader/compute/SSR_BlendColor_Shader.wgsl create mode 100644 src/engine/assets/shader/compute/SSR_IS_Shader.wgsl create mode 100644 src/engine/assets/shader/compute/SSR_RayTrace_Shader.wgsl create mode 100644 src/engine/assets/shader/compute/TAACopyTex.wgsl create mode 100644 src/engine/assets/shader/compute/TAASharpTex.wgsl create mode 100644 src/engine/assets/shader/compute/TAAcs.wgsl create mode 100644 src/engine/assets/shader/core/base/Common_frag.wgsl create mode 100644 src/engine/assets/shader/core/base/Common_vert.wgsl create mode 100644 src/engine/assets/shader/core/common/BrdfLut_frag.wgsl create mode 100644 src/engine/assets/shader/core/common/EnvMap_frag.wgsl create mode 100644 src/engine/assets/shader/core/common/GlobalUniform.wgsl create mode 100644 src/engine/assets/shader/core/common/InstanceUniform.wgsl create mode 100644 src/engine/assets/shader/core/common/WorldMatrixUniform.wgsl create mode 100644 src/engine/assets/shader/core/inline/Inline_vert.wgsl create mode 100644 src/engine/assets/shader/graphic/Graphic3DShader_fs.wgsl create mode 100644 src/engine/assets/shader/graphic/Graphic3DShader_vs.wgsl create mode 100644 src/engine/assets/shader/materials/GlassShader.wgsl create mode 100644 src/engine/assets/shader/materials/LitShader.wgsl create mode 100644 src/engine/assets/shader/materials/OutlinePass.wgsl create mode 100644 src/engine/assets/shader/materials/PBRLItShader.wgsl create mode 100644 src/engine/assets/shader/materials/UnLit.wgsl rename src/engine/assets/shader/{ => materials}/sky/AtmosphericScatteringSky_shader.ts (100%) rename src/engine/assets/shader/{ => materials}/sky/CubeSky_Shader.ts (100%) create mode 100644 src/engine/assets/shader/math/FastMathShader.wgsl create mode 100644 src/engine/assets/shader/post/FSAAShader.wgsl create mode 100644 src/engine/assets/shader/utils/BRDFLUT.wgsl create mode 100644 src/engine/assets/shader/utils/ColorUtil.wgsl create mode 100644 src/engine/assets/shader/utils/GenerayRandomDir.wgsl diff --git a/src/engine/assets/shader/ShaderLib.ts b/src/engine/assets/shader/ShaderLib.ts index 634540fe..a8007616 100644 --- a/src/engine/assets/shader/ShaderLib.ts +++ b/src/engine/assets/shader/ShaderLib.ts @@ -35,7 +35,7 @@ import { UnLitMaterialUniform_frag } from "./materials/uniforms/UnLitMaterialUni import { VideoUniform_frag } from "./materials/uniforms/VideoUniform_frag"; import { Bloom_shader } from "./post/Bloom_shader"; import { Quad_shader } from "./quad/Quad_shader"; -import { CubeSky_Shader } from "./sky/CubeSky_Shader"; +import { CubeSky_Shader } from "./materials/sky/CubeSky_Shader"; /** * @internal diff --git a/src/engine/assets/shader/compute/BLUR_CsShader.wgsl b/src/engine/assets/shader/compute/BLUR_CsShader.wgsl new file mode 100644 index 00000000..e5dd6680 --- /dev/null +++ b/src/engine/assets/shader/compute/BLUR_CsShader.wgsl @@ -0,0 +1,40 @@ +#include "GlobalUniform" + +struct UniformData { + radius: f32 , + bias: f32, + aoPower: f32 , + blurSize: f32 , +}; + +// @group(0) @binding(0) var standUniform: GlobalUniform; +@group(0) @binding(0) var uniformData: UniformData; +@group(0) @binding(1) var colorMap : texture_2d; +// @group(0) @binding(2) var ssaoMapSampler : sampler; +@group(0) @binding(2) var ssaoMap : texture_2d; +@group(0) @binding(3) var outTex : texture_storage_2d; + +@compute @workgroup_size( 8 , 8 ) +fn CsMain( @builtin(global_invocation_id) globalInvocation_id : vec3) +{ + var fragCoord = vec2( globalInvocation_id.xy ); + + var texSize = vec2(textureDimensions(ssaoMap).xy); + var texCoord = vec2(fragCoord) / texSize ; + + let blurSize = i32(uniformData.blurSize); + + var result = vec4(0.0) ; + var ii = 0.0 ; + for (var i = -2; i < 2 ; i+=1) { + for (var j = -2; j < 2 ; j+=1) { + var offset = vec2( i , j ) ; + result += textureLoad(ssaoMap, fragCoord + offset, 0 ); + // result += textureSampleLevel(ssaoMap,ssaoMapSampler, vec2( fragCoord + offset) / texSize , 0.0 ); + ii += 1.0 ; + } + } + var fResult = result.r / ii ; + var color = textureLoad(colorMap, fragCoord , 0 ); + textureStore(outTex, fragCoord , vec4(color.rgb * fResult,1.0) ); +} \ No newline at end of file diff --git a/src/engine/assets/shader/compute/DepthOfView_CsShader.wgsl b/src/engine/assets/shader/compute/DepthOfView_CsShader.wgsl new file mode 100644 index 00000000..f8420bda --- /dev/null +++ b/src/engine/assets/shader/compute/DepthOfView_CsShader.wgsl @@ -0,0 +1,81 @@ +#include "GlobalUniform" + + struct BlurSetting{ + near: f32, + far: f32, + pixelOffset: f32, + } + + @group(0) @binding(0) var standUniform: GlobalUniform; + @group(0) @binding(1) var blurSetting: BlurSetting; + + @group(0) @binding(2) var positionBufferTex : texture_2d; + @group(0) @binding(3) var normalBufferTex : texture_2d; + @group(0) @binding(4) var inTexSampler : sampler; + @group(0) @binding(5) var inTex : texture_2d; + @group(0) @binding(6) var outTex : texture_storage_2d; + + var cameraPosition: vec3; + var texSize: vec2; + var fragCoord: vec2; + var texelSize: vec2; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(inTex).xy; + texelSize = 1.0 / vec2(texSize - 1); + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + cameraPosition = vec3(standUniform.cameraWorldMatrix[3].xyz); + let wPosition:vec3 = textureLoad(positionBufferTex, fragCoord , 0).xyz; + var distance = length(wPosition - cameraPosition); + var oc:vec4 = textureLoad(inTex, fragCoord, 0); + if(distance > blurSetting.near){ + let normal = textureLoad(normalBufferTex, fragCoord, 0); + var pixelScale = 0.5; + if(normal.w > 0.5){ + distance = min(distance, blurSetting.far); + pixelScale = (distance - blurSetting.near) / (blurSetting.far - blurSetting.near); + } + oc = mixBlurColor(oc, fragCoord, blurSetting.pixelOffset, pixelScale); + } + textureStore(outTex, fragCoord, oc); + } + + fn mixBlurColor(orginColor:vec4, coord:vec2, pixelOffset:f32, scale:f32) -> vec4 { + + let uv = vec2(coord); + var uv0 = (uv + scale * vec2( pixelOffset, pixelOffset)) * texelSize; + var uv1 = (uv + scale * vec2(-pixelOffset, pixelOffset)) * texelSize; + var uv2 = (uv + scale * vec2(-pixelOffset, -pixelOffset)) * texelSize; + var uv3 = (uv + scale * vec2( pixelOffset, -pixelOffset)) * texelSize; + + uv0.x = processUVEdge(uv0.x); + uv0.y = processUVEdge(uv0.y); + uv1.x = processUVEdge(uv1.x); + uv1.y = processUVEdge(uv1.y); + uv2.x = processUVEdge(uv2.x); + uv2.y = processUVEdge(uv2.y); + uv3.x = processUVEdge(uv3.x); + uv3.y = processUVEdge(uv3.y); + + var ob = vec4(0.0); + ob += textureSampleLevel(inTex, inTexSampler, uv0, 0.0); + ob += textureSampleLevel(inTex, inTexSampler, uv1, 0.0); + ob += textureSampleLevel(inTex, inTexSampler, uv2, 0.0); + ob += textureSampleLevel(inTex, inTexSampler, uv3, 0.0); + return mix(orginColor, ob * 0.25, scale); + } + + fn processUVEdge(v: f32) -> f32{ + var value = v; + if(value < 0.0){ + value = - value; + }else if(value > 1.0){ + value = 2.0 - value; + } + return value; + } \ No newline at end of file diff --git a/src/engine/assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl b/src/engine/assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl new file mode 100644 index 00000000..f765bfd8 --- /dev/null +++ b/src/engine/assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl @@ -0,0 +1,65 @@ +struct ImageSize { + srcWidth : i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32 +}; + +@group(0) @binding(0) var size : ImageSize; +@group(0) @binding(1) var faceRotation: array>; +@group(0) @binding(2) var inputTexSampler : sampler; +@group(0) @binding(3) var inputTex : texture_2d; + +@group(1) @binding(0) var outputBuffer0 : texture_storage_2d_array; + +fn SampleSphericalMap(v: vec3) -> vec2 { + var uv:vec2 = vec2(atan2(v.z, v.x), asin(v.y)); + //uv = (uv * (vec2(0.1590999960899353, 0.3183000087738037) + vec2(0.0010000000474974513))); + uv = uv * vec2(0.1590999960899353, 0.3183000087738037); + uv = uv + vec2(0.5); + uv = clamp(uv, vec2(0.0), vec2(1.0)); + return uv; +} + + +fn applyQuaternion(position:vec3, q:vec4) -> vec3{ + let x:f32 = position.x; + let y:f32 = position.y; + let z:f32 = position.z; + + let qx:f32 = q.x; + let qy:f32 = q.y; + let qz:f32 = q.z; + let qw:f32 = q.w; + + let ix:f32 = qw * x + qy * z - qz * y; + let iy:f32 = qw * y + qz * x - qx * z; + let iz:f32 = qw * z + qx * y - qy * x; + let iw:f32 = -qx * x - qy * y - qz * z; + + var ret: vec3; + ret.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + ret.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + ret.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + + return ret; +} + +fn convertIdToDir3(uv_i32:vec2, quaternion:vec4) -> vec3{ + var uv_f32:vec2 = vec2(uv_i32.xy); + var halfSize:f32 = f32(size.dstWidth / 2); + var worldDirection:vec3 = vec3(uv_f32.x - halfSize, uv_f32.y - halfSize, -halfSize); + worldDirection = normalize(worldDirection); + worldDirection = applyQuaternion(worldDirection, quaternion); + return worldDirection; +} + +@compute @workgroup_size(8, 8, 1) +fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let coord = vec2(GlobalInvocationID.xy); + let quaternion = faceRotation[GlobalInvocationID.z]; + var worldDirection:vec3 = convertIdToDir3(coord, quaternion); + let uv_f32:vec2 = SampleSphericalMap(worldDirection); + let oc = textureSampleLevel(inputTex, inputTexSampler, uv_f32 , 0.0); + textureStore(outputBuffer0, coord, i32(GlobalInvocationID.z), oc); +} \ No newline at end of file diff --git a/src/engine/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl b/src/engine/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl new file mode 100644 index 00000000..aece1023 --- /dev/null +++ b/src/engine/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl @@ -0,0 +1,32 @@ +struct ImageSize { + srcWidth : i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32 +}; + +@group(0) @binding(0) var size : ImageSize; +@group(0) @binding(1) var tex_in: array>; +@group(0) @binding(2) var outputBuffer : texture_storage_2d; + +@compute @workgroup_size(8, 8, 1) +fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let fragCoord = vec2(i32(GlobalInvocationID.x), i32(GlobalInvocationID.y)); + var oc:vec4 = tex_in[fragCoord.y * size.srcWidth + fragCoord.x] / 256.0; + var e = pow(2.0, oc.w * 255.0 - 128.0); + oc = oc * e; + oc = scaleByThreshold(oc, 40.0); + textureStore(outputBuffer, fragCoord , vec4(oc.xyz, 1.0) ); +} + +fn scaleByThreshold(color:vec4, threshold:f32) -> vec4{ + var oc = color; + let brightness = length(vec3(oc.xyz)); + var scale = brightness / threshold; + if(scale > 1.0){ + scale = 1.0 / pow(scale, 0.7); + oc = oc * scale; + } + oc.a = 1.0; + return oc; +} \ No newline at end of file diff --git a/src/engine/assets/shader/compute/GTAOCs.wgsl b/src/engine/assets/shader/compute/GTAOCs.wgsl new file mode 100644 index 00000000..74210c98 --- /dev/null +++ b/src/engine/assets/shader/compute/GTAOCs.wgsl @@ -0,0 +1,133 @@ +#include "GlobalUniform" + + struct GTAO{ + maxDistance: f32, + maxPixel: f32, + darkFactor: f32, + rayMarchSegment: f32, + cameraNear: f32, + cameraFar: f32, + viewPortWidth: f32, + viewPortHeight: f32, + multiBounce: f32, + blendColor: f32, + slot1: f32, + slot2: f32, + } + + @group(0) @binding(0) var standUniform: GlobalUniform; + @group(0) @binding(1) var gtaoData: GTAO; + @group(0) @binding(2) var directions : array>; + @group(0) @binding(3) var aoBuffer : array; + + @group(0) @binding(4) var posTex : texture_2d; + @group(0) @binding(5) var normalTex : texture_2d; + @group(0) @binding(6) var inTex : texture_2d; + @group(0) @binding(7) var outTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + var wPosition: vec3; + var wNormal: vec4; + var maxPixelScaled: f32; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(inTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + wNormal = textureLoad(normalTex, fragCoord, 0); + wNormal = vec4(wNormal.rgb,wNormal.w) ; + var oc = textureLoad(inTex, fragCoord, 0); + let index = fragCoord.x + fragCoord.y * i32(texSize.x); + let lastFactor = aoBuffer[index]; + var newFactor = 0.0; + if(wNormal.w < 0.5){//sky + + }else{ + wPosition = textureLoad(posTex, fragCoord, 0).xyz; + let ndc = standUniform.projMat * standUniform.viewMat * vec4(wPosition, 1.0); + let ndcZ = ndc.z / ndc.w; + maxPixelScaled = calcPixelByNDC(ndcZ); + newFactor = rayMarch(); + } + + var factor:f32 = mix(lastFactor, newFactor, 0.6); + aoBuffer[index] = factor; + factor = blurFactor(factor); + factor = 1.0 - factor * gtaoData.darkFactor; + var gtao = vec3(factor); + if(gtaoData.multiBounce > 0.5){ + gtao = MultiBounce(factor, oc.xyz); + } + + var outColor = gtao; + if(gtaoData.blendColor > 0.5){ + outColor = oc.xyz * gtao; + } + textureStore(outTex, fragCoord , vec4(outColor, oc.w)); + } + + fn MultiBounce(AO:f32, Albedo:vec3) -> vec3 + { + var A = 2 * Albedo - 0.33; + var B = -4.8 * Albedo + 0.64; + var C = 2.75 * Albedo + 0.69; + return max(vec3(AO), ((AO * A + B) * AO + C) * AO); + } + + fn calcPixelByNDC(ndcZ:f32) -> f32{ + let nearAspect = gtaoData.cameraNear / (gtaoData.cameraFar - gtaoData.cameraNear); + let aspect = (1.0 + nearAspect) / (ndcZ + nearAspect); + var viewPortMax = max(gtaoData.viewPortWidth, gtaoData.viewPortHeight); + var maxPixel = min(viewPortMax, gtaoData.maxPixel * aspect); + maxPixel = max(0.1, maxPixel); + return maxPixel; + } + + fn blurFactor(centerFactor:f32) -> f32{ + var coord0 = clamp(fragCoord + vec2(1, 0) , vec2(0), vec2(texSize - 1)); + var coord1 = clamp(fragCoord + vec2(-1, 0), vec2(0), vec2(texSize - 1)); + var coord2 = clamp(fragCoord + vec2(0, 1) , vec2(0), vec2(texSize - 1)); + var coord3 = clamp(fragCoord + vec2(0, -1), vec2(0), vec2(texSize - 1)); + var index0 = coord0.x + coord0.y * i32(texSize.x); + var index1 = coord1.x + coord1.y * i32(texSize.x); + var index2 = coord2.x + coord2.y * i32(texSize.x); + var index3 = coord3.x + coord3.y * i32(texSize.x); + let factor0:f32 = aoBuffer[index0]; + let factor1:f32 = aoBuffer[index1]; + let factor2:f32 = aoBuffer[index2]; + let factor3:f32 = aoBuffer[index3]; + var factor = 0.25 * (factor0 + factor1 + factor2 + factor3); + factor = mix(factor, centerFactor, 0.8); + return factor; + } + + fn rayMarch() -> f32{ + let originNormal = normalize(vec3(wNormal.xyz) * 2.0 - 1.0); + let stepPixel = maxPixelScaled / gtaoData.rayMarchSegment; + var totalWeight:f32 = 0.001; + var darkWeight:f32 = 0.0; + for(var i:i32 = 0; i < 8; i += 1){ + let dirVec2 = directions[i]; + for(var j:f32 = 1.1; j < maxPixelScaled; j += stepPixel){ + var sampleCoord = vec2(dirVec2 * j) + fragCoord; + sampleCoord = clamp(sampleCoord, vec2(0), vec2(texSize - 1)); + let samplePosition = textureLoad(posTex, sampleCoord, 0).xyz; + let distanceVec2 = samplePosition - wPosition; + let distance = length(distanceVec2); + if(distance < gtaoData.maxDistance){ + let sampleDir = normalize(distanceVec2); + var factor = max(0.0, dot(sampleDir, originNormal) - 0.1); + factor *= 1.0 - distance / gtaoData.maxDistance; + darkWeight += factor; + totalWeight += 1.0; + } + } + } + + return darkWeight/totalWeight ; + } \ No newline at end of file diff --git a/src/engine/assets/shader/compute/IBLEnvMapCreator_compute.wgsl b/src/engine/assets/shader/compute/IBLEnvMapCreator_compute.wgsl new file mode 100644 index 00000000..4ab1a1ef --- /dev/null +++ b/src/engine/assets/shader/compute/IBLEnvMapCreator_compute.wgsl @@ -0,0 +1,174 @@ +struct ImageSize { + srcWidth : i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32 +}; + +@group(0) @binding(0) var size : ImageSize; +@group(0) @binding(1) var faceRotation: array>; +@group(0) @binding(2) var inputTexSampler : sampler; +@group(0) @binding(3) var inputTex : texture_2d; + +@group(1) @binding(0) var blurSetting : vec4; +@group(1) @binding(1) var outputBuffer0 : texture_storage_2d_array; + +var PI: f32 = 3.14159265359; + +fn applyQuaternion(position:vec3, q:vec4) -> vec3{ + let x:f32 = position.x; + let y:f32 = position.y; + let z:f32 = position.z; + + let qx:f32 = q.x; + let qy:f32 = q.y; + let qz:f32 = q.z; + let qw:f32 = q.w; + + let ix:f32 = qw * x + qy * z - qz * y; + let iy:f32 = qw * y + qz * x - qx * z; + let iz:f32 = qw * z + qx * y - qy * x; + let iw:f32 = -qx * x - qy * y - qz * z; + + var ret: vec3; + ret.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + ret.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + ret.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + + return ret; +} + +fn convertIdToDir3(uv_i32:vec2, quaternion:vec4) -> vec3{ + var uv_f32:vec2 = vec2(uv_i32.xy); + var halfSize:f32 = f32(size.dstWidth / 2); + var worldDirection:vec3 = vec3(uv_f32.x - halfSize, uv_f32.y - halfSize, -halfSize); + worldDirection = normalize(worldDirection); + worldDirection = applyQuaternion(worldDirection, quaternion); + return worldDirection; +} + +fn VanDerCorpus(n0:u32, base0:u32) -> f32 +{ + var n = n0; + var base = base0; + var invBase:f32 = 1.0 / f32(base); + var denom:f32 = 1.0; + var result:f32 = 0.0; + + for(var i:u32 = 0u; i < 32u; i = i + 1u) + { + if(n > 0u) + { + denom = f32(n) % 2.0; + result = result + denom * invBase; + invBase = invBase / 2.0; + n = u32(f32(n) / 2.0); + } + } + + return result; +} + +fn HammersleyNoBitOps(i:u32, N:u32) -> vec2 +{ + return vec2(f32(i)/f32(N), VanDerCorpus(i, 2u)); +} + +fn hammersley( i : u32 , N : u32 ) -> vec2 +{ + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + var bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + var rdi = f32(bits) * 2.3283064365386963e-10; + return vec2(f32(i) /f32(N), rdi); +} + +fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 +{ + var a = roughness*roughness; + + var phi = 2.0 * PI * Xi.x; + var cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); + var sinTheta = sqrt(1.0 - cosTheta*cosTheta); + + // from spherical coordinates to cartesian coordinates + var H:vec3; + H.x = cos(phi) * sinTheta; + H.y = sin(phi) * sinTheta; + H.z = cosTheta; + + // from tangent-space vector to world-space sample vector + var up:vec3; + if(abs(N.z) < 0.999) + { + up = vec3(0.0, 0.0, 1.0); + } + else + { + up = vec3(1.0, 0.0, 0.0); + } + var tangent:vec3 = normalize(cross(up, N)); + var bitangent:vec3 = cross(N, tangent); + var sampleVec:vec3 = tangent * H.x + bitangent * H.y + N * H.z; + return normalize(sampleVec); +} + +fn multiSample(localPos:vec3, roughness:f32) -> vec4 +{ + var N: vec3 = normalize(localPos); + var R: vec3 = N; + var V: vec3 = R; + + let SAMPLE_COUNT:u32 = 1024u; + var totalWeight:f32 = 0.0; + var prefilteredColor:vec3 = vec3(0.0, 0.0, 0.0); + for(var i:u32 = 0u; i < SAMPLE_COUNT; i = i + 1u) + { + var Xi:vec2 = hammersley(i, SAMPLE_COUNT); + var H :vec3 = ImportanceSampleGGX(Xi, N, roughness); + var L :vec3 = normalize(2.0 * dot(V, H) * H - V); + + var NdotL:f32 = max(dot(N, L), 0.0); + if(NdotL > 0.0) + { + var att = 1.0 ;//( f32(SAMPLE_COUNT - i) / f32(SAMPLE_COUNT)) ; + + prefilteredColor = prefilteredColor + sampleColor(L).rgb * NdotL; + prefilteredColor = prefilteredColor * att ; + totalWeight = totalWeight + NdotL; + } + } + prefilteredColor = prefilteredColor / totalWeight; + + return vec4(prefilteredColor, 1.0); +} + +fn SampleSphericalMap(v: vec3) -> vec2 { + var uv:vec2 = vec2(atan2(v.z, v.x), asin(v.y)); + //uv = (uv * (vec2(0.1590999960899353, 0.3183000087738037) + vec2(0.0010000000474974513))); + uv = uv * vec2(0.1590999960899353, 0.3183000087738037); + uv = uv + vec2(0.5); + uv = clamp(uv, vec2(0.0), vec2(1.0)); + return uv; +} + +fn sampleColor(d:vec3) -> vec4 +{ + let uv_f32:vec2 = SampleSphericalMap(d); + let oc = textureSampleLevel(inputTex, inputTexSampler, uv_f32 , 0.0); + //let dir = vec3(-d.x, -d.y, d.z); + //var oc:vec4 = textureSampleLevel(cubeMap, cubeMapSampler, dir, 0.0); + return oc; +} + +@compute @workgroup_size(8, 8, 1) +fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let coord = vec2(GlobalInvocationID.xy); + let quaternion = faceRotation[GlobalInvocationID.z]; + var worldDirection:vec3 = convertIdToDir3(coord, quaternion); + var oc:vec4 = multiSample(worldDirection, blurSetting.x); + textureStore(outputBuffer0, coord, i32(GlobalInvocationID.z), oc); +} diff --git a/src/engine/assets/shader/compute/MergeRGBA_Cs.wgsl b/src/engine/assets/shader/compute/MergeRGBA_Cs.wgsl new file mode 100644 index 00000000..c4ad1034 --- /dev/null +++ b/src/engine/assets/shader/compute/MergeRGBA_Cs.wgsl @@ -0,0 +1,29 @@ + +@group(0) @binding(0) var textureR : texture_2d; +@group(0) @binding(1) var textureG : texture_2d; +@group(0) @binding(2) var textureB : texture_2d; +@group(0) @binding(3) var textureA : texture_2d; +@group(0) @binding(4) var outTex : texture_storage_2d; + +@compute @workgroup_size(8, 8, 1) +fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let size = textureDimensions(outTex); + let fragCoord : vec2 = vec2(GlobalInvocationID.xy); + var uv:vec2; + uv.x = f32(fragCoord.x)/f32(size.x); + uv.y = f32(fragCoord.y)/f32(size.y); + var oc:vec4 = textureSampleLevel(atlasTexture, atlasTextureSampler, targetUV, 0.0); + + let sizeR = textureDimensions(textureR); + let sizeG = textureDimensions(textureG); + let sizeB = textureDimensions(textureB); + let sizeA = textureDimensions(textureA); + + var tr = textureLoad(textureR, vec2(uv * sizeR) , 0 ) ; + var tg = textureLoad(textureG, vec2(uv * sizeG) , 0 ) ; + var tb = textureLoad(textureB, vec2(uv * sizeB) , 0 ) ; + var ta = textureLoad(textureA, vec2(uv * sizeA) , 0 ) ; + + let color = vec4(tr,tg,tb,ta); + textureStore(outTex, fragCoord , vec4(color)); +} diff --git a/src/engine/assets/shader/compute/MultiBouncePass_Shader.wgsl b/src/engine/assets/shader/compute/MultiBouncePass_Shader.wgsl new file mode 100644 index 00000000..a5eb8983 --- /dev/null +++ b/src/engine/assets/shader/compute/MultiBouncePass_Shader.wgsl @@ -0,0 +1,185 @@ + + #include "MathShader" + #include "IrradianceVolumeData_frag" + + +struct IrradianceField { + probeStartPosition: vec4, + probeCounts:vec4, + probeStep:f32, + irradianceTextureWidth:f32, + irradianceTextureHeight:f32, + irradianceProbeSideLength:f32, +}; + + @group(0) @binding(0) var outputBuffer : texture_storage_2d; + @group(0) @binding(1) var uniformData : IrradianceVolumeData ; + + @group(1) @binding(0) var normalMapSampler : sampler; + @group(1) @binding(1) var normalMap : texture_2d; + + @group(1) @binding(2) var colorMapSampler : sampler; + @group(1) @binding(3) var colorMap : texture_2d; + + @group(1) @binding(4) var litMapSampler : sampler; + @group(1) @binding(5) var litMap : texture_2d; + + @group(1) @binding(6) var irradianceMapSampler : sampler; + @group(1) @binding(7) var irradianceMap : texture_2d; + + var wsn:vec3; + var ulitColor:vec4; + var litColor:vec4; + var irradianceFieldSurface : IrradianceField ; + var probeID:u32; + + var quaternion:vec4 = vec4(0.0, -0.7071067811865475, 0.7071067811865475, 0.0); + +fn getIrradianceFieldSurface() -> IrradianceField{ + let data = uniformData; + irradianceFieldSurface.probeStartPosition = vec4(data.startX, data.startY, data.startZ, 0.0); + irradianceFieldSurface.probeCounts = vec4(data.gridXCount, data.gridYCount, data.gridZCount, 0.0); + irradianceFieldSurface.probeStep = data.ProbeSpace; + irradianceFieldSurface.irradianceTextureWidth = data.OctRTMaxSize; + irradianceFieldSurface.irradianceTextureHeight = data.OctRTMaxSize; + irradianceFieldSurface.irradianceProbeSideLength = data.OctRTSideSize; + return irradianceFieldSurface; +} + + fn rotateDir(n:vec3) -> vec3{ + return normalize(applyQuaternion(-n, quaternion)); + } + + fn sampleLitColor(uv:vec2) -> vec4 + { + var oc1:vec4 = textureSampleLevel(litMap, litMapSampler, vec2(0.0), 0.0); + var oc:vec4 = textureLoad(litMap, uv, 0); + return oc; + } + + fn sampleNormal(uv:vec2) -> vec4 + { + var oc1:vec4 = textureSampleLevel(normalMap, normalMapSampler, vec2(0.0), 0.0); + var oc:vec4 = textureLoad(normalMap, uv, 0); + return oc; + } + + fn sampleColor(uv:vec2) -> vec4 + { + var oc1:vec4 = textureSampleLevel(colorMap, colorMapSampler, vec2(0.0), 0.0); + var oc:vec4 = textureLoad(colorMap, uv, 0); + return oc; + } + + fn sampleProbe(fragCoord:vec2){ + var uv = vec2(i32(fragCoord.x), i32(fragCoord.y)) ; + + litColor = sampleLitColor(uv); + + var normalMap = sampleNormal(uv); + wsn = normalMap.xyz * 2.0 - 1.0; + + ulitColor = sampleColor(uv); + } + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain(@builtin(global_invocation_id) globalInvocation_id : vec3) + { + getIrradianceFieldSurface(); + var fragCoord = vec2( globalInvocation_id.x, globalInvocation_id.y); + probeID = globalInvocation_id.z; + fragCoord = fragCoord + getCoordOffset(probeID); + + sampleProbe(fragCoord); + + let irradiance = getIrradianceColor(); + let result = blendIrradianceColor(irradiance); + textureStore(outputBuffer, vec2(fragCoord), result); + } + + fn blendIrradianceColor(irradiance:vec4) -> vec4{ + var bounceColor = irradiance * ulitColor; + let bounceIntensity = getBounceIntensity(uniformData.bounceIntensity); + let conservation1 = 1.0 / sqrt((1.0 + bounceIntensity * 0.55)); + let conservation2 = 1.0 / sqrt((1.0 + bounceIntensity)); + var result = litColor * conservation2 + bounceColor * sqrt(bounceIntensity) * conservation1; + return vec4(result.xyz, litColor.w); + } + + fn getBounceIntensity(intensity:f32) -> f32 { + var value = clamp(intensity, 0.0, 1.0) * 10.0; + return value; + } + + fn getCoordOffset(id:u32) -> vec2{ + var fullCol = u32(uniformData.ProbeSourceTextureSize / uniformData.ProbeSize); + var offsetSampleUv = vec2( (id / fullCol) * 6u , id % fullCol) * u32(uniformData.ProbeSize); + return offsetSampleUv; + } + + fn getIrradianceColor() -> vec4{ + var probeIrradiance: vec4 = vec4(0.0); + if(length(wsn) > 0.01){ + probeIrradiance = getIrrdiaceIndex(i32(probeID), wsn); + } + return probeIrradiance; + } + + fn getIrrdiaceIndex(index:i32, wsn:vec3) -> vec4{ + var wsN = rotateDir(wsn.xyz); + var texCoord:vec2 = textureCoordFromDirection(wsN, + index, + irradianceFieldSurface.irradianceTextureWidth, + irradianceFieldSurface.irradianceTextureHeight, + irradianceFieldSurface.irradianceProbeSideLength); + + var probeIrradiance: vec3 = textureSampleLevel(irradianceMap, irradianceMapSampler, texCoord, 0.0).xyz; + return vec4(probeIrradiance, 1.0); + } + + fn textureCoordFromDirection(dir:vec3, probeIndex:i32, width:f32, height:f32, sideLength:f32) -> vec2 + { + var uv = getWriteOctUVByID(dir, u32(probeIndex), sideLength) ; + uv.x = uv.x / irradianceFieldSurface.irradianceTextureWidth; + uv.y = uv.y / irradianceFieldSurface.irradianceTextureHeight; + return uv ; + } + + fn getWriteOctUVByID(dir:vec3 , probeID:u32, size: f32) -> vec2 + { + var blockCount = u32(irradianceFieldSurface.probeCounts.x * irradianceFieldSurface.probeCounts.z) ; + var offsetX = (probeID % blockCount) % u32(irradianceFieldSurface.probeCounts.x) ; + var offsetY = u32(irradianceFieldSurface.probeCounts.z - 1.0) - (probeID % blockCount) / u32(irradianceFieldSurface.probeCounts.x) ; + var offsetZ = probeID / blockCount ; + + var pixelCoord = (( octEncode(dir) + 1.0 ) * 0.5) * vec2(size,size) ; + + var blockOffset = vec2(0.0); + blockOffset.x = f32(offsetX) * size; + blockOffset.y = f32(offsetY) * size + f32(offsetZ) * f32(irradianceFieldSurface.probeCounts.z) * size; + + let mapHeight = u32(irradianceFieldSurface.irradianceTextureHeight); + var probeCounts:vec3 = vec3(irradianceFieldSurface.probeCounts.xyz); + + var gridOffsetFrom = vec2(blockOffset) + 1; + var gridOffsetTo = offsetByCol(gridOffsetFrom, size, mapHeight, probeCounts); + + pixelCoord = pixelCoord + vec2(gridOffsetTo - 1) + vec2(vec2(vec2(gridOffsetTo) / size) * 2); + + return pixelCoord + 1.0 ; + } + + fn offsetByCol(pixelCoord0:vec2, octSideSize:f32, mapHeight:u32, counts:vec3) -> vec2 + { + var pixelCoord = pixelCoord0; + let blockSize:vec2 = vec2(i32(octSideSize * counts.x), i32(octSideSize * counts.z)); + let blockSizeYBorder:i32 = i32((octSideSize + 2.0) * counts.z); + let blockMaxRowBorder:i32 = i32(mapHeight) / blockSizeYBorder; + let pixelCountYMax:i32 = blockMaxRowBorder * i32(octSideSize * counts.z); + let col:i32 = pixelCoord.y / pixelCountYMax; + + pixelCoord.x = col * i32(octSideSize * counts.x) + pixelCoord.x; + pixelCoord.y = pixelCoord.y % pixelCountYMax; + + return pixelCoord; + } diff --git a/src/engine/assets/shader/compute/OutLineBlendColor.wgsl b/src/engine/assets/shader/compute/OutLineBlendColor.wgsl new file mode 100644 index 00000000..70779dba --- /dev/null +++ b/src/engine/assets/shader/compute/OutLineBlendColor.wgsl @@ -0,0 +1,40 @@ +struct OutlineSettingData{ + strength: f32, + useAddMode: f32, + outlinePixel: f32, + fadeOutlinePixel: f32, + lowTexWidth: f32, + lowTexHeight: f32, + slot0: f32, + slot1: f32, + } + + @group(0) @binding(0) var outlineSetting: OutlineSettingData; + @group(0) @binding(1) var inTex : texture_2d; + @group(0) @binding(2) var lowTexSampler : sampler; + @group(0) @binding(3) var lowTex : texture_2d; + @group(0) @binding(4) var outlineTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(outlineTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + + let uv01 = vec2(fragCoord) / (vec2(texSize) - 1.0); + let outLineColor = textureSampleLevel(lowTex, lowTexSampler, uv01, 0.0) * outlineSetting.strength; + var newOC = textureLoad(inTex, fragCoord, 0); + var blendColor:vec3 = vec3(0.0); + if(outlineSetting.useAddMode > 0.5){ + blendColor = vec3(newOC.xyz) + vec3(outLineColor.xyz) * outLineColor.w; + }else{ + blendColor = mix(vec3(newOC.xyz), vec3(outLineColor.xyz), outLineColor.w); + } + textureStore(outlineTex, fragCoord , vec4(blendColor, newOC.w)); + } \ No newline at end of file diff --git a/src/engine/assets/shader/compute/OutlineCalcOutline.wgsl b/src/engine/assets/shader/compute/OutlineCalcOutline.wgsl new file mode 100644 index 00000000..792dc1c1 --- /dev/null +++ b/src/engine/assets/shader/compute/OutlineCalcOutline.wgsl @@ -0,0 +1,86 @@ +struct OutlineSettingData{ + strength: f32, + useAddMode: f32, + outlinePixel: f32, + fadeOutlinePixel: f32, + lowTexWidth: f32, + lowTexHeight: f32, + slot0: f32, + slot1: f32, + } + + struct OutlineSlotData{ + color: vec3, + count: f32, + } + + struct OutlineWeightData{ + slotIndex:f32, + outerSlotIndex:f32, + entityIndex:f32, + weight:f32 + } + + struct OutlineEntities{ + list: array, + } + + @group(0) @binding(0) var outlineSetting: OutlineSettingData; + @group(0) @binding(1) var slotsBuffer : array; + @group(0) @binding(2) var weightBuffer : array; + @group(0) @binding(3) var entitiesBuffer : array; + @group(0) @binding(4) var indexTexture : texture_2d; + + var texSize: vec2; + var lowSize: vec2; + var fragCoord: vec2; + var fragCoordLow: vec2; + var coordIndex: i32; + + var fragOutline: OutlineWeightData; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoordLow = vec2( globalInvocation_id.xy ); + fragCoord = fragCoordLow * 2; + texSize = textureDimensions(indexTexture).xy; + lowSize = vec2(i32(outlineSetting.lowTexWidth), i32(outlineSetting.lowTexHeight)); + + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + if(fragCoordLow.x >= lowSize.x || fragCoordLow.y >= lowSize.y){ + return; + } + + coordIndex = fragCoordLow.x + fragCoordLow.y * lowSize.x; + fragOutline = weightBuffer[coordIndex]; + var wPos = textureLoad(indexTexture, fragCoord, 0 ) ; + + fragOutline.entityIndex = round(wPos.w); + fragOutline.slotIndex = -1.0; + fragOutline.outerSlotIndex = -1.0; + fragOutline.weight = 0.0; + + if(fragOutline.entityIndex >= 0.0){ + fragOutline.slotIndex = f32(matchOutlineSlot()); + } + weightBuffer[coordIndex] = fragOutline; + } + + fn matchOutlineSlot() -> i32 + { + for(var i:i32 = 0; i < 8; i ++){ + var slotData:OutlineSlotData = slotsBuffer[i]; + var entities:array = entitiesBuffer[i].list; + let count:i32 = i32(slotData.count); + for(var j:i32 = 0; j < count; j ++){ + var outlineIndex = entities[j]; + if(abs(fragOutline.entityIndex - outlineIndex) < 0.1){ + return i; + } + } + } + return -1; + } \ No newline at end of file diff --git a/src/engine/assets/shader/compute/OutlineCs.wgsl b/src/engine/assets/shader/compute/OutlineCs.wgsl new file mode 100644 index 00000000..fd288996 --- /dev/null +++ b/src/engine/assets/shader/compute/OutlineCs.wgsl @@ -0,0 +1,120 @@ +struct OutlineSettingData{ + strength: f32, + useAddMode: f32, + outlinePixel: f32, + fadeOutlinePixel: f32, + lowTexWidth: f32, + lowTexHeight: f32, + slot0: f32, + slot1: f32, + } + + struct OutlineSlotData{ + color: vec3, + count: f32, + } + + struct OutlineWeightData{ + slotIndex:f32, + outerSlotIndex:f32, + entityIndex:f32, + weight:f32 + } + + @group(0) @binding(0) var outlineSetting: OutlineSettingData; + @group(0) @binding(1) var slotsBuffer : array; + @group(0) @binding(2) var weightBuffer : array; + @group(0) @binding(3) var oldOutlineColor : array>; + @group(0) @binding(4) var lowTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + var coordIndex: i32; + var fragOutline: OutlineWeightData; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(lowTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + + coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); + fragOutline = weightBuffer[coordIndex]; + + var blendColor = vec3(0.0); + var newOC = vec4(0.0); + + calcOutline(); + let outerSlotIndex:i32 = i32(round(fragOutline.outerSlotIndex)); + if(outerSlotIndex >= 0){ + let outLineColor = slotsBuffer[outerSlotIndex].color; + newOC = vec4(outLineColor, fragOutline.weight); + } + + let coordIndex0 = fragCoord.x + 1 + (fragCoord.y - 1) * i32(texSize.x); + let coordIndex1 = fragCoord.x - 1 + (fragCoord.y - 1) * i32(texSize.x); + let coordIndex2 = fragCoord.x + (fragCoord.y + 1) * i32(texSize.x); + + let oldOC = oldOutlineColor[coordIndex]; + let oldOC0 = oldOutlineColor[coordIndex0]; + let oldOC1 = oldOutlineColor[coordIndex1]; + let oldOC2 = oldOutlineColor[coordIndex2]; + + newOC = mix((oldOC + oldOC0 + oldOC1 + oldOC2) * 0.25, newOC, 0.4); + + oldOutlineColor[coordIndex] = newOC; + textureStore(lowTex, fragCoord, newOC); + } + + fn calcOutline() + { + let outlinePixel = outlineSetting.outlinePixel; + let fadeOutlinePixel = outlineSetting.fadeOutlinePixel; + let pixelRadius = outlinePixel + fadeOutlinePixel; + let minX = max(0.0, f32(fragCoord.x) - pixelRadius); + let maxX = min(f32(texSize.x), f32(fragCoord.x) + pixelRadius); + let minY = max(0.0, f32(fragCoord.y) - pixelRadius); + let maxY = min(f32(texSize.y), f32(fragCoord.y) + pixelRadius); + var coordTemp_f32 = vec2(0.0); + var coordCurrent_f32 = vec2(fragCoord); + var tempCoordIndex = 0; + var tempWeightData: OutlineWeightData; + for(var x:f32 = minX; x < maxX; x += 1.0){ + for(var y:f32 = minY; y < maxY; y += 1.0){ + coordTemp_f32.x = x; + coordTemp_f32.y = y; + let distanceToOuter = length(coordTemp_f32 - coordCurrent_f32); + if(distanceToOuter < pixelRadius){ + var coord_i32 = vec2(coordTemp_f32); + tempCoordIndex = coord_i32.x + coord_i32.y * i32(texSize.x); + tempWeightData = weightBuffer[tempCoordIndex]; + let outlineGap = abs(tempWeightData.slotIndex - fragOutline.slotIndex); + if(outlineGap > 0.1){ + if(tempWeightData.slotIndex > fragOutline.slotIndex){ + if(abs(tempWeightData.slotIndex - fragOutline.outerSlotIndex) < 0.1){ + fragOutline.weight = max(fragOutline.weight, calcWeight(pixelRadius, distanceToOuter, outlinePixel)); + fragOutline.outerSlotIndex = tempWeightData.slotIndex; + weightBuffer[tempCoordIndex] = tempWeightData; + }else if(tempWeightData.slotIndex > fragOutline.outerSlotIndex){ + fragOutline.weight = calcWeight(pixelRadius, distanceToOuter, outlinePixel); + fragOutline.outerSlotIndex = tempWeightData.slotIndex; + weightBuffer[tempCoordIndex] = tempWeightData; + } + } + } + } + } + } + } + + fn calcWeight(radius:f32, distance0:f32, outlinePixel:f32) -> f32{ + let distance = distance0 - outlinePixel; + if(distance < 0.0){ + return 1.0; + } + var ret = 1.0 - distance / (radius - outlinePixel); + return ret; + } \ No newline at end of file diff --git a/src/engine/assets/shader/compute/Picker_CsShader.wgsl b/src/engine/assets/shader/compute/Picker_CsShader.wgsl new file mode 100644 index 00000000..b6257e13 --- /dev/null +++ b/src/engine/assets/shader/compute/Picker_CsShader.wgsl @@ -0,0 +1,65 @@ +struct GlobalUniform { + projMat: mat4x4, + viewMat: mat4x4, + cameraWorldMatrix: mat4x4, + pvMatrixInv : mat4x4, + shadowMatrix: array,8>, + CameraPos: vec3, + + frame: f32, + time: f32, + delta: f32, + shadowBias: f32, + skyExposure: f32, + renderPassState:f32, + quadScale: f32, + hdrExposure: f32, + + renderState_left: i32, + renderState_right: i32, + renderState_split: f32, + + mouseX: f32, + mouseY: f32, + windowWidth: f32, + windowHeight: f32, + + near: f32, + far: f32, + + pointShadowBias: f32, + shadowMapSize: f32, + shadowSoft: f32, + }; + +struct PickResult{ + pick_meshID:f32, + pick_meshID2:f32, + pick_UV:vec2, + pick_Position:vec4, + pick_Normal:vec4, + pick_Tangent:vec4, +} + +@group(0) @binding(0) var standUniform: GlobalUniform; +@group(0) @binding(1) var outBuffer: PickResult; +@group(0) @binding(2) var visibleMap : texture_2d; + +@compute @workgroup_size( 1 ) +fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) +{ + var result:PickResult ; + // result.pick_meshID + let texSize = textureDimensions(visibleMap).xy; + let screenPoint = vec2(standUniform.mouseX/standUniform.windowWidth,standUniform.mouseY/standUniform.windowHeight); + + let mouseUV = screenPoint * vec2(texSize.xy); + let info = textureLoad(visibleMap, vec2(mouseUV) , 0); + + outBuffer.pick_meshID = f32(info.w) ; + outBuffer.pick_meshID2 = f32(info.w) ; + outBuffer.pick_Tangent = vec4(2.0,2.0,2.0,2.0) ; + outBuffer.pick_UV = vec2(standUniform.mouseX,standUniform.mouseY) ; + outBuffer.pick_Position = vec4(info.xyzw) ; + outBuffer.pick_Normal = vec4(info.xyzw) ; +} \ No newline at end of file diff --git a/src/engine/assets/shader/compute/SSAO_CsShader.wgsl b/src/engine/assets/shader/compute/SSAO_CsShader.wgsl new file mode 100644 index 00000000..da8b0ac8 --- /dev/null +++ b/src/engine/assets/shader/compute/SSAO_CsShader.wgsl @@ -0,0 +1,99 @@ + + + #include "GlobalUniform" + + struct UniformData { + radius: f32 , + bias: f32, + aoPower: f32 , + blurSize: f32 , + }; + + @group(0) @binding(0) var standUniform: GlobalUniform; + @group(0) @binding(1) var uniformData: UniformData; + @group(0) @binding(2) var sampleData: array>; + + // @group(0) @binding(3) var colorMap : texture_2d; + @group(0) @binding(3) var positionMap : texture_2d; + @group(0) @binding(4) var normalMap : texture_2d; + + @group(0) @binding(5) var noiseMapSampler: sampler; + @group(0) @binding(6) var noiseMap : texture_2d; + + @group(0) @binding(7) var outTex : texture_storage_2d; + + var kernelSize: i32 = 32 ; + + @compute @workgroup_size( 8 , 8 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + var fragCoord = vec2( globalInvocation_id.xy ); + + var texSize = textureDimensions(positionMap).xy; + var texCoord = vec2(fragCoord) / vec2(texSize); + + var fragColor = vec4(1.0); + + var viewMat = standUniform.viewMat ; + // var color = textureLoad(colorMap, fragCoord , 0 ) ; + var wPos = textureLoad(positionMap, fragCoord , 0 ) ; + + var fragPosition = viewMat * vec4(wPos.xyz,1.0); + fragPosition = vec4(fragPosition.xyz / fragPosition.w,1.0) ; + + var texNormal = textureLoad(normalMap, fragCoord , 0 ) ; + var sampleNormal = texNormal.xyz ; + sampleNormal = sampleNormal * 2.0 - 1.0; + var fragNormal = viewMat * vec4((sampleNormal.xyz),0.0); + + var pes = vec2(texSize.xy) / 4.0 ; + var noiseTex:vec4 = textureSampleLevel(noiseMap, noiseMapSampler, texCoord * pes , 0.0); + var randomVec = (viewMat * vec4(normalize(noiseTex.xyz),0.0)).xyz; + + var tangent = normalize(randomVec - fragNormal.xyz * dot(randomVec , fragNormal.xyz)); + var bTangent = cross(fragNormal.xyz, tangent) + 0.0001 ; + var tbn = mat3x3(tangent, bTangent, fragNormal.xyz); + + var offset:vec4; + var samplePos :vec3; + var offsetPosition:f32; + var sample_depth_v:vec4; + var occlusion:f32 = 0.0; + var rangeCheck:f32 = 0.0 ; + var radius:f32 = uniformData.radius * 32.0 * fragPosition.z ; + + for(var i:i32 = 0; i < 32 ; i = i + 1 ){ + samplePos = (tbn * sampleData[i].xyz ) ; + samplePos = fragPosition.xyz + samplePos * radius ; + + offset = vec4(samplePos, 1.0); + offset = standUniform.projMat * offset; + + var off = offset.xyz / offset.w; + off = (off.xyz * 0.5 ) + 0.5 ; + off.y = 1.0 - off.y ; + var offsetUV = vec2(off.xy * vec2(texSize.xy)); + + sample_depth_v = textureLoad(positionMap, offsetUV.xy , 0 ) ; + sample_depth_v = vec4((viewMat * vec4(sample_depth_v.xyz,1.0)).xyz,1.0); + offsetPosition = sample_depth_v.z / sample_depth_v.w ; + + rangeCheck = smoothstep(0.0, 1.0, radius / abs(offsetPosition - fragPosition.z )); + // rangeCheck = smoothstep(0.0, 1.0, radius / uniformData.bias); + + var a = 1.0 ; + if(offsetPosition >= (samplePos.z + uniformData.bias)){ + a = 0.0 ; + } + a = a * rangeCheck ; + occlusion = occlusion + a ; + } + + occlusion = 1.0 - ( occlusion / f32(kernelSize) * texNormal.w ); + occlusion = pow(occlusion, uniformData.aoPower) ; + + // color = color * occlusion ; + + textureStore(outTex, fragCoord , vec4(occlusion)); + } + diff --git a/src/engine/assets/shader/compute/SSR_BlendColor_Shader.wgsl b/src/engine/assets/shader/compute/SSR_BlendColor_Shader.wgsl new file mode 100644 index 00000000..e6d6e3df --- /dev/null +++ b/src/engine/assets/shader/compute/SSR_BlendColor_Shader.wgsl @@ -0,0 +1,45 @@ + + + @group(0) @binding(0) var rayTraceBuffer : array; + @group(0) @binding(1) var colorMap : texture_2d; + @group(0) @binding(2) var ssrMapSampler : sampler; + @group(0) @binding(3) var ssrMap : texture_2d; + @group(0) @binding(4) var outTex : texture_storage_2d; + + var colorTexSize: vec2; + var ssrTexSize: vec2; + var fragCoord: vec2; + var ssrCoord: vec2; + + struct RayTraceRetData{ + skyColor:vec3, + roughness:f32, + + hitCoord:vec2, + alpha:f32, + fresnel:f32, + } + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + colorTexSize = textureDimensions(colorMap).xy; + ssrTexSize = textureDimensions(ssrMap).xy; + if(fragCoord.x >= i32(colorTexSize.x) || fragCoord.y >= i32(colorTexSize.y)){ + return; + } + let scale:f32 = f32(ssrTexSize.x) / f32(colorTexSize.x); + ssrCoord = vec2(vec2(fragCoord.xy) * scale); + let index = ssrCoord.x + ssrCoord.y * i32(ssrTexSize.x); + let hitData = rayTraceBuffer[index]; + var color = textureLoad(colorMap, fragCoord , 0); + var uv01 = vec2(f32(fragCoord.x), f32(fragCoord.y)); + uv01 = uv01 / vec2(colorTexSize - 1); + + var ssrColor = textureSampleLevel(ssrMap, ssrMapSampler, uv01, 0.0); + var tc = mix(color, ssrColor, hitData.fresnel) ; + var outColor = tc ; + outColor.a = color.a ; + textureStore(outTex, fragCoord , outColor ); + } diff --git a/src/engine/assets/shader/compute/SSR_IS_Shader.wgsl b/src/engine/assets/shader/compute/SSR_IS_Shader.wgsl new file mode 100644 index 00000000..e110ad1b --- /dev/null +++ b/src/engine/assets/shader/compute/SSR_IS_Shader.wgsl @@ -0,0 +1,82 @@ + + + struct SSRUniformData { + ssrBufferSizeX: f32, + ssrBufferSizeY: f32, + colorMapSizeX: f32, + colorMapSizeY: f32, + + fadeEdgeRatio: f32, + rayMarchRatio: f32, + fadeDistanceMin: f32, + fadeDistanceMax: f32, + + mixThreshold: f32, + roughnessThreshold: f32, + reflectionRatio: f32, + powDotRN: f32, + + randomSeedX: f32, + randomSeedY: f32, + slot1: f32, + slot2: f32, + }; + + struct RayTraceRetData{ + skyColor:vec3, + roughness:f32, + + hitCoord:vec2, + alpha:f32, + fresnel:f32, + } + + @group(0) @binding(0) var ssrUniform: SSRUniformData; + @group(0) @binding(1) var rayTraceBuffer : array; + @group(0) @binding(2) var ssrColorData : array>; + @group(0) @binding(3) var historyPosition : array>; + + @group(0) @binding(4) var colorMap: texture_2d; + @group(0) @binding(5) var outTex : texture_storage_2d; + + var ssrBufferCoord: vec2; + var colorTexSize: vec2; + var bufferData: RayTraceRetData; + var ssrBufferSize: vec2; + var coordIndex: i32; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + ssrBufferCoord = vec2( globalInvocation_id.xy ); + ssrBufferSize = vec2(i32(ssrUniform.ssrBufferSizeX), i32(ssrUniform.ssrBufferSizeY)); + colorTexSize = vec2(i32(ssrUniform.colorMapSizeX), i32(ssrUniform.colorMapSizeY)); + + if(ssrBufferCoord.x >= ssrBufferSize.x || ssrBufferCoord.y >= ssrBufferSize.y){ + return; + } + + coordIndex = ssrBufferCoord.x + ssrBufferCoord.y * ssrBufferSize.x; + bufferData = rayTraceBuffer[coordIndex]; + var oc = vec4(0.0, 0.0, 0.0, -1.0); + + var mixFactor = historyPosition[coordIndex].w; + + if(bufferData.alpha >= 0.0 && bufferData.roughness < ssrUniform.roughnessThreshold){ + let roughness = clamp(bufferData.roughness, 0.0, 1.0); + let prefilterColor = bufferData.skyColor; + var ssrColor = textureLoad(colorMap, vec2(bufferData.hitCoord), 0); + ssrColor.w = bufferData.alpha; + oc = ssrColor; + } + let skyColor = vec4(bufferData.skyColor, 1.0); + oc = mix(oc, skyColor, 1.0 - bufferData.alpha); + + let lastColor = ssrColorData[coordIndex]; + var newColor = mix(oc, lastColor, mixFactor); + newColor.w = oc.w; + + ssrColorData[coordIndex] = newColor; + + textureStore(outTex, ssrBufferCoord , newColor); + } diff --git a/src/engine/assets/shader/compute/SSR_RayTrace_Shader.wgsl b/src/engine/assets/shader/compute/SSR_RayTrace_Shader.wgsl new file mode 100644 index 00000000..cc3d8261 --- /dev/null +++ b/src/engine/assets/shader/compute/SSR_RayTrace_Shader.wgsl @@ -0,0 +1,315 @@ + + + #include "GlobalUniform" + + struct SSRUniformData { + ssrBufferSizeX: f32, + ssrBufferSizeY: f32, + colorMapSizeX: f32, + colorMapSizeY: f32, + + fadeEdgeRatio: f32, + rayMarchRatio: f32, + fadeDistanceMin: f32, + fadeDistanceMax: f32, + + mixThreshold: f32, + roughnessThreshold: f32, + reflectionRatio: f32, + powDotRN: f32, + + randomSeedX: f32, + randomSeedY: f32, + slot1: f32, + slot2: f32, + }; + + struct HitData{ + hitPos:vec3, + hitNormal:vec3, + fadeAlpha:vec4, + hitCoord:vec2, + hitResult:i32, + hitSky:i32, + }; + + struct RayTraceRetData{ + skyColor:vec3, + roughness:f32, + + hitCoord:vec2, + alpha:f32, + fresnel:f32, + } + + @group(0) @binding(0) var standUniform: GlobalUniform; + @group(0) @binding(1) var ssrUniform: SSRUniformData; + @group(0) @binding(2) var rayTraceBuffer : array; + @group(0) @binding(4) var historyPosition : array>; + + @group(0) @binding(5) var zBufferTexture : texture_2d; + @group(0) @binding(6) var normalBufferTex : texture_2d; + @group(0) @binding(7) var materialBufferTex : texture_2d; + @group(0) @binding(8) var prefilterMapSampler: sampler; + @group(0) @binding(9) var prefilterMap: texture_cube; + + var rayOrigin: vec3; + var rayDirection: vec3; + var cameraPosition: vec3; + var reflectionDir: vec3; + var colorTexSize: vec2; + var fragCoordColor: vec2; + var ssrBufferCoord: vec2; + var ssrBufferSize: vec2; + var hitData: HitData; + var rayTraceRet: RayTraceRetData; + var worldPosition: vec3; + var worldNormal: vec3; + var roughness: f32; + var fresnel: f32; + + var historyPos: vec3; + var coordIndex: i32; + + var PI: f32 = 3.14159; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + ssrBufferCoord = vec2( globalInvocation_id.xy); + ssrBufferSize = vec2(i32(ssrUniform.ssrBufferSizeX), i32(ssrUniform.ssrBufferSizeY)); + if(ssrBufferCoord.x >= ssrBufferSize.x || ssrBufferCoord.y >= ssrBufferSize.y){ + return; + } + coordIndex = ssrBufferCoord.x + ssrBufferCoord.y * ssrBufferSize.x; + + colorTexSize = vec2(i32(ssrUniform.colorMapSizeX), i32(ssrUniform.colorMapSizeY)); + fragCoordColor = convertColorCoordFromSSRCoord(ssrBufferCoord); + + hitData.fadeAlpha = vec4(0.0); + hitData.hitCoord = vec2(0); + hitData.hitResult = 0; + hitData.hitNormal = vec3(0.0, 1.0, 0.0); + hitData.hitSky = 1; + + worldPosition = textureLoad(zBufferTexture, fragCoordColor , 0).xyz; + historyPos = historyPosition[coordIndex].xyz; + + var mixFactor = 0.2; + if(length(historyPos - worldPosition) < ssrUniform.mixThreshold){ + mixFactor = 0.9; + } + historyPosition[coordIndex] = vec4(worldPosition, mixFactor); + + let normal_v4 = textureLoad(normalBufferTex, fragCoordColor , 0); + worldNormal = normalize(vec3(normal_v4.xyz) * 2.0 - 1.0); + let materialData = textureLoad(materialBufferTex, fragCoordColor , 0 ); + let roughness = materialData.g * (1.0 - materialData.b); + fresnel = (1.0 - roughness) * ssrUniform.reflectionRatio; + + cameraPosition = vec3(standUniform.cameraWorldMatrix[3].xyz); + rayOrigin = vec3(worldPosition.xyz); + + rayDirection = normalize(vec3(worldPosition.xyz - cameraPosition)); + + var randomSeed = fract(ssrUniform.randomSeedX + worldPosition.x); + rand_seed.x = randomSeed; + rand_seed.y = fract(ssrUniform.randomSeedY + worldPosition.y + worldPosition.z); + randomSeed = rand(); + + let normalRandom = makeRandomDirection(worldNormal, u32(randomSeed * 256.0), 256, roughness); + + reflectionDir = normalize(reflect(rayDirection, normalRandom)); + + if(normal_v4.w > 0.5 && roughness < ssrUniform.roughnessThreshold){ + let uvOrigin = vec2(f32(fragCoordColor.x), f32(fragCoordColor.y)); + let rayMarchPosition = rayOrigin + reflectionDir * 100.0; + var uvRayMarch = standUniform.projMat * (standUniform.viewMat * vec4(rayMarchPosition, 1.0)); + var uvOffset = (vec2(uvRayMarch.xy / uvRayMarch.w) + 1.0) * 0.5; + uvOffset.y = 1.0 - uvOffset.y; + uvOffset = uvOffset * vec2(colorTexSize - 1) - uvOrigin; + uvOffset = normalize(uvOffset); + + rayTrace(uvOffset); + if(hitData.hitResult == 1){ + hidingArtifact(); + rayTraceRet.alpha = hitData.fadeAlpha.x * hitData.fadeAlpha.y * hitData.fadeAlpha.z * hitData.fadeAlpha.w; + if(hitData.hitSky == 1){ + rayTraceRet.alpha = 0.0; + } + }else{ + rayTraceRet.alpha = 0.0; + } + rayTraceRet.skyColor = getSkyColor(); + }else{ + rayTraceRet.alpha = -1.0; + rayTraceRet.skyColor = vec3(0.0); + } + + rayTraceRet.roughness = roughness; + rayTraceRet.fresnel = fresnel; + rayTraceRet.hitCoord = vec2(hitData.hitCoord); + + let index:i32 = ssrBufferCoord.x + ssrBufferCoord.y * ssrBufferSize.x; + rayTraceBuffer[index] = rayTraceRet; + } + +fn makeRandomDirection(srcDirection:vec3, i:u32, SAMPLE_COUNT:u32, roughness:f32) -> vec3 +{ + var N: vec3 = normalize(srcDirection); + var Xi:vec2 = hammersley(i, SAMPLE_COUNT); + return ImportanceSampleGGX(Xi, N, roughness); +} + +fn hammersley( i : u32 , N : u32 ) -> vec2 +{ + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + var bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + var rdi = f32(bits) * 2.3283064365386963e-10; + return vec2(f32(i) /f32(N), rdi); +} + +fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 +{ + var a = roughness*roughness; + + var phi = 2.0 * PI * Xi.x; + var cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); + var sinTheta = sqrt(1.0 - cosTheta*cosTheta); + + // from spherical coordinates to cartesian coordinates + var H:vec3; + H.x = cos(phi) * sinTheta; + H.y = sin(phi) * sinTheta; + H.z = cosTheta; + + // from tangent-space vector to world-space sample vector + var up:vec3; + if(abs(N.z) < 0.999) + { + up = vec3(0.0, 0.0, 1.0); + } + else + { + up = vec3(1.0, 0.0, 0.0); + } + var tangent:vec3 = normalize(cross(up, N)); + var bitangent:vec3 = cross(N, tangent); + var sampleVec:vec3 = tangent * H.x + bitangent * H.y + N * H.z; + return normalize(sampleVec); +} + + var rand_seed :vec2 = vec2(0.0); + fn rand() -> f32 { + rand_seed.x = fract(cos(dot(rand_seed, vec2(23.14077926, 232.61690225))) * 136.8168); + rand_seed.y = fract(cos(dot(rand_seed, vec2(54.47856553, 345.84153136))) * 534.7645); + return rand_seed.y; + } + + fn getSkyColor() -> vec3{ + let calcRoughness = clamp(roughness, 0.0, 1.0); + let MAX_REFLECTION_LOD = f32(textureNumLevels(prefilterMap)) ; + var prefilterColor = textureSampleLevel(prefilterMap, prefilterMapSampler, reflectionDir, calcRoughness * MAX_REFLECTION_LOD); + return LinearToGammaSpace(vec3(prefilterColor.xyz)) * standUniform.skyExposure; + } + + fn LinearToGammaSpace(linRGB: vec3) -> vec3 { + var linRGB1 = max(linRGB, vec3(0.0)); + linRGB1 = pow(linRGB1, vec3(0.4166666567325592)); + return max(((1.0549999475479126 * linRGB1) - vec3(0.054999999701976776)), vec3(0.0)); + } + + fn convertColorCoordFromSSRCoord(coord:vec2) -> vec2{ + let color_ssr_ratio = ssrUniform.colorMapSizeX / ssrUniform.ssrBufferSizeX; + let targetCoord = vec2(coord) * color_ssr_ratio; + return vec2(targetCoord); + } + + fn hidingArtifact(){ + let texSizeF32 = vec2(f32(colorTexSize.x), f32(colorTexSize.y)); + let halfTexSizeF32 = texSizeF32 * 0.5; + + //near screen edge + var distance2Center = abs(vec2(f32(hitData.hitCoord.x), f32(hitData.hitCoord.y)) - halfTexSizeF32); + let halfEdgeSize:f32 = min(texSizeF32.x, texSizeF32.y) * clamp(0.01, ssrUniform.fadeEdgeRatio, 1.0) * 0.5; + var distance2Edge = min(vec2(halfEdgeSize), halfTexSizeF32 - distance2Center); + var ratioXY = distance2Edge / halfEdgeSize; + hitData.fadeAlpha.x = sqrt(ratioXY.x * ratioXY.y); + + //back face hit + var backFaceBias = max(0.0, dot(hitData.hitNormal, -reflectionDir)); + hitData.fadeAlpha.y = pow(backFaceBias, max(0.0001, ssrUniform.powDotRN)); + + //screen distance ratio + let maxLength = max(f32(colorTexSize.x), f32(colorTexSize.y)) * ssrUniform.rayMarchRatio; + let screenPointer = hitData.hitCoord - fragCoordColor; + var screenDistance = length(vec2(f32(screenPointer.x), f32(screenPointer.y))); + screenDistance = clamp(screenDistance / maxLength, 0.0, 1.0); + hitData.fadeAlpha.z = 1.0 - screenDistance; + + //position distance ratio + var fadeDistance = length(vec3(hitData.hitPos - cameraPosition)); + var dFar = ssrUniform.fadeDistanceMax; + var dNear = ssrUniform.fadeDistanceMin; + dFar = max(1.0, dFar); + dNear = clamp(dNear, 0.001, dFar - 0.001); + fadeDistance = clamp(fadeDistance, dNear, dFar); + fadeDistance = (fadeDistance - dNear) / (dFar - dNear); + hitData.fadeAlpha.w = 1.0 - fadeDistance; + } + + fn rayTrace(rayMarchDir:vec2){ + let stepLength = 4.0; + let maxLength = max(f32(colorTexSize.x), f32(colorTexSize.y)) * ssrUniform.rayMarchRatio; + for(var i:f32 = 1.0; i < maxLength; i = i + stepLength){ + let offsetFloat32 = i * rayMarchDir; + var uv = fragCoordColor + vec2(i32(offsetFloat32.x), i32(offsetFloat32.y)); + let hitRet = rayInterestScene(uv); + if(hitRet > 0){ + hitData.hitResult = hitRet; + break; + } + } + if(hitData.hitResult == 1){ + let fromUV = hitData.hitCoord; + for(var i:f32 = -stepLength; i <= 0.0; i = i + 1.0){ + let offsetFloat32 = i * rayMarchDir; + var uv = fromUV + vec2(i32(offsetFloat32.x), i32(offsetFloat32.y)); + let hitRet = rayInterestScene(uv); + if(hitRet == 1){ + let WN = textureLoad(normalBufferTex, hitData.hitCoord , 0 ); + if(WN.w > 0.5){ + hitData.hitSky = 0; + } + let normal = vec3(WN.xyz) * 2.0 - 1.0; + hitData.hitNormal = normalize(vec3(normal.xyz)); + break; + } + } + } + } + + fn rayInterestScene(uv:vec2) -> i32 { + if(uv.x < 0 || uv.y < 0 || uv.x >= colorTexSize.x || uv.y >= colorTexSize.y){ + return 2; + }else{ + let hitPos = textureLoad(zBufferTexture, uv , 0 ); + let testDir = normalize(vec3(hitPos.xyz - rayOrigin)); + let cosValue = dot(reflectionDir, testDir); + + if(cosValue > 0.9996){ + let cross1 = cross(reflectionDir, -rayDirection); + let cross2 = cross(reflectionDir, testDir); + if(dot(cross1, cross2) > 0.0){ + hitData.hitPos = vec3(hitPos.xyz); + hitData.hitCoord = uv; + return 1; + } + } + } + return 0; + } diff --git a/src/engine/assets/shader/compute/TAACopyTex.wgsl b/src/engine/assets/shader/compute/TAACopyTex.wgsl new file mode 100644 index 00000000..4993fda2 --- /dev/null +++ b/src/engine/assets/shader/compute/TAACopyTex.wgsl @@ -0,0 +1,18 @@ + @group(0) @binding(0) var preColor : array>; + @group(0) @binding(1) var preColorTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + var coordIndex: i32; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(preColorTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); + textureStore(preColorTex, fragCoord , preColor[coordIndex]); + } \ No newline at end of file diff --git a/src/engine/assets/shader/compute/TAASharpTex.wgsl b/src/engine/assets/shader/compute/TAASharpTex.wgsl new file mode 100644 index 00000000..e57576c8 --- /dev/null +++ b/src/engine/assets/shader/compute/TAASharpTex.wgsl @@ -0,0 +1,41 @@ + + struct TAAData{ + preProjMatrix: mat4x4, + preViewMatrix: mat4x4, + jitterFrameIndex: f32, + blendFactor: f32, + sharpFactor: f32, + sharpPreBlurFactor: f32, + jitterX: f32, + jitterY: f32, + slot0: f32, + slot1: f32, + } + @group(0) @binding(0) var taaData: TAAData; + @group(0) @binding(1) var inTex : texture_2d; + @group(0) @binding(2) var outTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(outTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + + let c0 = textureLoad(inTex, vec2(fragCoord.x, fragCoord.y - 1), 0); + let c1 = textureLoad(inTex, vec2(fragCoord.x, fragCoord.y + 1), 0); + let c2 = textureLoad(inTex, vec2(fragCoord.x - 1, fragCoord.y), 0); + let c3 = textureLoad(inTex, vec2(fragCoord.x + 1, fragCoord.y), 0); + + var roundColor = (c0 + c1 + c2 + c3) * 0.25; + let originColor = textureLoad(inTex, fragCoord, 0); + let blurColor = mix(roundColor, originColor, taaData.sharpPreBlurFactor); + var oc = (originColor - blurColor * taaData.sharpFactor) / (1.0 - taaData.sharpFactor); + oc = clamp(oc, vec4(0.0), oc); + textureStore(outTex, fragCoord , oc); + } \ No newline at end of file diff --git a/src/engine/assets/shader/compute/TAAcs.wgsl b/src/engine/assets/shader/compute/TAAcs.wgsl new file mode 100644 index 00000000..6c82bc0a --- /dev/null +++ b/src/engine/assets/shader/compute/TAAcs.wgsl @@ -0,0 +1,155 @@ + + #include "GlobalUniform" + + struct TAAData{ + preProjMatrix: mat4x4, + preViewMatrix: mat4x4, + jitterFrameIndex: f32, + blendFactor: f32, + sharpFactor: f32, + sharpPreBlurFactor: f32, + jitterX: f32, + jitterY: f32, + slot0: f32, + slot1: f32, + } + + @group(0) @binding(0) var standUniform: GlobalUniform; + @group(0) @binding(1) var taaData: TAAData; + @group(0) @binding(2) var preColorBuffer : array>; + + @group(0) @binding(3) var preColorTexSampler : sampler; + @group(0) @binding(4) var preColorTex : texture_2d; + @group(0) @binding(5) var posTex : texture_2d; + @group(0) @binding(6) var inTexSampler : sampler; + @group(0) @binding(7) var inTex : texture_2d; + @group(0) @binding(8) var outTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + var coordIndex: i32; + var color_min: vec4; + var color_max: vec4; + var color_avg: vec4; + var re_proj_uv01: vec2; + var FLT_EPS:f32 = 5.960464478e-8; // 2^-24, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f) + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(inTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + let frame = standUniform.frame; + coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); + + let oc = blendColor(); + preColorBuffer[coordIndex] = oc; + textureStore(outTex, fragCoord , oc); + } + + fn blendColor() -> vec4 + { + var preCoord = fragCoord; + var mixWeight = 1.0; + re_proj_uv01 = vec2(0.0); + var reProjectionCoord:vec2 = vec2(fragCoord); + //var jitterUVOffset = 0.5 * vec2(taaData.jitterX, -taaData.jitterY); + if(taaData.jitterFrameIndex > 0.5){ + var wPos = textureLoad(posTex, fragCoord, 0); + let ndc = taaData.preProjMatrix * (taaData.preViewMatrix * vec4(wPos.xyz, 1.0)); + re_proj_uv01 = vec2(ndc.x, -ndc.y) / ndc.w; + re_proj_uv01 = (re_proj_uv01 + 1.0) * 0.5; + + if(re_proj_uv01.x >= 0.0 && re_proj_uv01.x <= 1.0 && re_proj_uv01.y >= 0.0 && re_proj_uv01.y <= 1.0){ + mixWeight = taaData.blendFactor; + //reProjectionCoord = re_proj_uv01 + jitterUVOffset; + reProjectionCoord.x = re_proj_uv01.x * f32(texSize.x - 1); + reProjectionCoord.y = re_proj_uv01.y * f32(texSize.y - 1); + preCoord = vec2(reProjectionCoord); + }else{ + //outside of screen + mixWeight = 1.0; + } + } + + var curUV01 = vec2(fragCoord) / vec2(texSize - 1); + //curUV01 += jitterUVOffset; + + let curColor = textureSampleLevel(inTex, inTexSampler, curUV01, 0.0); + + let preIndex = preCoord.x + preCoord.y * i32(texSize.x); + var preColor = textureSampleLevel(preColorTex, preColorTexSampler, re_proj_uv01, 0.0); + + //minmax9(fragCoord); + minmax4(fragCoord); + + preColor = clip_aabb(color_min.xyz, color_max.xyz, color_avg, preColor); + var outColor = mix(preColor, curColor, mixWeight); + + return outColor; + } + + fn clampCoord(coord0:vec2) -> vec2{ + return clamp(coord0, vec2(0), vec2(texSize - 1)); + } + + fn minmax4(coord:vec2) { + let uv0 = clampCoord(vec2(coord.x - 1, coord.y)); + let uv1 = clampCoord(vec2(coord.x, coord.y - 1)); + let uv2 = clampCoord(vec2(coord.x, coord.y + 1)); + let uv3 = clampCoord(vec2(coord.x + 1, coord.y)); + + let c0 = textureLoad(inTex, uv0, 0); + let c1 = textureLoad(inTex, uv1, 0); + let c2 = textureLoad(inTex, uv2, 0); + let c3 = textureLoad(inTex, uv3, 0); + + color_min = min(c0, min(c1, min(c2, c3))); + color_max = max(c0, max(c1, max(c2, c3))); + color_avg = (c0 + c1 + c2 + c3) * 0.25; + } + + fn minmax9(coord:vec2) { + let uv0 = clampCoord(vec2(coord.x - 1, coord.y - 1)); + let uv1 = clampCoord(vec2(coord.x - 1, coord.y)); + let uv2 = clampCoord(vec2(coord.x - 1, coord.y + 1)); + let uv3 = clampCoord(vec2(coord.x, coord.y - 1)); + let uv4 = clampCoord(vec2(coord.x, coord.y)); + let uv5 = clampCoord(vec2(coord.x, coord.y + 1)); + let uv6 = clampCoord(vec2(coord.x + 1, coord.y - 1)); + let uv7 = clampCoord(vec2(coord.x + 1, coord.y)); + let uv8 = clampCoord(vec2(coord.x + 1, coord.y + 1)); + + let ctl = textureLoad(inTex, uv0, 0); + let ctc = textureLoad(inTex, uv1, 0); + let ctr = textureLoad(inTex, uv2, 0); + let cml = textureLoad(inTex, uv3, 0); + let cmc = textureLoad(inTex, uv4, 0); + let cmr = textureLoad(inTex, uv5, 0); + let cbl = textureLoad(inTex, uv6, 0); + let cbc = textureLoad(inTex, uv7, 0); + let cbr = textureLoad(inTex, uv8, 0); + + color_min = min(ctl, min(ctc, min(ctr, min(cml, min(cmc, min(cmr, min(cbl, min(cbc, cbr)))))))); + color_max = max(ctl, max(ctc, max(ctr, max(cml, max(cmc, max(cmr, max(cbl, max(cbc, cbr)))))))); + color_avg = (ctl + ctc + ctr + cml + cmc + cmr + cbl + cbc + cbr) / 9.0; + } + + fn clip_aabb(aabb_max:vec3, aabb_min:vec3, color_avg:vec4, input_texel:vec4) -> vec4 + { + var p_clip:vec3 = 0.5 * (aabb_max + aabb_min); + var e_clip:vec3 = 0.5 * (aabb_max - aabb_min) + FLT_EPS; + var v_clip:vec4 = input_texel - vec4(p_clip, color_avg.w); + var v_unit:vec3 = v_clip.xyz / e_clip; + var a_unit:vec3 = abs(v_unit); + var ma_unit:f32 = max(a_unit.x, max(a_unit.y, a_unit.z)); + + if (ma_unit > 1.0){ + return vec4(p_clip, color_avg.w) + v_clip / ma_unit; + }else{ + return input_texel; + } + } \ No newline at end of file diff --git a/src/engine/assets/shader/core/base/Common_frag.wgsl b/src/engine/assets/shader/core/base/Common_frag.wgsl new file mode 100644 index 00000000..cf46db9c --- /dev/null +++ b/src/engine/assets/shader/core/base/Common_frag.wgsl @@ -0,0 +1,26 @@ +#include "GlobalUniform" +#include "FragmentVarying" +#include "ColorPassFragmentOutput" +#include "ShadingInput" + +var ORI_FragmentOutput: FragmentOutput; +var ORI_VertexVarying: FragmentVarying; +var ORI_ShadingInput: ShadingInput; +@fragment +fn FragMain( vertex_varying:FragmentVarying ) -> FragmentOutput { + ORI_VertexVarying = vertex_varying; + ORI_FragmentOutput.color = vec4(1.0, 0.0, 0.0, 1.0); + #if USE_WORLDPOS + ORI_FragmentOutput.worldPos = ORI_VertexVarying.vWorldPos; + #endif + #if USEGBUFFER + ORI_FragmentOutput.worldNormal = vec4(ORI_ShadingInput.Normal.rgb ,1.0); + ORI_FragmentOutput.material = vec4(0.0,1.0,0.0,0.0); + #endif + frag(); + #if USE_DEBUG + debugFragmentOut(); + #endif + + return ORI_FragmentOutput ; +} diff --git a/src/engine/assets/shader/core/base/Common_vert.wgsl b/src/engine/assets/shader/core/base/Common_vert.wgsl new file mode 100644 index 00000000..e5b674ae --- /dev/null +++ b/src/engine/assets/shader/core/base/Common_vert.wgsl @@ -0,0 +1,11 @@ +#include "WorldMatrixUniform" +#include "VertexAttributes_vert" +#include "GlobalUniform" +#include "Inline_vert" +@vertex +fn VertMain( vertex:VertexAttributes ) -> VertexOutput { + vertex_inline(vertex); + vert(vertex); + return ORI_VertexOut ; +} + diff --git a/src/engine/assets/shader/core/common/BrdfLut_frag.wgsl b/src/engine/assets/shader/core/common/BrdfLut_frag.wgsl new file mode 100644 index 00000000..6a10ea79 --- /dev/null +++ b/src/engine/assets/shader/core/common/BrdfLut_frag.wgsl @@ -0,0 +1,4 @@ +@group(1) @binding(auto) +var brdflutMapSampler: sampler; +@group(1) @binding(auto) +var brdflutMap: texture_2d; \ No newline at end of file diff --git a/src/engine/assets/shader/core/common/EnvMap_frag.wgsl b/src/engine/assets/shader/core/common/EnvMap_frag.wgsl new file mode 100644 index 00000000..a26b3e5e --- /dev/null +++ b/src/engine/assets/shader/core/common/EnvMap_frag.wgsl @@ -0,0 +1,9 @@ + +@group(1) @binding(auto) +var prefilterMapSampler: sampler; +@group(1) @binding(auto) +var prefilterMap: texture_cube; +@group(1) @binding(auto) +var envMapSampler: sampler; +@group(1) @binding(auto) +var envMap: texture_cube; \ No newline at end of file diff --git a/src/engine/assets/shader/core/common/GlobalUniform.wgsl b/src/engine/assets/shader/core/common/GlobalUniform.wgsl new file mode 100644 index 00000000..8cd5e057 --- /dev/null +++ b/src/engine/assets/shader/core/common/GlobalUniform.wgsl @@ -0,0 +1,37 @@ + + struct GlobalUniform { + projMat: mat4x4, + viewMat: mat4x4, + cameraWorldMatrix: mat4x4, + pvMatrixInv : mat4x4, + shadowMatrix: array,8>, + CameraPos: vec3, + + frame: f32, + time: f32, + delta: f32, + shadowBias: f32, + skyExposure: f32, + renderPassState:f32, + quadScale: f32, + hdrExposure: f32, + + renderState_left: i32, + renderState_right: i32, + renderState_split: f32, + + mouseX: f32, + mouseY: f32, + windowWidth: f32, + windowHeight: f32, + + near: f32, + far: f32, + + pointShadowBias: f32, + shadowMapSize: f32, + shadowSoft: f32, + }; + + @group(0) @binding(0) + var globalUniform: GlobalUniform; diff --git a/src/engine/assets/shader/core/common/InstanceUniform.wgsl b/src/engine/assets/shader/core/common/InstanceUniform.wgsl new file mode 100644 index 00000000..b3b943e4 --- /dev/null +++ b/src/engine/assets/shader/core/common/InstanceUniform.wgsl @@ -0,0 +1,7 @@ +#if USE_INSTANCEDRAW + struct InstanceUniform { + matrixIDs : array + }; + @group(2) @binding(7) + var instanceDrawID : InstanceUniform; +#endif \ No newline at end of file diff --git a/src/engine/assets/shader/core/common/WorldMatrixUniform.wgsl b/src/engine/assets/shader/core/common/WorldMatrixUniform.wgsl new file mode 100644 index 00000000..2f61b771 --- /dev/null +++ b/src/engine/assets/shader/core/common/WorldMatrixUniform.wgsl @@ -0,0 +1,9 @@ + + struct Uniforms { + matrix : array> + }; + + @group(0) @binding(1) + var models : Uniforms; + + diff --git a/src/engine/assets/shader/core/inline/Inline_vert.wgsl b/src/engine/assets/shader/core/inline/Inline_vert.wgsl new file mode 100644 index 00000000..d3ce06cf --- /dev/null +++ b/src/engine/assets/shader/core/inline/Inline_vert.wgsl @@ -0,0 +1,49 @@ + + #include "MathShader" + #include "FastMathShader" + #include "InstanceUniform" + + var ORI_MATRIX_P: mat4x4; + var ORI_MATRIX_V: mat4x4; + var ORI_MATRIX_M: mat4x4; + var ORI_MATRIX_PV: mat4x4; + var ORI_MATRIX_PVInv: mat4x4; + var ORI_MATRIX_World: mat4x4; + var ORI_CAMERAMATRIX: mat4x4; + var ORI_NORMALMATRIX: mat3x3; + var ORI_CameraWorldDir: vec3; + + var TIME: vec4; + var MOUSE: vec4; + var SCREEN: vec4; + + var ProjectionParams: vec4; + + fn vertex_inline(vertex:VertexAttributes){ + TIME.x = globalUniform.frame; + TIME.y = globalUniform.time; + TIME.z = globalUniform.delta; + + MOUSE.x = globalUniform.mouseX; + MOUSE.y = globalUniform.mouseY; + + SCREEN.x = globalUniform.windowWidth; + SCREEN.y = globalUniform.windowHeight; + + ProjectionParams.x = globalUniform.near; + ProjectionParams.y = globalUniform.far; + ProjectionParams.z = 1.0 + 1.0 / globalUniform.far; + + ORI_MATRIX_P = globalUniform.projMat ; + ORI_MATRIX_V = globalUniform.viewMat ; + ORI_MATRIX_PV = ORI_MATRIX_P * ORI_MATRIX_V ; + ORI_MATRIX_PVInv = globalUniform.pvMatrixInv ; + ORI_CAMERAMATRIX = globalUniform.cameraWorldMatrix ; + + ORI_MATRIX_M = models.matrix[u32(vertex.index)]; + + #if USE_INSTANCEDRAW + let modelID = instanceDrawID.matrixIDs[vertex.index]; + ORI_MATRIX_M = models.matrix[modelID]; + #endif + } \ No newline at end of file diff --git a/src/engine/assets/shader/graphic/Graphic3DShader_fs.wgsl b/src/engine/assets/shader/graphic/Graphic3DShader_fs.wgsl new file mode 100644 index 00000000..f0b039eb --- /dev/null +++ b/src/engine/assets/shader/graphic/Graphic3DShader_fs.wgsl @@ -0,0 +1,30 @@ +struct FragmentOutput { + @location(0) color: vec4, + // #if USE_WORLDPOS + @location(1) worldPos: vec4, + // #endif + // #if USEGBUFFER + @location(2) worldNormal: vec4, + @location(3) material: vec4 + // #endif +}; + +@fragment +fn main( + @location(0) vWorldPos: vec4, + @location(1) varying_Color: vec4, +) -> FragmentOutput { + var result: FragmentOutput; + + // #if USE_WORLDPOS + result.worldPos = vWorldPos; + // #endif + + // #if USEGBUFFER + // result.worldNormal = vec4(0.0, 0.0, 0.0, 1.0); + result.material = vec4(0.0, 1.0, 0.0, 0.0); + // #endif + + result.color = varying_Color; + return result; +} diff --git a/src/engine/assets/shader/graphic/Graphic3DShader_vs.wgsl b/src/engine/assets/shader/graphic/Graphic3DShader_vs.wgsl new file mode 100644 index 00000000..336abcde --- /dev/null +++ b/src/engine/assets/shader/graphic/Graphic3DShader_vs.wgsl @@ -0,0 +1,27 @@ +#include "WorldMatrixUniform" +#include "GlobalUniform" + +struct VertexAttributes { + @location(0) position: vec4, + @location(1) color: vec4, +} + +struct VertexOutput { + @location(0) varying_WPos: vec4, + @location(1) varying_Color: vec4, + @builtin(position) member: vec4 +}; + +@vertex +fn main( vertex:VertexAttributes ) -> VertexOutput { + var worldMatrix = models.matrix[u32(vertex.position.w)]; + var worldPos = (worldMatrix * vec4(vertex.position.xyz, 1.0)); + var viewPosition = ((globalUniform.viewMat) * worldPos); + var clipPosition = globalUniform.projMat * viewPosition; + + var ORI_VertexOut: VertexOutput; + ORI_VertexOut.varying_WPos = worldPos; + ORI_VertexOut.varying_Color = vertex.color; + ORI_VertexOut.member = clipPosition; + return ORI_VertexOut; +} diff --git a/src/engine/assets/shader/materials/GlassShader.wgsl b/src/engine/assets/shader/materials/GlassShader.wgsl new file mode 100644 index 00000000..19e5b95d --- /dev/null +++ b/src/engine/assets/shader/materials/GlassShader.wgsl @@ -0,0 +1,36 @@ + + #include "Common_vert" + #include "Common_frag" + #include "UnLit_frag" + #include "UnLitMaterialUniform_frag" + + // @group(1) @binding(auto) + // var noes_MapSampler: sampler; + // @group(1) @binding(auto) + // var noes_Map: texture_2d; + + @group(1) @binding(auto) + var splitTexture_MapSampler: sampler; + @group(1) @binding(auto) + var splitTexture_Map: texture_2d; + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + var screenUV = ORI_VertexVarying.fragPosition.xy / ORI_VertexVarying.fragPosition.w; + screenUV = (screenUV.xy + 1.0) * 0.5; + screenUV.y = 1.0 - screenUV.y; + + screenUV.x = clamp(sin(screenUV.x * 1.0),0.0,1.0) ; + screenUV.y = clamp(sin(screenUV.y * 1.0),0.0,1.0) ; + // screenUV.y = cos(ORI_VertexVarying.fragPosition.y/7.15); + + let frameMap = textureSample(splitTexture_Map,splitTexture_MapSampler,screenUV); + // let noesMap = textureSample(noes_Map,noes_MapSampler,screenUV); + + ORI_ShadingInput.BaseColor = vec4( frameMap.rgb , 1.0) ; + UnLit(); + } diff --git a/src/engine/assets/shader/materials/LitShader.wgsl b/src/engine/assets/shader/materials/LitShader.wgsl new file mode 100644 index 00000000..7e9aad9c --- /dev/null +++ b/src/engine/assets/shader/materials/LitShader.wgsl @@ -0,0 +1,22 @@ + + #include "Common_vert" + #include "Common_frag" + #include "BxDF_frag" + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + ORI_ShadingInput.BaseColor = materialUniform.baseColor ; + ORI_ShadingInput.Roughness = materialUniform.roughness ; + ORI_ShadingInput.Metallic = materialUniform.metallic ; + ORI_ShadingInput.Specular = 0.5 ; + ORI_ShadingInput.AmbientOcclusion = materialUniform.ao ; + ORI_ShadingInput.EmissiveColor = vec4(0.0); + + ORI_ShadingInput.Normal = ORI_VertexVarying.vWorldNormal.rgb ; + + BxDFShading(); + } diff --git a/src/engine/assets/shader/materials/OutlinePass.wgsl b/src/engine/assets/shader/materials/OutlinePass.wgsl new file mode 100644 index 00000000..028cc2c4 --- /dev/null +++ b/src/engine/assets/shader/materials/OutlinePass.wgsl @@ -0,0 +1,80 @@ + #include "Common_vert" + #include "Common_frag" + #include "UnLit_frag" + + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d; + + +struct MaterialUniform { + baseColor:vec4, + lineWeight:f32 +}; + +@group(2) @binding(0) +var materialUniform: MaterialUniform; + + fn vert(vertex:VertexAttributes) -> VertexOutput { + var vertexPosition = vertex.position; + var vertexNormal = vertex.normal; + + #if USE_MORPHTARGETS + vertexPosition = vertexPosition * morphTargetData.morphBaseInfluence + vertex.a_morphPositions_0 * morphTargetData.morphInfluence0; + #if USE_MORPHNORMALS + vertexNormal = vertexNormal * morphTargetData.morphBaseInfluence + vertex.a_morphNormals_0 * morphTargetData.morphInfluence0; + #endif + #endif + + #if USE_SKELETON + #if USE_JOINT_VEC8 + let skeletonNormal = getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); + ORI_MATRIX_M *= skeletonNormal ; + // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; + #else + let skeletonNormal = getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); + ORI_MATRIX_M *= skeletonNormal ; + // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; + #endif + #endif + + + #if USE_TANGENT + ORI_VertexOut.varying_Tangent = vertex.TANGENT ; + #endif + + ORI_NORMALMATRIX = transpose(inverse( mat3x3(ORI_MATRIX_M[0].xyz,ORI_MATRIX_M[1].xyz,ORI_MATRIX_M[2].xyz) )); + + let worldNormal = normalize(ORI_NORMALMATRIX * vertexNormal.xyz) ; + + vertexPosition = vertexPosition + worldNormal * materialUniform.lineWeight ; + + var worldPos = (ORI_MATRIX_M * vec4(vertexPosition.xyz, 1.0)); + var viewPosition = ORI_MATRIX_V * worldPos; + var clipPosition = ORI_MATRIX_P * viewPosition ; + + ORI_VertexOut.varying_UV0 = vertex.uv.xy ; + ORI_VertexOut.varying_UV1 = vertex.TEXCOORD_1.xy; + ORI_VertexOut.varying_ViewPos = viewPosition / viewPosition.w; + ORI_VertexOut.varying_Clip = clipPosition ; + ORI_VertexOut.varying_WPos = worldPos ; + ORI_VertexOut.varying_WPos.w = f32(vertex.index); + ORI_VertexOut.varying_WNormal = worldNormal ; + ORI_VertexOut.member = clipPosition ; + + + return ORI_VertexOut ; + } + + fn frag(){ + let color = textureSample(baseMap,baseMapSampler,ORI_VertexVarying.fragUV0) ; + ORI_ShadingInput.BaseColor = color * materialUniform.baseColor ; + ORI_ShadingInput.Roughness = 0.5 ; + ORI_ShadingInput.Metallic = 0.5 ; + ORI_ShadingInput.Specular = 0.5 ; + ORI_ShadingInput.AmbientOcclusion = 1.0 ; + ORI_ShadingInput.EmissiveColor = vec4(0.0); + ORI_ShadingInput.Normal = ORI_VertexVarying.vWorldNormal.rgb ; + UnLit(); + } \ No newline at end of file diff --git a/src/engine/assets/shader/materials/PBRLItShader.wgsl b/src/engine/assets/shader/materials/PBRLItShader.wgsl new file mode 100644 index 00000000..228dac62 --- /dev/null +++ b/src/engine/assets/shader/materials/PBRLItShader.wgsl @@ -0,0 +1,106 @@ + + #include "Common_vert" + #include "Common_frag" + #include "BxDF_frag" + + @group(1) @binding(auto) + var baseMapSampler: sampler; + @group(1) @binding(auto) + var baseMap: texture_2d; + + @group(1) @binding(auto) + var normalMapSampler: sampler; + @group(1) @binding(auto) + var normalMap: texture_2d; + + #if USE_ARMC + @group(1) @binding(auto) + var maskMapSampler: sampler; + @group(1) @binding(auto) + var maskMap: texture_2d; + #endif + + #if USE_AOTEX + @group(1) @binding(auto) + var aoMapSampler: sampler; + @group(1) @binding(auto) + var aomapMap: texture_2d; + #endif + + @group(1) @binding(auto) + var emissiveMapSampler: sampler; + @group(1) @binding(auto) + var emissiveMap: texture_2d; + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + var transformUV1 = materialUniform.transformUV1; + var transformUV2 = materialUniform.transformUV2; + + var uv = transformUV1.zw * ORI_VertexVarying.fragUV0 + transformUV1.xy; + + ORI_ShadingInput.BaseColor = textureSample(baseMap, baseMapSampler, uv ) * materialUniform.baseColor ; + + // #if USE_ALPHACUT + // ORI_ShadingInput.BaseColor.a = clamp(ORI_ShadingInput.BaseColor.a, 0.001 , 1.0 ); + if( (ORI_ShadingInput.BaseColor.a - materialUniform.alphaCutoff) <= 0.0 ){ + ORI_FragmentOutput.color = vec4(0.0,0.0,0.0,1.0); + ORI_FragmentOutput.worldPos = vec4(0.0,0.0,0.0,1.0); + ORI_FragmentOutput.worldNormal = vec4(0.0,0.0,0.0,1.0); + ORI_FragmentOutput.material = vec4(0.0,0.0,0.0,1.0); + discard; + } + // #endif + + #if USE_SHADOWMAPING + directShadowMaping(globalUniform.shadowBias); + pointShadowMapCompare(globalUniform.pointShadowBias); + #endif + + + // ORI_ShadingInput.BaseColor = vec4(sRGBToLinear(ORI_ShadingInput.BaseColor.xyz),ORI_ShadingInput.BaseColor.w); + + #if USE_ARMC + var maskTex = textureSample(maskMap, maskMapSampler, uv ) ; + + ORI_ShadingInput.AmbientOcclusion = maskTex.r * materialUniform.ao ; + + #if USE_AOTEX + var aoMap = textureSample(aomapMap, aoMapSampler, uv ); + ORI_ShadingInput.AmbientOcclusion = mix(0.0,aoMap.r,materialUniform.ao) ; + #endif + + ORI_ShadingInput.Roughness = maskTex.g * materialUniform.roughness ; + ORI_ShadingInput.Metallic = maskTex.b * materialUniform.metallic ; + + #else + ORI_ShadingInput.Roughness = materialUniform.roughness ; + ORI_ShadingInput.Metallic = materialUniform.metallic ; + ORI_ShadingInput.AmbientOcclusion = materialUniform.ao ; + #if USE_AOTEX + var aoMap = textureSample(aomapMap, aoMapSampler, ORI_VertexVarying.fragUV0.xy ); + ORI_ShadingInput.AmbientOcclusion = mix(0.0,aoMap.r,materialUniform.ao) ; + #endif + #endif + + ORI_ShadingInput.Roughness = clamp(ORI_ShadingInput.Roughness,0.084,1.0); + ORI_ShadingInput.Specular = 0.5 ; + + var emissiveColor = textureSample(emissiveMap, emissiveMapSampler , ORI_VertexVarying.fragUV0.xy) ; + ORI_ShadingInput.EmissiveColor = vec4(materialUniform.emissiveColor.rgb * emissiveColor.rgb * materialUniform.emissiveIntensity,1.0); + + var Normal = textureSample(normalMap,normalMapSampler,ORI_VertexVarying.fragUV0).rgb ; + // Normal.y = 1.0 - Normal.y ; + // let normal = unPackNormal(Normal,1.0,materialUniform.normalScale) ; + let normal = unPackNormal(Normal,materialUniform.normalScale) ; + ORI_ShadingInput.Normal = normal ; + + BxDFShading(); + + + + } diff --git a/src/engine/assets/shader/materials/UnLit.wgsl b/src/engine/assets/shader/materials/UnLit.wgsl new file mode 100644 index 00000000..0c31f8b2 --- /dev/null +++ b/src/engine/assets/shader/materials/UnLit.wgsl @@ -0,0 +1,28 @@ + #include "Common_vert" + #include "Common_frag" + #include "UnLit_frag" + #include "UnLitMaterialUniform_frag" + + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d; + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + var transformUV1 = materialUniform.transformUV1; + var transformUV2 = materialUniform.transformUV2; + + var uv = transformUV1.zw * ORI_VertexVarying.fragUV0 + transformUV1.xy; + let color = textureSample(baseMap,baseMapSampler,uv) ; + if(color.w < 0.5){ + discard ; + } + + ORI_ShadingInput.BaseColor = color * materialUniform.baseColor ; + UnLit(); + } \ No newline at end of file diff --git a/src/engine/assets/shader/sky/AtmosphericScatteringSky_shader.ts b/src/engine/assets/shader/materials/sky/AtmosphericScatteringSky_shader.ts similarity index 100% rename from src/engine/assets/shader/sky/AtmosphericScatteringSky_shader.ts rename to src/engine/assets/shader/materials/sky/AtmosphericScatteringSky_shader.ts diff --git a/src/engine/assets/shader/sky/CubeSky_Shader.ts b/src/engine/assets/shader/materials/sky/CubeSky_Shader.ts similarity index 100% rename from src/engine/assets/shader/sky/CubeSky_Shader.ts rename to src/engine/assets/shader/materials/sky/CubeSky_Shader.ts diff --git a/src/engine/assets/shader/math/FastMathShader.wgsl b/src/engine/assets/shader/math/FastMathShader.wgsl new file mode 100644 index 00000000..d10eaf7c --- /dev/null +++ b/src/engine/assets/shader/math/FastMathShader.wgsl @@ -0,0 +1,31 @@ +fn Pow3( x : f32 ) -> f32 +{ + var xx = x*x; + return x * xx; +} + +fn Pow4( x : f32 ) -> f32 +{ + var xx = x*x; + return xx * xx; +} + +fn pow5(x: f32) -> f32 { + var x2 = x * x; + return x2 * x2 * x; +} + +fn rcp( x:f32 ) -> f32 +{ + return 1.0 / x; +} + +fn rsqrt3( a : vec3 ) -> vec3 +{ + return pow(a, vec3(-0.5)); +} + +fn rsqrt( a : f32 ) -> f32 +{ + return pow(a, -0.5); +} diff --git a/src/engine/assets/shader/post/FSAAShader.wgsl b/src/engine/assets/shader/post/FSAAShader.wgsl new file mode 100644 index 00000000..67ba238e --- /dev/null +++ b/src/engine/assets/shader/post/FSAAShader.wgsl @@ -0,0 +1,76 @@ +struct FragmentOutput { + @location(0) o_Target: vec4 +}; + +var varying_uv: vec2; +@group(1) @binding(0) +var baseMapSampler: sampler; +@group(1) @binding(1) +var baseMap: texture_2d; + +struct MaterialUniform{ + u_texel: vec2, + u_strength: f32, +} + + @group(2) @binding(0) + var materialUniform: MaterialUniform; + + +fn LinearToGammaSpace(linRGB0: vec3) -> vec3 { + var linRGB = max(linRGB0, vec3(0.0, 0.0, 0.0)); + linRGB.r = pow(linRGB.r,0.416666667); + linRGB.g = pow(linRGB.g,0.416666667); + linRGB.b = pow(linRGB.b,0.416666667); + return max(1.055 * linRGB - 0.055, vec3(0.0, 0.0, 0.0)); +} + +fn texture2D( uv:vec2 , offset:vec2 ) -> vec4 { + return textureSample(baseMap, baseMapSampler, uv.xy + offset ).rgba ; +} + +@fragment +fn main(@location(0) fragUV: vec2) -> FragmentOutput { + var v_vTexcoord = fragUV ; + // v_vTexcoord.x = 1.0 - v_vTexcoord.x ; + v_vTexcoord.y = 1.0 - v_vTexcoord.y ; + + var reducemul = 1.0 / 8.0; + var reducemin = 1.0 / 128.0; + + var basecol = texture2D(v_vTexcoord , vec2(0.0)).rgba; + var baseNW = texture2D(v_vTexcoord , -materialUniform.u_texel).rgb; + var baseNE = texture2D(v_vTexcoord , vec2(materialUniform.u_texel.x, -materialUniform.u_texel.y)).rgb; + var baseSW = texture2D(v_vTexcoord , vec2(-materialUniform.u_texel.x, materialUniform.u_texel.y)).rgb; + var baseSE = texture2D(v_vTexcoord , materialUniform.u_texel ).rgb; + + // var gray = vec3(0.299, 0.587, 0.114); + var gray = vec3(0.213, 0.715, 0.072); + var monocol = dot(basecol.rgb, gray); + var monoNW = dot(baseNW, gray); + var monoNE = dot(baseNE, gray); + var monoSW = dot(baseSW, gray); + var monoSE = dot(baseSE, gray); + + var monomin = min(monocol, min(min(monoNW, monoNE), min(monoSW, monoSE))); + var monomax = max(monocol, max(max(monoNW, monoNE), max(monoSW, monoSE))); + + var dir = vec2(-((monoNW + monoNE) - (monoSW + monoSE)), ((monoNW + monoSW) - (monoNE + monoSE))); + var dirreduce = max((monoNW + monoNE + monoSW + monoSE) * reducemul * 0.25, reducemin); + var dirmin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirreduce); + dir = min(vec2(materialUniform.u_strength), max(vec2(-materialUniform.u_strength), dir * dirmin)) * materialUniform.u_texel; + + var resultA = 0.5 * (texture2D(v_vTexcoord , dir * -0.166667).rgb + + texture2D(v_vTexcoord , dir * 0.166667).rgb); + var resultB = resultA * 0.5 + 0.25 * (texture2D( v_vTexcoord , dir * -0.5).rgb + + texture2D( v_vTexcoord , dir * 0.5).rgb); + var monoB = dot(resultB.rgb, gray); + + var color:vec3 ; + if(monoB < monomin || monoB > monomax) { + color = resultA ;//* v_vColour; + } else { + color = resultB ;//* v_vColour; + } + return FragmentOutput(vec4(color.rgb,basecol.a)); +} \ No newline at end of file diff --git a/src/engine/assets/shader/utils/BRDFLUT.wgsl b/src/engine/assets/shader/utils/BRDFLUT.wgsl new file mode 100644 index 00000000..4a898192 --- /dev/null +++ b/src/engine/assets/shader/utils/BRDFLUT.wgsl @@ -0,0 +1,112 @@ + var PI:f32 = 3.141592653589793 ; + + // fn saturate( x : f32 ) -> f32 { + // return clamp(x, 0.0, 1.0); + // } + + fn hammersley( i : u32 , N : u32 ) -> vec2 + { + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + var bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + var rdi = f32(bits) * 2.3283064365386963e-10; + return vec2(f32(i) /f32(N), rdi); + } + + fn G_Smith( NoV:f32 , NoL : f32 , roughness : f32 ) -> f32 + { + var k = (roughness * roughness) / 2.0; + var GGXL = NoL / (NoL * (1.0 - k) + k); + var GGXV = NoV / (NoV * (1.0 - k) + k); + return GGXL * GGXV; + } + + fn V_SmithGGXCorrelated( NoV:f32 , NoL : f32 , roughness : f32 ) -> f32 + { + var a2 = pow(roughness, 4.0); + var GGXV = NoL * sqrt(NoV * NoV * (1.0 - a2) + a2); + var GGXL = NoV * sqrt(NoL * NoL * (1.0 - a2) + a2); + return 0.5 / (GGXV + GGXL); + } + + + // Based on Karis 2014 + fn importanceSampleGGX( Xi:vec2, roughness:f32 , N:vec3 ) -> vec3 + { + var a = roughness * roughness; + // Sample in spherical coordinates + var Phi = 2.0 * PI * Xi.x; + var CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); + var SinTheta = sqrt(1.0 - CosTheta * CosTheta); + // Construct tangent space vector + var H:vec3; + H.x = SinTheta * cos(Phi); + H.y = SinTheta * sin(Phi); + H.z = CosTheta; + + // Tangent to world space + var UpVector = vec3(1.0,0.0,0.0); + if(abs(N.z) < 0.999){ + UpVector = vec3(0.0,0.0,1.0) ; + } + var TangentX = normalize(cross(UpVector, N)); + var TangentY = cross(N, TangentX); + return TangentX * H.x + TangentY * H.y + N * H.z; + } + + + // Karis 2014 + fn integrateBRDF( roughness:f32 , NoV: f32) -> vec2 + { + var V : vec3 ; + V.x = sqrt(1.0 - NoV * NoV); // sin + V.y = 0.0; + V.z = NoV; // cos + + // N points straight upwards for this integration + var N = vec3(0.0, 0.0, 1.0); + + var A = 0.0; + var B = 0.0; + var numSamples = 1024u; + + for (var i = 0u; i < numSamples; i+=1u) { + var Xi = hammersley(i, numSamples); + // Sample microfacet direction + var H = importanceSampleGGX(Xi, roughness, N); + + // Get the light direction + var L = 2.0 * dot(V, H) * H - V; + + var NoL = saturate(dot(N, L)); + var NoH = saturate(dot(N, H)); + var VoH = saturate(dot(V, H)); + + if(NoL > 0.0) { + var V_pdf = V_SmithGGXCorrelated(NoV, NoL, roughness) * VoH * NoL / NoH; + var Fc = pow(1.0 - VoH, 5.0); + A += (1.0 - Fc) * V_pdf; + B += Fc * V_pdf; + } + } + + return 4.0 * vec2(A, B) / f32(numSamples); + } + + @group(0) @binding(0) var brdflutTexture : texture_storage_2d; + + @compute @workgroup_size(8,8,1) + // fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(local_invocation_id) local_invocation_id : vec3 ){ + fn CsMain( @builtin(global_invocation_id) global_invocation_id : vec3){ + var fragCoord = vec2( global_invocation_id.x, global_invocation_id.y); + + var fragColor = vec4(0.0) ; + // Output to screen + var res = integrateBRDF( f32(fragCoord.y+1u) / 256.0 , f32(fragCoord.x+1u) / 256.0 ); + fragColor = vec4(res.x, res.y, 0.0, 1.0) ; + + textureStore(brdflutTexture, vec2(fragCoord.xy), fragColor ); + } diff --git a/src/engine/assets/shader/utils/ColorUtil.wgsl b/src/engine/assets/shader/utils/ColorUtil.wgsl new file mode 100644 index 00000000..5db84e7a --- /dev/null +++ b/src/engine/assets/shader/utils/ColorUtil.wgsl @@ -0,0 +1,99 @@ + + + fn getHDRColor(color:vec3,exposure:f32)-> vec3{ + // var newColor = color * ( 1.0 / 255.0 ) ; + return color * pow(2.4 , exposure) ; + } + + fn lambda2rgb( lambda : f32 ) -> vec3 { + let ultraviolet = 400.0; + let infrared = 700.0; + + var a = (lambda - ultraviolet)/(infrared - ultraviolet); + let c = 10.0; + var b = vec3(a) - vec3(0.75,0.5,0.25); + return max((1.0 - c*b*b), vec3(0.0) ); + } + + fn CEToneMapping( color:vec3, adapted_lum:f32)-> vec3 + { + return 1.0 - exp(-adapted_lum * color); + } + + fn ACESToneMapping( color:vec3, adapted_lum:f32 )-> vec3 + { + let A = 2.51; + let B = 0.03; + let C = 2.43; + let D = 0.59; + let E = 0.14; + + var color2 = color * adapted_lum; + color2 = (color2 * (A * color2 + B)) / (color2 * (C * color2 + D) + E); + return color2 ; + } + + fn gammaToLiner(color:vec4) -> vec4 { + let gammaCorrect = 2.4; + var color2 = pow(color, vec4(gammaCorrect)); + return color2 ; + } + + fn linerToGamma4(color:vec4) -> vec4 { + let gammaCorrect = 1.0 / 2.4; + var color2 = pow(color, vec4(gammaCorrect)); + return color2 ; + } + + fn linerToGamma3(color:vec3) -> vec3 { + let gammaCorrect = 1.0 / 2.4; + var color2 = pow(color, vec3(gammaCorrect)); + return color2 ; + } + + fn LinearToGammaSpace(linRGB0: vec3) -> vec3 { + var linRGB = max(linRGB0, vec3(0.0, 0.0, 0.0)); + linRGB.r = pow(linRGB.r,0.416666667); + linRGB.g = pow(linRGB.g,0.416666667); + linRGB.b = pow(linRGB.b,0.416666667); + return max(1.055 * linRGB - 0.055, vec3(0.0, 0.0, 0.0)); + } + + var sRGB_2_LMS_MAT:mat3x3 = mat3x3( + 17.8824, 43.5161, 4.1193, + 3.4557, 27.1554, 3.8671, + 0.02996, 0.18431, 1.4670, + ) ; + + var LMS_2_sRGB_MAT:mat3x3 = mat3x3( + 0.0809, -0.1305, 0.1167, + -0.0102, 0.0540, -0.1136, + -0.0003, -0.0041, 0.6935, + ); + + fn sRGB_2_LMS( RGB:vec3 ) -> vec3 + { + return sRGB_2_LMS_MAT * RGB ; + } + + fn LMS_2_sRGB( LMS:vec3 ) -> vec3 + { + return LMS_2_sRGB_MAT * LMS; + } + + fn LinearToSrgbBranchless( lin:vec3 ) -> vec3 + { + var lin2 = max(vec3(6.10352e-5), lin); + return min(lin2 * 12.92, pow(max(lin2, vec3(0.00313067)), vec3(1.0/2.4)) * vec3(1.055) - vec3(0.055)); + } + + fn sRGBToLinear( color : vec3 ) -> vec3 + { + let color2 = max(vec3(6.10352e-5), color); + let c = 0.04045 ; + if(color2.r > c && color2.g > c && color2.b > c){ + return pow( color2 * (1.0 / 1.055) + 0.0521327, vec3(2.4) ) ; + }else{ + return color2 * (1.0 / 12.92); + } + } diff --git a/src/engine/assets/shader/utils/GenerayRandomDir.wgsl b/src/engine/assets/shader/utils/GenerayRandomDir.wgsl new file mode 100644 index 00000000..74a72796 --- /dev/null +++ b/src/engine/assets/shader/utils/GenerayRandomDir.wgsl @@ -0,0 +1,23 @@ + +fn madfrac(A:f32, B:f32)-> f32 { + return A*B-floor(A*B) ; +} + +fn sampleRandomDir(count:u32,SAMPLE_COUNT:u32) -> vec3{ + var ray_dir = sphericalFibonacci(f32((count)), f32(SAMPLE_COUNT) ); + return normalize(ray_dir) ; +} + +fn sphericalFibonacci( i : f32 , n : f32 ) -> vec3{ + const PHI = sqrt(5.0) * 0.5 + 0.5; + let phi = 2.0 * PI * madfrac(i, PHI - 1); + let cosTheta = 1.0 - (2.0 * i + 1.0) * (1.0 / n); + let sinTheta = sqrt(saturate(1.0 - cosTheta*cosTheta)); + + return vec3( + cos(phi) * sinTheta, + sin(phi) * sinTheta, + cosTheta); + +} + diff --git a/src/engine/textures/AtmosphericScatteringSky.ts b/src/engine/textures/AtmosphericScatteringSky.ts index 93784bbd..37e3a535 100644 --- a/src/engine/textures/AtmosphericScatteringSky.ts +++ b/src/engine/textures/AtmosphericScatteringSky.ts @@ -1,4 +1,4 @@ -import { AtmosphericScatteringSky_shader } from '../assets/shader/sky/AtmosphericScatteringSky_shader'; +import { AtmosphericScatteringSky_shader } from '../assets/shader/materials/sky/AtmosphericScatteringSky_shader'; import { UniformGPUBuffer } from '../gfx/graphics/webGpu/core/buffer/UniformGPUBuffer'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { ComputeShader } from '../gfx/graphics/webGpu/shader/ComputeShader'; From d7f5dee1c1d50d54576b2bba6fe4b291312f81a7 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Thu, 27 Apr 2023 21:23:09 +0800 Subject: [PATCH 065/100] docs: add CI & NPM badges (#80) --- .github/workflows/ci.yml | 2 +- README.md | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c6160944..211bc669 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: CI auto test on push +name: CI Test on: push: diff --git a/README.md b/README.md index c5b84e57..d155d086 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,15 @@ - ![Cover Art](https://github.com/Orillusion/orillusion-webgpu-samples/blob/main/logo_new.png) - + > **Note:** > > Currently, this repo is used to collect feedback on the NPM package of the Orillusion engine. According to all the feedback, we will carry on refining the engine core. Then, we need to set up the regulations for a long-term open source project and all the source code will be put in this repo in the near future, which indicates a brand new journey for Orillusion. ## Orillusion + +[![Test](https://github.com/Orillusion/orillusion/actions/workflows/ci.yml/badge.svg)](https://github.com/Orillusion/orillusion/actions/workflows/ci.yml) +[![npm](https://img.shields.io/npm/v/@orillusion/core)](https://www.npmjs.com/package/@orillusion/core) + `Orillusion` is a pure Web3D rendering engine which is fully developed based on the `WebGPU` standard. It aims to achieve desktop-level rendering effects and supports 3D rendering of complex scenes in the browser. ## Need to know From e22b4d46ad026812f55f63299ffeaede2c939353 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Sat, 29 Apr 2023 23:35:42 +0800 Subject: [PATCH 066/100] chore: update folder (#83) update folder fix not run update folder Removes all non-ASCII characters add gltf parser fix SkinMeshRender not work. --- index.html | 2 +- src/{engine => }/Engine3D.ts | 103 +- src/{engine => }/assets/Res.ts | 96 ++ src/{engine => }/assets/shader/ShaderLib.ts | 62 +- .../shader/anim/SkeletonAnimation_shader.ts | 0 .../cluster/ClusterBoundsSource_cs.wgsl | 0 .../shader/cluster/ClusterLighting_cs.wgsl | 0 .../assets/shader/compute/BLUR_CsShader.wgsl | 0 .../compute/BlurEffectCreator_compute.ts | 0 .../shader/compute/DepthOfView_CsShader.wgsl | 0 .../ErpImage2CubeMapCreateCube_compute.wgsl | 0 .../ErpImage2CubeMapRgbe2rgba_compute.wgsl | 0 .../assets/shader/compute/GTAOCs.wgsl | 0 .../compute/IBLEnvMapCreator_compute.wgsl | 0 .../assets/shader/compute/MergeRGBA_Cs.wgsl | 0 .../compute/MultiBouncePass_Shader.wgsl | 0 .../shader/compute/OutLineBlendColor.wgsl | 0 .../shader/compute/OutlineCalcOutline.wgsl | 0 .../assets/shader/compute/OutlineCs.wgsl | 0 .../shader/compute/Picker_CsShader.wgsl | 0 .../assets/shader/compute/SSAO_CsShader.wgsl | 0 .../shader/compute/SSR_BlendColor_Shader.wgsl | 0 .../assets/shader/compute/SSR_IS_Shader.wgsl | 0 .../shader/compute/SSR_RayTrace_Shader.wgsl | 0 .../assets/shader/compute/TAACopyTex.wgsl | 0 .../assets/shader/compute/TAASharpTex.wgsl | 0 .../assets/shader/compute/TAAcs.wgsl | 0 .../assets/shader/core/base/Common_frag.wgsl | 0 .../assets/shader/core/base/Common_vert.wgsl | 0 .../shader/core/common/BrdfLut_frag.wgsl | 0 .../shader/core/common/EnvMap_frag.wgsl | 0 .../shader/core/common/GlobalUniform.wgsl | 0 .../shader/core/common/InstanceUniform.wgsl | 0 .../core/common/WorldMatrixUniform.wgsl | 0 .../shader/core/inline/Inline_vert.wgsl | 0 .../shader/core/pass/CastShadowPass_wgsl.ts | 0 .../core/pass/FrustumCullingShader_cs.wgsl | 0 .../shader/core/pass/GBuffer_shader.wgsl | 0 .../shader/core/pass/SkyGBuffer_fs.wgsl | 0 .../shader/core/pass/ZPassShader_cs.wgsl | 0 .../shader/core/pass/ZPassShader_fs.wgsl | 0 .../assets/shader/core/pass/ZPassShader_vs.ts | 0 .../core/struct/ColorPassFragmentOutput.wgsl | 0 .../core/struct/EmptyFrag_CommonFragment.wgsl | 0 .../core/struct/EmptyFrag_FragmentOutput.wgsl | 0 .../shader/core/struct/FragmentVarying.wgsl | 0 .../shader/core/struct/LightStruct.wgsl | 0 .../shader/core/struct/LightStructFrag.ts | 0 .../shader/core/struct/ShadingInput.wgsl | 0 .../shader/core/struct/VertexAttributes.ts | 0 .../assets/shader/glsl/Quad_glsl.ts | 0 .../assets/shader/glsl/Sky_glsl.ts | 0 .../assets/shader/glsl/post/LUT_glsl.ts | 0 .../shader/graphic/Graphic3DShader_fs.wgsl | 0 .../shader/graphic/Graphic3DShader_vs.wgsl | 0 .../assets/shader/lighting/BRDF_frag.wgsl | 0 .../assets/shader/lighting/BxDF_frag.wgsl | 0 .../shader/lighting/IESProfiles_frag.wgsl | 0 .../lighting/IrradianceVolumeData_frag.ts | 49 + .../shader/lighting/Irradiance_frag.wgsl | 0 .../shader/lighting/LightingFunction_frag.ts | 0 .../assets/shader/lighting/UnLit_frag.ts | 0 .../assets/shader/materials/ColorLitShader.ts | 0 .../assets/shader/materials/GlassShader.wgsl | 0 .../assets/shader/materials/Lambert_shader.ts | 0 .../assets/shader/materials/LitShader.wgsl | 0 .../assets/shader/materials/OutlinePass.wgsl | 0 .../assets/shader/materials/PBRLItShader.wgsl | 0 .../assets/shader/materials/PavementShader.ts | 0 .../shader/materials/PointShadowDebug.ts | 0 .../assets/shader/materials/UnLit.wgsl | 0 .../materials/compute/BLUR_CsShader.wgsl | 40 + .../compute/DepthOfView_CsShader.wgsl | 81 ++ .../ErpImage2CubeMapCreateCube_compute.wgsl | 65 ++ .../ErpImage2CubeMapRgbe2rgba_compute.wgsl | 32 + .../shader/materials/compute/GTAOCs.wgsl | 133 +++ .../compute/IBLEnvMapCreator_compute.wgsl | 174 ++++ .../materials/compute/MergeRGBA_Cs.wgsl | 29 + .../compute/MultiBouncePass_Shader.wgsl | 185 ++++ .../materials/compute/OutLineBlendColor.wgsl | 40 + .../materials/compute/OutlineCalcOutline.wgsl | 86 ++ .../shader/materials/compute/OutlineCs.wgsl | 120 +++ .../materials/compute/Picker_CsShader.wgsl | 65 ++ .../materials/compute/SSAO_CsShader.wgsl | 99 ++ .../compute/SSR_BlendColor_Shader.wgsl | 45 + .../materials/compute/SSR_IS_Shader.wgsl | 82 ++ .../compute/SSR_RayTrace_Shader.wgsl | 315 +++++++ .../shader/materials/compute/TAACopyTex.wgsl | 18 + .../shader/materials/compute/TAASharpTex.wgsl | 41 + .../shader/materials/compute/TAAcs.wgsl | 155 ++++ .../materials/core/base/Common_frag.wgsl | 26 + .../materials/core/base/Common_vert.wgsl | 11 + .../materials/core/common/BrdfLut_frag.wgsl | 4 + .../materials/core/common/EnvMap_frag.wgsl | 9 + .../materials/core/common/GlobalUniform.wgsl | 37 + .../core/common/InstanceUniform.wgsl | 7 + .../core/common/WorldMatrixUniform.wgsl | 9 + .../materials/core/inline/Inline_vert.wgsl | 49 + .../materials/graphic/Graphic3DShader_fs.wgsl | 30 + .../materials/graphic/Graphic3DShader_vs.wgsl | 27 + .../materials/materials/GlassShader.wgsl | 36 + .../shader/materials/materials/LitShader.wgsl | 22 + .../materials/materials/OutlinePass.wgsl | 80 ++ .../materials/materials/PBRLItShader.wgsl | 106 +++ .../shader/materials/materials/UnLit.wgsl | 28 + .../sky/AtmosphericScatteringSky_shader.ts | 0 .../materials/sky/CubeSky_Shader.ts | 0 .../materials}/math/FastMathShader.wgsl | 0 .../shader/materials}/post/FSAAShader.wgsl | 0 .../materials/program/BxdfDebug_frag.wgsl | 0 .../materials/program/Clearcoat_frag.wgsl | 0 .../materials/program/ClusterDebug_frag.ts | 0 .../materials/program/NormalMap_frag.wgsl | 0 .../materials/program/ShadowMapping_frag.wgsl | 0 .../sky/AtmosphericScatteringSky_shader.ts | 311 +++++++ .../shader/materials/sky/CubeSky_Shader.ts | 98 ++ .../materials/uniforms/MaterialUniform.ts | 0 .../uniforms/PhysicMaterialUniform_frag.ts | 0 .../uniforms/UnLitMaterialUniform_frag.ts | 0 .../materials/uniforms/VideoUniform_frag.ts | 0 .../shader/materials}/utils/BRDFLUT.wgsl | 0 .../shader/materials}/utils/ColorUtil.wgsl | 0 .../materials}/utils/GenerayRandomDir.wgsl | 0 src/assets/shader/math/FastMathShader.wgsl | 31 + .../assets/shader/math/MathShader.ts | 0 .../assets/shader/post/Bloom_shader.ts | 0 src/assets/shader/post/FSAAShader.wgsl | 76 ++ .../assets/shader/post/GlobalFog_shader.ts | 0 .../assets/shader/quad/Quad_shader.ts | 0 src/assets/shader/utils/BRDFLUT.wgsl | 112 +++ src/assets/shader/utils/ColorUtil.wgsl | 99 ++ src/assets/shader/utils/GenerayRandomDir.wgsl | 23 + .../components/AtmosphericComponent.ts | 8 +- .../components/BillboardComponent.ts | 2 +- .../components/ColliderComponent.ts | 2 +- src/{engine => }/components/ComponentBase.ts | 78 +- src/components/IComponent.ts | 23 + .../components/SkeletonAnimationComponent.ts | 2 +- src/{engine => }/components/Transform.ts | 0 .../components/anim/OAnimationEvent.ts | 0 .../curveAnim/curveAnim/AnimationMonitor.ts | 0 .../curveAnim/curveAnim/AttributeAnimCurve.ts | 0 .../curveAnim/curveAnim/PropertyAnimClip.ts | 0 .../curveAnim/curveAnim/PropertyAnimation.ts | 0 .../curveAnim/PropertyAnimationEvent.ts | 0 .../anim/curveAnim/curveAnim/PropertyHelp.ts | 0 .../anim/morphAnim/MorphTargetBlender.ts | 2 +- .../anim/morphAnim/MorphTargetData.ts | 0 .../anim/morphAnim/MorphTargetFrame.ts | 0 .../anim/morphAnim/MorphTargetKey.ts | 0 .../anim/morphAnim/MorphTarget_shader.ts | 0 .../components/anim/skeletonAnim/Joint.ts | 0 .../components/anim/skeletonAnim/JointPose.ts | 0 .../components/anim/skeletonAnim/Skeleton.ts | 0 .../skeletonAnim/SkeletonAnimationClip.ts | 0 .../SkeletonAnimationClipState.ts | 0 .../skeletonAnim/SkeletonAnimationCompute.ts | 0 .../anim/skeletonAnim/SkeletonPose.ts | 0 .../buffer/SkeletonBlendComputeArgs.ts | 0 .../buffer/SkeletonTransformComputeArgs.ts | 0 .../shader/compute_skeleton_blend.ts | 0 .../shader/compute_skeleton_transform.ts | 0 .../components/audio/AudioListener.ts | 108 +-- .../components/audio/PositionAudio.ts | 362 ++++---- .../components/audio/StaticAudio.ts | 228 ++--- .../controller/CameraControllerBase.ts | 0 .../controller/FirstPersonCameraController.ts | 2 +- .../controller/FlyCameraController.ts | 2 +- .../controller/HoverCameraController.ts | 2 +- .../components/controller/OrbitController.ts | 674 +++++++------- .../controller/ThirdPersonCameraController.ts | 2 +- .../components/lights/DirectLight.ts | 4 +- .../components/lights/GILighting.ts | 8 +- .../components/lights/IESProfiles.ts | 0 src/components/lights/ILight.ts | 15 + .../components/lights/LightBase.ts | 11 +- .../components/lights/LightData.ts | 0 .../components/lights/PointLight.ts | 8 +- .../components/lights/SpotLight.ts | 8 +- .../post/PostProcessingComponent.ts | 10 +- .../renderer/InstanceDrawComponent.ts | 13 +- .../components/renderer/MaterialComponent.ts | 0 .../components/renderer/MeshComponent.ts | 2 +- .../components/renderer/MeshRenderer.ts | 18 +- .../components/renderer/RenderNode.ts | 34 +- .../renderer/SkinnedMeshRenderer.ts | 17 +- .../components/renderer/SkyRenderer.ts | 14 +- .../components/shape/BoxColliderShape.ts | 0 .../components/shape/CapsuleColliderShape.ts | 0 .../components/shape/ColliderShape.ts | 0 .../components/shape/MeshColliderShape.ts | 0 .../components/shape/SphereColliderShape.ts | 0 src/{engine => }/core/Camera3D.ts | 7 +- src/{engine => }/core/CameraType.ts | 0 src/{engine => }/core/CubeCamera.ts | 0 .../core/PointShadowCubeCamera.ts | 0 src/{engine => }/core/Scene3D.ts | 33 +- src/{engine => }/core/View3D.ts | 0 src/{engine => }/core/ViewQuad.ts | 73 +- src/{engine => }/core/bound/BoundingBox.ts | 6 +- src/{engine => }/core/bound/BoundingSphere.ts | 7 +- src/{engine => }/core/bound/Frustum.ts | 10 +- src/{engine => }/core/bound/IBound.ts | 5 +- src/{engine => }/core/entities/Entity.ts | 15 +- .../core/entities/InstancedMesh.ts | 0 src/{engine => }/core/entities/Object3D.ts | 55 +- .../core/geometry/GeometryBase.ts | 2 +- .../core/geometry/GeometryIndicesBuffer.ts | 2 +- .../core/geometry/GeometryVertexBuffer.ts | 0 .../core/geometry/GeometryVertexType.ts | 0 .../core/geometry/VertexAttribute.ts | 0 .../core/geometry/VertexAttributeData.ts | 2 +- .../core/geometry/VertexAttributeName.ts | 0 .../core/geometry/VertexAttributeSize.ts | 0 .../core/geometry/VertexAttributeStride.ts | 0 .../core/geometry/VertexFormat.ts | 0 src/{engine => }/core/pool/ObjectPool.ts | 0 src/{engine => }/core/pool/memory/MatrixDO.ts | 0 src/{engine => }/core/pool/memory/MemoryDO.ts | 0 .../core/pool/memory/MemoryInfo.ts | 0 .../core/tree/kdTree/IKDTreeUserData.ts | 0 .../core/tree/kdTree/KDTreeEntity.ts | 0 .../core/tree/kdTree/KDTreeNode.ts | 0 .../core/tree/kdTree/KDTreeSpace.ts | 0 src/engine/textures/DefaultRes.ts | 110 --- src/{engine => }/event/CEvent.ts | 246 ++--- src/{engine => }/event/CEventDispatcher.ts | 420 ++++----- src/{engine => }/event/CEventListener.ts | 122 +-- src/{engine => }/event/CResizeEvent.ts | 26 +- src/{engine => }/event/KeyCode.ts | 224 ++--- src/{engine => }/event/MouseCode.ts | 52 +- src/{engine => }/event/eventConst/KeyEvent.ts | 0 .../event/eventConst/LoaderEvent.ts | 0 .../event/eventConst/Object3DEvent.ts | 0 .../event/eventConst/PointerEvent3D.ts | 0 src/{engine => }/event/eventConst/UIEvent.ts | 0 src/gfx/data/IrradianceVolume.ts | 56 ++ .../gfx/generate/BrdfLUTGenerate.ts | 0 src/{engine => }/gfx/generate/PassGenerate.ts | 14 +- .../gfx/generate/convert/BlurEffectCreator.ts | 0 .../gfx/generate/convert/ErpImage2CubeMap.ts | 0 .../gfx/generate/convert/IBLEnvMapCreator.ts | 0 .../gfx/generate/convert/MergeRGBACreator.ts | 0 .../generate/convert/TextureCubeStdCreator.ts | 0 .../gfx/generate/convert/TextureCubeUtils.ts | 0 .../gfx/graphics/webGpu/CanvasConfig.ts | 1 - .../gfx/graphics/webGpu/Context3D.ts | 0 .../gfx/graphics/webGpu/WebGPUConst.ts | 0 .../webGpu/core/bindGroups/GlobalBindGroup.ts | 2 +- .../core/bindGroups/GlobalBindGroupLayout.ts | 0 .../core/bindGroups/GlobalUniformGroup.ts | 0 .../webGpu/core/bindGroups/MatrixBindGroup.ts | 0 .../core/bindGroups/TexturesBindGroup.ts | 0 .../core/bindGroups/groups/LightEntries.ts | 4 + .../webGpu/core/buffer/ArrayBufferData.ts | 1 + .../webGpu/core/buffer/ComputeGPUBuffer.ts | 2 + .../webGpu/core/buffer/GPUBufferBase.ts | 35 +- .../webGpu/core/buffer/GPUBufferType.ts | 9 + .../webGpu/core/buffer/IndicesGPUBuffer.ts | 5 +- .../buffer/MaterialDataUniformGPUBuffer.ts | 2 + .../webGpu/core/buffer/StorageGPUBuffer.ts | 5 +- .../core/buffer/StructStorageGPUBuffer.ts | 2 + .../webGpu/core/buffer/UniformGPUBuffer.ts | 2 + .../webGpu/core/buffer/VertexGPUBuffer.ts | 4 +- .../graphics/webGpu/core/texture/ITexture.ts | 0 .../graphics/webGpu/core/texture/Texture.ts | 6 +- .../webGpu/core/texture/TextureCube.ts | 0 .../core/texture/TextureMipmapCompute.ts | 0 .../core/texture/TextureMipmapGenerator.ts | 0 .../webGpu/core/uniforms/UniformNode.ts | 0 .../webGpu/descriptor/RTDescriptor.ts | 0 .../descriptor/WebGPUDescriptorCreator.ts | 0 .../graphics/webGpu/shader/ComputeShader.ts | 0 .../graphics/webGpu/shader/RenderShader.ts | 51 +- .../gfx/graphics/webGpu/shader/ShaderBase.ts | 0 .../gfx/graphics/webGpu/shader/ShaderStage.ts | 0 .../webGpu/shader/converter/GLSLLexer.ts | 0 .../webGpu/shader/converter/GLSLLexerToken.ts | 70 +- .../shader/converter/GLSLPreprocessor.ts | 0 .../webGpu/shader/converter/GLSLSyntax.ts | 0 .../webGpu/shader/converter/Reader.ts | 0 .../shader/converter/ShaderConverter.ts | 0 .../webGpu/shader/converter/StatementNode.ts | 8 +- .../webGpu/shader/converter/WGSLTranslator.ts | 0 .../webGpu/shader/util/MorePassParser.ts | 0 .../webGpu/shader/util/Preprocessor.ts | 0 .../graphics/webGpu/shader/util/ShaderUtil.ts | 13 +- .../webGpu/shader/value/ConstValue.ts | 0 .../webGpu/shader/value/DefineValue.ts | 0 .../shader/value/ShaderReflectionInfo.ts | 0 .../webGpu/shader/value/ShaderState.ts | 0 .../webGpu/shader/value/ShaderValue.ts | 0 .../webGpu/shader/value/UniformValue.ts | 1 - src/{engine => }/gfx/renderJob/GPUContext.ts | 68 -- .../gfx/renderJob/collect/CollectInfo.ts | 0 src/gfx/renderJob/collect/ComponentCollect.ts | 44 + .../renderJob/collect/EntityBatchCollect.ts | 0 .../gfx/renderJob/collect/EntityCollect.ts | 24 +- .../gfx/renderJob/collect/RenderGroup.ts | 0 .../renderJob/collect/ShadowLightsCollect.ts | 36 +- .../gfx/renderJob/config/RTResourceConfig.ts | 0 .../gfx/renderJob/config/RenderLayer.ts | 0 .../gfx/renderJob/frame/GBufferFrame.ts | 0 .../gfx/renderJob/frame/ProbeGBufferFrame.ts | 0 .../gfx/renderJob/frame/RTFrame.ts | 0 .../gfx/renderJob/frame/RTResourceMap.ts | 3 +- .../gfx/renderJob/jobs/ForwardRenderJob.ts | 2 +- .../gfx/renderJob/jobs/RenderMap.ts | 0 .../gfx/renderJob/jobs/RendererJob.ts | 15 +- .../renderJob/occlusion/OcclusionSystem.ts | 0 .../renderJob/passRenderer/RenderContext.ts | 0 .../renderJob/passRenderer/RendererBase.ts | 25 +- .../cluster/ClusterLightingBuffer.ts | 37 + .../cluster/ClusterLightingRender.ts | 52 +- .../passRenderer}/color/ColorPassRenderer.ts | 37 +- .../graphic/Graphic3DBatchRenderer.ts | 7 +- .../graphic/Graphic3DFillRenderer.ts | 0 .../graphic/Graphic3DFixedRenderPipeline.ts | 0 .../graphic/Graphic3DLineBatchRenderer.ts | 0 .../passRenderer/graphic/Graphic3DRender.ts | 0 .../passRenderer/graphic/GraphicConfig.ts | 0 .../passRenderer/graphic/Graphics3DShape.ts | 0 .../passRenderer/post/PostRenderer.ts | 4 +- .../preDepth/PreDepthPassRenderer.ts | 0 .../passRenderer/preDepth/ZCullingCompute.ts | 0 .../shadow/PointLightShadowRenderer.ts | 9 +- .../shadow/ShadowMapPassRenderer.ts | 9 +- .../passRenderer/state/RendererMask.ts | 2 +- .../passRenderer/state/RendererPassState.ts | 7 +- .../passRenderer/state/RendererType.ts | 0 .../gfx/renderJob/post/DepthOfFieldPost.ts | 2 +- .../gfx/renderJob/post/FXAAPost.ts | 8 - .../gfx/renderJob/post/GTAOPost.ts | 0 .../gfx/renderJob/post/GlobalFog.ts | 12 +- .../gfx/renderJob/post/HDRBloomPost.ts | 22 +- .../gfx/renderJob/post/OutlinePost.ts | 17 +- .../gfx/renderJob/post/PostBase.ts | 4 +- .../gfx/renderJob/post/SSRPost.ts | 5 +- .../gfx/renderJob/post/TAAPost.ts | 0 src/index.ts | 379 +++++++- src/{engine => }/io/InputSystem.ts | 2 +- src/{engine => }/io/PickFire.ts | 0 src/{engine => }/io/PickResult.ts | 0 src/{engine => }/io/RayCastMeshDetail.ts | 0 src/{engine => }/io/TouchData.ts | 2 +- src/{engine => }/io/picker/PickCompute.ts | 0 src/{engine => }/loader/FileLoader.ts | 0 src/{engine => }/loader/LoaderBase.ts | 0 src/{engine => }/loader/LoaderData.ts | 0 src/{engine => }/loader/LoaderFunctions.ts | 0 src/{engine => }/loader/LoaderManager.ts | 0 src/{engine => }/loader/parser/B3DMParser.ts | 0 src/{engine => }/loader/parser/I3DMParser.ts | 0 src/{engine => }/loader/parser/OBJParser.ts | 1 + src/{engine => }/loader/parser/ParserBase.ts | 0 src/{engine => }/loader/parser/RGBEParser.ts | 0 .../loader/parser/b3dm/B3DMLoader.ts | 6 +- .../loader/parser/b3dm/B3DMLoaderBase.ts | 0 .../loader/parser/b3dm/FeatureTable.ts | 0 .../loader/parser/b3dm/arrayToString.ts | 0 .../loader/parser/b3dm/readMagicBytes.ts | 0 .../loader/parser/gltf/GLBParser.ts | 16 +- .../loader/parser/gltf/GLTFInfo.ts | 6 +- .../loader/parser/gltf/GLTFParser.ts | 46 +- .../loader/parser/gltf/GLTFSubParser.ts | 298 +++++- .../loader/parser/gltf/GLTFSubParserCamera.ts | 2 +- .../parser/gltf/GLTFSubParserConverter.ts | 8 +- .../parser/gltf/GLTFSubParserMaterial.ts | 12 +- .../loader/parser/gltf/GLTFSubParserMesh.ts | 15 +- .../parser/gltf/GLTFSubParserSkeleton.ts | 2 +- .../loader/parser/gltf/GLTFSubParserSkin.ts | 5 +- src/loader/parser/gltf/GLTFType.ts | 41 + .../loader/parser/gltf/TypeArray.ts | 0 .../extends/KHR_draco_mesh_compression.ts | 0 .../gltf/extends/KHR_lights_punctual.ts | 0 .../gltf/extends/KHR_materials_clearcoat.ts | 0 .../KHR_materials_emissive_strength.ts | 6 +- .../parser/gltf/extends/KHR_materials_ior.ts | 0 .../gltf/extends/KHR_materials_sheen.ts | 0 .../gltf/extends/KHR_materials_specular.ts | 0 .../extends/KHR_materials_transmission.ts | 0 .../gltf/extends/KHR_materials_unlit.ts | 0 .../gltf/extends/KHR_materials_variants.ts | 0 .../gltf/extends/KHR_materials_volume.ts | 0 .../gltf/extends/KHR_mesh_quantization.ts | 0 .../parser/gltf/extends/KHR_texture_basisu.ts | 0 .../gltf/extends/KHR_texture_transform.ts | 0 .../loader/parser/i3dm/I3DMLoader.ts | 0 .../loader/parser/i3dm/I3DMLoaderBase.ts | 0 .../loader/parser/tileRenderer/TileSet.ts | 0 .../parser/tileRenderer/TilesRenderer.ts | 0 src/{engine => }/materials/BlendMode.ts | 0 .../materials/ColorLitMaterial.ts | 7 +- src/{engine => }/materials/GlassMaterial.ts | 8 +- src/{engine => }/materials/LambertMaterial.ts | 9 +- src/{engine => }/materials/LitMaterial.ts | 8 +- src/{engine => }/materials/MaterialBase.ts | 0 src/{engine => }/materials/MaterialPass.ts | 0 .../materials/MaterialRegister.ts | 8 +- .../materials/PavementMaterial.ts | 9 +- src/{engine => }/materials/PhysicMaterial.ts | 5 +- src/{engine => }/materials/PointMaterial.ts | 5 +- src/{engine => }/materials/SkyMaterial.ts | 0 src/{engine => }/materials/UnLitMaterial.ts | 5 +- .../materials/effectPass/OutLinePass.ts | 5 +- .../multiPass/CastPointShadowMaterialPass.ts | 0 .../multiPass/CastShadowMaterialPass.ts | 0 .../materials/multiPass/DepthMaterialPass.ts | 0 .../materials/multiPass/GBufferPass.ts | 5 +- .../materials/multiPass/SkyGBufferPass.ts | 0 src/{engine => }/math/AnimationCurve.ts | 614 ++++++------ src/{engine => }/math/Bezier2D.ts | 190 ++-- src/{engine => }/math/Bezier3D.ts | 244 ++--- src/{engine => }/math/Color.ts | 878 +++++++++--------- src/{engine => }/math/HaltonSeq.ts | 0 src/{engine => }/math/Line.ts | 0 src/{engine => }/math/MathUtil.ts | 0 src/{engine => }/math/Matrix3.ts | 0 src/{engine => }/math/Matrix4.ts | 0 src/{engine => }/math/Orientation3D.ts | 0 src/math/ParticleMath.ts | 28 + src/math/ParticleSystemCurves.ts | 235 +++++ src/{engine => }/math/Plane.ts | 0 src/{engine => }/math/PolynomialCurve.ts | 510 +++++----- src/{engine => }/math/Polynomials.ts | 194 ++-- src/{engine => }/math/Quaternion.ts | 0 src/{engine => }/math/Rand.ts | 0 src/{engine => }/math/Random.ts | 0 src/{engine => }/math/Ray.ts | 0 src/{engine => }/math/Rect.ts | 0 src/{engine => }/math/TimeInterpolator.ts | 0 src/{engine => }/math/Triangle.ts | 0 src/{engine => }/math/UV.ts | 0 src/{engine => }/math/Vector2.ts | 0 src/{engine => }/math/Vector3.ts | 2 +- src/{engine => }/math/Vector4.ts | 0 src/sample/index.ts | 77 -- src/{engine => }/setting/EngineSetting.ts | 0 .../setting/GlobalIlluminationSetting.ts | 0 src/{engine => }/setting/LightSetting.ts | 0 src/{engine => }/setting/MaterialSetting.ts | 0 .../setting/OcclusionQuerySetting.ts | 0 src/{engine => }/setting/PickSetting.ts | 0 src/{engine => }/setting/RenderSetting.ts | 0 src/{engine => }/setting/ShadowSetting.ts | 0 src/{engine => }/setting/SkySetting.ts | 0 src/{engine => }/setting/post/BloomSetting.ts | 0 .../setting/post/DepthOfViewSetting.ts | 0 src/{engine => }/setting/post/GTAOSetting.ts | 2 +- .../setting/post/GlobalFogSetting.ts | 2 +- .../setting/post/OutlineSetting.ts | 0 src/{engine => }/setting/post/SSRSetting.ts | 0 src/{engine => }/setting/post/TAASetting.ts | 0 src/{engine => }/shape/BoxGeometry.ts | 0 src/{engine => }/shape/CylinderGeometry.ts | 0 src/{engine => }/shape/PlaneGeometry.ts | 0 src/{engine => }/shape/SphereGeometry.ts | 0 src/{engine => }/shape/TorusGeometry.ts | 6 +- .../textures/AtmosphericScatteringSky.ts | 0 src/{engine => }/textures/BitmapTexture2D.ts | 2 +- .../textures/BitmapTexture2DArray.ts | 7 +- .../textures/BitmapTextureCube.ts | 0 .../textures/Depth2DTextureArray.ts | 0 .../textures/DepthCubeArrayTexture.ts | 0 src/{engine => }/textures/DepthCubeTexture.ts | 0 .../textures/Float16ArrayTexture.ts | 0 .../textures/Float32ArrayTexture.ts | 0 src/{engine => }/textures/HDRTexture.ts | 0 src/{engine => }/textures/HDRTextureCube.ts | 0 src/{engine => }/textures/LDRTextureCube.ts | 2 +- src/{engine => }/textures/SolidColorSky.ts | 7 +- src/{engine => }/textures/Uint16Texture.ts | 0 .../textures/Uint8ArrayTexture.ts | 0 src/{engine => }/textures/VirtualTexture.ts | 0 src/{engine => }/util/AxisObject.ts | 2 +- src/{engine => }/util/BytesStream.ts | 0 src/{engine => }/util/CameraUtil.ts | 0 src/{engine => }/util/Convert.ts | 0 src/{engine => }/util/GeometryUtil.ts | 0 src/{engine => }/util/Global.ts | 0 src/{engine => }/util/KelvinUtil.ts | 0 src/{engine => }/util/Object3DUtil.ts | 0 src/{engine => }/util/ProfilerUtil.ts | 0 src/{engine => }/util/StringUtil.ts | 0 src/{engine => }/util/Time.ts | 0 src/{engine => }/util/Vector3Ex.ts | 0 src/{engine => }/util/ZSorterUtil.ts | 2 +- src/{engine => }/util/struct/Struct.ts | 0 src/{engine => }/util/struct/StructValue.ts | 0 src/{engine => }/util/struct/Vector3Struct.ts | 0 test/base/base.test.ts | 3 +- tsconfig.json | 3 +- 492 files changed, 7551 insertions(+), 3548 deletions(-) rename src/{engine => }/Engine3D.ts (84%) rename src/{engine => }/assets/Res.ts (70%) rename src/{engine => }/assets/shader/ShaderLib.ts (84%) rename src/{engine => }/assets/shader/anim/SkeletonAnimation_shader.ts (100%) rename src/{engine => }/assets/shader/cluster/ClusterBoundsSource_cs.wgsl (100%) rename src/{engine => }/assets/shader/cluster/ClusterLighting_cs.wgsl (100%) rename src/{engine => }/assets/shader/compute/BLUR_CsShader.wgsl (100%) rename src/{engine => }/assets/shader/compute/BlurEffectCreator_compute.ts (100%) rename src/{engine => }/assets/shader/compute/DepthOfView_CsShader.wgsl (100%) rename src/{engine => }/assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl (100%) rename src/{engine => }/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl (100%) rename src/{engine => }/assets/shader/compute/GTAOCs.wgsl (100%) rename src/{engine => }/assets/shader/compute/IBLEnvMapCreator_compute.wgsl (100%) rename src/{engine => }/assets/shader/compute/MergeRGBA_Cs.wgsl (100%) rename src/{engine => }/assets/shader/compute/MultiBouncePass_Shader.wgsl (100%) rename src/{engine => }/assets/shader/compute/OutLineBlendColor.wgsl (100%) rename src/{engine => }/assets/shader/compute/OutlineCalcOutline.wgsl (100%) rename src/{engine => }/assets/shader/compute/OutlineCs.wgsl (100%) rename src/{engine => }/assets/shader/compute/Picker_CsShader.wgsl (100%) rename src/{engine => }/assets/shader/compute/SSAO_CsShader.wgsl (100%) rename src/{engine => }/assets/shader/compute/SSR_BlendColor_Shader.wgsl (100%) rename src/{engine => }/assets/shader/compute/SSR_IS_Shader.wgsl (100%) rename src/{engine => }/assets/shader/compute/SSR_RayTrace_Shader.wgsl (100%) rename src/{engine => }/assets/shader/compute/TAACopyTex.wgsl (100%) rename src/{engine => }/assets/shader/compute/TAASharpTex.wgsl (100%) rename src/{engine => }/assets/shader/compute/TAAcs.wgsl (100%) rename src/{engine => }/assets/shader/core/base/Common_frag.wgsl (100%) rename src/{engine => }/assets/shader/core/base/Common_vert.wgsl (100%) rename src/{engine => }/assets/shader/core/common/BrdfLut_frag.wgsl (100%) rename src/{engine => }/assets/shader/core/common/EnvMap_frag.wgsl (100%) rename src/{engine => }/assets/shader/core/common/GlobalUniform.wgsl (100%) rename src/{engine => }/assets/shader/core/common/InstanceUniform.wgsl (100%) rename src/{engine => }/assets/shader/core/common/WorldMatrixUniform.wgsl (100%) rename src/{engine => }/assets/shader/core/inline/Inline_vert.wgsl (100%) rename src/{engine => }/assets/shader/core/pass/CastShadowPass_wgsl.ts (100%) rename src/{engine => }/assets/shader/core/pass/FrustumCullingShader_cs.wgsl (100%) rename src/{engine => }/assets/shader/core/pass/GBuffer_shader.wgsl (100%) rename src/{engine => }/assets/shader/core/pass/SkyGBuffer_fs.wgsl (100%) rename src/{engine => }/assets/shader/core/pass/ZPassShader_cs.wgsl (100%) rename src/{engine => }/assets/shader/core/pass/ZPassShader_fs.wgsl (100%) rename src/{engine => }/assets/shader/core/pass/ZPassShader_vs.ts (100%) rename src/{engine => }/assets/shader/core/struct/ColorPassFragmentOutput.wgsl (100%) rename src/{engine => }/assets/shader/core/struct/EmptyFrag_CommonFragment.wgsl (100%) rename src/{engine => }/assets/shader/core/struct/EmptyFrag_FragmentOutput.wgsl (100%) rename src/{engine => }/assets/shader/core/struct/FragmentVarying.wgsl (100%) rename src/{engine => }/assets/shader/core/struct/LightStruct.wgsl (100%) rename src/{engine => }/assets/shader/core/struct/LightStructFrag.ts (100%) rename src/{engine => }/assets/shader/core/struct/ShadingInput.wgsl (100%) rename src/{engine => }/assets/shader/core/struct/VertexAttributes.ts (100%) rename src/{engine => }/assets/shader/glsl/Quad_glsl.ts (100%) rename src/{engine => }/assets/shader/glsl/Sky_glsl.ts (100%) rename src/{engine => }/assets/shader/glsl/post/LUT_glsl.ts (100%) rename src/{engine => }/assets/shader/graphic/Graphic3DShader_fs.wgsl (100%) rename src/{engine => }/assets/shader/graphic/Graphic3DShader_vs.wgsl (100%) rename src/{engine => }/assets/shader/lighting/BRDF_frag.wgsl (100%) rename src/{engine => }/assets/shader/lighting/BxDF_frag.wgsl (100%) rename src/{engine => }/assets/shader/lighting/IESProfiles_frag.wgsl (100%) create mode 100644 src/assets/shader/lighting/IrradianceVolumeData_frag.ts rename src/{engine => }/assets/shader/lighting/Irradiance_frag.wgsl (100%) rename src/{engine => }/assets/shader/lighting/LightingFunction_frag.ts (100%) rename src/{engine => }/assets/shader/lighting/UnLit_frag.ts (100%) rename src/{engine => }/assets/shader/materials/ColorLitShader.ts (100%) rename src/{engine => }/assets/shader/materials/GlassShader.wgsl (100%) rename src/{engine => }/assets/shader/materials/Lambert_shader.ts (100%) rename src/{engine => }/assets/shader/materials/LitShader.wgsl (100%) rename src/{engine => }/assets/shader/materials/OutlinePass.wgsl (100%) rename src/{engine => }/assets/shader/materials/PBRLItShader.wgsl (100%) rename src/{engine => }/assets/shader/materials/PavementShader.ts (100%) rename src/{engine => }/assets/shader/materials/PointShadowDebug.ts (100%) rename src/{engine => }/assets/shader/materials/UnLit.wgsl (100%) create mode 100644 src/assets/shader/materials/compute/BLUR_CsShader.wgsl create mode 100644 src/assets/shader/materials/compute/DepthOfView_CsShader.wgsl create mode 100644 src/assets/shader/materials/compute/ErpImage2CubeMapCreateCube_compute.wgsl create mode 100644 src/assets/shader/materials/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl create mode 100644 src/assets/shader/materials/compute/GTAOCs.wgsl create mode 100644 src/assets/shader/materials/compute/IBLEnvMapCreator_compute.wgsl create mode 100644 src/assets/shader/materials/compute/MergeRGBA_Cs.wgsl create mode 100644 src/assets/shader/materials/compute/MultiBouncePass_Shader.wgsl create mode 100644 src/assets/shader/materials/compute/OutLineBlendColor.wgsl create mode 100644 src/assets/shader/materials/compute/OutlineCalcOutline.wgsl create mode 100644 src/assets/shader/materials/compute/OutlineCs.wgsl create mode 100644 src/assets/shader/materials/compute/Picker_CsShader.wgsl create mode 100644 src/assets/shader/materials/compute/SSAO_CsShader.wgsl create mode 100644 src/assets/shader/materials/compute/SSR_BlendColor_Shader.wgsl create mode 100644 src/assets/shader/materials/compute/SSR_IS_Shader.wgsl create mode 100644 src/assets/shader/materials/compute/SSR_RayTrace_Shader.wgsl create mode 100644 src/assets/shader/materials/compute/TAACopyTex.wgsl create mode 100644 src/assets/shader/materials/compute/TAASharpTex.wgsl create mode 100644 src/assets/shader/materials/compute/TAAcs.wgsl create mode 100644 src/assets/shader/materials/core/base/Common_frag.wgsl create mode 100644 src/assets/shader/materials/core/base/Common_vert.wgsl create mode 100644 src/assets/shader/materials/core/common/BrdfLut_frag.wgsl create mode 100644 src/assets/shader/materials/core/common/EnvMap_frag.wgsl create mode 100644 src/assets/shader/materials/core/common/GlobalUniform.wgsl create mode 100644 src/assets/shader/materials/core/common/InstanceUniform.wgsl create mode 100644 src/assets/shader/materials/core/common/WorldMatrixUniform.wgsl create mode 100644 src/assets/shader/materials/core/inline/Inline_vert.wgsl create mode 100644 src/assets/shader/materials/graphic/Graphic3DShader_fs.wgsl create mode 100644 src/assets/shader/materials/graphic/Graphic3DShader_vs.wgsl create mode 100644 src/assets/shader/materials/materials/GlassShader.wgsl create mode 100644 src/assets/shader/materials/materials/LitShader.wgsl create mode 100644 src/assets/shader/materials/materials/OutlinePass.wgsl create mode 100644 src/assets/shader/materials/materials/PBRLItShader.wgsl create mode 100644 src/assets/shader/materials/materials/UnLit.wgsl rename src/{engine/assets/shader => assets/shader/materials}/materials/sky/AtmosphericScatteringSky_shader.ts (100%) rename src/{engine/assets/shader => assets/shader/materials}/materials/sky/CubeSky_Shader.ts (100%) rename src/{engine/assets/shader => assets/shader/materials}/math/FastMathShader.wgsl (100%) rename src/{engine/assets/shader => assets/shader/materials}/post/FSAAShader.wgsl (100%) rename src/{engine => }/assets/shader/materials/program/BxdfDebug_frag.wgsl (100%) rename src/{engine => }/assets/shader/materials/program/Clearcoat_frag.wgsl (100%) rename src/{engine => }/assets/shader/materials/program/ClusterDebug_frag.ts (100%) rename src/{engine => }/assets/shader/materials/program/NormalMap_frag.wgsl (100%) rename src/{engine => }/assets/shader/materials/program/ShadowMapping_frag.wgsl (100%) create mode 100644 src/assets/shader/materials/sky/AtmosphericScatteringSky_shader.ts create mode 100644 src/assets/shader/materials/sky/CubeSky_Shader.ts rename src/{engine => }/assets/shader/materials/uniforms/MaterialUniform.ts (100%) rename src/{engine => }/assets/shader/materials/uniforms/PhysicMaterialUniform_frag.ts (100%) rename src/{engine => }/assets/shader/materials/uniforms/UnLitMaterialUniform_frag.ts (100%) rename src/{engine => }/assets/shader/materials/uniforms/VideoUniform_frag.ts (100%) rename src/{engine/assets/shader => assets/shader/materials}/utils/BRDFLUT.wgsl (100%) rename src/{engine/assets/shader => assets/shader/materials}/utils/ColorUtil.wgsl (100%) rename src/{engine/assets/shader => assets/shader/materials}/utils/GenerayRandomDir.wgsl (100%) create mode 100644 src/assets/shader/math/FastMathShader.wgsl rename src/{engine => }/assets/shader/math/MathShader.ts (100%) rename src/{engine => }/assets/shader/post/Bloom_shader.ts (100%) create mode 100644 src/assets/shader/post/FSAAShader.wgsl rename src/{engine => }/assets/shader/post/GlobalFog_shader.ts (100%) rename src/{engine => }/assets/shader/quad/Quad_shader.ts (100%) create mode 100644 src/assets/shader/utils/BRDFLUT.wgsl create mode 100644 src/assets/shader/utils/ColorUtil.wgsl create mode 100644 src/assets/shader/utils/GenerayRandomDir.wgsl rename src/{engine => }/components/AtmosphericComponent.ts (95%) rename src/{engine => }/components/BillboardComponent.ts (98%) rename src/{engine => }/components/ColliderComponent.ts (98%) rename src/{engine => }/components/ComponentBase.ts (74%) create mode 100644 src/components/IComponent.ts rename src/{engine => }/components/SkeletonAnimationComponent.ts (99%) rename src/{engine => }/components/Transform.ts (100%) rename src/{engine => }/components/anim/OAnimationEvent.ts (100%) rename src/{engine => }/components/anim/curveAnim/curveAnim/AnimationMonitor.ts (100%) rename src/{engine => }/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts (100%) rename src/{engine => }/components/anim/curveAnim/curveAnim/PropertyAnimClip.ts (100%) rename src/{engine => }/components/anim/curveAnim/curveAnim/PropertyAnimation.ts (100%) rename src/{engine => }/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts (100%) rename src/{engine => }/components/anim/curveAnim/curveAnim/PropertyHelp.ts (100%) rename src/{engine => }/components/anim/morphAnim/MorphTargetBlender.ts (99%) rename src/{engine => }/components/anim/morphAnim/MorphTargetData.ts (100%) rename src/{engine => }/components/anim/morphAnim/MorphTargetFrame.ts (100%) rename src/{engine => }/components/anim/morphAnim/MorphTargetKey.ts (100%) rename src/{engine => }/components/anim/morphAnim/MorphTarget_shader.ts (100%) rename src/{engine => }/components/anim/skeletonAnim/Joint.ts (100%) rename src/{engine => }/components/anim/skeletonAnim/JointPose.ts (100%) rename src/{engine => }/components/anim/skeletonAnim/Skeleton.ts (100%) rename src/{engine => }/components/anim/skeletonAnim/SkeletonAnimationClip.ts (100%) rename src/{engine => }/components/anim/skeletonAnim/SkeletonAnimationClipState.ts (100%) rename src/{engine => }/components/anim/skeletonAnim/SkeletonAnimationCompute.ts (100%) rename src/{engine => }/components/anim/skeletonAnim/SkeletonPose.ts (100%) rename src/{engine => }/components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs.ts (100%) rename src/{engine => }/components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs.ts (100%) rename src/{engine => }/components/anim/skeletonAnim/shader/compute_skeleton_blend.ts (100%) rename src/{engine => }/components/anim/skeletonAnim/shader/compute_skeleton_transform.ts (100%) rename src/{engine => }/components/audio/AudioListener.ts (94%) rename src/{engine => }/components/audio/PositionAudio.ts (96%) rename src/{engine => }/components/audio/StaticAudio.ts (96%) rename src/{engine => }/components/controller/CameraControllerBase.ts (100%) rename src/{engine => }/components/controller/FirstPersonCameraController.ts (99%) rename src/{engine => }/components/controller/FlyCameraController.ts (99%) rename src/{engine => }/components/controller/HoverCameraController.ts (99%) rename src/{engine => }/components/controller/OrbitController.ts (96%) rename src/{engine => }/components/controller/ThirdPersonCameraController.ts (99%) rename src/{engine => }/components/lights/DirectLight.ts (97%) rename src/{engine => }/components/lights/GILighting.ts (68%) rename src/{engine => }/components/lights/IESProfiles.ts (100%) create mode 100644 src/components/lights/ILight.ts rename src/{engine => }/components/lights/LightBase.ts (96%) rename src/{engine => }/components/lights/LightData.ts (100%) rename src/{engine => }/components/lights/PointLight.ts (96%) rename src/{engine => }/components/lights/SpotLight.ts (97%) rename src/{engine => }/components/post/PostProcessingComponent.ts (91%) rename src/{engine => }/components/renderer/InstanceDrawComponent.ts (94%) rename src/{engine => }/components/renderer/MaterialComponent.ts (100%) rename src/{engine => }/components/renderer/MeshComponent.ts (98%) rename src/{engine => }/components/renderer/MeshRenderer.ts (91%) rename src/{engine => }/components/renderer/RenderNode.ts (94%) rename src/{engine => }/components/renderer/SkinnedMeshRenderer.ts (94%) rename src/{engine => }/components/renderer/SkyRenderer.ts (89%) rename src/{engine => }/components/shape/BoxColliderShape.ts (100%) rename src/{engine => }/components/shape/CapsuleColliderShape.ts (100%) rename src/{engine => }/components/shape/ColliderShape.ts (100%) rename src/{engine => }/components/shape/MeshColliderShape.ts (100%) rename src/{engine => }/components/shape/SphereColliderShape.ts (100%) rename src/{engine => }/core/Camera3D.ts (99%) rename src/{engine => }/core/CameraType.ts (100%) rename src/{engine => }/core/CubeCamera.ts (100%) rename src/{engine => }/core/PointShadowCubeCamera.ts (100%) rename src/{engine => }/core/Scene3D.ts (68%) rename src/{engine => }/core/View3D.ts (100%) rename src/{engine => }/core/ViewQuad.ts (53%) rename src/{engine => }/core/bound/BoundingBox.ts (100%) rename src/{engine => }/core/bound/BoundingSphere.ts (99%) rename src/{engine => }/core/bound/Frustum.ts (95%) rename src/{engine => }/core/bound/IBound.ts (99%) rename src/{engine => }/core/entities/Entity.ts (95%) rename src/{engine => }/core/entities/InstancedMesh.ts (100%) rename src/{engine => }/core/entities/Object3D.ts (87%) rename src/{engine => }/core/geometry/GeometryBase.ts (99%) rename src/{engine => }/core/geometry/GeometryIndicesBuffer.ts (98%) rename src/{engine => }/core/geometry/GeometryVertexBuffer.ts (100%) rename src/{engine => }/core/geometry/GeometryVertexType.ts (100%) rename src/{engine => }/core/geometry/VertexAttribute.ts (100%) rename src/{engine => }/core/geometry/VertexAttributeData.ts (85%) rename src/{engine => }/core/geometry/VertexAttributeName.ts (100%) rename src/{engine => }/core/geometry/VertexAttributeSize.ts (100%) rename src/{engine => }/core/geometry/VertexAttributeStride.ts (100%) rename src/{engine => }/core/geometry/VertexFormat.ts (100%) rename src/{engine => }/core/pool/ObjectPool.ts (100%) rename src/{engine => }/core/pool/memory/MatrixDO.ts (100%) rename src/{engine => }/core/pool/memory/MemoryDO.ts (100%) rename src/{engine => }/core/pool/memory/MemoryInfo.ts (100%) rename src/{engine => }/core/tree/kdTree/IKDTreeUserData.ts (100%) rename src/{engine => }/core/tree/kdTree/KDTreeEntity.ts (100%) rename src/{engine => }/core/tree/kdTree/KDTreeNode.ts (100%) rename src/{engine => }/core/tree/kdTree/KDTreeSpace.ts (100%) delete mode 100644 src/engine/textures/DefaultRes.ts rename src/{engine => }/event/CEvent.ts (95%) rename src/{engine => }/event/CEventDispatcher.ts (95%) rename src/{engine => }/event/CEventListener.ts (96%) rename src/{engine => }/event/CResizeEvent.ts (95%) rename src/{engine => }/event/KeyCode.ts (94%) rename src/{engine => }/event/MouseCode.ts (92%) rename src/{engine => }/event/eventConst/KeyEvent.ts (100%) rename src/{engine => }/event/eventConst/LoaderEvent.ts (100%) rename src/{engine => }/event/eventConst/Object3DEvent.ts (100%) rename src/{engine => }/event/eventConst/PointerEvent3D.ts (100%) rename src/{engine => }/event/eventConst/UIEvent.ts (100%) create mode 100644 src/gfx/data/IrradianceVolume.ts rename src/{engine => }/gfx/generate/BrdfLUTGenerate.ts (100%) rename src/{engine => }/gfx/generate/PassGenerate.ts (96%) rename src/{engine => }/gfx/generate/convert/BlurEffectCreator.ts (100%) rename src/{engine => }/gfx/generate/convert/ErpImage2CubeMap.ts (100%) rename src/{engine => }/gfx/generate/convert/IBLEnvMapCreator.ts (100%) rename src/{engine => }/gfx/generate/convert/MergeRGBACreator.ts (100%) rename src/{engine => }/gfx/generate/convert/TextureCubeStdCreator.ts (100%) rename src/{engine => }/gfx/generate/convert/TextureCubeUtils.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/CanvasConfig.ts (94%) rename src/{engine => }/gfx/graphics/webGpu/Context3D.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/WebGPUConst.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts (98%) rename src/{engine => }/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts (92%) create mode 100644 src/gfx/graphics/webGpu/core/buffer/ArrayBufferData.ts rename src/{engine => }/gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer.ts (80%) rename src/{engine => }/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts (93%) create mode 100644 src/gfx/graphics/webGpu/core/buffer/GPUBufferType.ts rename src/{engine => }/gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer.ts (86%) rename src/{engine => }/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts (94%) rename src/{engine => }/gfx/graphics/webGpu/core/buffer/StorageGPUBuffer.ts (71%) rename src/{engine => }/gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer.ts (84%) rename src/{engine => }/gfx/graphics/webGpu/core/buffer/UniformGPUBuffer.ts (84%) rename src/{engine => }/gfx/graphics/webGpu/core/buffer/VertexGPUBuffer.ts (88%) rename src/{engine => }/gfx/graphics/webGpu/core/texture/ITexture.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/core/texture/Texture.ts (98%) rename src/{engine => }/gfx/graphics/webGpu/core/texture/TextureCube.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/core/texture/TextureMipmapCompute.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/core/texture/TextureMipmapGenerator.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/core/uniforms/UniformNode.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/descriptor/RTDescriptor.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/ComputeShader.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/RenderShader.ts (95%) rename src/{engine => }/gfx/graphics/webGpu/shader/ShaderBase.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/ShaderStage.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/converter/GLSLLexer.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/converter/GLSLLexerToken.ts (87%) rename src/{engine => }/gfx/graphics/webGpu/shader/converter/GLSLPreprocessor.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/converter/GLSLSyntax.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/converter/Reader.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/converter/ShaderConverter.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/converter/StatementNode.ts (99%) rename src/{engine => }/gfx/graphics/webGpu/shader/converter/WGSLTranslator.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/util/MorePassParser.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/util/Preprocessor.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/util/ShaderUtil.ts (54%) rename src/{engine => }/gfx/graphics/webGpu/shader/value/ConstValue.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/value/DefineValue.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/value/ShaderReflectionInfo.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/value/ShaderState.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/value/ShaderValue.ts (100%) rename src/{engine => }/gfx/graphics/webGpu/shader/value/UniformValue.ts (85%) rename src/{engine => }/gfx/renderJob/GPUContext.ts (72%) rename src/{engine => }/gfx/renderJob/collect/CollectInfo.ts (100%) create mode 100644 src/gfx/renderJob/collect/ComponentCollect.ts rename src/{engine => }/gfx/renderJob/collect/EntityBatchCollect.ts (100%) rename src/{engine => }/gfx/renderJob/collect/EntityCollect.ts (91%) rename src/{engine => }/gfx/renderJob/collect/RenderGroup.ts (100%) rename src/{engine => }/gfx/renderJob/collect/ShadowLightsCollect.ts (82%) rename src/{engine => }/gfx/renderJob/config/RTResourceConfig.ts (100%) rename src/{engine => }/gfx/renderJob/config/RenderLayer.ts (100%) rename src/{engine => }/gfx/renderJob/frame/GBufferFrame.ts (100%) rename src/{engine => }/gfx/renderJob/frame/ProbeGBufferFrame.ts (100%) rename src/{engine => }/gfx/renderJob/frame/RTFrame.ts (100%) rename src/{engine => }/gfx/renderJob/frame/RTResourceMap.ts (96%) rename src/{engine => }/gfx/renderJob/jobs/ForwardRenderJob.ts (97%) rename src/{engine => }/gfx/renderJob/jobs/RenderMap.ts (100%) rename src/{engine => }/gfx/renderJob/jobs/RendererJob.ts (92%) rename src/{engine => }/gfx/renderJob/occlusion/OcclusionSystem.ts (100%) rename src/{engine => }/gfx/renderJob/passRenderer/RenderContext.ts (100%) rename src/{engine => }/gfx/renderJob/passRenderer/RendererBase.ts (92%) create mode 100644 src/gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer.ts rename src/{engine => }/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts (62%) rename src/{engine/gfx/renderJob => gfx/renderJob/passRenderer}/color/ColorPassRenderer.ts (78%) rename src/{engine => }/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts (93%) rename src/{engine => }/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts (100%) rename src/{engine => }/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts (100%) rename src/{engine => }/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts (100%) rename src/{engine => }/gfx/renderJob/passRenderer/graphic/Graphic3DRender.ts (100%) rename src/{engine => }/gfx/renderJob/passRenderer/graphic/GraphicConfig.ts (100%) rename src/{engine => }/gfx/renderJob/passRenderer/graphic/Graphics3DShape.ts (100%) rename src/{engine => }/gfx/renderJob/passRenderer/post/PostRenderer.ts (89%) rename src/{engine => }/gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer.ts (100%) rename src/{engine => }/gfx/renderJob/passRenderer/preDepth/ZCullingCompute.ts (100%) rename src/{engine => }/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts (97%) rename src/{engine => }/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts (96%) rename src/{engine => }/gfx/renderJob/passRenderer/state/RendererMask.ts (95%) rename src/{engine => }/gfx/renderJob/passRenderer/state/RendererPassState.ts (91%) rename src/{engine => }/gfx/renderJob/passRenderer/state/RendererType.ts (100%) rename src/{engine => }/gfx/renderJob/post/DepthOfFieldPost.ts (99%) rename src/{engine => }/gfx/renderJob/post/FXAAPost.ts (89%) rename src/{engine => }/gfx/renderJob/post/GTAOPost.ts (100%) rename src/{engine => }/gfx/renderJob/post/GlobalFog.ts (93%) rename src/{engine => }/gfx/renderJob/post/HDRBloomPost.ts (83%) rename src/{engine => }/gfx/renderJob/post/OutlinePost.ts (96%) rename src/{engine => }/gfx/renderJob/post/PostBase.ts (96%) rename src/{engine => }/gfx/renderJob/post/SSRPost.ts (98%) rename src/{engine => }/gfx/renderJob/post/TAAPost.ts (100%) rename src/{engine => }/io/InputSystem.ts (99%) rename src/{engine => }/io/PickFire.ts (100%) rename src/{engine => }/io/PickResult.ts (100%) rename src/{engine => }/io/RayCastMeshDetail.ts (100%) rename src/{engine => }/io/TouchData.ts (98%) rename src/{engine => }/io/picker/PickCompute.ts (100%) rename src/{engine => }/loader/FileLoader.ts (100%) rename src/{engine => }/loader/LoaderBase.ts (100%) rename src/{engine => }/loader/LoaderData.ts (100%) rename src/{engine => }/loader/LoaderFunctions.ts (100%) rename src/{engine => }/loader/LoaderManager.ts (100%) rename src/{engine => }/loader/parser/B3DMParser.ts (100%) rename src/{engine => }/loader/parser/I3DMParser.ts (100%) rename src/{engine => }/loader/parser/OBJParser.ts (99%) rename src/{engine => }/loader/parser/ParserBase.ts (100%) rename src/{engine => }/loader/parser/RGBEParser.ts (100%) rename src/{engine => }/loader/parser/b3dm/B3DMLoader.ts (94%) rename src/{engine => }/loader/parser/b3dm/B3DMLoaderBase.ts (100%) rename src/{engine => }/loader/parser/b3dm/FeatureTable.ts (100%) rename src/{engine => }/loader/parser/b3dm/arrayToString.ts (100%) rename src/{engine => }/loader/parser/b3dm/readMagicBytes.ts (100%) rename src/{engine => }/loader/parser/gltf/GLBParser.ts (92%) rename src/{engine => }/loader/parser/gltf/GLTFInfo.ts (97%) rename src/{engine => }/loader/parser/gltf/GLTFParser.ts (76%) rename src/{engine => }/loader/parser/gltf/GLTFSubParser.ts (57%) rename src/{engine => }/loader/parser/gltf/GLTFSubParserCamera.ts (97%) rename src/{engine => }/loader/parser/gltf/GLTFSubParserConverter.ts (98%) rename src/{engine => }/loader/parser/gltf/GLTFSubParserMaterial.ts (93%) rename src/{engine => }/loader/parser/gltf/GLTFSubParserMesh.ts (94%) rename src/{engine => }/loader/parser/gltf/GLTFSubParserSkeleton.ts (99%) rename src/{engine => }/loader/parser/gltf/GLTFSubParserSkin.ts (94%) create mode 100644 src/loader/parser/gltf/GLTFType.ts rename src/{engine => }/loader/parser/gltf/TypeArray.ts (100%) rename src/{engine => }/loader/parser/gltf/extends/KHR_draco_mesh_compression.ts (100%) rename src/{engine => }/loader/parser/gltf/extends/KHR_lights_punctual.ts (100%) rename src/{engine => }/loader/parser/gltf/extends/KHR_materials_clearcoat.ts (100%) rename src/{engine => }/loader/parser/gltf/extends/KHR_materials_emissive_strength.ts (73%) rename src/{engine => }/loader/parser/gltf/extends/KHR_materials_ior.ts (100%) rename src/{engine => }/loader/parser/gltf/extends/KHR_materials_sheen.ts (100%) rename src/{engine => }/loader/parser/gltf/extends/KHR_materials_specular.ts (100%) rename src/{engine => }/loader/parser/gltf/extends/KHR_materials_transmission.ts (100%) rename src/{engine => }/loader/parser/gltf/extends/KHR_materials_unlit.ts (100%) rename src/{engine => }/loader/parser/gltf/extends/KHR_materials_variants.ts (100%) rename src/{engine => }/loader/parser/gltf/extends/KHR_materials_volume.ts (100%) rename src/{engine => }/loader/parser/gltf/extends/KHR_mesh_quantization.ts (100%) rename src/{engine => }/loader/parser/gltf/extends/KHR_texture_basisu.ts (100%) rename src/{engine => }/loader/parser/gltf/extends/KHR_texture_transform.ts (100%) rename src/{engine => }/loader/parser/i3dm/I3DMLoader.ts (100%) rename src/{engine => }/loader/parser/i3dm/I3DMLoaderBase.ts (100%) rename src/{engine => }/loader/parser/tileRenderer/TileSet.ts (100%) rename src/{engine => }/loader/parser/tileRenderer/TilesRenderer.ts (100%) rename src/{engine => }/materials/BlendMode.ts (100%) rename src/{engine => }/materials/ColorLitMaterial.ts (87%) rename src/{engine => }/materials/GlassMaterial.ts (93%) rename src/{engine => }/materials/LambertMaterial.ts (91%) rename src/{engine => }/materials/LitMaterial.ts (93%) rename src/{engine => }/materials/MaterialBase.ts (100%) rename src/{engine => }/materials/MaterialPass.ts (100%) rename src/{engine => }/materials/MaterialRegister.ts (71%) rename src/{engine => }/materials/PavementMaterial.ts (88%) rename src/{engine => }/materials/PhysicMaterial.ts (98%) rename src/{engine => }/materials/PointMaterial.ts (94%) rename src/{engine => }/materials/SkyMaterial.ts (100%) rename src/{engine => }/materials/UnLitMaterial.ts (94%) rename src/{engine => }/materials/effectPass/OutLinePass.ts (93%) rename src/{engine => }/materials/multiPass/CastPointShadowMaterialPass.ts (100%) rename src/{engine => }/materials/multiPass/CastShadowMaterialPass.ts (100%) rename src/{engine => }/materials/multiPass/DepthMaterialPass.ts (100%) rename src/{engine => }/materials/multiPass/GBufferPass.ts (93%) rename src/{engine => }/materials/multiPass/SkyGBufferPass.ts (100%) rename src/{engine => }/math/AnimationCurve.ts (96%) rename src/{engine => }/math/Bezier2D.ts (96%) rename src/{engine => }/math/Bezier3D.ts (96%) rename src/{engine => }/math/Color.ts (96%) rename src/{engine => }/math/HaltonSeq.ts (100%) rename src/{engine => }/math/Line.ts (100%) rename src/{engine => }/math/MathUtil.ts (100%) rename src/{engine => }/math/Matrix3.ts (100%) rename src/{engine => }/math/Matrix4.ts (100%) rename src/{engine => }/math/Orientation3D.ts (100%) create mode 100644 src/math/ParticleMath.ts create mode 100644 src/math/ParticleSystemCurves.ts rename src/{engine => }/math/Plane.ts (100%) rename src/{engine => }/math/PolynomialCurve.ts (97%) rename src/{engine => }/math/Polynomials.ts (96%) rename src/{engine => }/math/Quaternion.ts (100%) rename src/{engine => }/math/Rand.ts (100%) rename src/{engine => }/math/Random.ts (100%) rename src/{engine => }/math/Ray.ts (100%) rename src/{engine => }/math/Rect.ts (100%) rename src/{engine => }/math/TimeInterpolator.ts (100%) rename src/{engine => }/math/Triangle.ts (100%) rename src/{engine => }/math/UV.ts (100%) rename src/{engine => }/math/Vector2.ts (100%) rename src/{engine => }/math/Vector3.ts (99%) rename src/{engine => }/math/Vector4.ts (100%) delete mode 100644 src/sample/index.ts rename src/{engine => }/setting/EngineSetting.ts (100%) rename src/{engine => }/setting/GlobalIlluminationSetting.ts (100%) rename src/{engine => }/setting/LightSetting.ts (100%) rename src/{engine => }/setting/MaterialSetting.ts (100%) rename src/{engine => }/setting/OcclusionQuerySetting.ts (100%) rename src/{engine => }/setting/PickSetting.ts (100%) rename src/{engine => }/setting/RenderSetting.ts (100%) rename src/{engine => }/setting/ShadowSetting.ts (100%) rename src/{engine => }/setting/SkySetting.ts (100%) rename src/{engine => }/setting/post/BloomSetting.ts (100%) rename src/{engine => }/setting/post/DepthOfViewSetting.ts (100%) rename src/{engine => }/setting/post/GTAOSetting.ts (88%) rename src/{engine => }/setting/post/GlobalFogSetting.ts (95%) rename src/{engine => }/setting/post/OutlineSetting.ts (100%) rename src/{engine => }/setting/post/SSRSetting.ts (100%) rename src/{engine => }/setting/post/TAASetting.ts (100%) rename src/{engine => }/shape/BoxGeometry.ts (100%) rename src/{engine => }/shape/CylinderGeometry.ts (100%) rename src/{engine => }/shape/PlaneGeometry.ts (100%) rename src/{engine => }/shape/SphereGeometry.ts (100%) rename src/{engine => }/shape/TorusGeometry.ts (97%) rename src/{engine => }/textures/AtmosphericScatteringSky.ts (100%) rename src/{engine => }/textures/BitmapTexture2D.ts (100%) rename src/{engine => }/textures/BitmapTexture2DArray.ts (99%) rename src/{engine => }/textures/BitmapTextureCube.ts (100%) rename src/{engine => }/textures/Depth2DTextureArray.ts (100%) rename src/{engine => }/textures/DepthCubeArrayTexture.ts (100%) rename src/{engine => }/textures/DepthCubeTexture.ts (100%) rename src/{engine => }/textures/Float16ArrayTexture.ts (100%) rename src/{engine => }/textures/Float32ArrayTexture.ts (100%) rename src/{engine => }/textures/HDRTexture.ts (100%) rename src/{engine => }/textures/HDRTextureCube.ts (100%) rename src/{engine => }/textures/LDRTextureCube.ts (98%) rename src/{engine => }/textures/SolidColorSky.ts (81%) rename src/{engine => }/textures/Uint16Texture.ts (100%) rename src/{engine => }/textures/Uint8ArrayTexture.ts (100%) rename src/{engine => }/textures/VirtualTexture.ts (100%) rename src/{engine => }/util/AxisObject.ts (97%) rename src/{engine => }/util/BytesStream.ts (100%) rename src/{engine => }/util/CameraUtil.ts (100%) rename src/{engine => }/util/Convert.ts (100%) rename src/{engine => }/util/GeometryUtil.ts (100%) rename src/{engine => }/util/Global.ts (100%) rename src/{engine => }/util/KelvinUtil.ts (100%) rename src/{engine => }/util/Object3DUtil.ts (100%) rename src/{engine => }/util/ProfilerUtil.ts (100%) rename src/{engine => }/util/StringUtil.ts (100%) rename src/{engine => }/util/Time.ts (100%) rename src/{engine => }/util/Vector3Ex.ts (100%) rename src/{engine => }/util/ZSorterUtil.ts (97%) rename src/{engine => }/util/struct/Struct.ts (100%) rename src/{engine => }/util/struct/StructValue.ts (100%) rename src/{engine => }/util/struct/Vector3Struct.ts (100%) diff --git a/index.html b/index.html index 96c1214a..adbfe2f2 100644 --- a/index.html +++ b/index.html @@ -72,7 +72,7 @@ - + \ No newline at end of file diff --git a/src/engine/Engine3D.ts b/src/Engine3D.ts similarity index 84% rename from src/engine/Engine3D.ts rename to src/Engine3D.ts index 5fc4120b..1798d480 100644 --- a/src/engine/Engine3D.ts +++ b/src/Engine3D.ts @@ -1,27 +1,28 @@ -import { version } from '../../package.json'; -import { Res } from './assets/Res'; -import { ShaderLib } from './assets/shader/ShaderLib'; +import { CanvasConfig } from './gfx/graphics/webGpu/CanvasConfig'; +import { Color } from './math/Color'; +import { EngineSetting } from './setting/EngineSetting'; +import { Time } from './util/Time'; +import { InputSystem } from './io/InputSystem'; import { View3D } from './core/View3D'; +import { version } from '../package.json'; import { webGPUContext } from './gfx/graphics/webGpu/Context3D'; -import { CanvasConfig } from './gfx/graphics/webGpu/CanvasConfig'; +import { FXAAPost } from './gfx/renderJob/post/FXAAPost'; +import { ForwardRenderJob } from './gfx/renderJob/jobs/ForwardRenderJob'; import { GlobalBindGroup } from './gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup'; +import { Interpolator } from './math/TimeInterpolator'; import { RTResourceMap } from './gfx/renderJob/frame/RTResourceMap'; -import { ForwardRenderJob } from './gfx/renderJob/jobs/ForwardRenderJob'; import { RendererJob } from './gfx/renderJob/jobs/RendererJob'; -import { FXAAPost } from './gfx/renderJob/post/FXAAPost'; -import { InputSystem } from './io/InputSystem'; -import { Color } from './math/Color'; -import { Interpolator } from './math/TimeInterpolator'; -import { EngineSetting } from './setting/EngineSetting'; -import { defaultRes } from './textures/DefaultRes'; -import { Time } from './util/Time'; +import { Res } from './assets/Res'; +import { ShaderLib } from './assets/shader/ShaderLib'; +import { ShaderUtil } from './gfx/graphics/webGpu/shader/util/ShaderUtil'; +import { ComponentCollect } from './gfx/renderJob/collect/ComponentCollect'; -/** +/** * Orillusion 3D Engine * @notExported * @group engine3D */ -class _Engine3D { +export class Engine3D { /** * @internal */ @@ -29,25 +30,25 @@ class _Engine3D { /** * resource manager */ - public res: Res; + public static res: Res; /** * input system */ - public inputSystem: InputSystem; - public views: View3D[]; + public static inputSystem: InputSystem; + public static views: View3D[]; - private _frameRateValue: number = 0; - private _frameRate: number = 360; - private _isRun: boolean = false; - private _frameTimeCount: number = 0; - private _deltaTime: number = 0; - private _time: number = 0; + private static _frameRateValue: number = 0; + private static _frameRate: number = 360; + private static _isRun: boolean = false; + private static _frameTimeCount: number = 0; + private static _deltaTime: number = 0; + private static _time: number = 0; - public get frameRate(): number { + public static get frameRate(): number { return this._frameRate; } - public set frameRate(value: number) { + public static set frameRate(value: number) { this._frameRate = value; this._frameRateValue = 1.0 / value; if (value >= 360) { @@ -55,18 +56,26 @@ class _Engine3D { } } - public get size(): number[] { + public static get size(): number[] { return webGPUContext.presentationSize; } - public get aspect(): number { + public static get aspect(): number { return webGPUContext.aspect; } + public static get width(): number { + return webGPUContext.windowWidth; + } + + public static get height(): number { + return webGPUContext.windowHeight; + } + /** * engine setting */ - public setting: EngineSetting = { + public static setting: EngineSetting = { occlusionQuery: { enable: true, debug: false, @@ -236,44 +245,40 @@ class _Engine3D { }, }; - private _beforeRender: Function; - private _renderLoop: Function; - private _lateRender: Function; + private static _beforeRender: Function; + private static _renderLoop: Function; + private static _lateRender: Function; /** * @internal */ - public renderJobs: Map; + public static renderJobs: Map; - public get width(): number { - return webGPUContext.windowWidth; - } - public get height(): number { - return webGPUContext.windowHeight; - } /** * create webgpu 3d engine * @param descriptor {@link CanvasConfig} * @returns */ - public async init(descriptor: { canvasConfig?: CanvasConfig; beforeRender?: Function; renderLoop?: Function; lateRender?: Function, engineSetting?: EngineSetting } = {}) { + public static async init(descriptor: { canvasConfig?: CanvasConfig; beforeRender?: Function; renderLoop?: Function; lateRender?: Function, engineSetting?: EngineSetting } = {}) { console.log('engine version', version); this.setting = { ...this.setting, ...descriptor.engineSetting } await webGPUContext.init(descriptor.canvasConfig); - ShaderLib.init(); + ComponentCollect.init(); - GlobalBindGroup.initCommon(); + ShaderLib.init(); - this.res = new Res(); + ShaderUtil.init(); - await defaultRes.initCommon(); + GlobalBindGroup.init(); RTResourceMap.init(); + this.res = new Res(); + this._beforeRender = descriptor.beforeRender; this._renderLoop = descriptor.renderLoop; this._lateRender = descriptor.lateRender; @@ -282,7 +287,7 @@ class _Engine3D { return; } - public startRenderView(view: View3D) { + public static startRenderView(view: View3D) { this.renderJobs ||= new Map(); this.views = [view]; let renderJob = new ForwardRenderJob(view); @@ -293,7 +298,7 @@ class _Engine3D { return renderJob; } - public startRenderViews(views: View3D[]) { + public static startRenderViews(views: View3D[]) { this.renderJobs ||= new Map(); this.views = views; for (let i = 0; i < views.length; i++) { @@ -306,7 +311,7 @@ class _Engine3D { this.render(0); } - public getRenderJob(view: View3D): RendererJob { + public static getRenderJob(view: View3D): RendererJob { return this.renderJobs.get(view); } @@ -314,7 +319,7 @@ class _Engine3D { /** * @internal */ - public render(time) { + public static render(time) { if (!this._isRun) { this._deltaTime = time - this._time; this._time = time; @@ -332,7 +337,7 @@ class _Engine3D { requestAnimationFrame((t) => this.render(t)); } - public updateFrame(time: number) { + public static updateFrame(time: number) { Time.delta = time - Time.time; Time.time = time; Time.frame += 1; @@ -352,4 +357,4 @@ class _Engine3D { * Orillusion 3D * @group engine3D */ -export let Engine3D = new _Engine3D(); +// export let Engine3D = new _Engine3D(); diff --git a/src/engine/assets/Res.ts b/src/assets/Res.ts similarity index 70% rename from src/engine/assets/Res.ts rename to src/assets/Res.ts index afc7c80b..e46c444c 100644 --- a/src/engine/assets/Res.ts +++ b/src/assets/Res.ts @@ -15,6 +15,8 @@ import { I3DMParser } from "../loader/parser/I3DMParser"; import { GLTF_Info } from '../loader/parser/gltf/GLTFInfo'; import { HDRTexture } from '../textures/HDRTexture'; import { LDRTextureCube } from '../textures/LDRTextureCube'; +import { BRDFLUTGenerate } from '../gfx/generate/BrdfLUTGenerate'; +import { Uint8ArrayTexture } from '../textures/Uint8ArrayTexture'; /** * Resource management classes for textures, materials, models, and preset bodies. @@ -24,6 +26,7 @@ export class Res { private _texturePool: Map; private _materialPool: Map; private _prefabPool: Map; + // private _prefabLoaderPool: Map; private _gltfPool: Map; /** @@ -33,7 +36,10 @@ export class Res { this._texturePool = new Map(); this._materialPool = new Map(); this._prefabPool = new Map(); + // this._prefabLoaderPool = new Map; this._gltfPool = new Map; + + this.initDefault(); } public getGltf(url: string): GLTF_Info { @@ -279,6 +285,10 @@ export class Res { return cubeMap; } + /** + * load json data from url. + * @param url the path of image + */ public async loadJSON(url: string, loaderFunctions?: LoaderFunctions) { return await new FileLoader() .loadJson(url, loaderFunctions) @@ -286,6 +296,92 @@ export class Res { return ret; }) .catch((e) => { + console.log(e); }); } + + /** + * normal texture + */ + public normalTexture: Uint8ArrayTexture; + public maskTexture: Uint8ArrayTexture; + public whiteTexture: Uint8ArrayTexture; + public blackTexture: Uint8ArrayTexture; + public redTexture: Uint8ArrayTexture; + public blueTexture: Uint8ArrayTexture; + public greenTexture: Uint8ArrayTexture; + public yellowTexture: Uint8ArrayTexture; + public grayTexture: Uint8ArrayTexture; + + public defaultSky: HDRTextureCube; + + /** + * create a texture + * @param width width of texture + * @param height height of texture + * @param r component-red + * @param g component-green + * @param b component-blue + * @param a component-alpha(0 for transparent,1 for opaque) + * @param name name string + * @returns + */ + public createTexture(width: number, height: number, r: number, g: number, b: number, a: number, name?: string) { + let w = 32; + let h = 32; + let textureData = new Uint8Array(w * h * 4); + this.fillColor(textureData, width, height, r, g, b, a); + let texture = new Uint8ArrayTexture(); + texture.name = name; + texture.create(16, 16, textureData, true); + if (name) { + this.addTexture(name, texture); + } + return texture; + } + + /** + * fill slod color to this texture + * @param array data of texture + * @param w width of texture + * @param h height of texture + * @param r component-red + * @param g component-green + * @param b component-blue + * @param a component-alpha(0 for transparent,1 for opaque) + */ + public fillColor(array: any, w: number, h: number, r: number, g: number, b: number, a: number) { + for (let i = 0; i < w; i++) { + for (let j = 0; j < h; j++) { + let pixelIndex = j * w + i; + array[pixelIndex * 4 + 0] = r; + array[pixelIndex * 4 + 1] = g; + array[pixelIndex * 4 + 2] = b; + array[pixelIndex * 4 + 3] = a; + } + } + } + + /** + * Initialize a common texture object. Provide a universal solid color texture object. + */ + private initDefault() { + this.normalTexture = this.createTexture(32, 32, 255 * 0.5, 255 * 0.5, 255.0, 255.0, 'default-normalTexture'); + this.maskTexture = this.createTexture(32, 32, 255, 255 * 0.5, 0.0, 255.0, 'default-maskTexture'); + this.whiteTexture = this.createTexture(32, 32, 255, 255, 255, 255, 'default-whiteTexture'); + this.blackTexture = this.createTexture(32, 32, 0, 0, 0, 255.0, 'default-blackTexture'); + this.redTexture = this.createTexture(32, 32, 255, 0, 0, 255.0, 'default-redTexture'); + this.blueTexture = this.createTexture(32, 32, 0, 0, 255, 255.0, 'default-blueTexture'); + this.greenTexture = this.createTexture(32, 32, 0, 255, 0, 255, 'default-greenTexture'); + this.yellowTexture = this.createTexture(32, 32, 0, 255, 255, 255.0, 'default-yellowTexture'); + this.grayTexture = this.createTexture(32, 32, 128, 128, 128, 255.0, 'default-grayTexture'); + + let brdf = new BRDFLUTGenerate(); + let texture = brdf.generateBRDFLUTTexture(); + let BRDFLUT = texture.name = 'BRDFLUT'; + this.addTexture(BRDFLUT, texture); + + this.defaultSky = new HDRTextureCube(); + this.defaultSky.createFromTexture(128, this.blackTexture); + } } diff --git a/src/engine/assets/shader/ShaderLib.ts b/src/assets/shader/ShaderLib.ts similarity index 84% rename from src/engine/assets/shader/ShaderLib.ts rename to src/assets/shader/ShaderLib.ts index a8007616..d502502d 100644 --- a/src/engine/assets/shader/ShaderLib.ts +++ b/src/assets/shader/ShaderLib.ts @@ -1,41 +1,40 @@ -import { VertexAttributes } from "./core/struct/VertexAttributes" +import BRDF_frag from "./lighting/BRDF_frag.wgsl?raw"; +import { Bloom_shader } from './post/Bloom_shader'; +import BrdfLut_frag from "./core/common/BrdfLut_frag.wgsl?raw"; +import BxDF_frag from "./lighting/BxDF_frag.wgsl?raw"; +import BxdfDebug_frag from "./materials/program/BxdfDebug_frag.wgsl?raw"; +import Clearcoat_frag from "./materials/program/Clearcoat_frag.wgsl?raw"; +import { ClusterDebug_frag } from './materials/program/ClusterDebug_frag'; import ColorPassFragmentOutput from "./core/struct/ColorPassFragmentOutput.wgsl?raw"; +import ColorUtil from './utils/ColorUtil.wgsl?raw' import Common_frag from "./core/base/Common_frag.wgsl?raw"; import Common_vert from "./core/base/Common_vert.wgsl?raw"; -import FragmentVarying from "./core/struct/FragmentVarying.wgsl?raw"; -import BxdfDebug_frag from "./materials/program/BxdfDebug_frag.wgsl?raw"; -import Clearcoat_frag from "./materials/program/Clearcoat_frag.wgsl?raw"; -import NormalMap_frag from "./materials/program/NormalMap_frag.wgsl?raw"; -import ShadowMapping_frag from "./materials/program/ShadowMapping_frag.wgsl?raw"; -import BrdfLut_frag from "./core/common/BrdfLut_frag.wgsl?raw"; +import { CubeSky_Shader } from './materials/sky/CubeSky_Shader'; import EnvMap_frag from "./core/common/EnvMap_frag.wgsl?raw"; +import FastMathShader from "./math/FastMathShader.wgsl?raw"; +import FragmentVarying from "./core/struct/FragmentVarying.wgsl?raw"; +import GenerayRandomDir from './utils/GenerayRandomDir.wgsl?raw' import GlobalUniform from "./core/common/GlobalUniform.wgsl?raw"; +import IESProfiles_frag from './lighting/IESProfiles_frag.wgsl?raw' import Inline_vert from "./core/inline/Inline_vert.wgsl?raw"; -import WorldMatrixUniform from "./core/common/WorldMatrixUniform.wgsl?raw"; import InstanceUniform from "./core/common/InstanceUniform.wgsl?raw"; -import { LightStructFrag } from "./core/struct/LightStructFrag"; -import { LightingFunction_frag } from "./lighting/LightingFunction_frag"; -import { PhysicMaterialUniform_frag } from "./materials/uniforms/PhysicMaterialUniform_frag"; -import { MathShader } from "./math/MathShader"; -import ShadingInput from "./core/struct/ShadingInput.wgsl?raw"; -import { ClusterDebug_frag } from "./materials/program/ClusterDebug_frag"; - -import FastMathShader from "./math/FastMathShader.wgsl?raw"; -import BRDF_frag from "./lighting/BRDF_frag.wgsl?raw"; -import BxDF_frag from "./lighting/BxDF_frag.wgsl?raw"; import Irradiance_frag from "./lighting/Irradiance_frag.wgsl?raw"; +import { LightStructFrag } from './core/struct/LightStructFrag'; +import { LightingFunction_frag } from './lighting/LightingFunction_frag'; import LitShader from '../shader/materials/LitShader.wgsl?raw' +import { MathShader } from './math/MathShader'; +import NormalMap_frag from "./materials/program/NormalMap_frag.wgsl?raw"; import PBRLItShader from '../shader/materials/PBRLItShader.wgsl?raw' - -import ColorUtil from './utils/ColorUtil.wgsl?raw' -import GenerayRandomDir from './utils/GenerayRandomDir.wgsl?raw' -import IESProfiles_frag from './lighting/IESProfiles_frag.wgsl?raw' -import { UnLit_frag } from "./lighting/UnLit_frag"; -import { UnLitMaterialUniform_frag } from "./materials/uniforms/UnLitMaterialUniform_frag"; -import { VideoUniform_frag } from "./materials/uniforms/VideoUniform_frag"; -import { Bloom_shader } from "./post/Bloom_shader"; -import { Quad_shader } from "./quad/Quad_shader"; -import { CubeSky_Shader } from "./materials/sky/CubeSky_Shader"; +import { PhysicMaterialUniform_frag } from './materials/uniforms/PhysicMaterialUniform_frag'; +import { Quad_shader } from './quad/Quad_shader'; +import ShadingInput from "./core/struct/ShadingInput.wgsl?raw"; +import ShadowMapping_frag from "./materials/program/ShadowMapping_frag.wgsl?raw"; +import { UnLitMaterialUniform_frag } from './materials/uniforms/UnLitMaterialUniform_frag'; +import { UnLit_frag } from './lighting/UnLit_frag'; +import { VertexAttributes } from './core/struct/VertexAttributes'; +import { VideoUniform_frag } from './materials/uniforms/VideoUniform_frag'; +import WorldMatrixUniform from "./core/common/WorldMatrixUniform.wgsl?raw"; +import { IrradianceVolumeData_frag } from "./lighting/IrradianceVolumeData_frag"; /** * @internal @@ -71,7 +70,7 @@ export class ShaderLib { ShaderLib.register('ShadowMapping_frag', ShadowMapping_frag); ShaderLib.register('Irradiance_frag', Irradiance_frag); - // ShaderLib.register('IrradianceVolumeData_frag', IrradianceVolumeData_frag); + ShaderLib.register('IrradianceVolumeData_frag', IrradianceVolumeData_frag); ShaderLib.register('BrdfLut_frag', BrdfLut_frag); ShaderLib.register('EnvMap_frag', EnvMap_frag); @@ -85,14 +84,9 @@ export class ShaderLib { ShaderLib.register('PBRLItShader', PBRLItShader); - - // ShaderLib.register('Surface', Surface_Shader.Surface_Common); - ShaderLib.register('ClusterDebug_frag', ClusterDebug_frag); ShaderLib.register('BxdfDebug_frag', BxdfDebug_frag); - ShaderLib.register('GenerayRandomDir', GenerayRandomDir); - ShaderLib.register('Quad_vert_wgsl', Quad_shader.Quad_vert_wgsl); ShaderLib.register('Quad_frag_wgsl', Quad_shader.Quad_frag_wgsl); ShaderLib.register('Quad_depth2d_frag_wgsl', Quad_shader.Quad_depth2d_frag_wgsl); diff --git a/src/engine/assets/shader/anim/SkeletonAnimation_shader.ts b/src/assets/shader/anim/SkeletonAnimation_shader.ts similarity index 100% rename from src/engine/assets/shader/anim/SkeletonAnimation_shader.ts rename to src/assets/shader/anim/SkeletonAnimation_shader.ts diff --git a/src/engine/assets/shader/cluster/ClusterBoundsSource_cs.wgsl b/src/assets/shader/cluster/ClusterBoundsSource_cs.wgsl similarity index 100% rename from src/engine/assets/shader/cluster/ClusterBoundsSource_cs.wgsl rename to src/assets/shader/cluster/ClusterBoundsSource_cs.wgsl diff --git a/src/engine/assets/shader/cluster/ClusterLighting_cs.wgsl b/src/assets/shader/cluster/ClusterLighting_cs.wgsl similarity index 100% rename from src/engine/assets/shader/cluster/ClusterLighting_cs.wgsl rename to src/assets/shader/cluster/ClusterLighting_cs.wgsl diff --git a/src/engine/assets/shader/compute/BLUR_CsShader.wgsl b/src/assets/shader/compute/BLUR_CsShader.wgsl similarity index 100% rename from src/engine/assets/shader/compute/BLUR_CsShader.wgsl rename to src/assets/shader/compute/BLUR_CsShader.wgsl diff --git a/src/engine/assets/shader/compute/BlurEffectCreator_compute.ts b/src/assets/shader/compute/BlurEffectCreator_compute.ts similarity index 100% rename from src/engine/assets/shader/compute/BlurEffectCreator_compute.ts rename to src/assets/shader/compute/BlurEffectCreator_compute.ts diff --git a/src/engine/assets/shader/compute/DepthOfView_CsShader.wgsl b/src/assets/shader/compute/DepthOfView_CsShader.wgsl similarity index 100% rename from src/engine/assets/shader/compute/DepthOfView_CsShader.wgsl rename to src/assets/shader/compute/DepthOfView_CsShader.wgsl diff --git a/src/engine/assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl b/src/assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl similarity index 100% rename from src/engine/assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl rename to src/assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl diff --git a/src/engine/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl b/src/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl similarity index 100% rename from src/engine/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl rename to src/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl diff --git a/src/engine/assets/shader/compute/GTAOCs.wgsl b/src/assets/shader/compute/GTAOCs.wgsl similarity index 100% rename from src/engine/assets/shader/compute/GTAOCs.wgsl rename to src/assets/shader/compute/GTAOCs.wgsl diff --git a/src/engine/assets/shader/compute/IBLEnvMapCreator_compute.wgsl b/src/assets/shader/compute/IBLEnvMapCreator_compute.wgsl similarity index 100% rename from src/engine/assets/shader/compute/IBLEnvMapCreator_compute.wgsl rename to src/assets/shader/compute/IBLEnvMapCreator_compute.wgsl diff --git a/src/engine/assets/shader/compute/MergeRGBA_Cs.wgsl b/src/assets/shader/compute/MergeRGBA_Cs.wgsl similarity index 100% rename from src/engine/assets/shader/compute/MergeRGBA_Cs.wgsl rename to src/assets/shader/compute/MergeRGBA_Cs.wgsl diff --git a/src/engine/assets/shader/compute/MultiBouncePass_Shader.wgsl b/src/assets/shader/compute/MultiBouncePass_Shader.wgsl similarity index 100% rename from src/engine/assets/shader/compute/MultiBouncePass_Shader.wgsl rename to src/assets/shader/compute/MultiBouncePass_Shader.wgsl diff --git a/src/engine/assets/shader/compute/OutLineBlendColor.wgsl b/src/assets/shader/compute/OutLineBlendColor.wgsl similarity index 100% rename from src/engine/assets/shader/compute/OutLineBlendColor.wgsl rename to src/assets/shader/compute/OutLineBlendColor.wgsl diff --git a/src/engine/assets/shader/compute/OutlineCalcOutline.wgsl b/src/assets/shader/compute/OutlineCalcOutline.wgsl similarity index 100% rename from src/engine/assets/shader/compute/OutlineCalcOutline.wgsl rename to src/assets/shader/compute/OutlineCalcOutline.wgsl diff --git a/src/engine/assets/shader/compute/OutlineCs.wgsl b/src/assets/shader/compute/OutlineCs.wgsl similarity index 100% rename from src/engine/assets/shader/compute/OutlineCs.wgsl rename to src/assets/shader/compute/OutlineCs.wgsl diff --git a/src/engine/assets/shader/compute/Picker_CsShader.wgsl b/src/assets/shader/compute/Picker_CsShader.wgsl similarity index 100% rename from src/engine/assets/shader/compute/Picker_CsShader.wgsl rename to src/assets/shader/compute/Picker_CsShader.wgsl diff --git a/src/engine/assets/shader/compute/SSAO_CsShader.wgsl b/src/assets/shader/compute/SSAO_CsShader.wgsl similarity index 100% rename from src/engine/assets/shader/compute/SSAO_CsShader.wgsl rename to src/assets/shader/compute/SSAO_CsShader.wgsl diff --git a/src/engine/assets/shader/compute/SSR_BlendColor_Shader.wgsl b/src/assets/shader/compute/SSR_BlendColor_Shader.wgsl similarity index 100% rename from src/engine/assets/shader/compute/SSR_BlendColor_Shader.wgsl rename to src/assets/shader/compute/SSR_BlendColor_Shader.wgsl diff --git a/src/engine/assets/shader/compute/SSR_IS_Shader.wgsl b/src/assets/shader/compute/SSR_IS_Shader.wgsl similarity index 100% rename from src/engine/assets/shader/compute/SSR_IS_Shader.wgsl rename to src/assets/shader/compute/SSR_IS_Shader.wgsl diff --git a/src/engine/assets/shader/compute/SSR_RayTrace_Shader.wgsl b/src/assets/shader/compute/SSR_RayTrace_Shader.wgsl similarity index 100% rename from src/engine/assets/shader/compute/SSR_RayTrace_Shader.wgsl rename to src/assets/shader/compute/SSR_RayTrace_Shader.wgsl diff --git a/src/engine/assets/shader/compute/TAACopyTex.wgsl b/src/assets/shader/compute/TAACopyTex.wgsl similarity index 100% rename from src/engine/assets/shader/compute/TAACopyTex.wgsl rename to src/assets/shader/compute/TAACopyTex.wgsl diff --git a/src/engine/assets/shader/compute/TAASharpTex.wgsl b/src/assets/shader/compute/TAASharpTex.wgsl similarity index 100% rename from src/engine/assets/shader/compute/TAASharpTex.wgsl rename to src/assets/shader/compute/TAASharpTex.wgsl diff --git a/src/engine/assets/shader/compute/TAAcs.wgsl b/src/assets/shader/compute/TAAcs.wgsl similarity index 100% rename from src/engine/assets/shader/compute/TAAcs.wgsl rename to src/assets/shader/compute/TAAcs.wgsl diff --git a/src/engine/assets/shader/core/base/Common_frag.wgsl b/src/assets/shader/core/base/Common_frag.wgsl similarity index 100% rename from src/engine/assets/shader/core/base/Common_frag.wgsl rename to src/assets/shader/core/base/Common_frag.wgsl diff --git a/src/engine/assets/shader/core/base/Common_vert.wgsl b/src/assets/shader/core/base/Common_vert.wgsl similarity index 100% rename from src/engine/assets/shader/core/base/Common_vert.wgsl rename to src/assets/shader/core/base/Common_vert.wgsl diff --git a/src/engine/assets/shader/core/common/BrdfLut_frag.wgsl b/src/assets/shader/core/common/BrdfLut_frag.wgsl similarity index 100% rename from src/engine/assets/shader/core/common/BrdfLut_frag.wgsl rename to src/assets/shader/core/common/BrdfLut_frag.wgsl diff --git a/src/engine/assets/shader/core/common/EnvMap_frag.wgsl b/src/assets/shader/core/common/EnvMap_frag.wgsl similarity index 100% rename from src/engine/assets/shader/core/common/EnvMap_frag.wgsl rename to src/assets/shader/core/common/EnvMap_frag.wgsl diff --git a/src/engine/assets/shader/core/common/GlobalUniform.wgsl b/src/assets/shader/core/common/GlobalUniform.wgsl similarity index 100% rename from src/engine/assets/shader/core/common/GlobalUniform.wgsl rename to src/assets/shader/core/common/GlobalUniform.wgsl diff --git a/src/engine/assets/shader/core/common/InstanceUniform.wgsl b/src/assets/shader/core/common/InstanceUniform.wgsl similarity index 100% rename from src/engine/assets/shader/core/common/InstanceUniform.wgsl rename to src/assets/shader/core/common/InstanceUniform.wgsl diff --git a/src/engine/assets/shader/core/common/WorldMatrixUniform.wgsl b/src/assets/shader/core/common/WorldMatrixUniform.wgsl similarity index 100% rename from src/engine/assets/shader/core/common/WorldMatrixUniform.wgsl rename to src/assets/shader/core/common/WorldMatrixUniform.wgsl diff --git a/src/engine/assets/shader/core/inline/Inline_vert.wgsl b/src/assets/shader/core/inline/Inline_vert.wgsl similarity index 100% rename from src/engine/assets/shader/core/inline/Inline_vert.wgsl rename to src/assets/shader/core/inline/Inline_vert.wgsl diff --git a/src/engine/assets/shader/core/pass/CastShadowPass_wgsl.ts b/src/assets/shader/core/pass/CastShadowPass_wgsl.ts similarity index 100% rename from src/engine/assets/shader/core/pass/CastShadowPass_wgsl.ts rename to src/assets/shader/core/pass/CastShadowPass_wgsl.ts diff --git a/src/engine/assets/shader/core/pass/FrustumCullingShader_cs.wgsl b/src/assets/shader/core/pass/FrustumCullingShader_cs.wgsl similarity index 100% rename from src/engine/assets/shader/core/pass/FrustumCullingShader_cs.wgsl rename to src/assets/shader/core/pass/FrustumCullingShader_cs.wgsl diff --git a/src/engine/assets/shader/core/pass/GBuffer_shader.wgsl b/src/assets/shader/core/pass/GBuffer_shader.wgsl similarity index 100% rename from src/engine/assets/shader/core/pass/GBuffer_shader.wgsl rename to src/assets/shader/core/pass/GBuffer_shader.wgsl diff --git a/src/engine/assets/shader/core/pass/SkyGBuffer_fs.wgsl b/src/assets/shader/core/pass/SkyGBuffer_fs.wgsl similarity index 100% rename from src/engine/assets/shader/core/pass/SkyGBuffer_fs.wgsl rename to src/assets/shader/core/pass/SkyGBuffer_fs.wgsl diff --git a/src/engine/assets/shader/core/pass/ZPassShader_cs.wgsl b/src/assets/shader/core/pass/ZPassShader_cs.wgsl similarity index 100% rename from src/engine/assets/shader/core/pass/ZPassShader_cs.wgsl rename to src/assets/shader/core/pass/ZPassShader_cs.wgsl diff --git a/src/engine/assets/shader/core/pass/ZPassShader_fs.wgsl b/src/assets/shader/core/pass/ZPassShader_fs.wgsl similarity index 100% rename from src/engine/assets/shader/core/pass/ZPassShader_fs.wgsl rename to src/assets/shader/core/pass/ZPassShader_fs.wgsl diff --git a/src/engine/assets/shader/core/pass/ZPassShader_vs.ts b/src/assets/shader/core/pass/ZPassShader_vs.ts similarity index 100% rename from src/engine/assets/shader/core/pass/ZPassShader_vs.ts rename to src/assets/shader/core/pass/ZPassShader_vs.ts diff --git a/src/engine/assets/shader/core/struct/ColorPassFragmentOutput.wgsl b/src/assets/shader/core/struct/ColorPassFragmentOutput.wgsl similarity index 100% rename from src/engine/assets/shader/core/struct/ColorPassFragmentOutput.wgsl rename to src/assets/shader/core/struct/ColorPassFragmentOutput.wgsl diff --git a/src/engine/assets/shader/core/struct/EmptyFrag_CommonFragment.wgsl b/src/assets/shader/core/struct/EmptyFrag_CommonFragment.wgsl similarity index 100% rename from src/engine/assets/shader/core/struct/EmptyFrag_CommonFragment.wgsl rename to src/assets/shader/core/struct/EmptyFrag_CommonFragment.wgsl diff --git a/src/engine/assets/shader/core/struct/EmptyFrag_FragmentOutput.wgsl b/src/assets/shader/core/struct/EmptyFrag_FragmentOutput.wgsl similarity index 100% rename from src/engine/assets/shader/core/struct/EmptyFrag_FragmentOutput.wgsl rename to src/assets/shader/core/struct/EmptyFrag_FragmentOutput.wgsl diff --git a/src/engine/assets/shader/core/struct/FragmentVarying.wgsl b/src/assets/shader/core/struct/FragmentVarying.wgsl similarity index 100% rename from src/engine/assets/shader/core/struct/FragmentVarying.wgsl rename to src/assets/shader/core/struct/FragmentVarying.wgsl diff --git a/src/engine/assets/shader/core/struct/LightStruct.wgsl b/src/assets/shader/core/struct/LightStruct.wgsl similarity index 100% rename from src/engine/assets/shader/core/struct/LightStruct.wgsl rename to src/assets/shader/core/struct/LightStruct.wgsl diff --git a/src/engine/assets/shader/core/struct/LightStructFrag.ts b/src/assets/shader/core/struct/LightStructFrag.ts similarity index 100% rename from src/engine/assets/shader/core/struct/LightStructFrag.ts rename to src/assets/shader/core/struct/LightStructFrag.ts diff --git a/src/engine/assets/shader/core/struct/ShadingInput.wgsl b/src/assets/shader/core/struct/ShadingInput.wgsl similarity index 100% rename from src/engine/assets/shader/core/struct/ShadingInput.wgsl rename to src/assets/shader/core/struct/ShadingInput.wgsl diff --git a/src/engine/assets/shader/core/struct/VertexAttributes.ts b/src/assets/shader/core/struct/VertexAttributes.ts similarity index 100% rename from src/engine/assets/shader/core/struct/VertexAttributes.ts rename to src/assets/shader/core/struct/VertexAttributes.ts diff --git a/src/engine/assets/shader/glsl/Quad_glsl.ts b/src/assets/shader/glsl/Quad_glsl.ts similarity index 100% rename from src/engine/assets/shader/glsl/Quad_glsl.ts rename to src/assets/shader/glsl/Quad_glsl.ts diff --git a/src/engine/assets/shader/glsl/Sky_glsl.ts b/src/assets/shader/glsl/Sky_glsl.ts similarity index 100% rename from src/engine/assets/shader/glsl/Sky_glsl.ts rename to src/assets/shader/glsl/Sky_glsl.ts diff --git a/src/engine/assets/shader/glsl/post/LUT_glsl.ts b/src/assets/shader/glsl/post/LUT_glsl.ts similarity index 100% rename from src/engine/assets/shader/glsl/post/LUT_glsl.ts rename to src/assets/shader/glsl/post/LUT_glsl.ts diff --git a/src/engine/assets/shader/graphic/Graphic3DShader_fs.wgsl b/src/assets/shader/graphic/Graphic3DShader_fs.wgsl similarity index 100% rename from src/engine/assets/shader/graphic/Graphic3DShader_fs.wgsl rename to src/assets/shader/graphic/Graphic3DShader_fs.wgsl diff --git a/src/engine/assets/shader/graphic/Graphic3DShader_vs.wgsl b/src/assets/shader/graphic/Graphic3DShader_vs.wgsl similarity index 100% rename from src/engine/assets/shader/graphic/Graphic3DShader_vs.wgsl rename to src/assets/shader/graphic/Graphic3DShader_vs.wgsl diff --git a/src/engine/assets/shader/lighting/BRDF_frag.wgsl b/src/assets/shader/lighting/BRDF_frag.wgsl similarity index 100% rename from src/engine/assets/shader/lighting/BRDF_frag.wgsl rename to src/assets/shader/lighting/BRDF_frag.wgsl diff --git a/src/engine/assets/shader/lighting/BxDF_frag.wgsl b/src/assets/shader/lighting/BxDF_frag.wgsl similarity index 100% rename from src/engine/assets/shader/lighting/BxDF_frag.wgsl rename to src/assets/shader/lighting/BxDF_frag.wgsl diff --git a/src/engine/assets/shader/lighting/IESProfiles_frag.wgsl b/src/assets/shader/lighting/IESProfiles_frag.wgsl similarity index 100% rename from src/engine/assets/shader/lighting/IESProfiles_frag.wgsl rename to src/assets/shader/lighting/IESProfiles_frag.wgsl diff --git a/src/assets/shader/lighting/IrradianceVolumeData_frag.ts b/src/assets/shader/lighting/IrradianceVolumeData_frag.ts new file mode 100644 index 00000000..414a03ee --- /dev/null +++ b/src/assets/shader/lighting/IrradianceVolumeData_frag.ts @@ -0,0 +1,49 @@ +export let IrradianceVolumeData_frag: string = + ` + struct IrradianceVolumeData { + //0 + orientationIndex:f32, + hysteresis:f32, + OctRTSideSize:f32, + OctRTMaxSize:f32, + + //1 + startX:f32, + startY:f32, + startZ:f32, + ProbeSpace:f32, + + //2 + gridXCount:f32, + gridYCount:f32, + gridZCount:f32, + maxDistance:f32, + + //3 + depthSharpness:f32, + ProbeSourceTextureSize:f32, + ProbeSize:f32, + bounceIntensity:f32, + + //4 + probeRoughness:f32, + normalBias:f32, + irradianceChebyshevBias:f32, + rayNumber:f32, + + //5 + irradianceDistanceBias:f32, + indirectIntensity:f32, + ddgiGamma:f32, + lerpHysteresis:f32, + //6 + + debugX:f32, + debugY:f32, + debugZ:f32, + slot0:f32, + + //.. + v7:vec4, +} +` \ No newline at end of file diff --git a/src/engine/assets/shader/lighting/Irradiance_frag.wgsl b/src/assets/shader/lighting/Irradiance_frag.wgsl similarity index 100% rename from src/engine/assets/shader/lighting/Irradiance_frag.wgsl rename to src/assets/shader/lighting/Irradiance_frag.wgsl diff --git a/src/engine/assets/shader/lighting/LightingFunction_frag.ts b/src/assets/shader/lighting/LightingFunction_frag.ts similarity index 100% rename from src/engine/assets/shader/lighting/LightingFunction_frag.ts rename to src/assets/shader/lighting/LightingFunction_frag.ts diff --git a/src/engine/assets/shader/lighting/UnLit_frag.ts b/src/assets/shader/lighting/UnLit_frag.ts similarity index 100% rename from src/engine/assets/shader/lighting/UnLit_frag.ts rename to src/assets/shader/lighting/UnLit_frag.ts diff --git a/src/engine/assets/shader/materials/ColorLitShader.ts b/src/assets/shader/materials/ColorLitShader.ts similarity index 100% rename from src/engine/assets/shader/materials/ColorLitShader.ts rename to src/assets/shader/materials/ColorLitShader.ts diff --git a/src/engine/assets/shader/materials/GlassShader.wgsl b/src/assets/shader/materials/GlassShader.wgsl similarity index 100% rename from src/engine/assets/shader/materials/GlassShader.wgsl rename to src/assets/shader/materials/GlassShader.wgsl diff --git a/src/engine/assets/shader/materials/Lambert_shader.ts b/src/assets/shader/materials/Lambert_shader.ts similarity index 100% rename from src/engine/assets/shader/materials/Lambert_shader.ts rename to src/assets/shader/materials/Lambert_shader.ts diff --git a/src/engine/assets/shader/materials/LitShader.wgsl b/src/assets/shader/materials/LitShader.wgsl similarity index 100% rename from src/engine/assets/shader/materials/LitShader.wgsl rename to src/assets/shader/materials/LitShader.wgsl diff --git a/src/engine/assets/shader/materials/OutlinePass.wgsl b/src/assets/shader/materials/OutlinePass.wgsl similarity index 100% rename from src/engine/assets/shader/materials/OutlinePass.wgsl rename to src/assets/shader/materials/OutlinePass.wgsl diff --git a/src/engine/assets/shader/materials/PBRLItShader.wgsl b/src/assets/shader/materials/PBRLItShader.wgsl similarity index 100% rename from src/engine/assets/shader/materials/PBRLItShader.wgsl rename to src/assets/shader/materials/PBRLItShader.wgsl diff --git a/src/engine/assets/shader/materials/PavementShader.ts b/src/assets/shader/materials/PavementShader.ts similarity index 100% rename from src/engine/assets/shader/materials/PavementShader.ts rename to src/assets/shader/materials/PavementShader.ts diff --git a/src/engine/assets/shader/materials/PointShadowDebug.ts b/src/assets/shader/materials/PointShadowDebug.ts similarity index 100% rename from src/engine/assets/shader/materials/PointShadowDebug.ts rename to src/assets/shader/materials/PointShadowDebug.ts diff --git a/src/engine/assets/shader/materials/UnLit.wgsl b/src/assets/shader/materials/UnLit.wgsl similarity index 100% rename from src/engine/assets/shader/materials/UnLit.wgsl rename to src/assets/shader/materials/UnLit.wgsl diff --git a/src/assets/shader/materials/compute/BLUR_CsShader.wgsl b/src/assets/shader/materials/compute/BLUR_CsShader.wgsl new file mode 100644 index 00000000..e5dd6680 --- /dev/null +++ b/src/assets/shader/materials/compute/BLUR_CsShader.wgsl @@ -0,0 +1,40 @@ +#include "GlobalUniform" + +struct UniformData { + radius: f32 , + bias: f32, + aoPower: f32 , + blurSize: f32 , +}; + +// @group(0) @binding(0) var standUniform: GlobalUniform; +@group(0) @binding(0) var uniformData: UniformData; +@group(0) @binding(1) var colorMap : texture_2d; +// @group(0) @binding(2) var ssaoMapSampler : sampler; +@group(0) @binding(2) var ssaoMap : texture_2d; +@group(0) @binding(3) var outTex : texture_storage_2d; + +@compute @workgroup_size( 8 , 8 ) +fn CsMain( @builtin(global_invocation_id) globalInvocation_id : vec3) +{ + var fragCoord = vec2( globalInvocation_id.xy ); + + var texSize = vec2(textureDimensions(ssaoMap).xy); + var texCoord = vec2(fragCoord) / texSize ; + + let blurSize = i32(uniformData.blurSize); + + var result = vec4(0.0) ; + var ii = 0.0 ; + for (var i = -2; i < 2 ; i+=1) { + for (var j = -2; j < 2 ; j+=1) { + var offset = vec2( i , j ) ; + result += textureLoad(ssaoMap, fragCoord + offset, 0 ); + // result += textureSampleLevel(ssaoMap,ssaoMapSampler, vec2( fragCoord + offset) / texSize , 0.0 ); + ii += 1.0 ; + } + } + var fResult = result.r / ii ; + var color = textureLoad(colorMap, fragCoord , 0 ); + textureStore(outTex, fragCoord , vec4(color.rgb * fResult,1.0) ); +} \ No newline at end of file diff --git a/src/assets/shader/materials/compute/DepthOfView_CsShader.wgsl b/src/assets/shader/materials/compute/DepthOfView_CsShader.wgsl new file mode 100644 index 00000000..f8420bda --- /dev/null +++ b/src/assets/shader/materials/compute/DepthOfView_CsShader.wgsl @@ -0,0 +1,81 @@ +#include "GlobalUniform" + + struct BlurSetting{ + near: f32, + far: f32, + pixelOffset: f32, + } + + @group(0) @binding(0) var standUniform: GlobalUniform; + @group(0) @binding(1) var blurSetting: BlurSetting; + + @group(0) @binding(2) var positionBufferTex : texture_2d; + @group(0) @binding(3) var normalBufferTex : texture_2d; + @group(0) @binding(4) var inTexSampler : sampler; + @group(0) @binding(5) var inTex : texture_2d; + @group(0) @binding(6) var outTex : texture_storage_2d; + + var cameraPosition: vec3; + var texSize: vec2; + var fragCoord: vec2; + var texelSize: vec2; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(inTex).xy; + texelSize = 1.0 / vec2(texSize - 1); + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + cameraPosition = vec3(standUniform.cameraWorldMatrix[3].xyz); + let wPosition:vec3 = textureLoad(positionBufferTex, fragCoord , 0).xyz; + var distance = length(wPosition - cameraPosition); + var oc:vec4 = textureLoad(inTex, fragCoord, 0); + if(distance > blurSetting.near){ + let normal = textureLoad(normalBufferTex, fragCoord, 0); + var pixelScale = 0.5; + if(normal.w > 0.5){ + distance = min(distance, blurSetting.far); + pixelScale = (distance - blurSetting.near) / (blurSetting.far - blurSetting.near); + } + oc = mixBlurColor(oc, fragCoord, blurSetting.pixelOffset, pixelScale); + } + textureStore(outTex, fragCoord, oc); + } + + fn mixBlurColor(orginColor:vec4, coord:vec2, pixelOffset:f32, scale:f32) -> vec4 { + + let uv = vec2(coord); + var uv0 = (uv + scale * vec2( pixelOffset, pixelOffset)) * texelSize; + var uv1 = (uv + scale * vec2(-pixelOffset, pixelOffset)) * texelSize; + var uv2 = (uv + scale * vec2(-pixelOffset, -pixelOffset)) * texelSize; + var uv3 = (uv + scale * vec2( pixelOffset, -pixelOffset)) * texelSize; + + uv0.x = processUVEdge(uv0.x); + uv0.y = processUVEdge(uv0.y); + uv1.x = processUVEdge(uv1.x); + uv1.y = processUVEdge(uv1.y); + uv2.x = processUVEdge(uv2.x); + uv2.y = processUVEdge(uv2.y); + uv3.x = processUVEdge(uv3.x); + uv3.y = processUVEdge(uv3.y); + + var ob = vec4(0.0); + ob += textureSampleLevel(inTex, inTexSampler, uv0, 0.0); + ob += textureSampleLevel(inTex, inTexSampler, uv1, 0.0); + ob += textureSampleLevel(inTex, inTexSampler, uv2, 0.0); + ob += textureSampleLevel(inTex, inTexSampler, uv3, 0.0); + return mix(orginColor, ob * 0.25, scale); + } + + fn processUVEdge(v: f32) -> f32{ + var value = v; + if(value < 0.0){ + value = - value; + }else if(value > 1.0){ + value = 2.0 - value; + } + return value; + } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/ErpImage2CubeMapCreateCube_compute.wgsl b/src/assets/shader/materials/compute/ErpImage2CubeMapCreateCube_compute.wgsl new file mode 100644 index 00000000..f765bfd8 --- /dev/null +++ b/src/assets/shader/materials/compute/ErpImage2CubeMapCreateCube_compute.wgsl @@ -0,0 +1,65 @@ +struct ImageSize { + srcWidth : i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32 +}; + +@group(0) @binding(0) var size : ImageSize; +@group(0) @binding(1) var faceRotation: array>; +@group(0) @binding(2) var inputTexSampler : sampler; +@group(0) @binding(3) var inputTex : texture_2d; + +@group(1) @binding(0) var outputBuffer0 : texture_storage_2d_array; + +fn SampleSphericalMap(v: vec3) -> vec2 { + var uv:vec2 = vec2(atan2(v.z, v.x), asin(v.y)); + //uv = (uv * (vec2(0.1590999960899353, 0.3183000087738037) + vec2(0.0010000000474974513))); + uv = uv * vec2(0.1590999960899353, 0.3183000087738037); + uv = uv + vec2(0.5); + uv = clamp(uv, vec2(0.0), vec2(1.0)); + return uv; +} + + +fn applyQuaternion(position:vec3, q:vec4) -> vec3{ + let x:f32 = position.x; + let y:f32 = position.y; + let z:f32 = position.z; + + let qx:f32 = q.x; + let qy:f32 = q.y; + let qz:f32 = q.z; + let qw:f32 = q.w; + + let ix:f32 = qw * x + qy * z - qz * y; + let iy:f32 = qw * y + qz * x - qx * z; + let iz:f32 = qw * z + qx * y - qy * x; + let iw:f32 = -qx * x - qy * y - qz * z; + + var ret: vec3; + ret.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + ret.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + ret.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + + return ret; +} + +fn convertIdToDir3(uv_i32:vec2, quaternion:vec4) -> vec3{ + var uv_f32:vec2 = vec2(uv_i32.xy); + var halfSize:f32 = f32(size.dstWidth / 2); + var worldDirection:vec3 = vec3(uv_f32.x - halfSize, uv_f32.y - halfSize, -halfSize); + worldDirection = normalize(worldDirection); + worldDirection = applyQuaternion(worldDirection, quaternion); + return worldDirection; +} + +@compute @workgroup_size(8, 8, 1) +fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let coord = vec2(GlobalInvocationID.xy); + let quaternion = faceRotation[GlobalInvocationID.z]; + var worldDirection:vec3 = convertIdToDir3(coord, quaternion); + let uv_f32:vec2 = SampleSphericalMap(worldDirection); + let oc = textureSampleLevel(inputTex, inputTexSampler, uv_f32 , 0.0); + textureStore(outputBuffer0, coord, i32(GlobalInvocationID.z), oc); +} \ No newline at end of file diff --git a/src/assets/shader/materials/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl b/src/assets/shader/materials/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl new file mode 100644 index 00000000..aece1023 --- /dev/null +++ b/src/assets/shader/materials/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl @@ -0,0 +1,32 @@ +struct ImageSize { + srcWidth : i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32 +}; + +@group(0) @binding(0) var size : ImageSize; +@group(0) @binding(1) var tex_in: array>; +@group(0) @binding(2) var outputBuffer : texture_storage_2d; + +@compute @workgroup_size(8, 8, 1) +fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let fragCoord = vec2(i32(GlobalInvocationID.x), i32(GlobalInvocationID.y)); + var oc:vec4 = tex_in[fragCoord.y * size.srcWidth + fragCoord.x] / 256.0; + var e = pow(2.0, oc.w * 255.0 - 128.0); + oc = oc * e; + oc = scaleByThreshold(oc, 40.0); + textureStore(outputBuffer, fragCoord , vec4(oc.xyz, 1.0) ); +} + +fn scaleByThreshold(color:vec4, threshold:f32) -> vec4{ + var oc = color; + let brightness = length(vec3(oc.xyz)); + var scale = brightness / threshold; + if(scale > 1.0){ + scale = 1.0 / pow(scale, 0.7); + oc = oc * scale; + } + oc.a = 1.0; + return oc; +} \ No newline at end of file diff --git a/src/assets/shader/materials/compute/GTAOCs.wgsl b/src/assets/shader/materials/compute/GTAOCs.wgsl new file mode 100644 index 00000000..74210c98 --- /dev/null +++ b/src/assets/shader/materials/compute/GTAOCs.wgsl @@ -0,0 +1,133 @@ +#include "GlobalUniform" + + struct GTAO{ + maxDistance: f32, + maxPixel: f32, + darkFactor: f32, + rayMarchSegment: f32, + cameraNear: f32, + cameraFar: f32, + viewPortWidth: f32, + viewPortHeight: f32, + multiBounce: f32, + blendColor: f32, + slot1: f32, + slot2: f32, + } + + @group(0) @binding(0) var standUniform: GlobalUniform; + @group(0) @binding(1) var gtaoData: GTAO; + @group(0) @binding(2) var directions : array>; + @group(0) @binding(3) var aoBuffer : array; + + @group(0) @binding(4) var posTex : texture_2d; + @group(0) @binding(5) var normalTex : texture_2d; + @group(0) @binding(6) var inTex : texture_2d; + @group(0) @binding(7) var outTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + var wPosition: vec3; + var wNormal: vec4; + var maxPixelScaled: f32; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(inTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + wNormal = textureLoad(normalTex, fragCoord, 0); + wNormal = vec4(wNormal.rgb,wNormal.w) ; + var oc = textureLoad(inTex, fragCoord, 0); + let index = fragCoord.x + fragCoord.y * i32(texSize.x); + let lastFactor = aoBuffer[index]; + var newFactor = 0.0; + if(wNormal.w < 0.5){//sky + + }else{ + wPosition = textureLoad(posTex, fragCoord, 0).xyz; + let ndc = standUniform.projMat * standUniform.viewMat * vec4(wPosition, 1.0); + let ndcZ = ndc.z / ndc.w; + maxPixelScaled = calcPixelByNDC(ndcZ); + newFactor = rayMarch(); + } + + var factor:f32 = mix(lastFactor, newFactor, 0.6); + aoBuffer[index] = factor; + factor = blurFactor(factor); + factor = 1.0 - factor * gtaoData.darkFactor; + var gtao = vec3(factor); + if(gtaoData.multiBounce > 0.5){ + gtao = MultiBounce(factor, oc.xyz); + } + + var outColor = gtao; + if(gtaoData.blendColor > 0.5){ + outColor = oc.xyz * gtao; + } + textureStore(outTex, fragCoord , vec4(outColor, oc.w)); + } + + fn MultiBounce(AO:f32, Albedo:vec3) -> vec3 + { + var A = 2 * Albedo - 0.33; + var B = -4.8 * Albedo + 0.64; + var C = 2.75 * Albedo + 0.69; + return max(vec3(AO), ((AO * A + B) * AO + C) * AO); + } + + fn calcPixelByNDC(ndcZ:f32) -> f32{ + let nearAspect = gtaoData.cameraNear / (gtaoData.cameraFar - gtaoData.cameraNear); + let aspect = (1.0 + nearAspect) / (ndcZ + nearAspect); + var viewPortMax = max(gtaoData.viewPortWidth, gtaoData.viewPortHeight); + var maxPixel = min(viewPortMax, gtaoData.maxPixel * aspect); + maxPixel = max(0.1, maxPixel); + return maxPixel; + } + + fn blurFactor(centerFactor:f32) -> f32{ + var coord0 = clamp(fragCoord + vec2(1, 0) , vec2(0), vec2(texSize - 1)); + var coord1 = clamp(fragCoord + vec2(-1, 0), vec2(0), vec2(texSize - 1)); + var coord2 = clamp(fragCoord + vec2(0, 1) , vec2(0), vec2(texSize - 1)); + var coord3 = clamp(fragCoord + vec2(0, -1), vec2(0), vec2(texSize - 1)); + var index0 = coord0.x + coord0.y * i32(texSize.x); + var index1 = coord1.x + coord1.y * i32(texSize.x); + var index2 = coord2.x + coord2.y * i32(texSize.x); + var index3 = coord3.x + coord3.y * i32(texSize.x); + let factor0:f32 = aoBuffer[index0]; + let factor1:f32 = aoBuffer[index1]; + let factor2:f32 = aoBuffer[index2]; + let factor3:f32 = aoBuffer[index3]; + var factor = 0.25 * (factor0 + factor1 + factor2 + factor3); + factor = mix(factor, centerFactor, 0.8); + return factor; + } + + fn rayMarch() -> f32{ + let originNormal = normalize(vec3(wNormal.xyz) * 2.0 - 1.0); + let stepPixel = maxPixelScaled / gtaoData.rayMarchSegment; + var totalWeight:f32 = 0.001; + var darkWeight:f32 = 0.0; + for(var i:i32 = 0; i < 8; i += 1){ + let dirVec2 = directions[i]; + for(var j:f32 = 1.1; j < maxPixelScaled; j += stepPixel){ + var sampleCoord = vec2(dirVec2 * j) + fragCoord; + sampleCoord = clamp(sampleCoord, vec2(0), vec2(texSize - 1)); + let samplePosition = textureLoad(posTex, sampleCoord, 0).xyz; + let distanceVec2 = samplePosition - wPosition; + let distance = length(distanceVec2); + if(distance < gtaoData.maxDistance){ + let sampleDir = normalize(distanceVec2); + var factor = max(0.0, dot(sampleDir, originNormal) - 0.1); + factor *= 1.0 - distance / gtaoData.maxDistance; + darkWeight += factor; + totalWeight += 1.0; + } + } + } + + return darkWeight/totalWeight ; + } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/IBLEnvMapCreator_compute.wgsl b/src/assets/shader/materials/compute/IBLEnvMapCreator_compute.wgsl new file mode 100644 index 00000000..4ab1a1ef --- /dev/null +++ b/src/assets/shader/materials/compute/IBLEnvMapCreator_compute.wgsl @@ -0,0 +1,174 @@ +struct ImageSize { + srcWidth : i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32 +}; + +@group(0) @binding(0) var size : ImageSize; +@group(0) @binding(1) var faceRotation: array>; +@group(0) @binding(2) var inputTexSampler : sampler; +@group(0) @binding(3) var inputTex : texture_2d; + +@group(1) @binding(0) var blurSetting : vec4; +@group(1) @binding(1) var outputBuffer0 : texture_storage_2d_array; + +var PI: f32 = 3.14159265359; + +fn applyQuaternion(position:vec3, q:vec4) -> vec3{ + let x:f32 = position.x; + let y:f32 = position.y; + let z:f32 = position.z; + + let qx:f32 = q.x; + let qy:f32 = q.y; + let qz:f32 = q.z; + let qw:f32 = q.w; + + let ix:f32 = qw * x + qy * z - qz * y; + let iy:f32 = qw * y + qz * x - qx * z; + let iz:f32 = qw * z + qx * y - qy * x; + let iw:f32 = -qx * x - qy * y - qz * z; + + var ret: vec3; + ret.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + ret.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + ret.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + + return ret; +} + +fn convertIdToDir3(uv_i32:vec2, quaternion:vec4) -> vec3{ + var uv_f32:vec2 = vec2(uv_i32.xy); + var halfSize:f32 = f32(size.dstWidth / 2); + var worldDirection:vec3 = vec3(uv_f32.x - halfSize, uv_f32.y - halfSize, -halfSize); + worldDirection = normalize(worldDirection); + worldDirection = applyQuaternion(worldDirection, quaternion); + return worldDirection; +} + +fn VanDerCorpus(n0:u32, base0:u32) -> f32 +{ + var n = n0; + var base = base0; + var invBase:f32 = 1.0 / f32(base); + var denom:f32 = 1.0; + var result:f32 = 0.0; + + for(var i:u32 = 0u; i < 32u; i = i + 1u) + { + if(n > 0u) + { + denom = f32(n) % 2.0; + result = result + denom * invBase; + invBase = invBase / 2.0; + n = u32(f32(n) / 2.0); + } + } + + return result; +} + +fn HammersleyNoBitOps(i:u32, N:u32) -> vec2 +{ + return vec2(f32(i)/f32(N), VanDerCorpus(i, 2u)); +} + +fn hammersley( i : u32 , N : u32 ) -> vec2 +{ + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + var bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + var rdi = f32(bits) * 2.3283064365386963e-10; + return vec2(f32(i) /f32(N), rdi); +} + +fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 +{ + var a = roughness*roughness; + + var phi = 2.0 * PI * Xi.x; + var cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); + var sinTheta = sqrt(1.0 - cosTheta*cosTheta); + + // from spherical coordinates to cartesian coordinates + var H:vec3; + H.x = cos(phi) * sinTheta; + H.y = sin(phi) * sinTheta; + H.z = cosTheta; + + // from tangent-space vector to world-space sample vector + var up:vec3; + if(abs(N.z) < 0.999) + { + up = vec3(0.0, 0.0, 1.0); + } + else + { + up = vec3(1.0, 0.0, 0.0); + } + var tangent:vec3 = normalize(cross(up, N)); + var bitangent:vec3 = cross(N, tangent); + var sampleVec:vec3 = tangent * H.x + bitangent * H.y + N * H.z; + return normalize(sampleVec); +} + +fn multiSample(localPos:vec3, roughness:f32) -> vec4 +{ + var N: vec3 = normalize(localPos); + var R: vec3 = N; + var V: vec3 = R; + + let SAMPLE_COUNT:u32 = 1024u; + var totalWeight:f32 = 0.0; + var prefilteredColor:vec3 = vec3(0.0, 0.0, 0.0); + for(var i:u32 = 0u; i < SAMPLE_COUNT; i = i + 1u) + { + var Xi:vec2 = hammersley(i, SAMPLE_COUNT); + var H :vec3 = ImportanceSampleGGX(Xi, N, roughness); + var L :vec3 = normalize(2.0 * dot(V, H) * H - V); + + var NdotL:f32 = max(dot(N, L), 0.0); + if(NdotL > 0.0) + { + var att = 1.0 ;//( f32(SAMPLE_COUNT - i) / f32(SAMPLE_COUNT)) ; + + prefilteredColor = prefilteredColor + sampleColor(L).rgb * NdotL; + prefilteredColor = prefilteredColor * att ; + totalWeight = totalWeight + NdotL; + } + } + prefilteredColor = prefilteredColor / totalWeight; + + return vec4(prefilteredColor, 1.0); +} + +fn SampleSphericalMap(v: vec3) -> vec2 { + var uv:vec2 = vec2(atan2(v.z, v.x), asin(v.y)); + //uv = (uv * (vec2(0.1590999960899353, 0.3183000087738037) + vec2(0.0010000000474974513))); + uv = uv * vec2(0.1590999960899353, 0.3183000087738037); + uv = uv + vec2(0.5); + uv = clamp(uv, vec2(0.0), vec2(1.0)); + return uv; +} + +fn sampleColor(d:vec3) -> vec4 +{ + let uv_f32:vec2 = SampleSphericalMap(d); + let oc = textureSampleLevel(inputTex, inputTexSampler, uv_f32 , 0.0); + //let dir = vec3(-d.x, -d.y, d.z); + //var oc:vec4 = textureSampleLevel(cubeMap, cubeMapSampler, dir, 0.0); + return oc; +} + +@compute @workgroup_size(8, 8, 1) +fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let coord = vec2(GlobalInvocationID.xy); + let quaternion = faceRotation[GlobalInvocationID.z]; + var worldDirection:vec3 = convertIdToDir3(coord, quaternion); + var oc:vec4 = multiSample(worldDirection, blurSetting.x); + textureStore(outputBuffer0, coord, i32(GlobalInvocationID.z), oc); +} diff --git a/src/assets/shader/materials/compute/MergeRGBA_Cs.wgsl b/src/assets/shader/materials/compute/MergeRGBA_Cs.wgsl new file mode 100644 index 00000000..c4ad1034 --- /dev/null +++ b/src/assets/shader/materials/compute/MergeRGBA_Cs.wgsl @@ -0,0 +1,29 @@ + +@group(0) @binding(0) var textureR : texture_2d; +@group(0) @binding(1) var textureG : texture_2d; +@group(0) @binding(2) var textureB : texture_2d; +@group(0) @binding(3) var textureA : texture_2d; +@group(0) @binding(4) var outTex : texture_storage_2d; + +@compute @workgroup_size(8, 8, 1) +fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let size = textureDimensions(outTex); + let fragCoord : vec2 = vec2(GlobalInvocationID.xy); + var uv:vec2; + uv.x = f32(fragCoord.x)/f32(size.x); + uv.y = f32(fragCoord.y)/f32(size.y); + var oc:vec4 = textureSampleLevel(atlasTexture, atlasTextureSampler, targetUV, 0.0); + + let sizeR = textureDimensions(textureR); + let sizeG = textureDimensions(textureG); + let sizeB = textureDimensions(textureB); + let sizeA = textureDimensions(textureA); + + var tr = textureLoad(textureR, vec2(uv * sizeR) , 0 ) ; + var tg = textureLoad(textureG, vec2(uv * sizeG) , 0 ) ; + var tb = textureLoad(textureB, vec2(uv * sizeB) , 0 ) ; + var ta = textureLoad(textureA, vec2(uv * sizeA) , 0 ) ; + + let color = vec4(tr,tg,tb,ta); + textureStore(outTex, fragCoord , vec4(color)); +} diff --git a/src/assets/shader/materials/compute/MultiBouncePass_Shader.wgsl b/src/assets/shader/materials/compute/MultiBouncePass_Shader.wgsl new file mode 100644 index 00000000..a5eb8983 --- /dev/null +++ b/src/assets/shader/materials/compute/MultiBouncePass_Shader.wgsl @@ -0,0 +1,185 @@ + + #include "MathShader" + #include "IrradianceVolumeData_frag" + + +struct IrradianceField { + probeStartPosition: vec4, + probeCounts:vec4, + probeStep:f32, + irradianceTextureWidth:f32, + irradianceTextureHeight:f32, + irradianceProbeSideLength:f32, +}; + + @group(0) @binding(0) var outputBuffer : texture_storage_2d; + @group(0) @binding(1) var uniformData : IrradianceVolumeData ; + + @group(1) @binding(0) var normalMapSampler : sampler; + @group(1) @binding(1) var normalMap : texture_2d; + + @group(1) @binding(2) var colorMapSampler : sampler; + @group(1) @binding(3) var colorMap : texture_2d; + + @group(1) @binding(4) var litMapSampler : sampler; + @group(1) @binding(5) var litMap : texture_2d; + + @group(1) @binding(6) var irradianceMapSampler : sampler; + @group(1) @binding(7) var irradianceMap : texture_2d; + + var wsn:vec3; + var ulitColor:vec4; + var litColor:vec4; + var irradianceFieldSurface : IrradianceField ; + var probeID:u32; + + var quaternion:vec4 = vec4(0.0, -0.7071067811865475, 0.7071067811865475, 0.0); + +fn getIrradianceFieldSurface() -> IrradianceField{ + let data = uniformData; + irradianceFieldSurface.probeStartPosition = vec4(data.startX, data.startY, data.startZ, 0.0); + irradianceFieldSurface.probeCounts = vec4(data.gridXCount, data.gridYCount, data.gridZCount, 0.0); + irradianceFieldSurface.probeStep = data.ProbeSpace; + irradianceFieldSurface.irradianceTextureWidth = data.OctRTMaxSize; + irradianceFieldSurface.irradianceTextureHeight = data.OctRTMaxSize; + irradianceFieldSurface.irradianceProbeSideLength = data.OctRTSideSize; + return irradianceFieldSurface; +} + + fn rotateDir(n:vec3) -> vec3{ + return normalize(applyQuaternion(-n, quaternion)); + } + + fn sampleLitColor(uv:vec2) -> vec4 + { + var oc1:vec4 = textureSampleLevel(litMap, litMapSampler, vec2(0.0), 0.0); + var oc:vec4 = textureLoad(litMap, uv, 0); + return oc; + } + + fn sampleNormal(uv:vec2) -> vec4 + { + var oc1:vec4 = textureSampleLevel(normalMap, normalMapSampler, vec2(0.0), 0.0); + var oc:vec4 = textureLoad(normalMap, uv, 0); + return oc; + } + + fn sampleColor(uv:vec2) -> vec4 + { + var oc1:vec4 = textureSampleLevel(colorMap, colorMapSampler, vec2(0.0), 0.0); + var oc:vec4 = textureLoad(colorMap, uv, 0); + return oc; + } + + fn sampleProbe(fragCoord:vec2){ + var uv = vec2(i32(fragCoord.x), i32(fragCoord.y)) ; + + litColor = sampleLitColor(uv); + + var normalMap = sampleNormal(uv); + wsn = normalMap.xyz * 2.0 - 1.0; + + ulitColor = sampleColor(uv); + } + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain(@builtin(global_invocation_id) globalInvocation_id : vec3) + { + getIrradianceFieldSurface(); + var fragCoord = vec2( globalInvocation_id.x, globalInvocation_id.y); + probeID = globalInvocation_id.z; + fragCoord = fragCoord + getCoordOffset(probeID); + + sampleProbe(fragCoord); + + let irradiance = getIrradianceColor(); + let result = blendIrradianceColor(irradiance); + textureStore(outputBuffer, vec2(fragCoord), result); + } + + fn blendIrradianceColor(irradiance:vec4) -> vec4{ + var bounceColor = irradiance * ulitColor; + let bounceIntensity = getBounceIntensity(uniformData.bounceIntensity); + let conservation1 = 1.0 / sqrt((1.0 + bounceIntensity * 0.55)); + let conservation2 = 1.0 / sqrt((1.0 + bounceIntensity)); + var result = litColor * conservation2 + bounceColor * sqrt(bounceIntensity) * conservation1; + return vec4(result.xyz, litColor.w); + } + + fn getBounceIntensity(intensity:f32) -> f32 { + var value = clamp(intensity, 0.0, 1.0) * 10.0; + return value; + } + + fn getCoordOffset(id:u32) -> vec2{ + var fullCol = u32(uniformData.ProbeSourceTextureSize / uniformData.ProbeSize); + var offsetSampleUv = vec2( (id / fullCol) * 6u , id % fullCol) * u32(uniformData.ProbeSize); + return offsetSampleUv; + } + + fn getIrradianceColor() -> vec4{ + var probeIrradiance: vec4 = vec4(0.0); + if(length(wsn) > 0.01){ + probeIrradiance = getIrrdiaceIndex(i32(probeID), wsn); + } + return probeIrradiance; + } + + fn getIrrdiaceIndex(index:i32, wsn:vec3) -> vec4{ + var wsN = rotateDir(wsn.xyz); + var texCoord:vec2 = textureCoordFromDirection(wsN, + index, + irradianceFieldSurface.irradianceTextureWidth, + irradianceFieldSurface.irradianceTextureHeight, + irradianceFieldSurface.irradianceProbeSideLength); + + var probeIrradiance: vec3 = textureSampleLevel(irradianceMap, irradianceMapSampler, texCoord, 0.0).xyz; + return vec4(probeIrradiance, 1.0); + } + + fn textureCoordFromDirection(dir:vec3, probeIndex:i32, width:f32, height:f32, sideLength:f32) -> vec2 + { + var uv = getWriteOctUVByID(dir, u32(probeIndex), sideLength) ; + uv.x = uv.x / irradianceFieldSurface.irradianceTextureWidth; + uv.y = uv.y / irradianceFieldSurface.irradianceTextureHeight; + return uv ; + } + + fn getWriteOctUVByID(dir:vec3 , probeID:u32, size: f32) -> vec2 + { + var blockCount = u32(irradianceFieldSurface.probeCounts.x * irradianceFieldSurface.probeCounts.z) ; + var offsetX = (probeID % blockCount) % u32(irradianceFieldSurface.probeCounts.x) ; + var offsetY = u32(irradianceFieldSurface.probeCounts.z - 1.0) - (probeID % blockCount) / u32(irradianceFieldSurface.probeCounts.x) ; + var offsetZ = probeID / blockCount ; + + var pixelCoord = (( octEncode(dir) + 1.0 ) * 0.5) * vec2(size,size) ; + + var blockOffset = vec2(0.0); + blockOffset.x = f32(offsetX) * size; + blockOffset.y = f32(offsetY) * size + f32(offsetZ) * f32(irradianceFieldSurface.probeCounts.z) * size; + + let mapHeight = u32(irradianceFieldSurface.irradianceTextureHeight); + var probeCounts:vec3 = vec3(irradianceFieldSurface.probeCounts.xyz); + + var gridOffsetFrom = vec2(blockOffset) + 1; + var gridOffsetTo = offsetByCol(gridOffsetFrom, size, mapHeight, probeCounts); + + pixelCoord = pixelCoord + vec2(gridOffsetTo - 1) + vec2(vec2(vec2(gridOffsetTo) / size) * 2); + + return pixelCoord + 1.0 ; + } + + fn offsetByCol(pixelCoord0:vec2, octSideSize:f32, mapHeight:u32, counts:vec3) -> vec2 + { + var pixelCoord = pixelCoord0; + let blockSize:vec2 = vec2(i32(octSideSize * counts.x), i32(octSideSize * counts.z)); + let blockSizeYBorder:i32 = i32((octSideSize + 2.0) * counts.z); + let blockMaxRowBorder:i32 = i32(mapHeight) / blockSizeYBorder; + let pixelCountYMax:i32 = blockMaxRowBorder * i32(octSideSize * counts.z); + let col:i32 = pixelCoord.y / pixelCountYMax; + + pixelCoord.x = col * i32(octSideSize * counts.x) + pixelCoord.x; + pixelCoord.y = pixelCoord.y % pixelCountYMax; + + return pixelCoord; + } diff --git a/src/assets/shader/materials/compute/OutLineBlendColor.wgsl b/src/assets/shader/materials/compute/OutLineBlendColor.wgsl new file mode 100644 index 00000000..70779dba --- /dev/null +++ b/src/assets/shader/materials/compute/OutLineBlendColor.wgsl @@ -0,0 +1,40 @@ +struct OutlineSettingData{ + strength: f32, + useAddMode: f32, + outlinePixel: f32, + fadeOutlinePixel: f32, + lowTexWidth: f32, + lowTexHeight: f32, + slot0: f32, + slot1: f32, + } + + @group(0) @binding(0) var outlineSetting: OutlineSettingData; + @group(0) @binding(1) var inTex : texture_2d; + @group(0) @binding(2) var lowTexSampler : sampler; + @group(0) @binding(3) var lowTex : texture_2d; + @group(0) @binding(4) var outlineTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(outlineTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + + let uv01 = vec2(fragCoord) / (vec2(texSize) - 1.0); + let outLineColor = textureSampleLevel(lowTex, lowTexSampler, uv01, 0.0) * outlineSetting.strength; + var newOC = textureLoad(inTex, fragCoord, 0); + var blendColor:vec3 = vec3(0.0); + if(outlineSetting.useAddMode > 0.5){ + blendColor = vec3(newOC.xyz) + vec3(outLineColor.xyz) * outLineColor.w; + }else{ + blendColor = mix(vec3(newOC.xyz), vec3(outLineColor.xyz), outLineColor.w); + } + textureStore(outlineTex, fragCoord , vec4(blendColor, newOC.w)); + } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/OutlineCalcOutline.wgsl b/src/assets/shader/materials/compute/OutlineCalcOutline.wgsl new file mode 100644 index 00000000..792dc1c1 --- /dev/null +++ b/src/assets/shader/materials/compute/OutlineCalcOutline.wgsl @@ -0,0 +1,86 @@ +struct OutlineSettingData{ + strength: f32, + useAddMode: f32, + outlinePixel: f32, + fadeOutlinePixel: f32, + lowTexWidth: f32, + lowTexHeight: f32, + slot0: f32, + slot1: f32, + } + + struct OutlineSlotData{ + color: vec3, + count: f32, + } + + struct OutlineWeightData{ + slotIndex:f32, + outerSlotIndex:f32, + entityIndex:f32, + weight:f32 + } + + struct OutlineEntities{ + list: array, + } + + @group(0) @binding(0) var outlineSetting: OutlineSettingData; + @group(0) @binding(1) var slotsBuffer : array; + @group(0) @binding(2) var weightBuffer : array; + @group(0) @binding(3) var entitiesBuffer : array; + @group(0) @binding(4) var indexTexture : texture_2d; + + var texSize: vec2; + var lowSize: vec2; + var fragCoord: vec2; + var fragCoordLow: vec2; + var coordIndex: i32; + + var fragOutline: OutlineWeightData; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoordLow = vec2( globalInvocation_id.xy ); + fragCoord = fragCoordLow * 2; + texSize = textureDimensions(indexTexture).xy; + lowSize = vec2(i32(outlineSetting.lowTexWidth), i32(outlineSetting.lowTexHeight)); + + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + if(fragCoordLow.x >= lowSize.x || fragCoordLow.y >= lowSize.y){ + return; + } + + coordIndex = fragCoordLow.x + fragCoordLow.y * lowSize.x; + fragOutline = weightBuffer[coordIndex]; + var wPos = textureLoad(indexTexture, fragCoord, 0 ) ; + + fragOutline.entityIndex = round(wPos.w); + fragOutline.slotIndex = -1.0; + fragOutline.outerSlotIndex = -1.0; + fragOutline.weight = 0.0; + + if(fragOutline.entityIndex >= 0.0){ + fragOutline.slotIndex = f32(matchOutlineSlot()); + } + weightBuffer[coordIndex] = fragOutline; + } + + fn matchOutlineSlot() -> i32 + { + for(var i:i32 = 0; i < 8; i ++){ + var slotData:OutlineSlotData = slotsBuffer[i]; + var entities:array = entitiesBuffer[i].list; + let count:i32 = i32(slotData.count); + for(var j:i32 = 0; j < count; j ++){ + var outlineIndex = entities[j]; + if(abs(fragOutline.entityIndex - outlineIndex) < 0.1){ + return i; + } + } + } + return -1; + } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/OutlineCs.wgsl b/src/assets/shader/materials/compute/OutlineCs.wgsl new file mode 100644 index 00000000..fd288996 --- /dev/null +++ b/src/assets/shader/materials/compute/OutlineCs.wgsl @@ -0,0 +1,120 @@ +struct OutlineSettingData{ + strength: f32, + useAddMode: f32, + outlinePixel: f32, + fadeOutlinePixel: f32, + lowTexWidth: f32, + lowTexHeight: f32, + slot0: f32, + slot1: f32, + } + + struct OutlineSlotData{ + color: vec3, + count: f32, + } + + struct OutlineWeightData{ + slotIndex:f32, + outerSlotIndex:f32, + entityIndex:f32, + weight:f32 + } + + @group(0) @binding(0) var outlineSetting: OutlineSettingData; + @group(0) @binding(1) var slotsBuffer : array; + @group(0) @binding(2) var weightBuffer : array; + @group(0) @binding(3) var oldOutlineColor : array>; + @group(0) @binding(4) var lowTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + var coordIndex: i32; + var fragOutline: OutlineWeightData; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(lowTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + + coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); + fragOutline = weightBuffer[coordIndex]; + + var blendColor = vec3(0.0); + var newOC = vec4(0.0); + + calcOutline(); + let outerSlotIndex:i32 = i32(round(fragOutline.outerSlotIndex)); + if(outerSlotIndex >= 0){ + let outLineColor = slotsBuffer[outerSlotIndex].color; + newOC = vec4(outLineColor, fragOutline.weight); + } + + let coordIndex0 = fragCoord.x + 1 + (fragCoord.y - 1) * i32(texSize.x); + let coordIndex1 = fragCoord.x - 1 + (fragCoord.y - 1) * i32(texSize.x); + let coordIndex2 = fragCoord.x + (fragCoord.y + 1) * i32(texSize.x); + + let oldOC = oldOutlineColor[coordIndex]; + let oldOC0 = oldOutlineColor[coordIndex0]; + let oldOC1 = oldOutlineColor[coordIndex1]; + let oldOC2 = oldOutlineColor[coordIndex2]; + + newOC = mix((oldOC + oldOC0 + oldOC1 + oldOC2) * 0.25, newOC, 0.4); + + oldOutlineColor[coordIndex] = newOC; + textureStore(lowTex, fragCoord, newOC); + } + + fn calcOutline() + { + let outlinePixel = outlineSetting.outlinePixel; + let fadeOutlinePixel = outlineSetting.fadeOutlinePixel; + let pixelRadius = outlinePixel + fadeOutlinePixel; + let minX = max(0.0, f32(fragCoord.x) - pixelRadius); + let maxX = min(f32(texSize.x), f32(fragCoord.x) + pixelRadius); + let minY = max(0.0, f32(fragCoord.y) - pixelRadius); + let maxY = min(f32(texSize.y), f32(fragCoord.y) + pixelRadius); + var coordTemp_f32 = vec2(0.0); + var coordCurrent_f32 = vec2(fragCoord); + var tempCoordIndex = 0; + var tempWeightData: OutlineWeightData; + for(var x:f32 = minX; x < maxX; x += 1.0){ + for(var y:f32 = minY; y < maxY; y += 1.0){ + coordTemp_f32.x = x; + coordTemp_f32.y = y; + let distanceToOuter = length(coordTemp_f32 - coordCurrent_f32); + if(distanceToOuter < pixelRadius){ + var coord_i32 = vec2(coordTemp_f32); + tempCoordIndex = coord_i32.x + coord_i32.y * i32(texSize.x); + tempWeightData = weightBuffer[tempCoordIndex]; + let outlineGap = abs(tempWeightData.slotIndex - fragOutline.slotIndex); + if(outlineGap > 0.1){ + if(tempWeightData.slotIndex > fragOutline.slotIndex){ + if(abs(tempWeightData.slotIndex - fragOutline.outerSlotIndex) < 0.1){ + fragOutline.weight = max(fragOutline.weight, calcWeight(pixelRadius, distanceToOuter, outlinePixel)); + fragOutline.outerSlotIndex = tempWeightData.slotIndex; + weightBuffer[tempCoordIndex] = tempWeightData; + }else if(tempWeightData.slotIndex > fragOutline.outerSlotIndex){ + fragOutline.weight = calcWeight(pixelRadius, distanceToOuter, outlinePixel); + fragOutline.outerSlotIndex = tempWeightData.slotIndex; + weightBuffer[tempCoordIndex] = tempWeightData; + } + } + } + } + } + } + } + + fn calcWeight(radius:f32, distance0:f32, outlinePixel:f32) -> f32{ + let distance = distance0 - outlinePixel; + if(distance < 0.0){ + return 1.0; + } + var ret = 1.0 - distance / (radius - outlinePixel); + return ret; + } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/Picker_CsShader.wgsl b/src/assets/shader/materials/compute/Picker_CsShader.wgsl new file mode 100644 index 00000000..b6257e13 --- /dev/null +++ b/src/assets/shader/materials/compute/Picker_CsShader.wgsl @@ -0,0 +1,65 @@ +struct GlobalUniform { + projMat: mat4x4, + viewMat: mat4x4, + cameraWorldMatrix: mat4x4, + pvMatrixInv : mat4x4, + shadowMatrix: array,8>, + CameraPos: vec3, + + frame: f32, + time: f32, + delta: f32, + shadowBias: f32, + skyExposure: f32, + renderPassState:f32, + quadScale: f32, + hdrExposure: f32, + + renderState_left: i32, + renderState_right: i32, + renderState_split: f32, + + mouseX: f32, + mouseY: f32, + windowWidth: f32, + windowHeight: f32, + + near: f32, + far: f32, + + pointShadowBias: f32, + shadowMapSize: f32, + shadowSoft: f32, + }; + +struct PickResult{ + pick_meshID:f32, + pick_meshID2:f32, + pick_UV:vec2, + pick_Position:vec4, + pick_Normal:vec4, + pick_Tangent:vec4, +} + +@group(0) @binding(0) var standUniform: GlobalUniform; +@group(0) @binding(1) var outBuffer: PickResult; +@group(0) @binding(2) var visibleMap : texture_2d; + +@compute @workgroup_size( 1 ) +fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) +{ + var result:PickResult ; + // result.pick_meshID + let texSize = textureDimensions(visibleMap).xy; + let screenPoint = vec2(standUniform.mouseX/standUniform.windowWidth,standUniform.mouseY/standUniform.windowHeight); + + let mouseUV = screenPoint * vec2(texSize.xy); + let info = textureLoad(visibleMap, vec2(mouseUV) , 0); + + outBuffer.pick_meshID = f32(info.w) ; + outBuffer.pick_meshID2 = f32(info.w) ; + outBuffer.pick_Tangent = vec4(2.0,2.0,2.0,2.0) ; + outBuffer.pick_UV = vec2(standUniform.mouseX,standUniform.mouseY) ; + outBuffer.pick_Position = vec4(info.xyzw) ; + outBuffer.pick_Normal = vec4(info.xyzw) ; +} \ No newline at end of file diff --git a/src/assets/shader/materials/compute/SSAO_CsShader.wgsl b/src/assets/shader/materials/compute/SSAO_CsShader.wgsl new file mode 100644 index 00000000..da8b0ac8 --- /dev/null +++ b/src/assets/shader/materials/compute/SSAO_CsShader.wgsl @@ -0,0 +1,99 @@ + + + #include "GlobalUniform" + + struct UniformData { + radius: f32 , + bias: f32, + aoPower: f32 , + blurSize: f32 , + }; + + @group(0) @binding(0) var standUniform: GlobalUniform; + @group(0) @binding(1) var uniformData: UniformData; + @group(0) @binding(2) var sampleData: array>; + + // @group(0) @binding(3) var colorMap : texture_2d; + @group(0) @binding(3) var positionMap : texture_2d; + @group(0) @binding(4) var normalMap : texture_2d; + + @group(0) @binding(5) var noiseMapSampler: sampler; + @group(0) @binding(6) var noiseMap : texture_2d; + + @group(0) @binding(7) var outTex : texture_storage_2d; + + var kernelSize: i32 = 32 ; + + @compute @workgroup_size( 8 , 8 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + var fragCoord = vec2( globalInvocation_id.xy ); + + var texSize = textureDimensions(positionMap).xy; + var texCoord = vec2(fragCoord) / vec2(texSize); + + var fragColor = vec4(1.0); + + var viewMat = standUniform.viewMat ; + // var color = textureLoad(colorMap, fragCoord , 0 ) ; + var wPos = textureLoad(positionMap, fragCoord , 0 ) ; + + var fragPosition = viewMat * vec4(wPos.xyz,1.0); + fragPosition = vec4(fragPosition.xyz / fragPosition.w,1.0) ; + + var texNormal = textureLoad(normalMap, fragCoord , 0 ) ; + var sampleNormal = texNormal.xyz ; + sampleNormal = sampleNormal * 2.0 - 1.0; + var fragNormal = viewMat * vec4((sampleNormal.xyz),0.0); + + var pes = vec2(texSize.xy) / 4.0 ; + var noiseTex:vec4 = textureSampleLevel(noiseMap, noiseMapSampler, texCoord * pes , 0.0); + var randomVec = (viewMat * vec4(normalize(noiseTex.xyz),0.0)).xyz; + + var tangent = normalize(randomVec - fragNormal.xyz * dot(randomVec , fragNormal.xyz)); + var bTangent = cross(fragNormal.xyz, tangent) + 0.0001 ; + var tbn = mat3x3(tangent, bTangent, fragNormal.xyz); + + var offset:vec4; + var samplePos :vec3; + var offsetPosition:f32; + var sample_depth_v:vec4; + var occlusion:f32 = 0.0; + var rangeCheck:f32 = 0.0 ; + var radius:f32 = uniformData.radius * 32.0 * fragPosition.z ; + + for(var i:i32 = 0; i < 32 ; i = i + 1 ){ + samplePos = (tbn * sampleData[i].xyz ) ; + samplePos = fragPosition.xyz + samplePos * radius ; + + offset = vec4(samplePos, 1.0); + offset = standUniform.projMat * offset; + + var off = offset.xyz / offset.w; + off = (off.xyz * 0.5 ) + 0.5 ; + off.y = 1.0 - off.y ; + var offsetUV = vec2(off.xy * vec2(texSize.xy)); + + sample_depth_v = textureLoad(positionMap, offsetUV.xy , 0 ) ; + sample_depth_v = vec4((viewMat * vec4(sample_depth_v.xyz,1.0)).xyz,1.0); + offsetPosition = sample_depth_v.z / sample_depth_v.w ; + + rangeCheck = smoothstep(0.0, 1.0, radius / abs(offsetPosition - fragPosition.z )); + // rangeCheck = smoothstep(0.0, 1.0, radius / uniformData.bias); + + var a = 1.0 ; + if(offsetPosition >= (samplePos.z + uniformData.bias)){ + a = 0.0 ; + } + a = a * rangeCheck ; + occlusion = occlusion + a ; + } + + occlusion = 1.0 - ( occlusion / f32(kernelSize) * texNormal.w ); + occlusion = pow(occlusion, uniformData.aoPower) ; + + // color = color * occlusion ; + + textureStore(outTex, fragCoord , vec4(occlusion)); + } + diff --git a/src/assets/shader/materials/compute/SSR_BlendColor_Shader.wgsl b/src/assets/shader/materials/compute/SSR_BlendColor_Shader.wgsl new file mode 100644 index 00000000..e6d6e3df --- /dev/null +++ b/src/assets/shader/materials/compute/SSR_BlendColor_Shader.wgsl @@ -0,0 +1,45 @@ + + + @group(0) @binding(0) var rayTraceBuffer : array; + @group(0) @binding(1) var colorMap : texture_2d; + @group(0) @binding(2) var ssrMapSampler : sampler; + @group(0) @binding(3) var ssrMap : texture_2d; + @group(0) @binding(4) var outTex : texture_storage_2d; + + var colorTexSize: vec2; + var ssrTexSize: vec2; + var fragCoord: vec2; + var ssrCoord: vec2; + + struct RayTraceRetData{ + skyColor:vec3, + roughness:f32, + + hitCoord:vec2, + alpha:f32, + fresnel:f32, + } + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + colorTexSize = textureDimensions(colorMap).xy; + ssrTexSize = textureDimensions(ssrMap).xy; + if(fragCoord.x >= i32(colorTexSize.x) || fragCoord.y >= i32(colorTexSize.y)){ + return; + } + let scale:f32 = f32(ssrTexSize.x) / f32(colorTexSize.x); + ssrCoord = vec2(vec2(fragCoord.xy) * scale); + let index = ssrCoord.x + ssrCoord.y * i32(ssrTexSize.x); + let hitData = rayTraceBuffer[index]; + var color = textureLoad(colorMap, fragCoord , 0); + var uv01 = vec2(f32(fragCoord.x), f32(fragCoord.y)); + uv01 = uv01 / vec2(colorTexSize - 1); + + var ssrColor = textureSampleLevel(ssrMap, ssrMapSampler, uv01, 0.0); + var tc = mix(color, ssrColor, hitData.fresnel) ; + var outColor = tc ; + outColor.a = color.a ; + textureStore(outTex, fragCoord , outColor ); + } diff --git a/src/assets/shader/materials/compute/SSR_IS_Shader.wgsl b/src/assets/shader/materials/compute/SSR_IS_Shader.wgsl new file mode 100644 index 00000000..e110ad1b --- /dev/null +++ b/src/assets/shader/materials/compute/SSR_IS_Shader.wgsl @@ -0,0 +1,82 @@ + + + struct SSRUniformData { + ssrBufferSizeX: f32, + ssrBufferSizeY: f32, + colorMapSizeX: f32, + colorMapSizeY: f32, + + fadeEdgeRatio: f32, + rayMarchRatio: f32, + fadeDistanceMin: f32, + fadeDistanceMax: f32, + + mixThreshold: f32, + roughnessThreshold: f32, + reflectionRatio: f32, + powDotRN: f32, + + randomSeedX: f32, + randomSeedY: f32, + slot1: f32, + slot2: f32, + }; + + struct RayTraceRetData{ + skyColor:vec3, + roughness:f32, + + hitCoord:vec2, + alpha:f32, + fresnel:f32, + } + + @group(0) @binding(0) var ssrUniform: SSRUniformData; + @group(0) @binding(1) var rayTraceBuffer : array; + @group(0) @binding(2) var ssrColorData : array>; + @group(0) @binding(3) var historyPosition : array>; + + @group(0) @binding(4) var colorMap: texture_2d; + @group(0) @binding(5) var outTex : texture_storage_2d; + + var ssrBufferCoord: vec2; + var colorTexSize: vec2; + var bufferData: RayTraceRetData; + var ssrBufferSize: vec2; + var coordIndex: i32; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + ssrBufferCoord = vec2( globalInvocation_id.xy ); + ssrBufferSize = vec2(i32(ssrUniform.ssrBufferSizeX), i32(ssrUniform.ssrBufferSizeY)); + colorTexSize = vec2(i32(ssrUniform.colorMapSizeX), i32(ssrUniform.colorMapSizeY)); + + if(ssrBufferCoord.x >= ssrBufferSize.x || ssrBufferCoord.y >= ssrBufferSize.y){ + return; + } + + coordIndex = ssrBufferCoord.x + ssrBufferCoord.y * ssrBufferSize.x; + bufferData = rayTraceBuffer[coordIndex]; + var oc = vec4(0.0, 0.0, 0.0, -1.0); + + var mixFactor = historyPosition[coordIndex].w; + + if(bufferData.alpha >= 0.0 && bufferData.roughness < ssrUniform.roughnessThreshold){ + let roughness = clamp(bufferData.roughness, 0.0, 1.0); + let prefilterColor = bufferData.skyColor; + var ssrColor = textureLoad(colorMap, vec2(bufferData.hitCoord), 0); + ssrColor.w = bufferData.alpha; + oc = ssrColor; + } + let skyColor = vec4(bufferData.skyColor, 1.0); + oc = mix(oc, skyColor, 1.0 - bufferData.alpha); + + let lastColor = ssrColorData[coordIndex]; + var newColor = mix(oc, lastColor, mixFactor); + newColor.w = oc.w; + + ssrColorData[coordIndex] = newColor; + + textureStore(outTex, ssrBufferCoord , newColor); + } diff --git a/src/assets/shader/materials/compute/SSR_RayTrace_Shader.wgsl b/src/assets/shader/materials/compute/SSR_RayTrace_Shader.wgsl new file mode 100644 index 00000000..cc3d8261 --- /dev/null +++ b/src/assets/shader/materials/compute/SSR_RayTrace_Shader.wgsl @@ -0,0 +1,315 @@ + + + #include "GlobalUniform" + + struct SSRUniformData { + ssrBufferSizeX: f32, + ssrBufferSizeY: f32, + colorMapSizeX: f32, + colorMapSizeY: f32, + + fadeEdgeRatio: f32, + rayMarchRatio: f32, + fadeDistanceMin: f32, + fadeDistanceMax: f32, + + mixThreshold: f32, + roughnessThreshold: f32, + reflectionRatio: f32, + powDotRN: f32, + + randomSeedX: f32, + randomSeedY: f32, + slot1: f32, + slot2: f32, + }; + + struct HitData{ + hitPos:vec3, + hitNormal:vec3, + fadeAlpha:vec4, + hitCoord:vec2, + hitResult:i32, + hitSky:i32, + }; + + struct RayTraceRetData{ + skyColor:vec3, + roughness:f32, + + hitCoord:vec2, + alpha:f32, + fresnel:f32, + } + + @group(0) @binding(0) var standUniform: GlobalUniform; + @group(0) @binding(1) var ssrUniform: SSRUniformData; + @group(0) @binding(2) var rayTraceBuffer : array; + @group(0) @binding(4) var historyPosition : array>; + + @group(0) @binding(5) var zBufferTexture : texture_2d; + @group(0) @binding(6) var normalBufferTex : texture_2d; + @group(0) @binding(7) var materialBufferTex : texture_2d; + @group(0) @binding(8) var prefilterMapSampler: sampler; + @group(0) @binding(9) var prefilterMap: texture_cube; + + var rayOrigin: vec3; + var rayDirection: vec3; + var cameraPosition: vec3; + var reflectionDir: vec3; + var colorTexSize: vec2; + var fragCoordColor: vec2; + var ssrBufferCoord: vec2; + var ssrBufferSize: vec2; + var hitData: HitData; + var rayTraceRet: RayTraceRetData; + var worldPosition: vec3; + var worldNormal: vec3; + var roughness: f32; + var fresnel: f32; + + var historyPos: vec3; + var coordIndex: i32; + + var PI: f32 = 3.14159; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + ssrBufferCoord = vec2( globalInvocation_id.xy); + ssrBufferSize = vec2(i32(ssrUniform.ssrBufferSizeX), i32(ssrUniform.ssrBufferSizeY)); + if(ssrBufferCoord.x >= ssrBufferSize.x || ssrBufferCoord.y >= ssrBufferSize.y){ + return; + } + coordIndex = ssrBufferCoord.x + ssrBufferCoord.y * ssrBufferSize.x; + + colorTexSize = vec2(i32(ssrUniform.colorMapSizeX), i32(ssrUniform.colorMapSizeY)); + fragCoordColor = convertColorCoordFromSSRCoord(ssrBufferCoord); + + hitData.fadeAlpha = vec4(0.0); + hitData.hitCoord = vec2(0); + hitData.hitResult = 0; + hitData.hitNormal = vec3(0.0, 1.0, 0.0); + hitData.hitSky = 1; + + worldPosition = textureLoad(zBufferTexture, fragCoordColor , 0).xyz; + historyPos = historyPosition[coordIndex].xyz; + + var mixFactor = 0.2; + if(length(historyPos - worldPosition) < ssrUniform.mixThreshold){ + mixFactor = 0.9; + } + historyPosition[coordIndex] = vec4(worldPosition, mixFactor); + + let normal_v4 = textureLoad(normalBufferTex, fragCoordColor , 0); + worldNormal = normalize(vec3(normal_v4.xyz) * 2.0 - 1.0); + let materialData = textureLoad(materialBufferTex, fragCoordColor , 0 ); + let roughness = materialData.g * (1.0 - materialData.b); + fresnel = (1.0 - roughness) * ssrUniform.reflectionRatio; + + cameraPosition = vec3(standUniform.cameraWorldMatrix[3].xyz); + rayOrigin = vec3(worldPosition.xyz); + + rayDirection = normalize(vec3(worldPosition.xyz - cameraPosition)); + + var randomSeed = fract(ssrUniform.randomSeedX + worldPosition.x); + rand_seed.x = randomSeed; + rand_seed.y = fract(ssrUniform.randomSeedY + worldPosition.y + worldPosition.z); + randomSeed = rand(); + + let normalRandom = makeRandomDirection(worldNormal, u32(randomSeed * 256.0), 256, roughness); + + reflectionDir = normalize(reflect(rayDirection, normalRandom)); + + if(normal_v4.w > 0.5 && roughness < ssrUniform.roughnessThreshold){ + let uvOrigin = vec2(f32(fragCoordColor.x), f32(fragCoordColor.y)); + let rayMarchPosition = rayOrigin + reflectionDir * 100.0; + var uvRayMarch = standUniform.projMat * (standUniform.viewMat * vec4(rayMarchPosition, 1.0)); + var uvOffset = (vec2(uvRayMarch.xy / uvRayMarch.w) + 1.0) * 0.5; + uvOffset.y = 1.0 - uvOffset.y; + uvOffset = uvOffset * vec2(colorTexSize - 1) - uvOrigin; + uvOffset = normalize(uvOffset); + + rayTrace(uvOffset); + if(hitData.hitResult == 1){ + hidingArtifact(); + rayTraceRet.alpha = hitData.fadeAlpha.x * hitData.fadeAlpha.y * hitData.fadeAlpha.z * hitData.fadeAlpha.w; + if(hitData.hitSky == 1){ + rayTraceRet.alpha = 0.0; + } + }else{ + rayTraceRet.alpha = 0.0; + } + rayTraceRet.skyColor = getSkyColor(); + }else{ + rayTraceRet.alpha = -1.0; + rayTraceRet.skyColor = vec3(0.0); + } + + rayTraceRet.roughness = roughness; + rayTraceRet.fresnel = fresnel; + rayTraceRet.hitCoord = vec2(hitData.hitCoord); + + let index:i32 = ssrBufferCoord.x + ssrBufferCoord.y * ssrBufferSize.x; + rayTraceBuffer[index] = rayTraceRet; + } + +fn makeRandomDirection(srcDirection:vec3, i:u32, SAMPLE_COUNT:u32, roughness:f32) -> vec3 +{ + var N: vec3 = normalize(srcDirection); + var Xi:vec2 = hammersley(i, SAMPLE_COUNT); + return ImportanceSampleGGX(Xi, N, roughness); +} + +fn hammersley( i : u32 , N : u32 ) -> vec2 +{ + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + var bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + var rdi = f32(bits) * 2.3283064365386963e-10; + return vec2(f32(i) /f32(N), rdi); +} + +fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 +{ + var a = roughness*roughness; + + var phi = 2.0 * PI * Xi.x; + var cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); + var sinTheta = sqrt(1.0 - cosTheta*cosTheta); + + // from spherical coordinates to cartesian coordinates + var H:vec3; + H.x = cos(phi) * sinTheta; + H.y = sin(phi) * sinTheta; + H.z = cosTheta; + + // from tangent-space vector to world-space sample vector + var up:vec3; + if(abs(N.z) < 0.999) + { + up = vec3(0.0, 0.0, 1.0); + } + else + { + up = vec3(1.0, 0.0, 0.0); + } + var tangent:vec3 = normalize(cross(up, N)); + var bitangent:vec3 = cross(N, tangent); + var sampleVec:vec3 = tangent * H.x + bitangent * H.y + N * H.z; + return normalize(sampleVec); +} + + var rand_seed :vec2 = vec2(0.0); + fn rand() -> f32 { + rand_seed.x = fract(cos(dot(rand_seed, vec2(23.14077926, 232.61690225))) * 136.8168); + rand_seed.y = fract(cos(dot(rand_seed, vec2(54.47856553, 345.84153136))) * 534.7645); + return rand_seed.y; + } + + fn getSkyColor() -> vec3{ + let calcRoughness = clamp(roughness, 0.0, 1.0); + let MAX_REFLECTION_LOD = f32(textureNumLevels(prefilterMap)) ; + var prefilterColor = textureSampleLevel(prefilterMap, prefilterMapSampler, reflectionDir, calcRoughness * MAX_REFLECTION_LOD); + return LinearToGammaSpace(vec3(prefilterColor.xyz)) * standUniform.skyExposure; + } + + fn LinearToGammaSpace(linRGB: vec3) -> vec3 { + var linRGB1 = max(linRGB, vec3(0.0)); + linRGB1 = pow(linRGB1, vec3(0.4166666567325592)); + return max(((1.0549999475479126 * linRGB1) - vec3(0.054999999701976776)), vec3(0.0)); + } + + fn convertColorCoordFromSSRCoord(coord:vec2) -> vec2{ + let color_ssr_ratio = ssrUniform.colorMapSizeX / ssrUniform.ssrBufferSizeX; + let targetCoord = vec2(coord) * color_ssr_ratio; + return vec2(targetCoord); + } + + fn hidingArtifact(){ + let texSizeF32 = vec2(f32(colorTexSize.x), f32(colorTexSize.y)); + let halfTexSizeF32 = texSizeF32 * 0.5; + + //near screen edge + var distance2Center = abs(vec2(f32(hitData.hitCoord.x), f32(hitData.hitCoord.y)) - halfTexSizeF32); + let halfEdgeSize:f32 = min(texSizeF32.x, texSizeF32.y) * clamp(0.01, ssrUniform.fadeEdgeRatio, 1.0) * 0.5; + var distance2Edge = min(vec2(halfEdgeSize), halfTexSizeF32 - distance2Center); + var ratioXY = distance2Edge / halfEdgeSize; + hitData.fadeAlpha.x = sqrt(ratioXY.x * ratioXY.y); + + //back face hit + var backFaceBias = max(0.0, dot(hitData.hitNormal, -reflectionDir)); + hitData.fadeAlpha.y = pow(backFaceBias, max(0.0001, ssrUniform.powDotRN)); + + //screen distance ratio + let maxLength = max(f32(colorTexSize.x), f32(colorTexSize.y)) * ssrUniform.rayMarchRatio; + let screenPointer = hitData.hitCoord - fragCoordColor; + var screenDistance = length(vec2(f32(screenPointer.x), f32(screenPointer.y))); + screenDistance = clamp(screenDistance / maxLength, 0.0, 1.0); + hitData.fadeAlpha.z = 1.0 - screenDistance; + + //position distance ratio + var fadeDistance = length(vec3(hitData.hitPos - cameraPosition)); + var dFar = ssrUniform.fadeDistanceMax; + var dNear = ssrUniform.fadeDistanceMin; + dFar = max(1.0, dFar); + dNear = clamp(dNear, 0.001, dFar - 0.001); + fadeDistance = clamp(fadeDistance, dNear, dFar); + fadeDistance = (fadeDistance - dNear) / (dFar - dNear); + hitData.fadeAlpha.w = 1.0 - fadeDistance; + } + + fn rayTrace(rayMarchDir:vec2){ + let stepLength = 4.0; + let maxLength = max(f32(colorTexSize.x), f32(colorTexSize.y)) * ssrUniform.rayMarchRatio; + for(var i:f32 = 1.0; i < maxLength; i = i + stepLength){ + let offsetFloat32 = i * rayMarchDir; + var uv = fragCoordColor + vec2(i32(offsetFloat32.x), i32(offsetFloat32.y)); + let hitRet = rayInterestScene(uv); + if(hitRet > 0){ + hitData.hitResult = hitRet; + break; + } + } + if(hitData.hitResult == 1){ + let fromUV = hitData.hitCoord; + for(var i:f32 = -stepLength; i <= 0.0; i = i + 1.0){ + let offsetFloat32 = i * rayMarchDir; + var uv = fromUV + vec2(i32(offsetFloat32.x), i32(offsetFloat32.y)); + let hitRet = rayInterestScene(uv); + if(hitRet == 1){ + let WN = textureLoad(normalBufferTex, hitData.hitCoord , 0 ); + if(WN.w > 0.5){ + hitData.hitSky = 0; + } + let normal = vec3(WN.xyz) * 2.0 - 1.0; + hitData.hitNormal = normalize(vec3(normal.xyz)); + break; + } + } + } + } + + fn rayInterestScene(uv:vec2) -> i32 { + if(uv.x < 0 || uv.y < 0 || uv.x >= colorTexSize.x || uv.y >= colorTexSize.y){ + return 2; + }else{ + let hitPos = textureLoad(zBufferTexture, uv , 0 ); + let testDir = normalize(vec3(hitPos.xyz - rayOrigin)); + let cosValue = dot(reflectionDir, testDir); + + if(cosValue > 0.9996){ + let cross1 = cross(reflectionDir, -rayDirection); + let cross2 = cross(reflectionDir, testDir); + if(dot(cross1, cross2) > 0.0){ + hitData.hitPos = vec3(hitPos.xyz); + hitData.hitCoord = uv; + return 1; + } + } + } + return 0; + } diff --git a/src/assets/shader/materials/compute/TAACopyTex.wgsl b/src/assets/shader/materials/compute/TAACopyTex.wgsl new file mode 100644 index 00000000..4993fda2 --- /dev/null +++ b/src/assets/shader/materials/compute/TAACopyTex.wgsl @@ -0,0 +1,18 @@ + @group(0) @binding(0) var preColor : array>; + @group(0) @binding(1) var preColorTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + var coordIndex: i32; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(preColorTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); + textureStore(preColorTex, fragCoord , preColor[coordIndex]); + } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/TAASharpTex.wgsl b/src/assets/shader/materials/compute/TAASharpTex.wgsl new file mode 100644 index 00000000..e57576c8 --- /dev/null +++ b/src/assets/shader/materials/compute/TAASharpTex.wgsl @@ -0,0 +1,41 @@ + + struct TAAData{ + preProjMatrix: mat4x4, + preViewMatrix: mat4x4, + jitterFrameIndex: f32, + blendFactor: f32, + sharpFactor: f32, + sharpPreBlurFactor: f32, + jitterX: f32, + jitterY: f32, + slot0: f32, + slot1: f32, + } + @group(0) @binding(0) var taaData: TAAData; + @group(0) @binding(1) var inTex : texture_2d; + @group(0) @binding(2) var outTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(outTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + + let c0 = textureLoad(inTex, vec2(fragCoord.x, fragCoord.y - 1), 0); + let c1 = textureLoad(inTex, vec2(fragCoord.x, fragCoord.y + 1), 0); + let c2 = textureLoad(inTex, vec2(fragCoord.x - 1, fragCoord.y), 0); + let c3 = textureLoad(inTex, vec2(fragCoord.x + 1, fragCoord.y), 0); + + var roundColor = (c0 + c1 + c2 + c3) * 0.25; + let originColor = textureLoad(inTex, fragCoord, 0); + let blurColor = mix(roundColor, originColor, taaData.sharpPreBlurFactor); + var oc = (originColor - blurColor * taaData.sharpFactor) / (1.0 - taaData.sharpFactor); + oc = clamp(oc, vec4(0.0), oc); + textureStore(outTex, fragCoord , oc); + } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/TAAcs.wgsl b/src/assets/shader/materials/compute/TAAcs.wgsl new file mode 100644 index 00000000..6c82bc0a --- /dev/null +++ b/src/assets/shader/materials/compute/TAAcs.wgsl @@ -0,0 +1,155 @@ + + #include "GlobalUniform" + + struct TAAData{ + preProjMatrix: mat4x4, + preViewMatrix: mat4x4, + jitterFrameIndex: f32, + blendFactor: f32, + sharpFactor: f32, + sharpPreBlurFactor: f32, + jitterX: f32, + jitterY: f32, + slot0: f32, + slot1: f32, + } + + @group(0) @binding(0) var standUniform: GlobalUniform; + @group(0) @binding(1) var taaData: TAAData; + @group(0) @binding(2) var preColorBuffer : array>; + + @group(0) @binding(3) var preColorTexSampler : sampler; + @group(0) @binding(4) var preColorTex : texture_2d; + @group(0) @binding(5) var posTex : texture_2d; + @group(0) @binding(6) var inTexSampler : sampler; + @group(0) @binding(7) var inTex : texture_2d; + @group(0) @binding(8) var outTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + var coordIndex: i32; + var color_min: vec4; + var color_max: vec4; + var color_avg: vec4; + var re_proj_uv01: vec2; + var FLT_EPS:f32 = 5.960464478e-8; // 2^-24, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f) + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(inTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + let frame = standUniform.frame; + coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); + + let oc = blendColor(); + preColorBuffer[coordIndex] = oc; + textureStore(outTex, fragCoord , oc); + } + + fn blendColor() -> vec4 + { + var preCoord = fragCoord; + var mixWeight = 1.0; + re_proj_uv01 = vec2(0.0); + var reProjectionCoord:vec2 = vec2(fragCoord); + //var jitterUVOffset = 0.5 * vec2(taaData.jitterX, -taaData.jitterY); + if(taaData.jitterFrameIndex > 0.5){ + var wPos = textureLoad(posTex, fragCoord, 0); + let ndc = taaData.preProjMatrix * (taaData.preViewMatrix * vec4(wPos.xyz, 1.0)); + re_proj_uv01 = vec2(ndc.x, -ndc.y) / ndc.w; + re_proj_uv01 = (re_proj_uv01 + 1.0) * 0.5; + + if(re_proj_uv01.x >= 0.0 && re_proj_uv01.x <= 1.0 && re_proj_uv01.y >= 0.0 && re_proj_uv01.y <= 1.0){ + mixWeight = taaData.blendFactor; + //reProjectionCoord = re_proj_uv01 + jitterUVOffset; + reProjectionCoord.x = re_proj_uv01.x * f32(texSize.x - 1); + reProjectionCoord.y = re_proj_uv01.y * f32(texSize.y - 1); + preCoord = vec2(reProjectionCoord); + }else{ + //outside of screen + mixWeight = 1.0; + } + } + + var curUV01 = vec2(fragCoord) / vec2(texSize - 1); + //curUV01 += jitterUVOffset; + + let curColor = textureSampleLevel(inTex, inTexSampler, curUV01, 0.0); + + let preIndex = preCoord.x + preCoord.y * i32(texSize.x); + var preColor = textureSampleLevel(preColorTex, preColorTexSampler, re_proj_uv01, 0.0); + + //minmax9(fragCoord); + minmax4(fragCoord); + + preColor = clip_aabb(color_min.xyz, color_max.xyz, color_avg, preColor); + var outColor = mix(preColor, curColor, mixWeight); + + return outColor; + } + + fn clampCoord(coord0:vec2) -> vec2{ + return clamp(coord0, vec2(0), vec2(texSize - 1)); + } + + fn minmax4(coord:vec2) { + let uv0 = clampCoord(vec2(coord.x - 1, coord.y)); + let uv1 = clampCoord(vec2(coord.x, coord.y - 1)); + let uv2 = clampCoord(vec2(coord.x, coord.y + 1)); + let uv3 = clampCoord(vec2(coord.x + 1, coord.y)); + + let c0 = textureLoad(inTex, uv0, 0); + let c1 = textureLoad(inTex, uv1, 0); + let c2 = textureLoad(inTex, uv2, 0); + let c3 = textureLoad(inTex, uv3, 0); + + color_min = min(c0, min(c1, min(c2, c3))); + color_max = max(c0, max(c1, max(c2, c3))); + color_avg = (c0 + c1 + c2 + c3) * 0.25; + } + + fn minmax9(coord:vec2) { + let uv0 = clampCoord(vec2(coord.x - 1, coord.y - 1)); + let uv1 = clampCoord(vec2(coord.x - 1, coord.y)); + let uv2 = clampCoord(vec2(coord.x - 1, coord.y + 1)); + let uv3 = clampCoord(vec2(coord.x, coord.y - 1)); + let uv4 = clampCoord(vec2(coord.x, coord.y)); + let uv5 = clampCoord(vec2(coord.x, coord.y + 1)); + let uv6 = clampCoord(vec2(coord.x + 1, coord.y - 1)); + let uv7 = clampCoord(vec2(coord.x + 1, coord.y)); + let uv8 = clampCoord(vec2(coord.x + 1, coord.y + 1)); + + let ctl = textureLoad(inTex, uv0, 0); + let ctc = textureLoad(inTex, uv1, 0); + let ctr = textureLoad(inTex, uv2, 0); + let cml = textureLoad(inTex, uv3, 0); + let cmc = textureLoad(inTex, uv4, 0); + let cmr = textureLoad(inTex, uv5, 0); + let cbl = textureLoad(inTex, uv6, 0); + let cbc = textureLoad(inTex, uv7, 0); + let cbr = textureLoad(inTex, uv8, 0); + + color_min = min(ctl, min(ctc, min(ctr, min(cml, min(cmc, min(cmr, min(cbl, min(cbc, cbr)))))))); + color_max = max(ctl, max(ctc, max(ctr, max(cml, max(cmc, max(cmr, max(cbl, max(cbc, cbr)))))))); + color_avg = (ctl + ctc + ctr + cml + cmc + cmr + cbl + cbc + cbr) / 9.0; + } + + fn clip_aabb(aabb_max:vec3, aabb_min:vec3, color_avg:vec4, input_texel:vec4) -> vec4 + { + var p_clip:vec3 = 0.5 * (aabb_max + aabb_min); + var e_clip:vec3 = 0.5 * (aabb_max - aabb_min) + FLT_EPS; + var v_clip:vec4 = input_texel - vec4(p_clip, color_avg.w); + var v_unit:vec3 = v_clip.xyz / e_clip; + var a_unit:vec3 = abs(v_unit); + var ma_unit:f32 = max(a_unit.x, max(a_unit.y, a_unit.z)); + + if (ma_unit > 1.0){ + return vec4(p_clip, color_avg.w) + v_clip / ma_unit; + }else{ + return input_texel; + } + } \ No newline at end of file diff --git a/src/assets/shader/materials/core/base/Common_frag.wgsl b/src/assets/shader/materials/core/base/Common_frag.wgsl new file mode 100644 index 00000000..cf46db9c --- /dev/null +++ b/src/assets/shader/materials/core/base/Common_frag.wgsl @@ -0,0 +1,26 @@ +#include "GlobalUniform" +#include "FragmentVarying" +#include "ColorPassFragmentOutput" +#include "ShadingInput" + +var ORI_FragmentOutput: FragmentOutput; +var ORI_VertexVarying: FragmentVarying; +var ORI_ShadingInput: ShadingInput; +@fragment +fn FragMain( vertex_varying:FragmentVarying ) -> FragmentOutput { + ORI_VertexVarying = vertex_varying; + ORI_FragmentOutput.color = vec4(1.0, 0.0, 0.0, 1.0); + #if USE_WORLDPOS + ORI_FragmentOutput.worldPos = ORI_VertexVarying.vWorldPos; + #endif + #if USEGBUFFER + ORI_FragmentOutput.worldNormal = vec4(ORI_ShadingInput.Normal.rgb ,1.0); + ORI_FragmentOutput.material = vec4(0.0,1.0,0.0,0.0); + #endif + frag(); + #if USE_DEBUG + debugFragmentOut(); + #endif + + return ORI_FragmentOutput ; +} diff --git a/src/assets/shader/materials/core/base/Common_vert.wgsl b/src/assets/shader/materials/core/base/Common_vert.wgsl new file mode 100644 index 00000000..e5b674ae --- /dev/null +++ b/src/assets/shader/materials/core/base/Common_vert.wgsl @@ -0,0 +1,11 @@ +#include "WorldMatrixUniform" +#include "VertexAttributes_vert" +#include "GlobalUniform" +#include "Inline_vert" +@vertex +fn VertMain( vertex:VertexAttributes ) -> VertexOutput { + vertex_inline(vertex); + vert(vertex); + return ORI_VertexOut ; +} + diff --git a/src/assets/shader/materials/core/common/BrdfLut_frag.wgsl b/src/assets/shader/materials/core/common/BrdfLut_frag.wgsl new file mode 100644 index 00000000..6a10ea79 --- /dev/null +++ b/src/assets/shader/materials/core/common/BrdfLut_frag.wgsl @@ -0,0 +1,4 @@ +@group(1) @binding(auto) +var brdflutMapSampler: sampler; +@group(1) @binding(auto) +var brdflutMap: texture_2d; \ No newline at end of file diff --git a/src/assets/shader/materials/core/common/EnvMap_frag.wgsl b/src/assets/shader/materials/core/common/EnvMap_frag.wgsl new file mode 100644 index 00000000..a26b3e5e --- /dev/null +++ b/src/assets/shader/materials/core/common/EnvMap_frag.wgsl @@ -0,0 +1,9 @@ + +@group(1) @binding(auto) +var prefilterMapSampler: sampler; +@group(1) @binding(auto) +var prefilterMap: texture_cube; +@group(1) @binding(auto) +var envMapSampler: sampler; +@group(1) @binding(auto) +var envMap: texture_cube; \ No newline at end of file diff --git a/src/assets/shader/materials/core/common/GlobalUniform.wgsl b/src/assets/shader/materials/core/common/GlobalUniform.wgsl new file mode 100644 index 00000000..8cd5e057 --- /dev/null +++ b/src/assets/shader/materials/core/common/GlobalUniform.wgsl @@ -0,0 +1,37 @@ + + struct GlobalUniform { + projMat: mat4x4, + viewMat: mat4x4, + cameraWorldMatrix: mat4x4, + pvMatrixInv : mat4x4, + shadowMatrix: array,8>, + CameraPos: vec3, + + frame: f32, + time: f32, + delta: f32, + shadowBias: f32, + skyExposure: f32, + renderPassState:f32, + quadScale: f32, + hdrExposure: f32, + + renderState_left: i32, + renderState_right: i32, + renderState_split: f32, + + mouseX: f32, + mouseY: f32, + windowWidth: f32, + windowHeight: f32, + + near: f32, + far: f32, + + pointShadowBias: f32, + shadowMapSize: f32, + shadowSoft: f32, + }; + + @group(0) @binding(0) + var globalUniform: GlobalUniform; diff --git a/src/assets/shader/materials/core/common/InstanceUniform.wgsl b/src/assets/shader/materials/core/common/InstanceUniform.wgsl new file mode 100644 index 00000000..b3b943e4 --- /dev/null +++ b/src/assets/shader/materials/core/common/InstanceUniform.wgsl @@ -0,0 +1,7 @@ +#if USE_INSTANCEDRAW + struct InstanceUniform { + matrixIDs : array + }; + @group(2) @binding(7) + var instanceDrawID : InstanceUniform; +#endif \ No newline at end of file diff --git a/src/assets/shader/materials/core/common/WorldMatrixUniform.wgsl b/src/assets/shader/materials/core/common/WorldMatrixUniform.wgsl new file mode 100644 index 00000000..2f61b771 --- /dev/null +++ b/src/assets/shader/materials/core/common/WorldMatrixUniform.wgsl @@ -0,0 +1,9 @@ + + struct Uniforms { + matrix : array> + }; + + @group(0) @binding(1) + var models : Uniforms; + + diff --git a/src/assets/shader/materials/core/inline/Inline_vert.wgsl b/src/assets/shader/materials/core/inline/Inline_vert.wgsl new file mode 100644 index 00000000..d3ce06cf --- /dev/null +++ b/src/assets/shader/materials/core/inline/Inline_vert.wgsl @@ -0,0 +1,49 @@ + + #include "MathShader" + #include "FastMathShader" + #include "InstanceUniform" + + var ORI_MATRIX_P: mat4x4; + var ORI_MATRIX_V: mat4x4; + var ORI_MATRIX_M: mat4x4; + var ORI_MATRIX_PV: mat4x4; + var ORI_MATRIX_PVInv: mat4x4; + var ORI_MATRIX_World: mat4x4; + var ORI_CAMERAMATRIX: mat4x4; + var ORI_NORMALMATRIX: mat3x3; + var ORI_CameraWorldDir: vec3; + + var TIME: vec4; + var MOUSE: vec4; + var SCREEN: vec4; + + var ProjectionParams: vec4; + + fn vertex_inline(vertex:VertexAttributes){ + TIME.x = globalUniform.frame; + TIME.y = globalUniform.time; + TIME.z = globalUniform.delta; + + MOUSE.x = globalUniform.mouseX; + MOUSE.y = globalUniform.mouseY; + + SCREEN.x = globalUniform.windowWidth; + SCREEN.y = globalUniform.windowHeight; + + ProjectionParams.x = globalUniform.near; + ProjectionParams.y = globalUniform.far; + ProjectionParams.z = 1.0 + 1.0 / globalUniform.far; + + ORI_MATRIX_P = globalUniform.projMat ; + ORI_MATRIX_V = globalUniform.viewMat ; + ORI_MATRIX_PV = ORI_MATRIX_P * ORI_MATRIX_V ; + ORI_MATRIX_PVInv = globalUniform.pvMatrixInv ; + ORI_CAMERAMATRIX = globalUniform.cameraWorldMatrix ; + + ORI_MATRIX_M = models.matrix[u32(vertex.index)]; + + #if USE_INSTANCEDRAW + let modelID = instanceDrawID.matrixIDs[vertex.index]; + ORI_MATRIX_M = models.matrix[modelID]; + #endif + } \ No newline at end of file diff --git a/src/assets/shader/materials/graphic/Graphic3DShader_fs.wgsl b/src/assets/shader/materials/graphic/Graphic3DShader_fs.wgsl new file mode 100644 index 00000000..f0b039eb --- /dev/null +++ b/src/assets/shader/materials/graphic/Graphic3DShader_fs.wgsl @@ -0,0 +1,30 @@ +struct FragmentOutput { + @location(0) color: vec4, + // #if USE_WORLDPOS + @location(1) worldPos: vec4, + // #endif + // #if USEGBUFFER + @location(2) worldNormal: vec4, + @location(3) material: vec4 + // #endif +}; + +@fragment +fn main( + @location(0) vWorldPos: vec4, + @location(1) varying_Color: vec4, +) -> FragmentOutput { + var result: FragmentOutput; + + // #if USE_WORLDPOS + result.worldPos = vWorldPos; + // #endif + + // #if USEGBUFFER + // result.worldNormal = vec4(0.0, 0.0, 0.0, 1.0); + result.material = vec4(0.0, 1.0, 0.0, 0.0); + // #endif + + result.color = varying_Color; + return result; +} diff --git a/src/assets/shader/materials/graphic/Graphic3DShader_vs.wgsl b/src/assets/shader/materials/graphic/Graphic3DShader_vs.wgsl new file mode 100644 index 00000000..336abcde --- /dev/null +++ b/src/assets/shader/materials/graphic/Graphic3DShader_vs.wgsl @@ -0,0 +1,27 @@ +#include "WorldMatrixUniform" +#include "GlobalUniform" + +struct VertexAttributes { + @location(0) position: vec4, + @location(1) color: vec4, +} + +struct VertexOutput { + @location(0) varying_WPos: vec4, + @location(1) varying_Color: vec4, + @builtin(position) member: vec4 +}; + +@vertex +fn main( vertex:VertexAttributes ) -> VertexOutput { + var worldMatrix = models.matrix[u32(vertex.position.w)]; + var worldPos = (worldMatrix * vec4(vertex.position.xyz, 1.0)); + var viewPosition = ((globalUniform.viewMat) * worldPos); + var clipPosition = globalUniform.projMat * viewPosition; + + var ORI_VertexOut: VertexOutput; + ORI_VertexOut.varying_WPos = worldPos; + ORI_VertexOut.varying_Color = vertex.color; + ORI_VertexOut.member = clipPosition; + return ORI_VertexOut; +} diff --git a/src/assets/shader/materials/materials/GlassShader.wgsl b/src/assets/shader/materials/materials/GlassShader.wgsl new file mode 100644 index 00000000..19e5b95d --- /dev/null +++ b/src/assets/shader/materials/materials/GlassShader.wgsl @@ -0,0 +1,36 @@ + + #include "Common_vert" + #include "Common_frag" + #include "UnLit_frag" + #include "UnLitMaterialUniform_frag" + + // @group(1) @binding(auto) + // var noes_MapSampler: sampler; + // @group(1) @binding(auto) + // var noes_Map: texture_2d; + + @group(1) @binding(auto) + var splitTexture_MapSampler: sampler; + @group(1) @binding(auto) + var splitTexture_Map: texture_2d; + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + var screenUV = ORI_VertexVarying.fragPosition.xy / ORI_VertexVarying.fragPosition.w; + screenUV = (screenUV.xy + 1.0) * 0.5; + screenUV.y = 1.0 - screenUV.y; + + screenUV.x = clamp(sin(screenUV.x * 1.0),0.0,1.0) ; + screenUV.y = clamp(sin(screenUV.y * 1.0),0.0,1.0) ; + // screenUV.y = cos(ORI_VertexVarying.fragPosition.y/7.15); + + let frameMap = textureSample(splitTexture_Map,splitTexture_MapSampler,screenUV); + // let noesMap = textureSample(noes_Map,noes_MapSampler,screenUV); + + ORI_ShadingInput.BaseColor = vec4( frameMap.rgb , 1.0) ; + UnLit(); + } diff --git a/src/assets/shader/materials/materials/LitShader.wgsl b/src/assets/shader/materials/materials/LitShader.wgsl new file mode 100644 index 00000000..7e9aad9c --- /dev/null +++ b/src/assets/shader/materials/materials/LitShader.wgsl @@ -0,0 +1,22 @@ + + #include "Common_vert" + #include "Common_frag" + #include "BxDF_frag" + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + ORI_ShadingInput.BaseColor = materialUniform.baseColor ; + ORI_ShadingInput.Roughness = materialUniform.roughness ; + ORI_ShadingInput.Metallic = materialUniform.metallic ; + ORI_ShadingInput.Specular = 0.5 ; + ORI_ShadingInput.AmbientOcclusion = materialUniform.ao ; + ORI_ShadingInput.EmissiveColor = vec4(0.0); + + ORI_ShadingInput.Normal = ORI_VertexVarying.vWorldNormal.rgb ; + + BxDFShading(); + } diff --git a/src/assets/shader/materials/materials/OutlinePass.wgsl b/src/assets/shader/materials/materials/OutlinePass.wgsl new file mode 100644 index 00000000..028cc2c4 --- /dev/null +++ b/src/assets/shader/materials/materials/OutlinePass.wgsl @@ -0,0 +1,80 @@ + #include "Common_vert" + #include "Common_frag" + #include "UnLit_frag" + + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d; + + +struct MaterialUniform { + baseColor:vec4, + lineWeight:f32 +}; + +@group(2) @binding(0) +var materialUniform: MaterialUniform; + + fn vert(vertex:VertexAttributes) -> VertexOutput { + var vertexPosition = vertex.position; + var vertexNormal = vertex.normal; + + #if USE_MORPHTARGETS + vertexPosition = vertexPosition * morphTargetData.morphBaseInfluence + vertex.a_morphPositions_0 * morphTargetData.morphInfluence0; + #if USE_MORPHNORMALS + vertexNormal = vertexNormal * morphTargetData.morphBaseInfluence + vertex.a_morphNormals_0 * morphTargetData.morphInfluence0; + #endif + #endif + + #if USE_SKELETON + #if USE_JOINT_VEC8 + let skeletonNormal = getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); + ORI_MATRIX_M *= skeletonNormal ; + // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; + #else + let skeletonNormal = getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); + ORI_MATRIX_M *= skeletonNormal ; + // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; + #endif + #endif + + + #if USE_TANGENT + ORI_VertexOut.varying_Tangent = vertex.TANGENT ; + #endif + + ORI_NORMALMATRIX = transpose(inverse( mat3x3(ORI_MATRIX_M[0].xyz,ORI_MATRIX_M[1].xyz,ORI_MATRIX_M[2].xyz) )); + + let worldNormal = normalize(ORI_NORMALMATRIX * vertexNormal.xyz) ; + + vertexPosition = vertexPosition + worldNormal * materialUniform.lineWeight ; + + var worldPos = (ORI_MATRIX_M * vec4(vertexPosition.xyz, 1.0)); + var viewPosition = ORI_MATRIX_V * worldPos; + var clipPosition = ORI_MATRIX_P * viewPosition ; + + ORI_VertexOut.varying_UV0 = vertex.uv.xy ; + ORI_VertexOut.varying_UV1 = vertex.TEXCOORD_1.xy; + ORI_VertexOut.varying_ViewPos = viewPosition / viewPosition.w; + ORI_VertexOut.varying_Clip = clipPosition ; + ORI_VertexOut.varying_WPos = worldPos ; + ORI_VertexOut.varying_WPos.w = f32(vertex.index); + ORI_VertexOut.varying_WNormal = worldNormal ; + ORI_VertexOut.member = clipPosition ; + + + return ORI_VertexOut ; + } + + fn frag(){ + let color = textureSample(baseMap,baseMapSampler,ORI_VertexVarying.fragUV0) ; + ORI_ShadingInput.BaseColor = color * materialUniform.baseColor ; + ORI_ShadingInput.Roughness = 0.5 ; + ORI_ShadingInput.Metallic = 0.5 ; + ORI_ShadingInput.Specular = 0.5 ; + ORI_ShadingInput.AmbientOcclusion = 1.0 ; + ORI_ShadingInput.EmissiveColor = vec4(0.0); + ORI_ShadingInput.Normal = ORI_VertexVarying.vWorldNormal.rgb ; + UnLit(); + } \ No newline at end of file diff --git a/src/assets/shader/materials/materials/PBRLItShader.wgsl b/src/assets/shader/materials/materials/PBRLItShader.wgsl new file mode 100644 index 00000000..228dac62 --- /dev/null +++ b/src/assets/shader/materials/materials/PBRLItShader.wgsl @@ -0,0 +1,106 @@ + + #include "Common_vert" + #include "Common_frag" + #include "BxDF_frag" + + @group(1) @binding(auto) + var baseMapSampler: sampler; + @group(1) @binding(auto) + var baseMap: texture_2d; + + @group(1) @binding(auto) + var normalMapSampler: sampler; + @group(1) @binding(auto) + var normalMap: texture_2d; + + #if USE_ARMC + @group(1) @binding(auto) + var maskMapSampler: sampler; + @group(1) @binding(auto) + var maskMap: texture_2d; + #endif + + #if USE_AOTEX + @group(1) @binding(auto) + var aoMapSampler: sampler; + @group(1) @binding(auto) + var aomapMap: texture_2d; + #endif + + @group(1) @binding(auto) + var emissiveMapSampler: sampler; + @group(1) @binding(auto) + var emissiveMap: texture_2d; + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + var transformUV1 = materialUniform.transformUV1; + var transformUV2 = materialUniform.transformUV2; + + var uv = transformUV1.zw * ORI_VertexVarying.fragUV0 + transformUV1.xy; + + ORI_ShadingInput.BaseColor = textureSample(baseMap, baseMapSampler, uv ) * materialUniform.baseColor ; + + // #if USE_ALPHACUT + // ORI_ShadingInput.BaseColor.a = clamp(ORI_ShadingInput.BaseColor.a, 0.001 , 1.0 ); + if( (ORI_ShadingInput.BaseColor.a - materialUniform.alphaCutoff) <= 0.0 ){ + ORI_FragmentOutput.color = vec4(0.0,0.0,0.0,1.0); + ORI_FragmentOutput.worldPos = vec4(0.0,0.0,0.0,1.0); + ORI_FragmentOutput.worldNormal = vec4(0.0,0.0,0.0,1.0); + ORI_FragmentOutput.material = vec4(0.0,0.0,0.0,1.0); + discard; + } + // #endif + + #if USE_SHADOWMAPING + directShadowMaping(globalUniform.shadowBias); + pointShadowMapCompare(globalUniform.pointShadowBias); + #endif + + + // ORI_ShadingInput.BaseColor = vec4(sRGBToLinear(ORI_ShadingInput.BaseColor.xyz),ORI_ShadingInput.BaseColor.w); + + #if USE_ARMC + var maskTex = textureSample(maskMap, maskMapSampler, uv ) ; + + ORI_ShadingInput.AmbientOcclusion = maskTex.r * materialUniform.ao ; + + #if USE_AOTEX + var aoMap = textureSample(aomapMap, aoMapSampler, uv ); + ORI_ShadingInput.AmbientOcclusion = mix(0.0,aoMap.r,materialUniform.ao) ; + #endif + + ORI_ShadingInput.Roughness = maskTex.g * materialUniform.roughness ; + ORI_ShadingInput.Metallic = maskTex.b * materialUniform.metallic ; + + #else + ORI_ShadingInput.Roughness = materialUniform.roughness ; + ORI_ShadingInput.Metallic = materialUniform.metallic ; + ORI_ShadingInput.AmbientOcclusion = materialUniform.ao ; + #if USE_AOTEX + var aoMap = textureSample(aomapMap, aoMapSampler, ORI_VertexVarying.fragUV0.xy ); + ORI_ShadingInput.AmbientOcclusion = mix(0.0,aoMap.r,materialUniform.ao) ; + #endif + #endif + + ORI_ShadingInput.Roughness = clamp(ORI_ShadingInput.Roughness,0.084,1.0); + ORI_ShadingInput.Specular = 0.5 ; + + var emissiveColor = textureSample(emissiveMap, emissiveMapSampler , ORI_VertexVarying.fragUV0.xy) ; + ORI_ShadingInput.EmissiveColor = vec4(materialUniform.emissiveColor.rgb * emissiveColor.rgb * materialUniform.emissiveIntensity,1.0); + + var Normal = textureSample(normalMap,normalMapSampler,ORI_VertexVarying.fragUV0).rgb ; + // Normal.y = 1.0 - Normal.y ; + // let normal = unPackNormal(Normal,1.0,materialUniform.normalScale) ; + let normal = unPackNormal(Normal,materialUniform.normalScale) ; + ORI_ShadingInput.Normal = normal ; + + BxDFShading(); + + + + } diff --git a/src/assets/shader/materials/materials/UnLit.wgsl b/src/assets/shader/materials/materials/UnLit.wgsl new file mode 100644 index 00000000..0c31f8b2 --- /dev/null +++ b/src/assets/shader/materials/materials/UnLit.wgsl @@ -0,0 +1,28 @@ + #include "Common_vert" + #include "Common_frag" + #include "UnLit_frag" + #include "UnLitMaterialUniform_frag" + + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d; + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + var transformUV1 = materialUniform.transformUV1; + var transformUV2 = materialUniform.transformUV2; + + var uv = transformUV1.zw * ORI_VertexVarying.fragUV0 + transformUV1.xy; + let color = textureSample(baseMap,baseMapSampler,uv) ; + if(color.w < 0.5){ + discard ; + } + + ORI_ShadingInput.BaseColor = color * materialUniform.baseColor ; + UnLit(); + } \ No newline at end of file diff --git a/src/engine/assets/shader/materials/sky/AtmosphericScatteringSky_shader.ts b/src/assets/shader/materials/materials/sky/AtmosphericScatteringSky_shader.ts similarity index 100% rename from src/engine/assets/shader/materials/sky/AtmosphericScatteringSky_shader.ts rename to src/assets/shader/materials/materials/sky/AtmosphericScatteringSky_shader.ts diff --git a/src/engine/assets/shader/materials/sky/CubeSky_Shader.ts b/src/assets/shader/materials/materials/sky/CubeSky_Shader.ts similarity index 100% rename from src/engine/assets/shader/materials/sky/CubeSky_Shader.ts rename to src/assets/shader/materials/materials/sky/CubeSky_Shader.ts diff --git a/src/engine/assets/shader/math/FastMathShader.wgsl b/src/assets/shader/materials/math/FastMathShader.wgsl similarity index 100% rename from src/engine/assets/shader/math/FastMathShader.wgsl rename to src/assets/shader/materials/math/FastMathShader.wgsl diff --git a/src/engine/assets/shader/post/FSAAShader.wgsl b/src/assets/shader/materials/post/FSAAShader.wgsl similarity index 100% rename from src/engine/assets/shader/post/FSAAShader.wgsl rename to src/assets/shader/materials/post/FSAAShader.wgsl diff --git a/src/engine/assets/shader/materials/program/BxdfDebug_frag.wgsl b/src/assets/shader/materials/program/BxdfDebug_frag.wgsl similarity index 100% rename from src/engine/assets/shader/materials/program/BxdfDebug_frag.wgsl rename to src/assets/shader/materials/program/BxdfDebug_frag.wgsl diff --git a/src/engine/assets/shader/materials/program/Clearcoat_frag.wgsl b/src/assets/shader/materials/program/Clearcoat_frag.wgsl similarity index 100% rename from src/engine/assets/shader/materials/program/Clearcoat_frag.wgsl rename to src/assets/shader/materials/program/Clearcoat_frag.wgsl diff --git a/src/engine/assets/shader/materials/program/ClusterDebug_frag.ts b/src/assets/shader/materials/program/ClusterDebug_frag.ts similarity index 100% rename from src/engine/assets/shader/materials/program/ClusterDebug_frag.ts rename to src/assets/shader/materials/program/ClusterDebug_frag.ts diff --git a/src/engine/assets/shader/materials/program/NormalMap_frag.wgsl b/src/assets/shader/materials/program/NormalMap_frag.wgsl similarity index 100% rename from src/engine/assets/shader/materials/program/NormalMap_frag.wgsl rename to src/assets/shader/materials/program/NormalMap_frag.wgsl diff --git a/src/engine/assets/shader/materials/program/ShadowMapping_frag.wgsl b/src/assets/shader/materials/program/ShadowMapping_frag.wgsl similarity index 100% rename from src/engine/assets/shader/materials/program/ShadowMapping_frag.wgsl rename to src/assets/shader/materials/program/ShadowMapping_frag.wgsl diff --git a/src/assets/shader/materials/sky/AtmosphericScatteringSky_shader.ts b/src/assets/shader/materials/sky/AtmosphericScatteringSky_shader.ts new file mode 100644 index 00000000..278c3d3a --- /dev/null +++ b/src/assets/shader/materials/sky/AtmosphericScatteringSky_shader.ts @@ -0,0 +1,311 @@ +/** + * @internal + */ +export class AtmosphericScatteringSky_shader { + public static cs: string = /* wgsl */ ` + struct UniformData { + width: f32, + height: f32, + sunU: f32, + sunV: f32, + eyePos: f32, + sunRadius: f32, // = 500.0; + sunRadiance: f32, // = 20.0; + mieG: f32, // = 0.76; + mieHeight: f32, // = 1200; + sunBrightness: f32, // = 1.0; + displaySun: f32, // > 0.5: true + }; + + @group(0) @binding(0) var uniformBuffer: UniformData; + @group(0) @binding(1) var outTexture : texture_storage_2d; + + var uv01: vec2; + var fragCoord: vec2; + var texSizeF32: vec2; + + var PI:f32 = 3.1415926535; + var PI_2:f32 = 0.0; + var EPSILON:f32 = 0.00001; + var SAMPLES_NUMS:i32 = 16; + + var transmittance:vec3; + var insctrMie:vec3; + var insctrRayleigh:vec3; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2(globalInvocation_id.xy); + texSizeF32 = vec2( uniformBuffer.width, uniformBuffer.height); + uv01 = vec2(globalInvocation_id.xy) / texSizeF32; + uv01.y = 1.0 - uv01.y - EPSILON; + PI_2 = PI * 2.0; + textureStore(outTexture, fragCoord , mainImage(uv01));//vec4(uv01, 0.0, 1.0)); + } + + struct ScatteringParams + { + sunRadius:f32, + sunRadiance:f32, + + mieG:f32, + mieHeight:f32, + + rayleighHeight:f32, + + waveLambdaMie:vec3, + waveLambdaOzone:vec3, + waveLambdaRayleigh:vec3, + + earthRadius:f32, + earthAtmTopRadius:f32, + earthCenter:vec3, + } + + fn ComputeSphereNormal(coord:vec2, phiStart:f32, phiLength:f32, thetaStart:f32, thetaLength:f32) -> vec3 + { + var normal:vec3; + normal.x = -sin(thetaStart + coord.y * thetaLength) * sin(phiStart + coord.x * phiLength); + normal.y = -cos(thetaStart + coord.y * thetaLength); + normal.z = -sin(thetaStart + coord.y * thetaLength) * cos(phiStart + coord.x * phiLength); + return normalize(normal); + } + + fn ComputeRaySphereIntersection(position:vec3, dir:vec3, center:vec3, radius:f32) -> vec2 + { + var origin:vec3 = position - center; + var B = dot(origin, dir); + var C = dot(origin, origin) - radius * radius; + var D = B * B - C; + + var minimaxIntersections:vec2; + if (D < 0.0) + { + minimaxIntersections = vec2(-1.0, -1.0); + } + else + { + D = sqrt(D); + minimaxIntersections = vec2(-B - D, -B + D); + } + + return minimaxIntersections; + } + + fn ComputeWaveLambdaRayleigh(lambda: vec3) -> vec3 + { + var n:f32 = 1.0003; + var N:f32 = 2.545E25; + var pn:f32 = 0.035; + var n2:f32 = n * n; + var pi3:f32 = PI * PI * PI; + var rayleighConst:f32 = (8.0 * pi3 * pow(n2 - 1.0,2.0)) / (3.0 * N) * ((6.0 + 3.0 * pn) / (6.0 - 7.0 * pn)); + return vec3(rayleighConst) / (lambda * lambda * lambda * lambda); + } + + fn ComputePhaseMie(theta: f32, g:f32) -> f32 + { + var g2 = g * g; + return (1.0 - g2) / pow(1.0 + g2 - 2.0 * g * saturate(theta), 1.5) / (4.0 * PI); + } + + fn ComputePhaseRayleigh(theta: f32) -> f32 + { + var theta2 = theta * theta; + return (theta2 * 0.75 + 0.75) / (4.0 * PI); + } + + fn ChapmanApproximation(X: f32, h: f32, cosZenith: f32) -> f32 + { + var c = sqrt(X + h); + var c_exp_h = c * exp(-h); + + if (cosZenith >= 0.0) + { + return c_exp_h / (c * cosZenith + 1.0); + } + else + { + var x0 = sqrt(1.0 - cosZenith * cosZenith) * (X + h); + var c0 = sqrt(x0); + + return 2.0 * c0 * exp(X - x0) - c_exp_h / (1.0 - c * cosZenith); + } + } + + fn GetOpticalDepthSchueler(h: f32, H: f32, earthRadius: f32, cosZenith: f32) -> f32 + { + return H * ChapmanApproximation(earthRadius / H, h / H, cosZenith); + } + + fn GetTransmittance(setting: ScatteringParams, L:vec3, V: vec3) -> vec3 + { + var ch = GetOpticalDepthSchueler(L.y, setting.rayleighHeight, setting.earthRadius, V.y); + return exp(-(setting.waveLambdaMie + setting.waveLambdaRayleigh) * ch); + } + + fn ComputeOpticalDepth(setting: ScatteringParams, samplePoint: vec3, V: vec3, L: vec3, neg: f32) -> vec2 + { + var rl = length(samplePoint); + var h = rl - setting.earthRadius; + var r: vec3 = samplePoint / rl; + + var cos_chi_sun = dot(r, L); + var cos_chi_ray = dot(r, V * neg); + + var opticalDepthSun = GetOpticalDepthSchueler(h, setting.rayleighHeight, setting.earthRadius, cos_chi_sun); + var opticalDepthCamera = GetOpticalDepthSchueler(h, setting.rayleighHeight, setting.earthRadius, cos_chi_ray) * neg; + + return vec2(opticalDepthSun, opticalDepthCamera); + } + + fn AerialPerspective(setting:ScatteringParams, start: vec3, end: vec3, V: vec3, L: vec3, infinite:i32) + { + var inf_neg:f32 = 1.0; + if( infinite == 0){ + inf_neg = -1.0; + } + + var sampleStep: vec3 = (end - start) / f32(SAMPLES_NUMS); + var samplePoint: vec3 = end - sampleStep; + var sampleLambda: vec3 = setting.waveLambdaMie + setting.waveLambdaRayleigh + setting.waveLambdaOzone; + + var sampleLength:f32 = length(sampleStep); + + var scattering:vec3 = vec3(0.0); + var lastOpticalDepth:vec2 = ComputeOpticalDepth(setting, end, V, L, inf_neg); + + for (var i:i32 = 1; i < SAMPLES_NUMS; i = i + 1) + { + var opticalDepth: vec2 = ComputeOpticalDepth(setting, samplePoint, V, L, inf_neg); + + var segment_s: vec3 = exp(-sampleLambda * (opticalDepth.x + lastOpticalDepth.x)); + var segment_t: vec3 = exp(-sampleLambda * (opticalDepth.y - lastOpticalDepth.y)); + + transmittance *= segment_t; + + scattering = scattering * segment_t; + scattering += exp(-(length(samplePoint) - setting.earthRadius) / setting.rayleighHeight) * segment_s; + + lastOpticalDepth = opticalDepth; + samplePoint = samplePoint - sampleStep; + } + + insctrMie = scattering * setting.waveLambdaMie * sampleLength; + insctrRayleigh = scattering * setting.waveLambdaRayleigh * sampleLength; + } + + fn ComputeSkyboxChapman(setting: ScatteringParams, eye:vec3, V:vec3, L:vec3) -> f32 + { + var neg:i32 = 1; + var outerIntersections: vec2 = ComputeRaySphereIntersection(eye, V, setting.earthCenter, setting.earthAtmTopRadius); + if (outerIntersections.y < 0.0){ + return 0.0; + } + var innerIntersections: vec2 = ComputeRaySphereIntersection(eye, V, setting.earthCenter, setting.earthRadius); + if (innerIntersections.x > 0.0) + { + neg = 0; + outerIntersections.y = innerIntersections.x; + } + + let eye0 = eye - setting.earthCenter; + + var start : vec3 = eye0 + V * max(0.0, outerIntersections.x); + var end : vec3= eye0 + V * outerIntersections.y; + + AerialPerspective(setting, start, end, V, L, neg); + + //bool intersectionTest = innerIntersections.x < 0.0 && innerIntersections.y < 0.0; + //return intersectionTest ? 1.0 : 0.0; + + if(innerIntersections.x < 0.0 && innerIntersections.y < 0.0){ + return 1.0; + } + return 0.0; + } + + fn ComputeSkyInscattering(setting: ScatteringParams, eye: vec3, V: vec3, L: vec3) -> vec4 + { + transmittance = vec3(1.0); + insctrMie = vec3(0.0); + insctrRayleigh = vec3(0.0); + var intersectionTest:f32 = ComputeSkyboxChapman(setting, eye, V, L); + + var phaseTheta = dot(V, L); + var phaseMie = ComputePhaseMie(phaseTheta, setting.mieG); + var phaseRayleigh = ComputePhaseRayleigh(phaseTheta); + var phaseNight = 1.0 - saturate(transmittance.x * EPSILON); + + var insctrTotalMie: vec3 = insctrMie * phaseMie; + var insctrTotalRayleigh: vec3 = insctrRayleigh * phaseRayleigh; + + var sky: vec3 = (insctrTotalMie + insctrTotalRayleigh) * setting.sunRadiance; + if(uniformBuffer.displaySun > 0.5){ + var angle:f32 = saturate((1.0 - phaseTheta) * setting.sunRadius); + var cosAngle:f32 = cos(angle * PI * 0.5); + var edge:f32 = 0.0; + if(angle >= 0.9){ + edge = smoothstep(0.9, 1.0, angle); + } + + var limbDarkening: vec3 = GetTransmittance(setting, -L, V); + limbDarkening *= pow(vec3(cosAngle), vec3(0.420, 0.503, 0.652)) * mix(vec3(1.0), vec3(1.2,0.9,0.5), edge) * intersectionTest; + sky += limbDarkening * uniformBuffer.sunBrightness; + } + return vec4(sky, phaseNight * intersectionTest); + } + + fn TonemapACES(x: vec3) -> vec3 + { + var A:f32 = 2.51f; + var B:f32 = 0.03f; + var C:f32 = 2.43f; + var D:f32 = 0.59f; + var E:f32 = 0.14f; + return (x * (A * x + B)) / (x * (C * x + D) + E); + } + + fn noise(uv:vec2) -> f32 + { + return fract(dot(sin(vec3(uv.xyx) * vec3(uv.xyy) * 1024.0), vec3(341896.483, 891618.637, 602649.7031))); + } + + fn mainImage( uv:vec2 ) -> vec4 + { + let eyePosition = uniformBuffer.eyePos; + var sun = vec2(uniformBuffer.sunU, uniformBuffer.sunV); + var V: vec3 = ComputeSphereNormal(uv, 0.0, PI_2, 0.0, PI); + var L: vec3 = ComputeSphereNormal(vec2(sun.x, sun.y), 0.0, PI_2, 0.0, PI); + + var setting: ScatteringParams; + setting.sunRadius = uniformBuffer.sunRadius;//500.0; + setting.sunRadiance = uniformBuffer.sunRadiance;//20.0; + setting.mieG = uniformBuffer.mieG;//0.76; + setting.mieHeight = uniformBuffer.mieHeight;// 1200.0; + setting.rayleighHeight = 8000.0; + setting.earthRadius = 6360000.0; + setting.earthAtmTopRadius = 6420000.0; + setting.earthCenter = vec3(0, -setting.earthRadius, 0); + setting.waveLambdaMie = vec3(0.0000002); + + // wavelength with 680nm, 550nm, 450nm + setting.waveLambdaRayleigh = ComputeWaveLambdaRayleigh(vec3(0.000000680, 0.000000550, 0.000000450)); + + // see https://www.shadertoy.com/view/MllBR2 + setting.waveLambdaOzone = vec3(1.36820899679147, 3.31405330400124, 0.13601728252538) * 0.0000006 * 2.504; + + var eye:vec3 = vec3(0,eyePosition,0); + var sky0:vec4 = ComputeSkyInscattering(setting, eye, V, L); + var sky = vec3(sky0.rgb); + + // sky = TonemapACES(sky.rgb * 2.0); + // sky = pow(sky.rgb, vec3(2.4)); // gamma + // sky.rgb += noise(uv*iTime) / 255.0; // dither + + var fragColor:vec4 = vec4(sky, 1.0); + return fragColor; + } + `; +} diff --git a/src/assets/shader/materials/sky/CubeSky_Shader.ts b/src/assets/shader/materials/sky/CubeSky_Shader.ts new file mode 100644 index 00000000..dca45731 --- /dev/null +++ b/src/assets/shader/materials/sky/CubeSky_Shader.ts @@ -0,0 +1,98 @@ +export class CubeSky_Shader { + public static sky_vs_frag_wgsl: string = /* wgsl */ ` + #include "WorldMatrixUniform" + #include "GlobalUniform" + + struct VertexOutput { + @location(0) fragUV: vec2, + @location(1) vWorldPos: vec4, + @location(2) vWorldNormal: vec3, + @builtin(position) member: vec4 + }; + + var ORI_VertexOut: VertexOutput ; + + @vertex + fn main( + @builtin(instance_index) index : u32, + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) uv: vec2 + ) -> VertexOutput { + ORI_VertexOut.fragUV = uv; + let modelMat = models.matrix[u32(index)]; + let vm = globalUniform.viewMat * modelMat; + let normalMatrix = mat3x3(vm[0].xyz,vm[1].xyz,vm[2].xyz); + ORI_VertexOut.vWorldNormal = normalize( normalMatrix * normal ); + ORI_VertexOut.vWorldPos = modelMat * vec4(position.xyz,1.0) ; + + var fixProjMat = globalUniform.projMat ; + fixProjMat[2].z = 1.0 ;//99999.0 / (99999.0 - 1.0) ; + fixProjMat[3].z = -1.0 ;//(-1.0 * 99999.0) / (99999.0 - 1.0) ; + + var fixViewMat = globalUniform.viewMat ; + fixViewMat[3].x = 0.0 ; + fixViewMat[3].y = 0.0 ; + fixViewMat[3].z = 0.0 ; + + var clipPos = fixProjMat * fixViewMat * ORI_VertexOut.vWorldPos; + ORI_VertexOut.member = clipPos; + return ORI_VertexOut; + } + ` + + public static sky_fs_frag_wgsl: string = /* wgsl */ ` + #include "GlobalUniform" + + struct uniformData { + exposure: f32, + roughness: f32 + }; + + struct FragmentOutput { + @location(0) o_Target: vec4, + #if USE_WORLDPOS + @location(1) o_Position: vec4, + #endif + #if USEGBUFFER + @location(2) o_Normal: vec4, + @location(3) o_Material: vec4 + #endif + }; + + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_cube; + + @group(2) @binding(0) + var global: uniformData; + + fn LinearToGammaSpace(linRGB: vec3) -> vec3 { + var linRGB1 = max(linRGB, vec3(0.0)); + linRGB1 = pow(linRGB1, vec3(0.4166666567325592)); + return max(((1.0549999475479126 * linRGB1) - vec3(0.054999999701976776)), vec3(0.0)); + } + + @fragment + fn main(@location(0) fragUV: vec2, @location(1) vWorldPos: vec4, @location(2) vWorldNormal: vec3) -> FragmentOutput { + let maxLevel: u32 = textureNumLevels(baseMap); + let textureColor:vec3 = textureSampleLevel(baseMap, baseMapSampler, normalize(vWorldPos.xyz), global.roughness * f32(maxLevel) ).xyz; + let o_Target: vec4 = vec4(LinearToGammaSpace(textureColor),1.0) * globalUniform.skyExposure ; + var normal_rgba8unorm = (vWorldNormal + 1.0) * 0.5; + normal_rgba8unorm = clamp(normal_rgba8unorm, vec3(0.0), vec3(1.0)); + + return FragmentOutput( + o_Target, + #if USE_WORLDPOS + vWorldPos, + #endif + #if USEGBUFFER + vec4(normal_rgba8unorm,0.0), + vec4(0.0,1.0,0.0,0.0) + #endif + ); + } + `; + +} \ No newline at end of file diff --git a/src/engine/assets/shader/materials/uniforms/MaterialUniform.ts b/src/assets/shader/materials/uniforms/MaterialUniform.ts similarity index 100% rename from src/engine/assets/shader/materials/uniforms/MaterialUniform.ts rename to src/assets/shader/materials/uniforms/MaterialUniform.ts diff --git a/src/engine/assets/shader/materials/uniforms/PhysicMaterialUniform_frag.ts b/src/assets/shader/materials/uniforms/PhysicMaterialUniform_frag.ts similarity index 100% rename from src/engine/assets/shader/materials/uniforms/PhysicMaterialUniform_frag.ts rename to src/assets/shader/materials/uniforms/PhysicMaterialUniform_frag.ts diff --git a/src/engine/assets/shader/materials/uniforms/UnLitMaterialUniform_frag.ts b/src/assets/shader/materials/uniforms/UnLitMaterialUniform_frag.ts similarity index 100% rename from src/engine/assets/shader/materials/uniforms/UnLitMaterialUniform_frag.ts rename to src/assets/shader/materials/uniforms/UnLitMaterialUniform_frag.ts diff --git a/src/engine/assets/shader/materials/uniforms/VideoUniform_frag.ts b/src/assets/shader/materials/uniforms/VideoUniform_frag.ts similarity index 100% rename from src/engine/assets/shader/materials/uniforms/VideoUniform_frag.ts rename to src/assets/shader/materials/uniforms/VideoUniform_frag.ts diff --git a/src/engine/assets/shader/utils/BRDFLUT.wgsl b/src/assets/shader/materials/utils/BRDFLUT.wgsl similarity index 100% rename from src/engine/assets/shader/utils/BRDFLUT.wgsl rename to src/assets/shader/materials/utils/BRDFLUT.wgsl diff --git a/src/engine/assets/shader/utils/ColorUtil.wgsl b/src/assets/shader/materials/utils/ColorUtil.wgsl similarity index 100% rename from src/engine/assets/shader/utils/ColorUtil.wgsl rename to src/assets/shader/materials/utils/ColorUtil.wgsl diff --git a/src/engine/assets/shader/utils/GenerayRandomDir.wgsl b/src/assets/shader/materials/utils/GenerayRandomDir.wgsl similarity index 100% rename from src/engine/assets/shader/utils/GenerayRandomDir.wgsl rename to src/assets/shader/materials/utils/GenerayRandomDir.wgsl diff --git a/src/assets/shader/math/FastMathShader.wgsl b/src/assets/shader/math/FastMathShader.wgsl new file mode 100644 index 00000000..d10eaf7c --- /dev/null +++ b/src/assets/shader/math/FastMathShader.wgsl @@ -0,0 +1,31 @@ +fn Pow3( x : f32 ) -> f32 +{ + var xx = x*x; + return x * xx; +} + +fn Pow4( x : f32 ) -> f32 +{ + var xx = x*x; + return xx * xx; +} + +fn pow5(x: f32) -> f32 { + var x2 = x * x; + return x2 * x2 * x; +} + +fn rcp( x:f32 ) -> f32 +{ + return 1.0 / x; +} + +fn rsqrt3( a : vec3 ) -> vec3 +{ + return pow(a, vec3(-0.5)); +} + +fn rsqrt( a : f32 ) -> f32 +{ + return pow(a, -0.5); +} diff --git a/src/engine/assets/shader/math/MathShader.ts b/src/assets/shader/math/MathShader.ts similarity index 100% rename from src/engine/assets/shader/math/MathShader.ts rename to src/assets/shader/math/MathShader.ts diff --git a/src/engine/assets/shader/post/Bloom_shader.ts b/src/assets/shader/post/Bloom_shader.ts similarity index 100% rename from src/engine/assets/shader/post/Bloom_shader.ts rename to src/assets/shader/post/Bloom_shader.ts diff --git a/src/assets/shader/post/FSAAShader.wgsl b/src/assets/shader/post/FSAAShader.wgsl new file mode 100644 index 00000000..67ba238e --- /dev/null +++ b/src/assets/shader/post/FSAAShader.wgsl @@ -0,0 +1,76 @@ +struct FragmentOutput { + @location(0) o_Target: vec4 +}; + +var varying_uv: vec2; +@group(1) @binding(0) +var baseMapSampler: sampler; +@group(1) @binding(1) +var baseMap: texture_2d; + +struct MaterialUniform{ + u_texel: vec2, + u_strength: f32, +} + + @group(2) @binding(0) + var materialUniform: MaterialUniform; + + +fn LinearToGammaSpace(linRGB0: vec3) -> vec3 { + var linRGB = max(linRGB0, vec3(0.0, 0.0, 0.0)); + linRGB.r = pow(linRGB.r,0.416666667); + linRGB.g = pow(linRGB.g,0.416666667); + linRGB.b = pow(linRGB.b,0.416666667); + return max(1.055 * linRGB - 0.055, vec3(0.0, 0.0, 0.0)); +} + +fn texture2D( uv:vec2 , offset:vec2 ) -> vec4 { + return textureSample(baseMap, baseMapSampler, uv.xy + offset ).rgba ; +} + +@fragment +fn main(@location(0) fragUV: vec2) -> FragmentOutput { + var v_vTexcoord = fragUV ; + // v_vTexcoord.x = 1.0 - v_vTexcoord.x ; + v_vTexcoord.y = 1.0 - v_vTexcoord.y ; + + var reducemul = 1.0 / 8.0; + var reducemin = 1.0 / 128.0; + + var basecol = texture2D(v_vTexcoord , vec2(0.0)).rgba; + var baseNW = texture2D(v_vTexcoord , -materialUniform.u_texel).rgb; + var baseNE = texture2D(v_vTexcoord , vec2(materialUniform.u_texel.x, -materialUniform.u_texel.y)).rgb; + var baseSW = texture2D(v_vTexcoord , vec2(-materialUniform.u_texel.x, materialUniform.u_texel.y)).rgb; + var baseSE = texture2D(v_vTexcoord , materialUniform.u_texel ).rgb; + + // var gray = vec3(0.299, 0.587, 0.114); + var gray = vec3(0.213, 0.715, 0.072); + var monocol = dot(basecol.rgb, gray); + var monoNW = dot(baseNW, gray); + var monoNE = dot(baseNE, gray); + var monoSW = dot(baseSW, gray); + var monoSE = dot(baseSE, gray); + + var monomin = min(monocol, min(min(monoNW, monoNE), min(monoSW, monoSE))); + var monomax = max(monocol, max(max(monoNW, monoNE), max(monoSW, monoSE))); + + var dir = vec2(-((monoNW + monoNE) - (monoSW + monoSE)), ((monoNW + monoSW) - (monoNE + monoSE))); + var dirreduce = max((monoNW + monoNE + monoSW + monoSE) * reducemul * 0.25, reducemin); + var dirmin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirreduce); + dir = min(vec2(materialUniform.u_strength), max(vec2(-materialUniform.u_strength), dir * dirmin)) * materialUniform.u_texel; + + var resultA = 0.5 * (texture2D(v_vTexcoord , dir * -0.166667).rgb + + texture2D(v_vTexcoord , dir * 0.166667).rgb); + var resultB = resultA * 0.5 + 0.25 * (texture2D( v_vTexcoord , dir * -0.5).rgb + + texture2D( v_vTexcoord , dir * 0.5).rgb); + var monoB = dot(resultB.rgb, gray); + + var color:vec3 ; + if(monoB < monomin || monoB > monomax) { + color = resultA ;//* v_vColour; + } else { + color = resultB ;//* v_vColour; + } + return FragmentOutput(vec4(color.rgb,basecol.a)); +} \ No newline at end of file diff --git a/src/engine/assets/shader/post/GlobalFog_shader.ts b/src/assets/shader/post/GlobalFog_shader.ts similarity index 100% rename from src/engine/assets/shader/post/GlobalFog_shader.ts rename to src/assets/shader/post/GlobalFog_shader.ts diff --git a/src/engine/assets/shader/quad/Quad_shader.ts b/src/assets/shader/quad/Quad_shader.ts similarity index 100% rename from src/engine/assets/shader/quad/Quad_shader.ts rename to src/assets/shader/quad/Quad_shader.ts diff --git a/src/assets/shader/utils/BRDFLUT.wgsl b/src/assets/shader/utils/BRDFLUT.wgsl new file mode 100644 index 00000000..4a898192 --- /dev/null +++ b/src/assets/shader/utils/BRDFLUT.wgsl @@ -0,0 +1,112 @@ + var PI:f32 = 3.141592653589793 ; + + // fn saturate( x : f32 ) -> f32 { + // return clamp(x, 0.0, 1.0); + // } + + fn hammersley( i : u32 , N : u32 ) -> vec2 + { + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + var bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + var rdi = f32(bits) * 2.3283064365386963e-10; + return vec2(f32(i) /f32(N), rdi); + } + + fn G_Smith( NoV:f32 , NoL : f32 , roughness : f32 ) -> f32 + { + var k = (roughness * roughness) / 2.0; + var GGXL = NoL / (NoL * (1.0 - k) + k); + var GGXV = NoV / (NoV * (1.0 - k) + k); + return GGXL * GGXV; + } + + fn V_SmithGGXCorrelated( NoV:f32 , NoL : f32 , roughness : f32 ) -> f32 + { + var a2 = pow(roughness, 4.0); + var GGXV = NoL * sqrt(NoV * NoV * (1.0 - a2) + a2); + var GGXL = NoV * sqrt(NoL * NoL * (1.0 - a2) + a2); + return 0.5 / (GGXV + GGXL); + } + + + // Based on Karis 2014 + fn importanceSampleGGX( Xi:vec2, roughness:f32 , N:vec3 ) -> vec3 + { + var a = roughness * roughness; + // Sample in spherical coordinates + var Phi = 2.0 * PI * Xi.x; + var CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); + var SinTheta = sqrt(1.0 - CosTheta * CosTheta); + // Construct tangent space vector + var H:vec3; + H.x = SinTheta * cos(Phi); + H.y = SinTheta * sin(Phi); + H.z = CosTheta; + + // Tangent to world space + var UpVector = vec3(1.0,0.0,0.0); + if(abs(N.z) < 0.999){ + UpVector = vec3(0.0,0.0,1.0) ; + } + var TangentX = normalize(cross(UpVector, N)); + var TangentY = cross(N, TangentX); + return TangentX * H.x + TangentY * H.y + N * H.z; + } + + + // Karis 2014 + fn integrateBRDF( roughness:f32 , NoV: f32) -> vec2 + { + var V : vec3 ; + V.x = sqrt(1.0 - NoV * NoV); // sin + V.y = 0.0; + V.z = NoV; // cos + + // N points straight upwards for this integration + var N = vec3(0.0, 0.0, 1.0); + + var A = 0.0; + var B = 0.0; + var numSamples = 1024u; + + for (var i = 0u; i < numSamples; i+=1u) { + var Xi = hammersley(i, numSamples); + // Sample microfacet direction + var H = importanceSampleGGX(Xi, roughness, N); + + // Get the light direction + var L = 2.0 * dot(V, H) * H - V; + + var NoL = saturate(dot(N, L)); + var NoH = saturate(dot(N, H)); + var VoH = saturate(dot(V, H)); + + if(NoL > 0.0) { + var V_pdf = V_SmithGGXCorrelated(NoV, NoL, roughness) * VoH * NoL / NoH; + var Fc = pow(1.0 - VoH, 5.0); + A += (1.0 - Fc) * V_pdf; + B += Fc * V_pdf; + } + } + + return 4.0 * vec2(A, B) / f32(numSamples); + } + + @group(0) @binding(0) var brdflutTexture : texture_storage_2d; + + @compute @workgroup_size(8,8,1) + // fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(local_invocation_id) local_invocation_id : vec3 ){ + fn CsMain( @builtin(global_invocation_id) global_invocation_id : vec3){ + var fragCoord = vec2( global_invocation_id.x, global_invocation_id.y); + + var fragColor = vec4(0.0) ; + // Output to screen + var res = integrateBRDF( f32(fragCoord.y+1u) / 256.0 , f32(fragCoord.x+1u) / 256.0 ); + fragColor = vec4(res.x, res.y, 0.0, 1.0) ; + + textureStore(brdflutTexture, vec2(fragCoord.xy), fragColor ); + } diff --git a/src/assets/shader/utils/ColorUtil.wgsl b/src/assets/shader/utils/ColorUtil.wgsl new file mode 100644 index 00000000..5db84e7a --- /dev/null +++ b/src/assets/shader/utils/ColorUtil.wgsl @@ -0,0 +1,99 @@ + + + fn getHDRColor(color:vec3,exposure:f32)-> vec3{ + // var newColor = color * ( 1.0 / 255.0 ) ; + return color * pow(2.4 , exposure) ; + } + + fn lambda2rgb( lambda : f32 ) -> vec3 { + let ultraviolet = 400.0; + let infrared = 700.0; + + var a = (lambda - ultraviolet)/(infrared - ultraviolet); + let c = 10.0; + var b = vec3(a) - vec3(0.75,0.5,0.25); + return max((1.0 - c*b*b), vec3(0.0) ); + } + + fn CEToneMapping( color:vec3, adapted_lum:f32)-> vec3 + { + return 1.0 - exp(-adapted_lum * color); + } + + fn ACESToneMapping( color:vec3, adapted_lum:f32 )-> vec3 + { + let A = 2.51; + let B = 0.03; + let C = 2.43; + let D = 0.59; + let E = 0.14; + + var color2 = color * adapted_lum; + color2 = (color2 * (A * color2 + B)) / (color2 * (C * color2 + D) + E); + return color2 ; + } + + fn gammaToLiner(color:vec4) -> vec4 { + let gammaCorrect = 2.4; + var color2 = pow(color, vec4(gammaCorrect)); + return color2 ; + } + + fn linerToGamma4(color:vec4) -> vec4 { + let gammaCorrect = 1.0 / 2.4; + var color2 = pow(color, vec4(gammaCorrect)); + return color2 ; + } + + fn linerToGamma3(color:vec3) -> vec3 { + let gammaCorrect = 1.0 / 2.4; + var color2 = pow(color, vec3(gammaCorrect)); + return color2 ; + } + + fn LinearToGammaSpace(linRGB0: vec3) -> vec3 { + var linRGB = max(linRGB0, vec3(0.0, 0.0, 0.0)); + linRGB.r = pow(linRGB.r,0.416666667); + linRGB.g = pow(linRGB.g,0.416666667); + linRGB.b = pow(linRGB.b,0.416666667); + return max(1.055 * linRGB - 0.055, vec3(0.0, 0.0, 0.0)); + } + + var sRGB_2_LMS_MAT:mat3x3 = mat3x3( + 17.8824, 43.5161, 4.1193, + 3.4557, 27.1554, 3.8671, + 0.02996, 0.18431, 1.4670, + ) ; + + var LMS_2_sRGB_MAT:mat3x3 = mat3x3( + 0.0809, -0.1305, 0.1167, + -0.0102, 0.0540, -0.1136, + -0.0003, -0.0041, 0.6935, + ); + + fn sRGB_2_LMS( RGB:vec3 ) -> vec3 + { + return sRGB_2_LMS_MAT * RGB ; + } + + fn LMS_2_sRGB( LMS:vec3 ) -> vec3 + { + return LMS_2_sRGB_MAT * LMS; + } + + fn LinearToSrgbBranchless( lin:vec3 ) -> vec3 + { + var lin2 = max(vec3(6.10352e-5), lin); + return min(lin2 * 12.92, pow(max(lin2, vec3(0.00313067)), vec3(1.0/2.4)) * vec3(1.055) - vec3(0.055)); + } + + fn sRGBToLinear( color : vec3 ) -> vec3 + { + let color2 = max(vec3(6.10352e-5), color); + let c = 0.04045 ; + if(color2.r > c && color2.g > c && color2.b > c){ + return pow( color2 * (1.0 / 1.055) + 0.0521327, vec3(2.4) ) ; + }else{ + return color2 * (1.0 / 12.92); + } + } diff --git a/src/assets/shader/utils/GenerayRandomDir.wgsl b/src/assets/shader/utils/GenerayRandomDir.wgsl new file mode 100644 index 00000000..74a72796 --- /dev/null +++ b/src/assets/shader/utils/GenerayRandomDir.wgsl @@ -0,0 +1,23 @@ + +fn madfrac(A:f32, B:f32)-> f32 { + return A*B-floor(A*B) ; +} + +fn sampleRandomDir(count:u32,SAMPLE_COUNT:u32) -> vec3{ + var ray_dir = sphericalFibonacci(f32((count)), f32(SAMPLE_COUNT) ); + return normalize(ray_dir) ; +} + +fn sphericalFibonacci( i : f32 , n : f32 ) -> vec3{ + const PHI = sqrt(5.0) * 0.5 + 0.5; + let phi = 2.0 * PI * madfrac(i, PHI - 1); + let cosTheta = 1.0 - (2.0 * i + 1.0) * (1.0 / n); + let sinTheta = sqrt(saturate(1.0 - cosTheta*cosTheta)); + + return vec3( + cos(phi) * sinTheta, + sin(phi) * sinTheta, + cosTheta); + +} + diff --git a/src/engine/components/AtmosphericComponent.ts b/src/components/AtmosphericComponent.ts similarity index 95% rename from src/engine/components/AtmosphericComponent.ts rename to src/components/AtmosphericComponent.ts index e637920a..1749b083 100644 --- a/src/engine/components/AtmosphericComponent.ts +++ b/src/components/AtmosphericComponent.ts @@ -73,23 +73,23 @@ export class AtmosphericComponent extends SkyRenderer { this._atmosphericScatteringSky.apply(); } - protected init(): void { + public init(): void { super.init(); this._atmosphericScatteringSky = new AtmosphericScatteringSky(new AtmosphericScatteringSkySetting()); } - protected start(): void { + public start(): void { let scene = this.transform.scene3D; this.map = this._atmosphericScatteringSky; scene.envMap = this._atmosphericScatteringSky; super.start(); } - protected onEnable(): void { + public onEnable(): void { } - protected onDisable(): void { + public onDisable(): void { } diff --git a/src/engine/components/BillboardComponent.ts b/src/components/BillboardComponent.ts similarity index 98% rename from src/engine/components/BillboardComponent.ts rename to src/components/BillboardComponent.ts index 1419e2bd..6c3d8d2b 100644 --- a/src/engine/components/BillboardComponent.ts +++ b/src/components/BillboardComponent.ts @@ -19,7 +19,7 @@ export class BillboardComponent extends ComponentBase { this._cameraDirection = new Vector3(); } - protected onUpdate() { + public onUpdate() { super.onUpdate(); if (this.enable && this.transform.view3D.camera) { this.updateBillboardMatrix(); diff --git a/src/engine/components/ColliderComponent.ts b/src/components/ColliderComponent.ts similarity index 98% rename from src/engine/components/ColliderComponent.ts rename to src/components/ColliderComponent.ts index 9d25b2ff..9e8e8a7e 100644 --- a/src/engine/components/ColliderComponent.ts +++ b/src/components/ColliderComponent.ts @@ -19,7 +19,7 @@ export class ColliderComponent extends ComponentBase { /** * @internal */ - protected start(): void { + public start(): void { if (Engine3D.setting.pick.mode == `pixel`) { this.transform.scene3D.view.pickFire.mouseEnableMap.set(this.transform.worldMatrix.index, this); } diff --git a/src/engine/components/ComponentBase.ts b/src/components/ComponentBase.ts similarity index 74% rename from src/engine/components/ComponentBase.ts rename to src/components/ComponentBase.ts index 1dc9a660..3328b02b 100644 --- a/src/engine/components/ComponentBase.ts +++ b/src/components/ComponentBase.ts @@ -1,6 +1,8 @@ import { View3D } from "../core/View3D"; import { Object3D } from "../core/entities/Object3D"; import { CEventDispatcher } from "../event/CEventDispatcher"; +import { ComponentCollect } from "../gfx/renderJob/collect/ComponentCollect"; +import { IComponent } from "./IComponent"; import { Transform } from "./Transform"; /** @@ -8,7 +10,7 @@ import { Transform } from "./Transform"; * The component can receive update events at each frame. * @group Components */ -export class ComponentBase { +export class ComponentBase implements IComponent { /** * owner object3D */ @@ -99,25 +101,19 @@ export class ComponentBase { this._onCompute(null); this._onGraphic(null); - this.onEnable = null; - this.onDisable = null; - this.onUpdate = null; - this.onLateUpdate = null; - this.onBeforeUpdate = null; - this.onCompute = null; - this.onGraphic = null; + } - protected init(param?: any) { } - protected start() { } - protected stop() { } - protected onEnable?(view?: View3D); - protected onDisable?(view?: View3D); - protected onUpdate?(view?: View3D); - protected onLateUpdate?(view?: View3D); - protected onBeforeUpdate?(view?: View3D); - protected onCompute?(view?: View3D, command?: GPUCommandEncoder); - protected onGraphic?(view?: View3D); + public init(param?: any) { } + public start() { } + public stop() { } + public onEnable?(view?: View3D); + public onDisable?(view?: View3D); + public onUpdate?(view?: View3D); + public onLateUpdate?(view?: View3D); + public onBeforeUpdate?(view?: View3D); + public onCompute?(view?: View3D, command?: GPUCommandEncoder); + public onGraphic?(view?: View3D); /** * @@ -133,9 +129,9 @@ export class ComponentBase { */ private _onUpdate(call: Function) { if (call != null) { - ComponentBase.componentsUpdateList.set(this, call); + ComponentCollect.componentsUpdateList.set(this, call); } else { - ComponentBase.componentsUpdateList.delete(this); + ComponentCollect.componentsUpdateList.delete(this); } } @@ -146,9 +142,9 @@ export class ComponentBase { private _onLateUpdate(call: Function) { // if(!this.enable) return; if (call != null) { - ComponentBase.componentsLateUpdateList.set(this, call); + ComponentCollect.componentsLateUpdateList.set(this, call); } else { - ComponentBase.componentsLateUpdateList.delete(this); + ComponentCollect.componentsLateUpdateList.delete(this); } } @@ -159,9 +155,9 @@ export class ComponentBase { private _onBeforeUpdate(call: Function) { // if(!this.enable) return; if (call != null) { - ComponentBase.componentsBeforeUpdateList.set(this, call); + ComponentCollect.componentsBeforeUpdateList.set(this, call); } else { - ComponentBase.componentsBeforeUpdateList.delete(this); + ComponentCollect.componentsBeforeUpdateList.delete(this); } } @@ -172,9 +168,9 @@ export class ComponentBase { */ private _onCompute(call: Function) { if (call != null) { - ComponentBase.componentsComputeList.set(this, call); + ComponentCollect.componentsComputeList.set(this, call); } else { - ComponentBase.componentsComputeList.delete(this); + ComponentCollect.componentsComputeList.delete(this); } } @@ -184,9 +180,9 @@ export class ComponentBase { */ private _onGraphic(call: Function) { if (call != null) { - ComponentBase.graphicComponent.set(this, call); + ComponentCollect.graphicComponent.set(this, call); } else { - ComponentBase.graphicComponent.delete(this); + ComponentCollect.graphicComponent.delete(this); } } @@ -199,27 +195,17 @@ export class ComponentBase { this._onBeforeUpdate(null); this._onUpdate(null); this._onLateUpdate(null); - } - /** - * @internal - */ - static componentsUpdateList: Map = new Map(); - - /** - * @internal - */ - static componentsLateUpdateList: Map = new Map(); + this.onEnable = null; + this.onDisable = null; + this.onUpdate = null; + this.onLateUpdate = null; + this.onBeforeUpdate = null; + this.onCompute = null; + this.onGraphic = null; + } - /** - * @internal - */ - static componentsBeforeUpdateList: Map = new Map(); - /** - * @internal - */ - static componentsComputeList: Map = new Map(); /** * @internal diff --git a/src/components/IComponent.ts b/src/components/IComponent.ts new file mode 100644 index 00000000..d6b5a28e --- /dev/null +++ b/src/components/IComponent.ts @@ -0,0 +1,23 @@ +import { View3D } from "../core/View3D"; +import { Object3D } from "../core/entities/Object3D"; +import { CEventDispatcher } from "../event/CEventDispatcher"; +import { Transform } from "./Transform"; + +export interface IComponent { + object3D: Object3D; + eventDispatcher: CEventDispatcher; + transform: Transform; + enable: boolean; + init(param?: any); + start(); + stop(); + onEnable?(view?: View3D); + onDisable?(view?: View3D); + onUpdate?(view?: View3D); + onLateUpdate?(view?: View3D); + onBeforeUpdate?(view?: View3D); + onCompute?(view?: View3D, command?: GPUCommandEncoder); + onGraphic?(view?: View3D); + cloneTo(obj: Object3D); + destroy() +} \ No newline at end of file diff --git a/src/engine/components/SkeletonAnimationComponent.ts b/src/components/SkeletonAnimationComponent.ts similarity index 99% rename from src/engine/components/SkeletonAnimationComponent.ts rename to src/components/SkeletonAnimationComponent.ts index e5403baa..313bc754 100644 --- a/src/engine/components/SkeletonAnimationComponent.ts +++ b/src/components/SkeletonAnimationComponent.ts @@ -36,7 +36,7 @@ export class SkeletonAnimationComponent extends ComponentBase { super(); } - protected start() { + public start() { } diff --git a/src/engine/components/Transform.ts b/src/components/Transform.ts similarity index 100% rename from src/engine/components/Transform.ts rename to src/components/Transform.ts diff --git a/src/engine/components/anim/OAnimationEvent.ts b/src/components/anim/OAnimationEvent.ts similarity index 100% rename from src/engine/components/anim/OAnimationEvent.ts rename to src/components/anim/OAnimationEvent.ts diff --git a/src/engine/components/anim/curveAnim/curveAnim/AnimationMonitor.ts b/src/components/anim/curveAnim/curveAnim/AnimationMonitor.ts similarity index 100% rename from src/engine/components/anim/curveAnim/curveAnim/AnimationMonitor.ts rename to src/components/anim/curveAnim/curveAnim/AnimationMonitor.ts diff --git a/src/engine/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts b/src/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts similarity index 100% rename from src/engine/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts rename to src/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts diff --git a/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimClip.ts b/src/components/anim/curveAnim/curveAnim/PropertyAnimClip.ts similarity index 100% rename from src/engine/components/anim/curveAnim/curveAnim/PropertyAnimClip.ts rename to src/components/anim/curveAnim/curveAnim/PropertyAnimClip.ts diff --git a/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimation.ts b/src/components/anim/curveAnim/curveAnim/PropertyAnimation.ts similarity index 100% rename from src/engine/components/anim/curveAnim/curveAnim/PropertyAnimation.ts rename to src/components/anim/curveAnim/curveAnim/PropertyAnimation.ts diff --git a/src/engine/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts b/src/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts similarity index 100% rename from src/engine/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts rename to src/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts diff --git a/src/engine/components/anim/curveAnim/curveAnim/PropertyHelp.ts b/src/components/anim/curveAnim/curveAnim/PropertyHelp.ts similarity index 100% rename from src/engine/components/anim/curveAnim/curveAnim/PropertyHelp.ts rename to src/components/anim/curveAnim/curveAnim/PropertyHelp.ts diff --git a/src/engine/components/anim/morphAnim/MorphTargetBlender.ts b/src/components/anim/morphAnim/MorphTargetBlender.ts similarity index 99% rename from src/engine/components/anim/morphAnim/MorphTargetBlender.ts rename to src/components/anim/morphAnim/MorphTargetBlender.ts index 13d33aaf..7e1af99a 100644 --- a/src/engine/components/anim/morphAnim/MorphTargetBlender.ts +++ b/src/components/anim/morphAnim/MorphTargetBlender.ts @@ -14,7 +14,7 @@ export class MorphTargetBlender extends ComponentBase { private _matrix4: Matrix4 = new Matrix4(); private _quaternion: Quaternion = new Quaternion(); - protected init(param?: any): void { + public init(param?: any): void { let meshRenders: MeshRenderer[] = this.fetchMorphRenderers(this.object3D); for (const renderer of meshRenders) { let hasMorphTarget = RendererMaskUtil.hasMask(renderer.rendererMask, RendererMask.MorphTarget); diff --git a/src/engine/components/anim/morphAnim/MorphTargetData.ts b/src/components/anim/morphAnim/MorphTargetData.ts similarity index 100% rename from src/engine/components/anim/morphAnim/MorphTargetData.ts rename to src/components/anim/morphAnim/MorphTargetData.ts diff --git a/src/engine/components/anim/morphAnim/MorphTargetFrame.ts b/src/components/anim/morphAnim/MorphTargetFrame.ts similarity index 100% rename from src/engine/components/anim/morphAnim/MorphTargetFrame.ts rename to src/components/anim/morphAnim/MorphTargetFrame.ts diff --git a/src/engine/components/anim/morphAnim/MorphTargetKey.ts b/src/components/anim/morphAnim/MorphTargetKey.ts similarity index 100% rename from src/engine/components/anim/morphAnim/MorphTargetKey.ts rename to src/components/anim/morphAnim/MorphTargetKey.ts diff --git a/src/engine/components/anim/morphAnim/MorphTarget_shader.ts b/src/components/anim/morphAnim/MorphTarget_shader.ts similarity index 100% rename from src/engine/components/anim/morphAnim/MorphTarget_shader.ts rename to src/components/anim/morphAnim/MorphTarget_shader.ts diff --git a/src/engine/components/anim/skeletonAnim/Joint.ts b/src/components/anim/skeletonAnim/Joint.ts similarity index 100% rename from src/engine/components/anim/skeletonAnim/Joint.ts rename to src/components/anim/skeletonAnim/Joint.ts diff --git a/src/engine/components/anim/skeletonAnim/JointPose.ts b/src/components/anim/skeletonAnim/JointPose.ts similarity index 100% rename from src/engine/components/anim/skeletonAnim/JointPose.ts rename to src/components/anim/skeletonAnim/JointPose.ts diff --git a/src/engine/components/anim/skeletonAnim/Skeleton.ts b/src/components/anim/skeletonAnim/Skeleton.ts similarity index 100% rename from src/engine/components/anim/skeletonAnim/Skeleton.ts rename to src/components/anim/skeletonAnim/Skeleton.ts diff --git a/src/engine/components/anim/skeletonAnim/SkeletonAnimationClip.ts b/src/components/anim/skeletonAnim/SkeletonAnimationClip.ts similarity index 100% rename from src/engine/components/anim/skeletonAnim/SkeletonAnimationClip.ts rename to src/components/anim/skeletonAnim/SkeletonAnimationClip.ts diff --git a/src/engine/components/anim/skeletonAnim/SkeletonAnimationClipState.ts b/src/components/anim/skeletonAnim/SkeletonAnimationClipState.ts similarity index 100% rename from src/engine/components/anim/skeletonAnim/SkeletonAnimationClipState.ts rename to src/components/anim/skeletonAnim/SkeletonAnimationClipState.ts diff --git a/src/engine/components/anim/skeletonAnim/SkeletonAnimationCompute.ts b/src/components/anim/skeletonAnim/SkeletonAnimationCompute.ts similarity index 100% rename from src/engine/components/anim/skeletonAnim/SkeletonAnimationCompute.ts rename to src/components/anim/skeletonAnim/SkeletonAnimationCompute.ts diff --git a/src/engine/components/anim/skeletonAnim/SkeletonPose.ts b/src/components/anim/skeletonAnim/SkeletonPose.ts similarity index 100% rename from src/engine/components/anim/skeletonAnim/SkeletonPose.ts rename to src/components/anim/skeletonAnim/SkeletonPose.ts diff --git a/src/engine/components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs.ts b/src/components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs.ts similarity index 100% rename from src/engine/components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs.ts rename to src/components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs.ts diff --git a/src/engine/components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs.ts b/src/components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs.ts similarity index 100% rename from src/engine/components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs.ts rename to src/components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs.ts diff --git a/src/engine/components/anim/skeletonAnim/shader/compute_skeleton_blend.ts b/src/components/anim/skeletonAnim/shader/compute_skeleton_blend.ts similarity index 100% rename from src/engine/components/anim/skeletonAnim/shader/compute_skeleton_blend.ts rename to src/components/anim/skeletonAnim/shader/compute_skeleton_blend.ts diff --git a/src/engine/components/anim/skeletonAnim/shader/compute_skeleton_transform.ts b/src/components/anim/skeletonAnim/shader/compute_skeleton_transform.ts similarity index 100% rename from src/engine/components/anim/skeletonAnim/shader/compute_skeleton_transform.ts rename to src/components/anim/skeletonAnim/shader/compute_skeleton_transform.ts diff --git a/src/engine/components/audio/AudioListener.ts b/src/components/audio/AudioListener.ts similarity index 94% rename from src/engine/components/audio/AudioListener.ts rename to src/components/audio/AudioListener.ts index ef73fe67..0148945b 100644 --- a/src/engine/components/audio/AudioListener.ts +++ b/src/components/audio/AudioListener.ts @@ -1,54 +1,54 @@ -import { ComponentBase } from '../ComponentBase'; - -/** - * Audio Listener - * Used in conjunction {@link PositionAudio} or {@link StaticAudio} - * @internal - * @group Audio - */ -export class AudioListener extends ComponentBase { - public readonly context: AudioContext; - public readonly gain: GainNode; - constructor() { - super(); - this.context = new AudioContext(); - this.gain = this.context.createGain(); - this.gain.connect(this.context.destination); - } - protected start() { - - } - protected update() { - if (!this.context) { - return; - } - const listener = this.context.listener; - const _position = this.object3D.transform.worldPosition; - const _orientation = this.object3D.transform.forward; - const up = this.object3D.transform.up; - if (isNaN(_orientation.x)) { - return; - } - if (listener.positionX) { - const endTime = this.context.currentTime; - listener.positionX.linearRampToValueAtTime(_position.x, endTime); - listener.positionY.linearRampToValueAtTime(_position.y, endTime); - listener.positionZ.linearRampToValueAtTime(_position.z, endTime); - listener.forwardX.linearRampToValueAtTime(_orientation.x, endTime); - listener.forwardY.linearRampToValueAtTime(_orientation.y, endTime); - listener.forwardZ.linearRampToValueAtTime(_orientation.z, endTime); - listener.upX.linearRampToValueAtTime(up.x, endTime); - listener.upY.linearRampToValueAtTime(up.y, endTime); - listener.upZ.linearRampToValueAtTime(up.z, endTime); - } else { - listener.setPosition(_position.x, _position.y, _position.z); - listener.setOrientation(_orientation.x, _orientation.y, _orientation.z, up.x, up.y, up.z); - } - } - - destroy() { - this.gain.disconnect(); - this.context.close(); - super.destroy(); - } -} +import { ComponentBase } from '../ComponentBase'; + +/** + * Audio Listener + * Used in conjunction {@link PositionAudio} or {@link StaticAudio} + * @internal + * @group Audio + */ +export class AudioListener extends ComponentBase { + public readonly context: AudioContext; + public readonly gain: GainNode; + constructor() { + super(); + this.context = new AudioContext(); + this.gain = this.context.createGain(); + this.gain.connect(this.context.destination); + } + public start() { + + } + public onUpdate() { + if (!this.context) { + return; + } + const listener = this.context.listener; + const _position = this.object3D.transform.worldPosition; + const _orientation = this.object3D.transform.forward; + const up = this.object3D.transform.up; + if (isNaN(_orientation.x)) { + return; + } + if (listener.positionX) { + const endTime = this.context.currentTime; + listener.positionX.linearRampToValueAtTime(_position.x, endTime); + listener.positionY.linearRampToValueAtTime(_position.y, endTime); + listener.positionZ.linearRampToValueAtTime(_position.z, endTime); + listener.forwardX.linearRampToValueAtTime(_orientation.x, endTime); + listener.forwardY.linearRampToValueAtTime(_orientation.y, endTime); + listener.forwardZ.linearRampToValueAtTime(_orientation.z, endTime); + listener.upX.linearRampToValueAtTime(up.x, endTime); + listener.upY.linearRampToValueAtTime(up.y, endTime); + listener.upZ.linearRampToValueAtTime(up.z, endTime); + } else { + listener.setPosition(_position.x, _position.y, _position.z); + listener.setOrientation(_orientation.x, _orientation.y, _orientation.z, up.x, up.y, up.z); + } + } + + destroy() { + this.gain.disconnect(); + this.context.close(); + super.destroy(); + } +} diff --git a/src/engine/components/audio/PositionAudio.ts b/src/components/audio/PositionAudio.ts similarity index 96% rename from src/engine/components/audio/PositionAudio.ts rename to src/components/audio/PositionAudio.ts index 73439adb..d7ab1008 100644 --- a/src/engine/components/audio/PositionAudio.ts +++ b/src/components/audio/PositionAudio.ts @@ -1,181 +1,181 @@ -import { Object3D } from '../../core/entities/Object3D'; -import { UnLitMaterial } from '../../materials/UnLitMaterial'; -import { Color } from '../../math/Color'; -import { Vector3 } from '../../math/Vector3'; -import { BoxGeometry } from '../../shape/BoxGeometry'; -import { MeshRenderer } from '../renderer/MeshRenderer'; -import { AudioListener } from './AudioListener'; -import { StaticAudio } from './StaticAudio'; -/** - * Dynamic audio component, with volume varying based on the relative position of the monitor - * @internal - * @group Audio - */ -export class PositionAudio extends StaticAudio { - public panner: PannerNode; - private _helper: boolean = false; - private _thickness: number = 0.1; - private _step: number = 16; - private _lines: Object3D[] = []; - constructor() { - super(); - } - public setLister(listener: AudioListener): this { - super.setLister(listener); - this.panner = this.context?.createPanner() as PannerNode; - this.panner.panningModel = 'HRTF'; - this.panner.connect(this.gainNode as GainNode); - return this; - } - public showHelper(thickness?: number, step?: number) { - this._helper = true - if (thickness) { - this._thickness = thickness; - } - if (step) { - this._step = step; - } - const innerAngle = this.panner.coneInnerAngle; - const outerAngle = this.panner.coneOuterAngle; - const diffAngle = (outerAngle - innerAngle) / 2; - let refLength = this.panner.refDistance; - let maxLength = this.panner.maxDistance; - let box = new BoxGeometry(1, 1, 1); - - let m1 = new UnLitMaterial(); - m1.baseColor = new Color(1, 0, 0); - let m2 = new UnLitMaterial(); - m2.baseColor = new Color(0, 0, 1); - let m3 = new UnLitMaterial(); - m3.baseColor = new Color(0, 1, 0); - let m4 = new UnLitMaterial(); - m4.baseColor = new Color(1, 1, 0); - for (let i = 0; i < this._step; i++) { - let group = new Object3D(); - let angle = (i * outerAngle) / (this._step - 1); - let isOuterAngle = angle < diffAngle || angle > innerAngle + diffAngle; - { - let line = new Object3D(); - let mr = line.addComponent(MeshRenderer); - mr.geometry = box; - mr.material = isOuterAngle ? m2 : m1; - mr.castShadow = false; - mr.castGI = false; - line.localScale = new Vector3(refLength, this._thickness, this._thickness); - line.x = refLength / 2; - group.addChild(line); - } - { - let line = new Object3D(); - let mr = line.addComponent(MeshRenderer); - mr.geometry = box; - mr.material = isOuterAngle ? m4 : m3; - mr.castShadow = false; - mr.castGI = false; - line.localScale = new Vector3(maxLength, this._thickness / 2, this._thickness / 2); - line.x = maxLength / 2; - group.addChild(line); - } - group.rotationY = -90 + outerAngle / 2 - angle; - this.object3D.addChild(group); - this._lines.push(group); - } - } - public hideHelper() { - this._helper = false; - for (let l of this._lines) { - l.removeAllChild(); - l.removeFromParent(); - l.dispose(); - } - this._lines.length = 0; - } - public toggleHelper() { - if (this._helper) { - this.hideHelper(); - } - else { - this.showHelper(); - } - } - public updateHeler() { - this.hideHelper(); - this.showHelper(); - } - public get refDistance() { - return this.panner.refDistance; - } - public set refDistance(value: number) { - this.panner.refDistance = value; - if (this._helper) { - this.updateHeler(); - } - } - public get rolloffFactor() { - return this.panner.rolloffFactor; - } - public set rolloffFactor(value: number) { - this.panner.rolloffFactor = value; - } - public get distanceModel() { - return this.panner.distanceModel; - } - public set distanceModel(value: DistanceModelType) { - this.panner.distanceModel = value; - } - public get maxDistance() { - return this.panner.maxDistance; - } - public set maxDistance(value: number) { - this.panner.maxDistance = value; - if (this._helper) { - this.updateHeler(); - } - } - - public setDirectionalCone(coneInnerAngle: number, coneOuterAngle: number, coneOuterGain: number) { - this.panner.coneInnerAngle = coneInnerAngle; - this.panner.coneOuterAngle = coneOuterAngle; - this.panner.coneOuterGain = coneOuterGain; - if (this._helper) { - this.updateHeler(); - } - return this; - } - protected connect() { - this.source?.connect(this.panner); - } - public start() { - } - public stop(): this { - return super.stop(); - } - protected onUpdate() { - if (!this.playing) { - return; - } - const panner = this.panner; - const _position = this.object3D.transform.worldPosition; - const _orientation = this.object3D.transform.forward; - if (isNaN(_orientation.x)) { - return; - } - if (panner.positionX && this.context) { - const endTime = this.context.currentTime; - panner.positionX.linearRampToValueAtTime(_position.x, endTime); - panner.positionY.linearRampToValueAtTime(_position.y, endTime); - panner.positionZ.linearRampToValueAtTime(_position.z, endTime); - panner.orientationX.linearRampToValueAtTime(_orientation.x, endTime); - panner.orientationY.linearRampToValueAtTime(_orientation.y, endTime); - panner.orientationZ.linearRampToValueAtTime(_orientation.z, endTime); - } else { - panner.setPosition(_position.x, _position.y, _position.z); - panner.setOrientation(_orientation.x, _orientation.y, _orientation.z); - } - } - public destroy() { - this.panner.disconnect(); - this.hideHelper(); - super.destroy(); - } -} +import { Object3D } from '../../core/entities/Object3D'; +import { UnLitMaterial } from '../../materials/UnLitMaterial'; +import { Color } from '../../math/Color'; +import { Vector3 } from '../../math/Vector3'; +import { BoxGeometry } from '../../shape/BoxGeometry'; +import { MeshRenderer } from '../renderer/MeshRenderer'; +import { AudioListener } from './AudioListener'; +import { StaticAudio } from './StaticAudio'; +/** + * Dynamic audio component, with volume varying based on the relative position of the monitor + * @internal + * @group Audio + */ +export class PositionAudio extends StaticAudio { + public panner: PannerNode; + private _helper: boolean = false; + private _thickness: number = 0.1; + private _step: number = 16; + private _lines: Object3D[] = []; + constructor() { + super(); + } + public setLister(listener: AudioListener): this { + super.setLister(listener); + this.panner = this.context?.createPanner() as PannerNode; + this.panner.panningModel = 'HRTF'; + this.panner.connect(this.gainNode as GainNode); + return this; + } + public showHelper(thickness?: number, step?: number) { + this._helper = true + if (thickness) { + this._thickness = thickness; + } + if (step) { + this._step = step; + } + const innerAngle = this.panner.coneInnerAngle; + const outerAngle = this.panner.coneOuterAngle; + const diffAngle = (outerAngle - innerAngle) / 2; + let refLength = this.panner.refDistance; + let maxLength = this.panner.maxDistance; + let box = new BoxGeometry(1, 1, 1); + + let m1 = new UnLitMaterial(); + m1.baseColor = new Color(1, 0, 0); + let m2 = new UnLitMaterial(); + m2.baseColor = new Color(0, 0, 1); + let m3 = new UnLitMaterial(); + m3.baseColor = new Color(0, 1, 0); + let m4 = new UnLitMaterial(); + m4.baseColor = new Color(1, 1, 0); + for (let i = 0; i < this._step; i++) { + let group = new Object3D(); + let angle = (i * outerAngle) / (this._step - 1); + let isOuterAngle = angle < diffAngle || angle > innerAngle + diffAngle; + { + let line = new Object3D(); + let mr = line.addComponent(MeshRenderer); + mr.geometry = box; + mr.material = isOuterAngle ? m2 : m1; + mr.castShadow = false; + mr.castGI = false; + line.localScale = new Vector3(refLength, this._thickness, this._thickness); + line.x = refLength / 2; + group.addChild(line); + } + { + let line = new Object3D(); + let mr = line.addComponent(MeshRenderer); + mr.geometry = box; + mr.material = isOuterAngle ? m4 : m3; + mr.castShadow = false; + mr.castGI = false; + line.localScale = new Vector3(maxLength, this._thickness / 2, this._thickness / 2); + line.x = maxLength / 2; + group.addChild(line); + } + group.rotationY = -90 + outerAngle / 2 - angle; + this.object3D.addChild(group); + this._lines.push(group); + } + } + public hideHelper() { + this._helper = false; + for (let l of this._lines) { + l.removeAllChild(); + l.removeFromParent(); + l.dispose(); + } + this._lines.length = 0; + } + public toggleHelper() { + if (this._helper) { + this.hideHelper(); + } + else { + this.showHelper(); + } + } + public updateHeler() { + this.hideHelper(); + this.showHelper(); + } + public get refDistance() { + return this.panner.refDistance; + } + public set refDistance(value: number) { + this.panner.refDistance = value; + if (this._helper) { + this.updateHeler(); + } + } + public get rolloffFactor() { + return this.panner.rolloffFactor; + } + public set rolloffFactor(value: number) { + this.panner.rolloffFactor = value; + } + public get distanceModel() { + return this.panner.distanceModel; + } + public set distanceModel(value: DistanceModelType) { + this.panner.distanceModel = value; + } + public get maxDistance() { + return this.panner.maxDistance; + } + public set maxDistance(value: number) { + this.panner.maxDistance = value; + if (this._helper) { + this.updateHeler(); + } + } + + public setDirectionalCone(coneInnerAngle: number, coneOuterAngle: number, coneOuterGain: number) { + this.panner.coneInnerAngle = coneInnerAngle; + this.panner.coneOuterAngle = coneOuterAngle; + this.panner.coneOuterGain = coneOuterGain; + if (this._helper) { + this.updateHeler(); + } + return this; + } + protected connect() { + this.source?.connect(this.panner); + } + public start() { + } + public stop(): this { + return super.stop(); + } + public onUpdate() { + if (!this.playing) { + return; + } + const panner = this.panner; + const _position = this.object3D.transform.worldPosition; + const _orientation = this.object3D.transform.forward; + if (isNaN(_orientation.x)) { + return; + } + if (panner.positionX && this.context) { + const endTime = this.context.currentTime; + panner.positionX.linearRampToValueAtTime(_position.x, endTime); + panner.positionY.linearRampToValueAtTime(_position.y, endTime); + panner.positionZ.linearRampToValueAtTime(_position.z, endTime); + panner.orientationX.linearRampToValueAtTime(_orientation.x, endTime); + panner.orientationY.linearRampToValueAtTime(_orientation.y, endTime); + panner.orientationZ.linearRampToValueAtTime(_orientation.z, endTime); + } else { + panner.setPosition(_position.x, _position.y, _position.z); + panner.setOrientation(_orientation.x, _orientation.y, _orientation.z); + } + } + public destroy() { + this.panner.disconnect(); + this.hideHelper(); + super.destroy(); + } +} diff --git a/src/engine/components/audio/StaticAudio.ts b/src/components/audio/StaticAudio.ts similarity index 96% rename from src/engine/components/audio/StaticAudio.ts rename to src/components/audio/StaticAudio.ts index 448b9c0a..cdc18294 100644 --- a/src/engine/components/audio/StaticAudio.ts +++ b/src/components/audio/StaticAudio.ts @@ -1,114 +1,114 @@ -import { ComponentBase } from '../ComponentBase'; -import { AudioListener } from './AudioListener'; -/** - * Static audio component, volume level does not vary depending on the position of the monitor - * @internal - * @group Audio - */ -export class StaticAudio extends ComponentBase { - private listener: AudioListener | null = null; - public context: AudioContext | null = null; - public gainNode: GainNode | null = null; - public source: AudioBufferSourceNode | null = null - private _options = { - loop: true, - volume: 1, - }; - public playing = false; - private _currentTime: number = 0; - private _buffer: AudioBuffer | null = null - constructor() { - super(); - } - public setLister(listener: AudioListener): this { - this.listener = listener; - this.context = listener.context as AudioContext; - this.gainNode = this.context.createGain(); - this.gainNode.connect(this.listener.gain); - - this.context.addEventListener('statechange', () => { - if (this.context?.state === 'closed') { - console.warn('AudioListener removed'); - this.stop(); - this.gainNode?.disconnect(); - this.listener = null; - this.context = null; - this.gainNode = null; - } - }) - return this; - } - async load(url: string, options: {} = {}) { - Object.assign(this._options, options); - let req = await fetch(url); - let buffer = await req.arrayBuffer(); - this._buffer = await this.context?.decodeAudioData(buffer) as AudioBuffer; - } - async loadBuffer(buffer: ArrayBuffer, options: {} = {}) { - Object.assign(this._options, options); - this._buffer = await this.context?.decodeAudioData(buffer) as AudioBuffer; - } - // loadAudio(mediaElement: HTMLAudioElement) { - // this.element = mediaElement; - // this.source = this.context.createMediaElementSource(mediaElement); - // this.connect(); - // } - public play(): this { - if (!this.context) { - console.warn('no audio source yet'); - return this; - } - if (this.playing) { - console.warn('Audio is alredy playing'); - return this; - } - if (!this._buffer) { - console.warn('Audio is not ready'); - return this; - } - const source = this.context.createBufferSource(); - source.buffer = this._buffer; - source.loop = this._options.loop; - this.source = source; - this.connect(); - this.source.start(0, this._currentTime); - this.setVolume(this._options.volume); - this.playing = true; - return this; - } - public pause(): this { - if (!this.playing) { - console.warn('Audio is not playing'); - return this; - } - this._currentTime = this.context?.currentTime || 0; - this.source?.stop(); - this.source?.disconnect(); - this.playing = false; - return this; - } - public stop(): this { - this.pause(); - this._currentTime = 0; - return this; - } - public setVolume(value: number): this { - if (!this.context) { - console.warn('no audio source yet'); - return this; - } - this.gainNode?.gain.setTargetAtTime(value, this.context ? this.context.currentTime : 0, 0.01); - return this; - } - protected connect() { - this.source?.connect(this.gainNode as GainNode); - } - protected onUpdate() { - super.onUpdate(); - } - public destroy() { - this.stop(); - this.gainNode?.disconnect(); - super.destroy(); - } -} +import { ComponentBase } from '../ComponentBase'; +import { AudioListener } from './AudioListener'; +/** + * Static audio component, volume level does not vary depending on the position of the monitor + * @internal + * @group Audio + */ +export class StaticAudio extends ComponentBase { + private listener: AudioListener | null = null; + public context: AudioContext | null = null; + public gainNode: GainNode | null = null; + public source: AudioBufferSourceNode | null = null + private _options = { + loop: true, + volume: 1, + }; + public playing = false; + private _currentTime: number = 0; + private _buffer: AudioBuffer | null = null + constructor() { + super(); + } + public setLister(listener: AudioListener): this { + this.listener = listener; + this.context = listener.context as AudioContext; + this.gainNode = this.context.createGain(); + this.gainNode.connect(this.listener.gain); + + this.context.addEventListener('statechange', () => { + if (this.context?.state === 'closed') { + console.warn('AudioListener removed'); + this.stop(); + this.gainNode?.disconnect(); + this.listener = null; + this.context = null; + this.gainNode = null; + } + }) + return this; + } + async load(url: string, options: {} = {}) { + Object.assign(this._options, options); + let req = await fetch(url); + let buffer = await req.arrayBuffer(); + this._buffer = await this.context?.decodeAudioData(buffer) as AudioBuffer; + } + async loadBuffer(buffer: ArrayBuffer, options: {} = {}) { + Object.assign(this._options, options); + this._buffer = await this.context?.decodeAudioData(buffer) as AudioBuffer; + } + // loadAudio(mediaElement: HTMLAudioElement) { + // this.element = mediaElement; + // this.source = this.context.createMediaElementSource(mediaElement); + // this.connect(); + // } + public play(): this { + if (!this.context) { + console.warn('no audio source yet'); + return this; + } + if (this.playing) { + console.warn('Audio is alredy playing'); + return this; + } + if (!this._buffer) { + console.warn('Audio is not ready'); + return this; + } + const source = this.context.createBufferSource(); + source.buffer = this._buffer; + source.loop = this._options.loop; + this.source = source; + this.connect(); + this.source.start(0, this._currentTime); + this.setVolume(this._options.volume); + this.playing = true; + return this; + } + public pause(): this { + if (!this.playing) { + console.warn('Audio is not playing'); + return this; + } + this._currentTime = this.context?.currentTime || 0; + this.source?.stop(); + this.source?.disconnect(); + this.playing = false; + return this; + } + public stop(): this { + this.pause(); + this._currentTime = 0; + return this; + } + public setVolume(value: number): this { + if (!this.context) { + console.warn('no audio source yet'); + return this; + } + this.gainNode?.gain.setTargetAtTime(value, this.context ? this.context.currentTime : 0, 0.01); + return this; + } + protected connect() { + this.source?.connect(this.gainNode as GainNode); + } + public onUpdate() { + super.onUpdate(); + } + public destroy() { + this.stop(); + this.gainNode?.disconnect(); + super.destroy(); + } +} diff --git a/src/engine/components/controller/CameraControllerBase.ts b/src/components/controller/CameraControllerBase.ts similarity index 100% rename from src/engine/components/controller/CameraControllerBase.ts rename to src/components/controller/CameraControllerBase.ts diff --git a/src/engine/components/controller/FirstPersonCameraController.ts b/src/components/controller/FirstPersonCameraController.ts similarity index 99% rename from src/engine/components/controller/FirstPersonCameraController.ts rename to src/components/controller/FirstPersonCameraController.ts index 7bd75f43..4f047849 100644 --- a/src/engine/components/controller/FirstPersonCameraController.ts +++ b/src/components/controller/FirstPersonCameraController.ts @@ -20,7 +20,7 @@ export class FirstPersonCameraController extends ComponentBase { super(); } - protected start() { + public start() { this._camera = this.object3D.getOrAddComponent(Camera3D); if (!this._camera) { console.error('FirstPersonCameraController need camera'); diff --git a/src/engine/components/controller/FlyCameraController.ts b/src/components/controller/FlyCameraController.ts similarity index 99% rename from src/engine/components/controller/FlyCameraController.ts rename to src/components/controller/FlyCameraController.ts index d902df9a..09897f96 100644 --- a/src/engine/components/controller/FlyCameraController.ts +++ b/src/components/controller/FlyCameraController.ts @@ -80,7 +80,7 @@ export class FlyCameraController extends ComponentBase { /** * @internal */ - protected start(): void { + public start(): void { Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_WHEEL, this.mouseWheel, this); Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_UP, this.mouseUp, this); Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_DOWN, this.mouseDown, this); diff --git a/src/engine/components/controller/HoverCameraController.ts b/src/components/controller/HoverCameraController.ts similarity index 99% rename from src/engine/components/controller/HoverCameraController.ts rename to src/components/controller/HoverCameraController.ts index 8416b625..9c9be517 100644 --- a/src/engine/components/controller/HoverCameraController.ts +++ b/src/components/controller/HoverCameraController.ts @@ -115,7 +115,7 @@ export class HoverCameraController extends ComponentBase { /** * @internal */ - protected start(): void { + public start(): void { this.camera = this.object3D.getOrAddComponent(Camera3D); Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_DOWN, this.onMouseDown, this); Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_MOVE, this.onMouseMove, this); diff --git a/src/engine/components/controller/OrbitController.ts b/src/components/controller/OrbitController.ts similarity index 96% rename from src/engine/components/controller/OrbitController.ts rename to src/components/controller/OrbitController.ts index a3b6d1e1..bdf3700a 100644 --- a/src/engine/components/controller/OrbitController.ts +++ b/src/components/controller/OrbitController.ts @@ -1,338 +1,338 @@ -import { Engine3D } from '../../Engine3D'; -import { Camera3D } from '../../core/Camera3D'; -import { ComponentBase } from '../ComponentBase'; -import { Vector3 } from '../../math/Vector3'; -import { Vector3Ex } from '../../util/Vector3Ex'; -import { clamp } from '../../math/MathUtil'; -import { PointerEvent3D } from '../../event/eventConst/PointerEvent3D'; - -/** - * Orbit Camera Controller - * @group CameraController - */ -export class OrbitController extends ComponentBase { - /** - * internal camera - */ - private _camera: Camera3D; - /** - * Whether to enable automatic rotation - */ - public autoRotate: boolean = false; - /** - * Automatic rotation speed coefficient - */ - public autoRotateSpeed: number = 0.1; - /** - * Rotation speed coefficient - */ - public rotateFactor: number = 0.5; - /** - * Scale speed coefficient - */ - public zoomFactor: number = 0.1; - /** - * Angle translation velocity coefficient - */ - public panFactor: number = 0.25; - - private _smooth: number = 5; - private _minDistance: number = 1; - private _maxDistance: number = 100000; - private _maxPolarAngle: number = 90; - private _minPolarAngle: number = -90; - private _target: Vector3 = new Vector3(0, 0, 0); - private _cTarget: Vector3 = new Vector3(0, 0, 0); - private _position: Vector3 = new Vector3(0, 0, 0); - private _cPosition: Vector3 = new Vector3(0, 0, 0); - private _spherical: Spherical = new Spherical() - private _isMouseDown: boolean = false; - private _lastMouseX: number = -1; - private _lastMouseY: number = -1; - private _isPanning: boolean = false - - /** - * @constructor - */ - constructor() { - super(); - } - /** - * Get the target position - */ - public get target(): Vector3 { - return this._target; - } - /** - * Set the target position - */ - public set target(v: Vector3) { - this._target = v; - } - - /** - * Set smoothing coefficient of controller - */ - public get smooth(): number { - return this._smooth; - } - /** - * Get smoothing coefficient of controller - */ - public set smooth(v: number) { - this._smooth = Math.max(v, 1) - } - /** - * Get the minimum distance between the camera and the target coordinate - * @defaultValue 1 - */ - public get minDistance(): number { - return this._minDistance; - } - /** - * Set the minimum distance between the camera and the target position - * min value: 0.000002 - * max value: `this._maxDistance` {@link maxDistance} - */ - public set minDistance(v: number) { - this._minDistance = clamp(v, 0.000002, this._maxDistance); - } - /** - * Get the max distance between the camera and the target position - * @defaultValue 100000 - */ - public get maxDistance(): number { - return this._maxDistance; - } - /** - * Set the max distance between the camera and the target position - * min - `this._maxDistance` - * max - Infinity - */ - public set maxDistance(v: number) { - this._maxDistance = clamp(v, this._minDistance, Infinity); - } - - /** - * Get the lower elevation limit of the camera from the xz plane - * @defaultValue -90 - */ - public get minPolarAngle(): number { - return this._minPolarAngle; - } - /** - * Set the lower elevation limit of the camera from the xz plane - * min - -90 - * max - {@link maxPolarAngle} - */ - public set minPolarAngle(v: number) { - this._minPolarAngle = clamp(v, -90, this._maxPolarAngle); - } - /** - * Get the upper elevation limit of the camera from the xz plane - * @defaultValue 90 - */ - public get maxPolarAngle(): number { - return this._maxPolarAngle; - } - /** - * Set the upper elevation limit of the camera to the xz plane - * min - less than {@link minPolarAngle} - * max - 90 - */ - public set maxPolarAngle(v: number) { - this._maxPolarAngle = clamp(v, this._minPolarAngle, 90); - } - /** - * @internal - */ - protected start() { - this._camera = this.object3D.getComponent(Camera3D); - this._position = this.object3D.transform.localPosition.clone(); - this._cPosition = this._position.clone(); - this._target = this._camera.lookTarget.clone() - this._cTarget = this._target.clone() - this._spherical.setCoords(this._position.x - this._target.x, this._position.y - this._target.y, this._position.z - this._target.z) - this._camera.lookAt(this._cPosition, this._cTarget, Vector3.UP); - this.addEventListener() - } - /** - * @internal - */ - protected onEnable() { - this.addEventListener() - } - /** - * @internal - */ - protected onDisable() { - this.removeEventListener() - } - /** - * @internal - */ - protected onUpdate() { - let step = this._isPanning ? 1 : this.smooth - let changed = false - if (!this._cPosition.equals(this.object3D.transform.localPosition)) { - this._position.copyFrom(this.object3D.transform.localPosition) - step = 1 - changed = true - } - if (!this._cTarget.equals(this._target)) { - this._cTarget.copyFrom(this._target) - step = 1 - changed = true - } - if (changed) { - this._spherical.setCoords(this._position.x - this._target.x, this._position.y - this._target.y, this._position.z - this._target.z) - } else if (!this._isMouseDown && this.autoRotate) { - this._spherical.theta -= this.autoRotateSpeed * Math.PI / 180; - this.updateCamera(); - } - let x = (this._position.x - this._cPosition.x) / step - let y = (this._position.y - this._cPosition.y) / step - let z = (this._position.z - this._cPosition.z) / step - this._cPosition.x = Math.abs(x) > 1e-10 ? this._cPosition.x + x : this._position.x - this._cPosition.y = Math.abs(y) > 1e-10 ? this._cPosition.y + y : this._position.y - this._cPosition.z = Math.abs(z) > 1e-10 ? this._cPosition.z + z : this._position.z - this._camera.lookAt(this._cPosition, this._cTarget, Vector3.UP); - } - /** - * @internal - */ - private onWheel(e: PointerEvent3D) { - this._spherical.radius += e.deltaY * this.zoomFactor; - this._spherical.radius = clamp(this._spherical.radius, this.minDistance, this.maxDistance); - this.updateCamera(); - } - /** - * @internal - */ - private onPointerDown(e: PointerEvent3D) { - this._isMouseDown = true; - this._lastMouseX = e.mouseX; - this._lastMouseY = e.mouseY; - if (e.mouseCode === 2) - this._isPanning = true - } - /** - * @internal - */ - private onPointerMove(e: PointerEvent3D) { - if (!this._isMouseDown || !this.enable) return; - let mousex = e.mouseX; - let mousey = e.mouseY; - // rotate - if (e.mouseCode === 0 && this._lastMouseX > 0 && this._lastMouseY > 0) { - const ra = -(mousex - this._lastMouseX) * this.rotateFactor; - const rb = (mousey - this._lastMouseY) * this.rotateFactor; - this._spherical.theta += ra * Math.PI / 180; - this._spherical.phi -= rb * Math.PI / 180; - this._spherical.phi = clamp(this._spherical.phi, this.minPolarAngle, this.maxPolarAngle); - this.updateCamera(); - // pan - } else if (e.mouseCode === 2) { - Vector3Ex.mulScale(this.object3D.transform.up, e.movementY * this.panFactor * this._camera.aspect, Vector3.HELP_1); - this._target.y += Vector3.HELP_1.y; - Vector3Ex.mulScale(this.object3D.transform.right, -e.movementX * this.panFactor, Vector3.HELP_1); - this._target.x -= Vector3.HELP_1.x; - this._target.z -= Vector3.HELP_1.z; - this._cTarget.copyFrom(this._target) - this.updateCamera(); - } - this._lastMouseX = mousex; - this._lastMouseY = mousey; - } - /** - * @internal - */ - private onPointerUp(e: PointerEvent3D) { - this._isMouseDown = false; - if (e.mouseCode === 2) { - this._isPanning = false; - } - } - private onPointerLeave() { - this._isMouseDown = false; - this._isPanning = false; - } - /** - * @internal - */ - private updateCamera() { - this._spherical.makeSafe(); - let pos = this._spherical.getCoords(); - this._position.set(pos.x + this._target.x, pos.y + this._target.y, pos.z + this._target.z); - } - /** - * @internal - */ - private addEventListener() { - Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_WHEEL, this.onWheel, this); - Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_DOWN, this.onPointerDown, this); - Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_MOVE, this.onPointerMove, this); - Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_UP, this.onPointerUp, this); - Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_OUT, this.onPointerLeave, this); - } - /** - * @internal - */ - private removeEventListener() { - Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_WHEEL, this.onWheel, this); - Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_DOWN, this.onPointerDown, this); - Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_MOVE, this.onPointerMove, this); - Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_UP, this.onPointerUp, this); - Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_OUT, this.onPointerLeave, this); - } -} - -/** - * @internal - */ -class Spherical { - public radius: number; - public phi: number; - public theta: number; - public coords: Vector3; - constructor(radius = 1, phi = 0, theta = 0) { - this.radius = radius; - this.phi = phi; // polar angle - this.theta = theta; // azimuthal angle - this.coords = new Vector3() - return this; - } - public set(radius: number, phi: number, theta: number) { - this.radius = radius; - this.phi = phi; - this.theta = theta; - return this; - } - // restrict phi to be between EPS and PI-EPS - public makeSafe(): this { - const EPS = 0.0002; - this.phi = Math.max(EPS, Math.min(Math.PI - EPS, this.phi)); - return this; - } - public setFromVector3(v: Vector3): this { - return this.setCoords(v.x, v.y, v.z); - } - public setCoords(x: number, y: number, z: number): this { - this.radius = Math.sqrt(x * x + y * y + z * z); - if (this.radius === 0) { - this.theta = 0; - this.phi = 0; - } else { - this.theta = Math.atan2(x, z); - this.phi = Math.acos(clamp(y / this.radius, - 1, 1)); - } - return this; - } - public getCoords(): Vector3 { - const sinPhiRadius = Math.sin(this.phi) * this.radius; - this.coords.x = sinPhiRadius * Math.sin(this.theta); - this.coords.y = Math.cos(this.phi) * this.radius; - this.coords.z = sinPhiRadius * Math.cos(this.theta); - return this.coords; - } +import { Engine3D } from '../../Engine3D'; +import { Camera3D } from '../../core/Camera3D'; +import { ComponentBase } from '../ComponentBase'; +import { Vector3 } from '../../math/Vector3'; +import { Vector3Ex } from '../../util/Vector3Ex'; +import { clamp } from '../../math/MathUtil'; +import { PointerEvent3D } from '../../event/eventConst/PointerEvent3D'; + +/** + * Orbit Camera Controller + * @group CameraController + */ +export class OrbitController extends ComponentBase { + /** + * internal camera + */ + private _camera: Camera3D; + /** + * Whether to enable automatic rotation + */ + public autoRotate: boolean = false; + /** + * Automatic rotation speed coefficient + */ + public autoRotateSpeed: number = 0.1; + /** + * Rotation speed coefficient + */ + public rotateFactor: number = 0.5; + /** + * Scale speed coefficient + */ + public zoomFactor: number = 0.1; + /** + * Angle translation velocity coefficient + */ + public panFactor: number = 0.25; + + private _smooth: number = 5; + private _minDistance: number = 1; + private _maxDistance: number = 100000; + private _maxPolarAngle: number = 90; + private _minPolarAngle: number = -90; + private _target: Vector3 = new Vector3(0, 0, 0); + private _cTarget: Vector3 = new Vector3(0, 0, 0); + private _position: Vector3 = new Vector3(0, 0, 0); + private _cPosition: Vector3 = new Vector3(0, 0, 0); + private _spherical: Spherical = new Spherical() + private _isMouseDown: boolean = false; + private _lastMouseX: number = -1; + private _lastMouseY: number = -1; + private _isPanning: boolean = false + + /** + * @constructor + */ + constructor() { + super(); + } + /** + * Get the target position + */ + public get target(): Vector3 { + return this._target; + } + /** + * Set the target position + */ + public set target(v: Vector3) { + this._target = v; + } + + /** + * Set smoothing coefficient of controller + */ + public get smooth(): number { + return this._smooth; + } + /** + * Get smoothing coefficient of controller + */ + public set smooth(v: number) { + this._smooth = Math.max(v, 1) + } + /** + * Get the minimum distance between the camera and the target coordinate + * @defaultValue 1 + */ + public get minDistance(): number { + return this._minDistance; + } + /** + * Set the minimum distance between the camera and the target position + * min value: 0.000002 + * max value: `this._maxDistance` {@link maxDistance} + */ + public set minDistance(v: number) { + this._minDistance = clamp(v, 0.000002, this._maxDistance); + } + /** + * Get the max distance between the camera and the target position + * @defaultValue 100000 + */ + public get maxDistance(): number { + return this._maxDistance; + } + /** + * Set the max distance between the camera and the target position + * min - `this._maxDistance` + * max - Infinity + */ + public set maxDistance(v: number) { + this._maxDistance = clamp(v, this._minDistance, Infinity); + } + + /** + * Get the lower elevation limit of the camera from the xz plane + * @defaultValue -90 + */ + public get minPolarAngle(): number { + return this._minPolarAngle; + } + /** + * Set the lower elevation limit of the camera from the xz plane + * min - -90 + * max - {@link maxPolarAngle} + */ + public set minPolarAngle(v: number) { + this._minPolarAngle = clamp(v, -90, this._maxPolarAngle); + } + /** + * Get the upper elevation limit of the camera from the xz plane + * @defaultValue 90 + */ + public get maxPolarAngle(): number { + return this._maxPolarAngle; + } + /** + * Set the upper elevation limit of the camera to the xz plane + * min - less than {@link minPolarAngle} + * max - 90 + */ + public set maxPolarAngle(v: number) { + this._maxPolarAngle = clamp(v, this._minPolarAngle, 90); + } + /** + * @internal + */ + public start() { + this._camera = this.object3D.getComponent(Camera3D); + this._position = this.object3D.transform.localPosition.clone(); + this._cPosition = this._position.clone(); + this._target = this._camera.lookTarget.clone() + this._cTarget = this._target.clone() + this._spherical.setCoords(this._position.x - this._target.x, this._position.y - this._target.y, this._position.z - this._target.z) + this._camera.lookAt(this._cPosition, this._cTarget, Vector3.UP); + this.addEventListener() + } + /** + * @internal + */ + public onEnable() { + this.addEventListener() + } + /** + * @internal + */ + public onDisable() { + this.removeEventListener() + } + /** + * @internal + */ + public onUpdate() { + let step = this._isPanning ? 1 : this.smooth + let changed = false + if (!this._cPosition.equals(this.object3D.transform.localPosition)) { + this._position.copyFrom(this.object3D.transform.localPosition) + step = 1 + changed = true + } + if (!this._cTarget.equals(this._target)) { + this._cTarget.copyFrom(this._target) + step = 1 + changed = true + } + if (changed) { + this._spherical.setCoords(this._position.x - this._target.x, this._position.y - this._target.y, this._position.z - this._target.z) + } else if (!this._isMouseDown && this.autoRotate) { + this._spherical.theta -= this.autoRotateSpeed * Math.PI / 180; + this.updateCamera(); + } + let x = (this._position.x - this._cPosition.x) / step + let y = (this._position.y - this._cPosition.y) / step + let z = (this._position.z - this._cPosition.z) / step + this._cPosition.x = Math.abs(x) > 1e-10 ? this._cPosition.x + x : this._position.x + this._cPosition.y = Math.abs(y) > 1e-10 ? this._cPosition.y + y : this._position.y + this._cPosition.z = Math.abs(z) > 1e-10 ? this._cPosition.z + z : this._position.z + this._camera.lookAt(this._cPosition, this._cTarget, Vector3.UP); + } + /** + * @internal + */ + private onWheel(e: PointerEvent3D) { + this._spherical.radius += e.deltaY * this.zoomFactor; + this._spherical.radius = clamp(this._spherical.radius, this.minDistance, this.maxDistance); + this.updateCamera(); + } + /** + * @internal + */ + private onPointerDown(e: PointerEvent3D) { + this._isMouseDown = true; + this._lastMouseX = e.mouseX; + this._lastMouseY = e.mouseY; + if (e.mouseCode === 2) + this._isPanning = true + } + /** + * @internal + */ + private onPointerMove(e: PointerEvent3D) { + if (!this._isMouseDown || !this.enable) return; + let mousex = e.mouseX; + let mousey = e.mouseY; + // rotate + if (e.mouseCode === 0 && this._lastMouseX > 0 && this._lastMouseY > 0) { + const ra = -(mousex - this._lastMouseX) * this.rotateFactor; + const rb = (mousey - this._lastMouseY) * this.rotateFactor; + this._spherical.theta += ra * Math.PI / 180; + this._spherical.phi -= rb * Math.PI / 180; + this._spherical.phi = clamp(this._spherical.phi, this.minPolarAngle, this.maxPolarAngle); + this.updateCamera(); + // pan + } else if (e.mouseCode === 2) { + Vector3Ex.mulScale(this.object3D.transform.up, e.movementY * this.panFactor * this._camera.aspect, Vector3.HELP_1); + this._target.y += Vector3.HELP_1.y; + Vector3Ex.mulScale(this.object3D.transform.right, -e.movementX * this.panFactor, Vector3.HELP_1); + this._target.x -= Vector3.HELP_1.x; + this._target.z -= Vector3.HELP_1.z; + this._cTarget.copyFrom(this._target) + this.updateCamera(); + } + this._lastMouseX = mousex; + this._lastMouseY = mousey; + } + /** + * @internal + */ + private onPointerUp(e: PointerEvent3D) { + this._isMouseDown = false; + if (e.mouseCode === 2) { + this._isPanning = false; + } + } + private onPointerLeave() { + this._isMouseDown = false; + this._isPanning = false; + } + /** + * @internal + */ + private updateCamera() { + this._spherical.makeSafe(); + let pos = this._spherical.getCoords(); + this._position.set(pos.x + this._target.x, pos.y + this._target.y, pos.z + this._target.z); + } + /** + * @internal + */ + private addEventListener() { + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_WHEEL, this.onWheel, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_DOWN, this.onPointerDown, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_MOVE, this.onPointerMove, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_UP, this.onPointerUp, this); + Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_OUT, this.onPointerLeave, this); + } + /** + * @internal + */ + private removeEventListener() { + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_WHEEL, this.onWheel, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_DOWN, this.onPointerDown, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_MOVE, this.onPointerMove, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_UP, this.onPointerUp, this); + Engine3D.inputSystem.removeEventListener(PointerEvent3D.POINTER_OUT, this.onPointerLeave, this); + } +} + +/** + * @internal + */ +class Spherical { + public radius: number; + public phi: number; + public theta: number; + public coords: Vector3; + constructor(radius = 1, phi = 0, theta = 0) { + this.radius = radius; + this.phi = phi; // polar angle + this.theta = theta; // azimuthal angle + this.coords = new Vector3() + return this; + } + public set(radius: number, phi: number, theta: number) { + this.radius = radius; + this.phi = phi; + this.theta = theta; + return this; + } + // restrict phi to be between EPS and PI-EPS + public makeSafe(): this { + const EPS = 0.0002; + this.phi = Math.max(EPS, Math.min(Math.PI - EPS, this.phi)); + return this; + } + public setFromVector3(v: Vector3): this { + return this.setCoords(v.x, v.y, v.z); + } + public setCoords(x: number, y: number, z: number): this { + this.radius = Math.sqrt(x * x + y * y + z * z); + if (this.radius === 0) { + this.theta = 0; + this.phi = 0; + } else { + this.theta = Math.atan2(x, z); + this.phi = Math.acos(clamp(y / this.radius, - 1, 1)); + } + return this; + } + public getCoords(): Vector3 { + const sinPhiRadius = Math.sin(this.phi) * this.radius; + this.coords.x = sinPhiRadius * Math.sin(this.theta); + this.coords.y = Math.cos(this.phi) * this.radius; + this.coords.z = sinPhiRadius * Math.cos(this.theta); + return this.coords; + } } \ No newline at end of file diff --git a/src/engine/components/controller/ThirdPersonCameraController.ts b/src/components/controller/ThirdPersonCameraController.ts similarity index 99% rename from src/engine/components/controller/ThirdPersonCameraController.ts rename to src/components/controller/ThirdPersonCameraController.ts index d5e541ed..0cc0d980 100644 --- a/src/engine/components/controller/ThirdPersonCameraController.ts +++ b/src/components/controller/ThirdPersonCameraController.ts @@ -21,7 +21,7 @@ export class ThirdPersonCameraController extends ComponentBase { super(); } - protected start() { + public start() { this._camera = this.object3D.getOrAddComponent(Camera3D); if (!this._camera) { console.error('ThirdPersonCameraController need camera'); diff --git a/src/engine/components/lights/DirectLight.ts b/src/components/lights/DirectLight.ts similarity index 97% rename from src/engine/components/lights/DirectLight.ts rename to src/components/lights/DirectLight.ts index 9c043395..cd526f9a 100644 --- a/src/engine/components/lights/DirectLight.ts +++ b/src/components/lights/DirectLight.ts @@ -15,7 +15,7 @@ export class DirectLight extends LightBase { super(); } - protected init(): void { + public init(): void { super.init(); if (this.object3D.name == "") { this.object3D.name = "DirectionLight_" + UUID(); @@ -25,7 +25,7 @@ export class DirectLight extends LightBase { this.lightData.linear = 0; } - protected start(): void { + public start(): void { super.start(); this.castGI = true; } diff --git a/src/engine/components/lights/GILighting.ts b/src/components/lights/GILighting.ts similarity index 68% rename from src/engine/components/lights/GILighting.ts rename to src/components/lights/GILighting.ts index 947ed8a6..c6f1525e 100644 --- a/src/engine/components/lights/GILighting.ts +++ b/src/components/lights/GILighting.ts @@ -1,4 +1,4 @@ -import { LightBase } from './LightBase'; +import { ILight } from "./ILight"; /** * Collecting and storing light that affects GI @@ -6,15 +6,15 @@ import { LightBase } from './LightBase'; * @group Lights */ export class GILighting { - public static list: LightBase[] = []; - public static add(light: LightBase) { + public static list: ILight[] = []; + public static add(light: ILight) { let index = this.list.indexOf(light); if (index == -1) { this.list.push(light); } } - public static remove(light: LightBase) { + public static remove(light: ILight) { let index = this.list.indexOf(light); if (index != -1) { this.list.splice(index, 1); diff --git a/src/engine/components/lights/IESProfiles.ts b/src/components/lights/IESProfiles.ts similarity index 100% rename from src/engine/components/lights/IESProfiles.ts rename to src/components/lights/IESProfiles.ts diff --git a/src/components/lights/ILight.ts b/src/components/lights/ILight.ts new file mode 100644 index 00000000..f88ee5f3 --- /dev/null +++ b/src/components/lights/ILight.ts @@ -0,0 +1,15 @@ +import { Camera3D } from "../../core/Camera3D"; +import { Transform } from "../Transform"; +import { LightData } from "./LightData"; + +export interface ILight { + name: string; + transform: Transform; + lightData: LightData; + needUpdateShadow: boolean; + realTimeShadow: boolean; + + shadowIndex: number; + + shadowCamera?: Camera3D; +} \ No newline at end of file diff --git a/src/engine/components/lights/LightBase.ts b/src/components/lights/LightBase.ts similarity index 96% rename from src/engine/components/lights/LightBase.ts rename to src/components/lights/LightBase.ts index b6b48618..a03f15da 100644 --- a/src/engine/components/lights/LightBase.ts +++ b/src/components/lights/LightBase.ts @@ -8,12 +8,13 @@ import { GILighting } from './GILighting'; import { LightData } from './LightData'; import { ShadowLightsCollect } from '../../gfx/renderJob/collect/ShadowLightsCollect'; import { IESProfiles } from './IESProfiles'; +import { ILight } from './ILight'; /** * @internal * @group Lights */ -export class LightBase extends ComponentBase { +export class LightBase extends ComponentBase implements ILight { /** * light name */ @@ -53,7 +54,7 @@ export class LightBase extends ComponentBase { super(); } - protected init(): void { + public init(): void { this.transform.object3D.bound = new BoundingBox(new Vector3(), new Vector3()); this.lightData = new LightData(); @@ -74,7 +75,7 @@ export class LightBase extends ComponentBase { } } - protected start(): void { + public start(): void { this.transform.onScaleChange = () => this.onScaleChange(); this.transform.onRotationChange = () => this.onRotChange(); this.onRotChange(); @@ -95,12 +96,12 @@ export class LightBase extends ComponentBase { this.onChange(); } - protected onEnable(): void { + public onEnable(): void { this.onChange(); EntityCollect.instance.addLight(this.transform.scene3D, this); } - protected onDisable(): void { + public onDisable(): void { this.onChange(); EntityCollect.instance.removeLight(this.transform.scene3D, this); } diff --git a/src/engine/components/lights/LightData.ts b/src/components/lights/LightData.ts similarity index 100% rename from src/engine/components/lights/LightData.ts rename to src/components/lights/LightData.ts diff --git a/src/engine/components/lights/PointLight.ts b/src/components/lights/PointLight.ts similarity index 96% rename from src/engine/components/lights/PointLight.ts rename to src/components/lights/PointLight.ts index 1466c17d..d63f178b 100644 --- a/src/engine/components/lights/PointLight.ts +++ b/src/components/lights/PointLight.ts @@ -16,7 +16,7 @@ export class PointLight extends LightBase { super(); } - protected init(): void { + public init(): void { super.init(); this.lightData.lightType = LightType.PointLight; if (this.object3D.name == "") { @@ -106,16 +106,16 @@ export class PointLight extends LightBase { this._castShadow = value; } - protected start(): void { + public start(): void { this.transform.rotationX = 90; super.start(); } - protected onUpdate(): void { + public onUpdate(): void { this.transform.updateWorldMatrix(true); } - protected onGraphic(view?: View3D): void { + public onGraphic(view?: View3D): void { let custom = Engine3D.getRenderJob(view).graphic3D.createCustomShape( `PointLight_${this.object3D.uuid}`, this.transform, diff --git a/src/engine/components/lights/SpotLight.ts b/src/components/lights/SpotLight.ts similarity index 97% rename from src/engine/components/lights/SpotLight.ts rename to src/components/lights/SpotLight.ts index a4b183e3..b1950f4b 100644 --- a/src/engine/components/lights/SpotLight.ts +++ b/src/components/lights/SpotLight.ts @@ -17,7 +17,7 @@ export class SpotLight extends LightBase { super(); } - protected init(): void { + public init(): void { super.init(); this.lightData.lightType = LightType.SpotLight; if (this.object3D.name == "") { @@ -123,16 +123,16 @@ export class SpotLight extends LightBase { this._castShadow = value; } - protected start(): void { + public start(): void { super.start(); this.lightData.lightType = LightType.SpotLight; } - protected onUpdate(): void { + public onUpdate(): void { this.transform.updateWorldMatrix(true); } - protected onGraphic(view: View3D) { + public onGraphic(view: View3D) { let custom = Engine3D.getRenderJob(view).graphic3D.createCustomShape( `SpotLight_${this.object3D.uuid}`, this.transform, diff --git a/src/engine/components/post/PostProcessingComponent.ts b/src/components/post/PostProcessingComponent.ts similarity index 91% rename from src/engine/components/post/PostProcessingComponent.ts rename to src/components/post/PostProcessingComponent.ts index 5b81bb27..21c716e1 100644 --- a/src/engine/components/post/PostProcessingComponent.ts +++ b/src/components/post/PostProcessingComponent.ts @@ -5,23 +5,23 @@ import { ComponentBase } from "../ComponentBase"; export class PostProcessingComponent extends ComponentBase { private _postList: Map; - protected init(param?: any): void { + public init(param?: any): void { this._postList = new Map(); } - protected start(): void { + public start(): void { } - protected stop(): void { + public stop(): void { } - protected onEnable(): void { + public onEnable(): void { this.activePost(); } - protected onDisable(): void { + public onDisable(): void { this.unActivePost(); } diff --git a/src/engine/components/renderer/InstanceDrawComponent.ts b/src/components/renderer/InstanceDrawComponent.ts similarity index 94% rename from src/engine/components/renderer/InstanceDrawComponent.ts rename to src/components/renderer/InstanceDrawComponent.ts index b7bcfc82..3030f7e2 100644 --- a/src/engine/components/renderer/InstanceDrawComponent.ts +++ b/src/components/renderer/InstanceDrawComponent.ts @@ -8,16 +8,17 @@ import { StorageGPUBuffer } from "../../gfx/graphics/webGpu/core/buffer/StorageG import { View3D } from "../../core/View3D"; import { RendererPassState } from "../../gfx/renderJob/passRenderer/state/RendererPassState"; import { RendererType } from "../../gfx/renderJob/passRenderer/state/RendererType"; +import { ClusterLightingBuffer } from "../../gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer"; export class InstanceDrawComponent extends RenderNode { private _keyGroup: Map; private _instanceMatrixBuffer: StorageGPUBuffer; - protected init(param?: any): void { + public init(param?: any): void { this._keyGroup = new Map(); } - protected start(): void { + public start(): void { let meshRenders: MeshRenderer[] = []; this.object3D.getComponents(MeshRenderer, meshRenders, true); @@ -47,11 +48,11 @@ export class InstanceDrawComponent extends RenderNode { this._instanceMatrixBuffer.apply(); } - protected stop(): void { + public stop(): void { } - public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingRender?: ClusterLightingRender): void { + public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingBuffer?: ClusterLightingBuffer): void { this._keyGroup.forEach((v, k) => { @@ -68,9 +69,9 @@ export class InstanceDrawComponent extends RenderNode { } } } - renderNode.nodeUpdate(view, passType, renderPassState, clusterLightingRender); + renderNode.nodeUpdate(view, passType, renderPassState, clusterLightingBuffer); }) - super.nodeUpdate(view, passType, renderPassState, clusterLightingRender); + super.nodeUpdate(view, passType, renderPassState, clusterLightingBuffer); } diff --git a/src/engine/components/renderer/MaterialComponent.ts b/src/components/renderer/MaterialComponent.ts similarity index 100% rename from src/engine/components/renderer/MaterialComponent.ts rename to src/components/renderer/MaterialComponent.ts diff --git a/src/engine/components/renderer/MeshComponent.ts b/src/components/renderer/MeshComponent.ts similarity index 98% rename from src/engine/components/renderer/MeshComponent.ts rename to src/components/renderer/MeshComponent.ts index 79bc30f0..9b943e14 100644 --- a/src/engine/components/renderer/MeshComponent.ts +++ b/src/components/renderer/MeshComponent.ts @@ -33,7 +33,7 @@ export class MeshComponent extends ComponentBase { super(); } - protected init() { } + public init() { } public cloneTo(obj: Object3D) { let mc = obj.addComponent(MeshComponent); diff --git a/src/engine/components/renderer/MeshRenderer.ts b/src/components/renderer/MeshRenderer.ts similarity index 91% rename from src/engine/components/renderer/MeshRenderer.ts rename to src/components/renderer/MeshRenderer.ts index a5585c6e..3ec6f4ae 100644 --- a/src/engine/components/renderer/MeshRenderer.ts +++ b/src/components/renderer/MeshRenderer.ts @@ -1,7 +1,7 @@ import { Object3D } from '../../core/entities/Object3D'; -import { GeometryBase } from '../../core/geometry/GeometryBase'; import { View3D } from '../../core/View3D'; -import { ClusterLightingRender } from '../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender'; +import { ClusterLightingBuffer } from '../../gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer'; +import { GeometryBase } from '../../core/geometry/GeometryBase'; import { RendererMask } from '../../gfx/renderJob/passRenderer/state/RendererMask'; import { RendererPassState } from '../../gfx/renderJob/passRenderer/state/RendererPassState'; import { RendererType } from '../../gfx/renderJob/passRenderer/state/RendererType'; @@ -24,9 +24,13 @@ export class MeshRenderer extends RenderNode { super(); } - protected start(): void { } + public onEnable(): void { + super.onEnable(); + } - protected stop(): void { } + public onDisable(): void { + super.onDisable(); + } /** * The geometry of the mesh determines its shape @@ -87,7 +91,7 @@ export class MeshRenderer extends RenderNode { } - protected onCompute(view: View3D, command: GPUCommandEncoder): void { + public onCompute(view: View3D, command: GPUCommandEncoder): void { if (this.morphData && this.morphData.enable) { this.morphData.computeMorphTarget(command); } @@ -101,7 +105,7 @@ export class MeshRenderer extends RenderNode { * @param clusterLightingRender * @param probes */ - public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingRender?: ClusterLightingRender) { + public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingBuffer: ClusterLightingBuffer) { if (this.morphData && this.morphData.enable) { for (let i = 0; i < this.materials.length; i++) { const material = this.materials[i]; @@ -115,7 +119,7 @@ export class MeshRenderer extends RenderNode { } } - super.nodeUpdate(view, passType, renderPassState, clusterLightingRender); + super.nodeUpdate(view, passType, renderPassState, clusterLightingBuffer); } cloneTo(obj: Object3D) { diff --git a/src/engine/components/renderer/RenderNode.ts b/src/components/renderer/RenderNode.ts similarity index 94% rename from src/engine/components/renderer/RenderNode.ts rename to src/components/renderer/RenderNode.ts index db08d8cc..07982f0e 100644 --- a/src/engine/components/renderer/RenderNode.ts +++ b/src/components/renderer/RenderNode.ts @@ -9,7 +9,7 @@ import { GPUContext } from "../../gfx/renderJob/GPUContext"; import { EntityCollect } from "../../gfx/renderJob/collect/EntityCollect"; import { RTResourceMap } from "../../gfx/renderJob/frame/RTResourceMap"; import { RenderContext } from "../../gfx/renderJob/passRenderer/RenderContext"; -import { ClusterLightingRender } from "../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender"; +import { ClusterLightingBuffer } from "../../gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer"; import { RendererMask, RendererMaskUtil } from "../../gfx/renderJob/passRenderer/state/RendererMask"; import { RendererPassState } from "../../gfx/renderJob/passRenderer/state/RendererPassState"; import { RendererType } from "../../gfx/renderJob/passRenderer/state/RendererType"; @@ -98,7 +98,7 @@ export class RenderNode extends ComponentBase { } } - protected init() { + public init() { // this.renderPasses = new Map(); this.instanceID = UUID(); } @@ -111,17 +111,15 @@ export class RenderNode extends ComponentBase { this._rendererMask = RendererMaskUtil.removeMask(this._rendererMask, tag); } - protected onEnable(): void { + public onEnable(): void { if (!this._readyPipeline) { this.initPipeline(); - - } EntityCollect.instance.addRenderNode(this.transform.scene3D, this); } - protected onDisable(): void { + public onDisable(): void { EntityCollect.instance.removeRenderNode(this.transform.scene3D, this); } @@ -293,9 +291,9 @@ export class RenderNode extends ComponentBase { * @param encoder * @returns */ - public renderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingRender: ClusterLightingRender, encoder: GPURenderPassEncoder, useBundle: boolean = false) { + public renderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingBuffer: ClusterLightingBuffer, encoder: GPURenderPassEncoder, useBundle: boolean = false) { if (!this.enable) return; - this.nodeUpdate(view, passType, rendererPassState, clusterLightingRender); + this.nodeUpdate(view, passType, rendererPassState, clusterLightingBuffer); let node = this; for (let i = 0; i < this.materials.length; i++) { @@ -333,9 +331,9 @@ export class RenderNode extends ComponentBase { } - public recordRenderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingRender: ClusterLightingRender, encoder: GPURenderPassEncoder, useBundle: boolean = false) { + public recordRenderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingBuffer: ClusterLightingBuffer, encoder: GPURenderPassEncoder, useBundle: boolean = false) { if (!this.enable) return; - this.nodeUpdate(view, passType, rendererPassState, clusterLightingRender); + this.nodeUpdate(view, passType, rendererPassState, clusterLightingBuffer); let node = this; for (let i = 0; i < this.materials.length; i++) { @@ -367,7 +365,7 @@ export class RenderNode extends ComponentBase { } } - public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingRender?: ClusterLightingRender) { + public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingBuffer?: ClusterLightingBuffer) { let node = this; for (let i = 0; i < this.materials.length; i++) { @@ -424,14 +422,16 @@ export class RenderNode extends ComponentBase { let lightUniformEntries = GlobalBindGroup.getLightEntries(view.scene); if (lightUniformEntries) { renderShader.setStorageBuffer(`lightBuffer`, lightUniformEntries.storageGPUBuffer); + if (lightUniformEntries.irradianceVolume) { + renderShader.setStructStorageBuffer(`irradianceData`, lightUniformEntries.irradianceVolume.irradianceVolumeBuffer); + } } - - if (clusterLightingRender) { - renderShader.setStorageBuffer(`clustersUniform`, clusterLightingRender.clustersUniformBuffer); - renderShader.setStorageBuffer(`lightAssignBuffer`, clusterLightingRender.lightAssignBuffer); - renderShader.setStorageBuffer(`assignTable`, clusterLightingRender.assignTableBuffer); - renderShader.setStorageBuffer(`clusterBuffer`, clusterLightingRender.clusterBuffer); + if (clusterLightingBuffer) { + renderShader.setStorageBuffer(`clustersUniform`, clusterLightingBuffer.clustersUniformBuffer); + renderShader.setStorageBuffer(`lightAssignBuffer`, clusterLightingBuffer.lightAssignBuffer); + renderShader.setStorageBuffer(`assignTable`, clusterLightingBuffer.assignTableBuffer); + renderShader.setStorageBuffer(`clusterBuffer`, clusterLightingBuffer.clusterBuffer); } renderShader.apply(this._geometry, pass, renderPassState); diff --git a/src/engine/components/renderer/SkinnedMeshRenderer.ts b/src/components/renderer/SkinnedMeshRenderer.ts similarity index 94% rename from src/engine/components/renderer/SkinnedMeshRenderer.ts rename to src/components/renderer/SkinnedMeshRenderer.ts index 866d1d16..31f17c2b 100644 --- a/src/engine/components/renderer/SkinnedMeshRenderer.ts +++ b/src/components/renderer/SkinnedMeshRenderer.ts @@ -1,12 +1,13 @@ import { View3D } from "../../core/View3D"; import { Object3D } from "../../core/entities/Object3D"; +import { MeshRenderer } from "./MeshRenderer"; +import { RendererMask } from "../../gfx/renderJob/passRenderer/state/RendererMask"; import { StorageGPUBuffer } from "../../gfx/graphics/webGpu/core/buffer/StorageGPUBuffer"; +import { RendererType } from "../../gfx/renderJob/passRenderer/state/RendererType"; import { ClusterLightingRender } from "../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender"; -import { RendererMask } from "../../gfx/renderJob/passRenderer/state/RendererMask"; import { RendererPassState } from "../../gfx/renderJob/passRenderer/state/RendererPassState"; -import { RendererType } from "../../gfx/renderJob/passRenderer/state/RendererType"; import { SkeletonAnimationComponent } from "../SkeletonAnimationComponent"; -import { MeshRenderer } from "./MeshRenderer"; +import { ClusterLightingBuffer } from "../../gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer"; /** * Skin Mesh Renderer Component @@ -27,7 +28,7 @@ export class SkinnedMeshRenderer extends MeshRenderer { this.addRendererMask(RendererMask.SkinnedMesh); } - protected start() { + public start() { super.start(); this.skeletonAnimation = this.object3D.getComponent(SkeletonAnimationComponent); if (!this.skeletonAnimation) { @@ -41,6 +42,10 @@ export class SkinnedMeshRenderer extends MeshRenderer { } } + public onEnable(): void { + super.onEnable(); + } + public get skeletonAnimation(): SkeletonAnimationComponent { return this.mSkeletonAnimation; } @@ -103,7 +108,7 @@ export class SkinnedMeshRenderer extends MeshRenderer { * @param clusterLightingRender * @param probes */ - public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingRender?: ClusterLightingRender) { + public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingBuffer: ClusterLightingBuffer) { for (let i = 0; i < this.materials.length; i++) { const material = this.materials[i]; let passes = material.renderPasses.get(passType); @@ -116,7 +121,7 @@ export class SkinnedMeshRenderer extends MeshRenderer { } } } - super.nodeUpdate(view, passType, renderPassState, clusterLightingRender); + super.nodeUpdate(view, passType, renderPassState, clusterLightingBuffer); } } diff --git a/src/engine/components/renderer/SkyRenderer.ts b/src/components/renderer/SkyRenderer.ts similarity index 89% rename from src/engine/components/renderer/SkyRenderer.ts rename to src/components/renderer/SkyRenderer.ts index 2cd818c4..5c0faeca 100644 --- a/src/engine/components/renderer/SkyRenderer.ts +++ b/src/components/renderer/SkyRenderer.ts @@ -1,17 +1,17 @@ import { Engine3D } from '../../Engine3D'; import { View3D } from '../../core/View3D'; +import { MeshRenderer } from './MeshRenderer'; import { BoundingBox } from '../../core/bound/BoundingBox'; import { Texture } from '../../gfx/graphics/webGpu/core/texture/Texture'; import { EntityCollect } from '../../gfx/renderJob/collect/EntityCollect'; -import { ClusterLightingRender } from '../../gfx/renderJob/passRenderer/cluster/ClusterLightingRender'; +import { ClusterLightingBuffer } from '../../gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer'; import { RendererMask } from '../../gfx/renderJob/passRenderer/state/RendererMask'; import { RendererPassState } from '../../gfx/renderJob/passRenderer/state/RendererPassState'; import { RendererType } from '../../gfx/renderJob/passRenderer/state/RendererType'; import { SkyMaterial } from '../../materials/SkyMaterial'; import { Vector3 } from '../../math/Vector3'; import { SphereGeometry } from '../../shape/SphereGeometry'; -import { MeshRenderer } from './MeshRenderer'; /** * @@ -32,14 +32,14 @@ export class SkyRenderer extends MeshRenderer { this.alwaysRender = true; } - protected init(): void { + public init(): void { super.init(); this.object3D.bound = new BoundingBox(Vector3.ZERO.clone(), Vector3.MAX); this.geometry = new SphereGeometry(Engine3D.setting.sky.defaultFar, 20, 20); this.skyMaterial ||= new SkyMaterial(); } - protected onEnable(): void { + public onEnable(): void { if (!this._readyPipeline) { this.initPipeline(); } else { @@ -52,16 +52,16 @@ export class SkyRenderer extends MeshRenderer { } } - protected onDisable(): void { + public onDisable(): void { if (this._inRenderer && this.transform.scene3D) { this._inRenderer = false; EntityCollect.instance.sky = null; } } - public renderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingRender: ClusterLightingRender, encoder: GPURenderPassEncoder, useBundle: boolean = false) { + public renderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingBuffer: ClusterLightingBuffer, encoder: GPURenderPassEncoder, useBundle: boolean = false) { this.transform.updateWorldMatrix(); - super.renderPass2(view, passType, rendererPassState, clusterLightingRender, encoder, useBundle); + super.renderPass2(view, passType, rendererPassState, clusterLightingBuffer, encoder, useBundle); // this.transform.localPosition = Camera3D.mainCamera.transform.localPosition ; } diff --git a/src/engine/components/shape/BoxColliderShape.ts b/src/components/shape/BoxColliderShape.ts similarity index 100% rename from src/engine/components/shape/BoxColliderShape.ts rename to src/components/shape/BoxColliderShape.ts diff --git a/src/engine/components/shape/CapsuleColliderShape.ts b/src/components/shape/CapsuleColliderShape.ts similarity index 100% rename from src/engine/components/shape/CapsuleColliderShape.ts rename to src/components/shape/CapsuleColliderShape.ts diff --git a/src/engine/components/shape/ColliderShape.ts b/src/components/shape/ColliderShape.ts similarity index 100% rename from src/engine/components/shape/ColliderShape.ts rename to src/components/shape/ColliderShape.ts diff --git a/src/engine/components/shape/MeshColliderShape.ts b/src/components/shape/MeshColliderShape.ts similarity index 100% rename from src/engine/components/shape/MeshColliderShape.ts rename to src/components/shape/MeshColliderShape.ts diff --git a/src/engine/components/shape/SphereColliderShape.ts b/src/components/shape/SphereColliderShape.ts similarity index 100% rename from src/engine/components/shape/SphereColliderShape.ts rename to src/components/shape/SphereColliderShape.ts diff --git a/src/engine/core/Camera3D.ts b/src/core/Camera3D.ts similarity index 99% rename from src/engine/core/Camera3D.ts rename to src/core/Camera3D.ts index de5d80be..1084ca45 100644 --- a/src/engine/core/Camera3D.ts +++ b/src/core/Camera3D.ts @@ -99,7 +99,7 @@ export class Camera3D extends ComponentBase { super(); } - protected init() { + public init() { super.init(); this._ray = new Ray(); this.frustum = new Frustum(); @@ -111,11 +111,6 @@ export class Camera3D extends ComponentBase { this.lookTarget = new Vector3(0, 0, 0); } - /** - * @internal - */ - protected start() { } - /** * Create a perspective camera * @param fov diff --git a/src/engine/core/CameraType.ts b/src/core/CameraType.ts similarity index 100% rename from src/engine/core/CameraType.ts rename to src/core/CameraType.ts diff --git a/src/engine/core/CubeCamera.ts b/src/core/CubeCamera.ts similarity index 100% rename from src/engine/core/CubeCamera.ts rename to src/core/CubeCamera.ts diff --git a/src/engine/core/PointShadowCubeCamera.ts b/src/core/PointShadowCubeCamera.ts similarity index 100% rename from src/engine/core/PointShadowCubeCamera.ts rename to src/core/PointShadowCubeCamera.ts diff --git a/src/engine/core/Scene3D.ts b/src/core/Scene3D.ts similarity index 68% rename from src/engine/core/Scene3D.ts rename to src/core/Scene3D.ts index 8a75d6df..a5e36b0a 100644 --- a/src/engine/core/Scene3D.ts +++ b/src/core/Scene3D.ts @@ -1,7 +1,6 @@ import { Engine3D } from '../Engine3D'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { EntityCollect } from '../gfx/renderJob/collect/EntityCollect'; -import { defaultRes } from '../textures/DefaultRes'; import { View3D } from './View3D'; import { Object3D } from './entities/Object3D'; @@ -25,7 +24,7 @@ export class Scene3D extends Object3D { this.skyObject = new Object3D(); this.addChild(this.skyObject); this._isScene3D = true; - this.envMap ||= defaultRes.defaultSky; + this.envMap ||= Engine3D.res.defaultSky; } /** @@ -44,7 +43,7 @@ export class Scene3D extends Object3D { this.envMapChange = true; } this._envMap = value; - if (EntityCollect.instance.sky) + if (EntityCollect.instance.sky && `map` in EntityCollect.instance.sky) EntityCollect.instance.sky.map = value; } @@ -62,35 +61,37 @@ export class Scene3D extends Object3D { * Exposure of Sky Box. A larger value produces a sky box with stronger exposure and a brighter appearance. * A smaller value produces a sky box with weaker exposure and a darker appearance. */ - public get exposure() { - if (EntityCollect.instance.sky) - return EntityCollect.instance.sky.exposure; + public get exposure(): number { + if (EntityCollect.instance.sky && `exposure` in EntityCollect.instance.sky) + return EntityCollect.instance.sky.exposure as number; return 0; } /** * Set the exposure of the Sky Box. */ - public set exposure(value) { - if (EntityCollect.instance.sky) + public set exposure(value: number) { + if (EntityCollect.instance.sky && `exposure` in EntityCollect.instance.sky) { EntityCollect.instance.sky.exposure = value; - Engine3D.setting.sky.skyExposure = value; + Engine3D.setting.sky.skyExposure = value; + } } /** * Get the roughness of the Sky Box. */ - public get roughness() { - if (EntityCollect.instance.sky) - return EntityCollect.instance.sky.roughness; + public get roughness(): number { + if (EntityCollect.instance.sky && `roughness` in EntityCollect.instance.sky) { + return EntityCollect.instance.sky.roughness as number; + } } /** * Set the roughness of the Sky Box. */ - public set roughness(value) { - if (EntityCollect.instance.sky) - EntityCollect.instance.sky.skyMaterial.roughness = value; + public set roughness(value: number) { + if (EntityCollect.instance.sky && `roughness` in EntityCollect.instance.sky) { + EntityCollect.instance.sky.roughness = value; + } } - } diff --git a/src/engine/core/View3D.ts b/src/core/View3D.ts similarity index 100% rename from src/engine/core/View3D.ts rename to src/core/View3D.ts diff --git a/src/engine/core/ViewQuad.ts b/src/core/ViewQuad.ts similarity index 53% rename from src/engine/core/ViewQuad.ts rename to src/core/ViewQuad.ts index 5a599a65..e92ac97c 100644 --- a/src/engine/core/ViewQuad.ts +++ b/src/core/ViewQuad.ts @@ -11,10 +11,13 @@ import { BlendMode } from '../materials/BlendMode'; import { MaterialBase } from '../materials/MaterialBase'; import { Color } from '../math/Color'; import { PlaneGeometry } from '../shape/PlaneGeometry'; -import { defaultRes } from '../textures/DefaultRes'; -import { VirtualTexture } from '../textures/VirtualTexture'; + import { Object3D } from './entities/Object3D'; import { RendererPassState } from '../gfx/renderJob/passRenderer/state/RendererPassState'; +import { Engine3D } from '../Engine3D'; +import { GPUContext } from '../gfx/renderJob/GPUContext'; +import { RendererType } from '../gfx/renderJob/passRenderer/state/RendererType'; +import { View3D } from './View3D'; /** * @internal * @group Entity @@ -57,7 +60,7 @@ export class ViewQuad extends Object3D { this.quadRenderer[`__start`](); this.quadRenderer[`_enable`] = true; this.quadRenderer[`onEnable`](); - this.colorTexture = defaultRes.blackTexture; + this.colorTexture = Engine3D.res.blackTexture; shader.setUniformFloat(`x`, 0); shader.setUniformFloat(`y`, 0); @@ -84,4 +87,68 @@ export class ViewQuad extends Object3D { public set colorTexture(tex: Texture) { this.material.baseMap = tex; } + + /** + * By inputting a map to viewQuad and setting corresponding + * processing shaders, the corresponding results are output for off-screen rendering + * Can also be directly used as the final display rendering result rendering canvas + * @param viewQuad + * @see ViewQuad + * @param scene3D + * @see Scene3D + * @param command + */ + public renderTarget(view: View3D, viewQuad: ViewQuad, command: GPUCommandEncoder) { + let camera = view.camera; + let encoder = GPUContext.beginRenderPass(command, viewQuad.rendererPassState); + GPUContext.bindCamera(encoder, camera); + viewQuad.quadRenderer.nodeUpdate(view, RendererType.COLOR, viewQuad.rendererPassState, null); + viewQuad.quadRenderer.renderPass2(view, RendererType.COLOR, viewQuad.rendererPassState, null, encoder); + GPUContext.endPass(encoder); + } + + /** + * Output to screen through screen based shading + * @param viewQuad + * @see ViewQuad + * @param scene3D + * @see Scene3D + * @param command + * @param colorTexture + */ + public renderToViewQuad(view: View3D, viewQuad: ViewQuad, command: GPUCommandEncoder, colorTexture: Texture) { + let camera = view.camera; + viewQuad.colorTexture = colorTexture; + let encoder = GPUContext.beginRenderPass(command, viewQuad.rendererPassState); + GPUContext.bindCamera(encoder, camera); + + // viewQuad.x = view.viewPort.x; + // viewQuad.y = view.viewPort.y; + // viewQuad.scaleX = view.viewPort.width; + // viewQuad.scaleY = view.viewPort.height; + // viewQuad.transform.updateWorldMatrix(true); + // encoder.setViewport( + // view.viewPort.x * webGPUContext.presentationSize[0], + // view.viewPort.y * webGPUContext.presentationSize[1], + // view.viewPort.width * webGPUContext.presentationSize[0], + // view.viewPort.height * webGPUContext.presentationSize[1], + // 0.0, 1.0); + // encoder.setScissorRect( + // view.viewPort.x * webGPUContext.presentationSize[0], + // view.viewPort.y * webGPUContext.presentationSize[0], + // view.viewPort.width * webGPUContext.presentationSize[0], + // view.viewPort.height * webGPUContext.presentationSize[1], + // ); + + // encoder.setScissorRect(view.viewPort.x, view.viewPort.y, 300, 150); + // encoder.setViewport(view.viewPort.x, view.viewPort.y, view.viewPort.width / (view.viewPort.width / view.viewPort.height), view.viewPort.height, 0.0, 1.0); + // encoder.setScissorRect(view.viewPort.x, view.viewPort.y, view.viewPort.width, view.viewPort.height); + + // encoder.setViewport(camera.viewPort.x, camera.viewPort.y, camera.viewPort.width, camera.viewPort.height, 0.0, 1.0); + // encoder.setScissorRect(camera.viewPort.x, camera.viewPort.y, camera.viewPort.width, camera.viewPort.height); + + viewQuad.quadRenderer.nodeUpdate(view, RendererType.COLOR, viewQuad.rendererPassState, null); + viewQuad.quadRenderer.renderPass2(view, RendererType.COLOR, viewQuad.rendererPassState, null, encoder); + GPUContext.endPass(encoder); + } } diff --git a/src/engine/core/bound/BoundingBox.ts b/src/core/bound/BoundingBox.ts similarity index 100% rename from src/engine/core/bound/BoundingBox.ts rename to src/core/bound/BoundingBox.ts index a11622f1..1bebf601 100644 --- a/src/engine/core/bound/BoundingBox.ts +++ b/src/core/bound/BoundingBox.ts @@ -1,8 +1,8 @@ -import { Ray } from '../../math/Ray'; -import { Vector3 } from '../../math/Vector3'; -import { Object3D } from '../entities/Object3D'; import { Frustum } from './Frustum'; import { IBound } from './IBound'; +import { Object3D } from '../entities/Object3D'; +import { Ray } from '../../math/Ray'; +import { Vector3 } from '../../math/Vector3'; /** * BoundingBox diff --git a/src/engine/core/bound/BoundingSphere.ts b/src/core/bound/BoundingSphere.ts similarity index 99% rename from src/engine/core/bound/BoundingSphere.ts rename to src/core/bound/BoundingSphere.ts index d452c40d..4940a947 100644 --- a/src/engine/core/bound/BoundingSphere.ts +++ b/src/core/bound/BoundingSphere.ts @@ -1,8 +1,9 @@ -import { Ray } from '../../math/Ray'; -import { Vector3 } from '../../math/Vector3'; -import { Object3D } from '../entities/Object3D'; import { Frustum } from './Frustum'; import { IBound } from './IBound'; +import { Object3D } from '../entities/Object3D'; +import { Ray } from '../../math/Ray'; +import { Vector3 } from '../../math/Vector3'; + /** * BoundingSphere * @internal diff --git a/src/engine/core/bound/Frustum.ts b/src/core/bound/Frustum.ts similarity index 95% rename from src/engine/core/bound/Frustum.ts rename to src/core/bound/Frustum.ts index b641a0cc..492f2b70 100644 --- a/src/engine/core/bound/Frustum.ts +++ b/src/core/bound/Frustum.ts @@ -1,9 +1,7 @@ -import { Matrix4 } from "../../math/Matrix4"; -import { Vector3 } from "../../math/Vector3"; -import { Camera3D } from "../Camera3D"; -import { Object3D } from "../entities/Object3D"; -import { BoundingBox } from "./BoundingBox"; -import { BoundingSphere } from "./BoundingSphere"; +import { BoundingSphere } from './BoundingSphere'; +import { Matrix4 } from '../../math/Matrix4'; +import { Object3D } from '../entities/Object3D'; +import { Vector3 } from '../../math/Vector3'; /** * @internal diff --git a/src/engine/core/bound/IBound.ts b/src/core/bound/IBound.ts similarity index 99% rename from src/engine/core/bound/IBound.ts rename to src/core/bound/IBound.ts index f7e88906..32607e95 100644 --- a/src/engine/core/bound/IBound.ts +++ b/src/core/bound/IBound.ts @@ -1,7 +1,8 @@ +import { Frustum } from './Frustum'; +import { Object3D } from '../entities/Object3D'; import { Ray } from '../../math/Ray'; import { Vector3 } from '../../math/Vector3'; -import { Object3D } from '../entities/Object3D'; -import { Frustum } from './Frustum'; + /** * @internal */ diff --git a/src/engine/core/entities/Entity.ts b/src/core/entities/Entity.ts similarity index 95% rename from src/engine/core/entities/Entity.ts rename to src/core/entities/Entity.ts index 9863bff3..737a677f 100644 --- a/src/engine/core/entities/Entity.ts +++ b/src/core/entities/Entity.ts @@ -1,7 +1,8 @@ -import { ComponentBase } from '../../components/ComponentBase'; +import { IComponent } from '../../components/IComponent'; import { RenderNode } from '../../components/renderer/RenderNode'; import { Transform } from '../../components/Transform'; import { CEventDispatcher } from '../../event/CEventDispatcher'; +import { ComponentCollect } from '../../gfx/renderJob/collect/ComponentCollect'; import { RenderLayer } from '../../gfx/renderJob/config/RenderLayer'; import { Vector3 } from '../../math/Vector3'; import { UUID } from '../../util/Global'; @@ -70,14 +71,14 @@ export class Entity extends CEventDispatcher { * * List of components attached to an object */ - public components: Map; + public components: Map; /** * * The bounding box of an object */ public bound: IBound; - protected waitDisposeComponents: ComponentBase[]; + protected waitDisposeComponents: IComponent[]; private _dispose: boolean = false; // private _visible: boolean = true; @@ -115,7 +116,7 @@ export class Entity extends CEventDispatcher { constructor() { super(); this.entityChildren = []; - this.components = new Map(); + this.components = new Map(); this.waitDisposeComponents = []; this._uuid = UUID(); } @@ -244,7 +245,7 @@ export class Entity extends CEventDispatcher { /** * - * Search for object children and return a child object with a matching name。 + * Search for object children and return a child object with a matching name. * @param name matching name * @param loopChild Whether to traverse the children of the child object. The default value is true * @returns result @@ -303,11 +304,11 @@ export class Entity extends CEventDispatcher { }); this.components.clear(); } else { - ComponentBase.waitStartComponent.forEach((v, k) => { + ComponentCollect.waitStartComponent.forEach((v, k) => { v.forEach((v) => { v[`__start`](); }) - ComponentBase.waitStartComponent.delete(k); + ComponentCollect.waitStartComponent.delete(k); }); } } diff --git a/src/engine/core/entities/InstancedMesh.ts b/src/core/entities/InstancedMesh.ts similarity index 100% rename from src/engine/core/entities/InstancedMesh.ts rename to src/core/entities/InstancedMesh.ts diff --git a/src/engine/core/entities/Object3D.ts b/src/core/entities/Object3D.ts similarity index 87% rename from src/engine/core/entities/Object3D.ts rename to src/core/entities/Object3D.ts index 65ef26df..cb019852 100644 --- a/src/engine/core/entities/Object3D.ts +++ b/src/core/entities/Object3D.ts @@ -1,9 +1,10 @@ -import { ComponentBase } from '../../components/ComponentBase'; import { Transform } from '../../components/Transform'; import { Quaternion } from '../../math/Quaternion'; import { Vector3 } from '../../math/Vector3'; import { Entity } from './Entity'; import { Ctor } from "../../util/Global"; +import { IComponent } from '../../components/IComponent'; +import { ComponentCollect } from '../../gfx/renderJob/collect/ComponentCollect'; /** * The base class of most objects provides a series of properties and methods for manipulating objects in three-dimensional space. * @group Entity @@ -45,23 +46,23 @@ export class Object3D extends Entity { * @param c class of component * @return result component */ - public addComponent(c: Ctor, param?: any): T { - if (!this.components.has(c.prototype)) { + public addComponent(c: Ctor, param?: any): T { + let className = c.name; + if (!this.components.has(className)) { let instance: T = new c() as T; instance.object3D = this; instance[`__init`](param); - // instance[`__start`](); - this.components.set(c.prototype, instance); + this.components.set(className, instance); this.appendLateStart(instance); return instance; } return null; } - private appendLateStart(component: ComponentBase) { - let arr = ComponentBase.waitStartComponent.get(this); + private appendLateStart(component: IComponent) { + let arr = ComponentCollect.waitStartComponent.get(this); if (!arr) { - ComponentBase.waitStartComponent.set(this, [component]); + ComponentCollect.waitStartComponent.set(this, [component]); } else { let index = arr.indexOf(component); if (index == -1) { @@ -77,8 +78,9 @@ export class Object3D extends Entity { * @param c class of component * @returns result component */ - public getOrAddComponent(c: Ctor): T { - let component = this.components.get(c.prototype); + public getOrAddComponent(c: Ctor): T { + let className = c.name; + let component = this.components.get(className); if (!component) { component = this.addComponent(c); } @@ -90,10 +92,11 @@ export class Object3D extends Entity { * Remove components of the specified type * @param c class of component */ - public removeComponent(c: Ctor) { - if (this.components.has(c.prototype)) { - let component = this.components.get(c.prototype); - this.components.delete(c.prototype); + public removeComponent(c: Ctor) { + let className = c.name; + if (this.components.has(className)) { + let component = this.components.get(className); + this.components.delete(className); component[`__stop`](); component.destroy(); } @@ -105,8 +108,9 @@ export class Object3D extends Entity { * @param c type of component * @returns boolean */ - public hasComponent(c: Ctor): boolean { - return this.components.has(c.prototype); + public hasComponent(c: Ctor): boolean { + let className = c.name; + return this.components.has(className); } /** @@ -115,8 +119,9 @@ export class Object3D extends Entity { * @param c class of component * @returns result component */ - public getComponent(c: Ctor): T { - return this.components.get(c.prototype) as T; + public getComponent(c: Ctor): T { + let className = c.name; + return this.components.get(className) as T; } /** @@ -127,7 +132,7 @@ export class Object3D extends Entity { * @param c class of component * @returns reulst component */ - public getComponentFromParent(c: Ctor): T { + public getComponentFromParent(c: Ctor): T { if (!this.parent) { return null; } @@ -147,9 +152,10 @@ export class Object3D extends Entity { * @param c class of component * @returns result components */ - public getComponentsInChild(c: Ctor): T[] { + public getComponentsInChild(c: Ctor): T[] { let list: T[] = []; - let component = this.components.get(c.prototype); + let className = c.name; + let component = this.components.get(className); if (component) { list.push(component as T); } @@ -170,7 +176,7 @@ export class Object3D extends Entity { * @param includeInactive Whether to include invisible objects, default to false * @returns {outList} */ - public getComponents(c: Ctor, outList?: Array, includeInactive?: boolean): T[] { + public getComponents(c: Ctor, outList?: Array, includeInactive?: boolean): T[] { outList ||= []; let component = this.getComponent(c); if (component && (component.enable || includeInactive)) { @@ -195,9 +201,10 @@ export class Object3D extends Entity { * @return {*} {T} * @memberof ELPObject3D */ - public getComponentsExt(c: Ctor, ret?: T[], includeInactive?: boolean): T[] { + public getComponentsExt(c: Ctor, ret?: T[], includeInactive?: boolean): T[] { if (!ret) ret = []; - let component = this.components.get(c.prototype); + let className = c.name; + let component = this.components.get(className); if (component && (component.enable || includeInactive)) { ret.push(component as T); } else { diff --git a/src/engine/core/geometry/GeometryBase.ts b/src/core/geometry/GeometryBase.ts similarity index 99% rename from src/engine/core/geometry/GeometryBase.ts rename to src/core/geometry/GeometryBase.ts index e1fd6b2f..5cf15cc8 100644 --- a/src/engine/core/geometry/GeometryBase.ts +++ b/src/core/geometry/GeometryBase.ts @@ -1,4 +1,3 @@ -import { ArrayBufferData } from "../../gfx/graphics/webGpu/core/buffer/GPUBufferBase"; import { ShaderReflection } from "../../gfx/graphics/webGpu/shader/value/ShaderReflectionInfo"; import { Vector3 } from "../../math/Vector3"; import { UUID } from "../../util/Global"; @@ -8,6 +7,7 @@ import { GeometryVertexBuffer } from "./GeometryVertexBuffer"; import { GeometryIndicesBuffer } from "./GeometryIndicesBuffer"; import { GeometryVertexType } from "./GeometryVertexType"; import { VertexAttributeData } from "./VertexAttributeData"; +import { ArrayBufferData } from "../../gfx/graphics/webGpu/core/buffer/ArrayBufferData"; export type LodLevel = { indexStart: number; diff --git a/src/engine/core/geometry/GeometryIndicesBuffer.ts b/src/core/geometry/GeometryIndicesBuffer.ts similarity index 98% rename from src/engine/core/geometry/GeometryIndicesBuffer.ts rename to src/core/geometry/GeometryIndicesBuffer.ts index 50429331..0776cd5a 100644 --- a/src/engine/core/geometry/GeometryIndicesBuffer.ts +++ b/src/core/geometry/GeometryIndicesBuffer.ts @@ -1,4 +1,4 @@ -import { ArrayBufferData } from "../../gfx/graphics/webGpu/core/buffer/GPUBufferBase"; +import { ArrayBufferData } from "../../gfx/graphics/webGpu/core/buffer/ArrayBufferData"; import { IndicesGPUBuffer } from "../../gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer"; import { VertexAttributeData } from "./VertexAttributeData"; diff --git a/src/engine/core/geometry/GeometryVertexBuffer.ts b/src/core/geometry/GeometryVertexBuffer.ts similarity index 100% rename from src/engine/core/geometry/GeometryVertexBuffer.ts rename to src/core/geometry/GeometryVertexBuffer.ts diff --git a/src/engine/core/geometry/GeometryVertexType.ts b/src/core/geometry/GeometryVertexType.ts similarity index 100% rename from src/engine/core/geometry/GeometryVertexType.ts rename to src/core/geometry/GeometryVertexType.ts diff --git a/src/engine/core/geometry/VertexAttribute.ts b/src/core/geometry/VertexAttribute.ts similarity index 100% rename from src/engine/core/geometry/VertexAttribute.ts rename to src/core/geometry/VertexAttribute.ts diff --git a/src/engine/core/geometry/VertexAttributeData.ts b/src/core/geometry/VertexAttributeData.ts similarity index 85% rename from src/engine/core/geometry/VertexAttributeData.ts rename to src/core/geometry/VertexAttributeData.ts index 9d4595e6..946d492d 100644 --- a/src/engine/core/geometry/VertexAttributeData.ts +++ b/src/core/geometry/VertexAttributeData.ts @@ -1,4 +1,4 @@ -import { ArrayBufferData } from "../../gfx/graphics/webGpu/core/buffer/GPUBufferBase"; +import { ArrayBufferData } from "../../gfx/graphics/webGpu/core/buffer/ArrayBufferData"; export type VertexAttributeData = { attribute: string, diff --git a/src/engine/core/geometry/VertexAttributeName.ts b/src/core/geometry/VertexAttributeName.ts similarity index 100% rename from src/engine/core/geometry/VertexAttributeName.ts rename to src/core/geometry/VertexAttributeName.ts diff --git a/src/engine/core/geometry/VertexAttributeSize.ts b/src/core/geometry/VertexAttributeSize.ts similarity index 100% rename from src/engine/core/geometry/VertexAttributeSize.ts rename to src/core/geometry/VertexAttributeSize.ts diff --git a/src/engine/core/geometry/VertexAttributeStride.ts b/src/core/geometry/VertexAttributeStride.ts similarity index 100% rename from src/engine/core/geometry/VertexAttributeStride.ts rename to src/core/geometry/VertexAttributeStride.ts diff --git a/src/engine/core/geometry/VertexFormat.ts b/src/core/geometry/VertexFormat.ts similarity index 100% rename from src/engine/core/geometry/VertexFormat.ts rename to src/core/geometry/VertexFormat.ts diff --git a/src/engine/core/pool/ObjectPool.ts b/src/core/pool/ObjectPool.ts similarity index 100% rename from src/engine/core/pool/ObjectPool.ts rename to src/core/pool/ObjectPool.ts diff --git a/src/engine/core/pool/memory/MatrixDO.ts b/src/core/pool/memory/MatrixDO.ts similarity index 100% rename from src/engine/core/pool/memory/MatrixDO.ts rename to src/core/pool/memory/MatrixDO.ts diff --git a/src/engine/core/pool/memory/MemoryDO.ts b/src/core/pool/memory/MemoryDO.ts similarity index 100% rename from src/engine/core/pool/memory/MemoryDO.ts rename to src/core/pool/memory/MemoryDO.ts diff --git a/src/engine/core/pool/memory/MemoryInfo.ts b/src/core/pool/memory/MemoryInfo.ts similarity index 100% rename from src/engine/core/pool/memory/MemoryInfo.ts rename to src/core/pool/memory/MemoryInfo.ts diff --git a/src/engine/core/tree/kdTree/IKDTreeUserData.ts b/src/core/tree/kdTree/IKDTreeUserData.ts similarity index 100% rename from src/engine/core/tree/kdTree/IKDTreeUserData.ts rename to src/core/tree/kdTree/IKDTreeUserData.ts diff --git a/src/engine/core/tree/kdTree/KDTreeEntity.ts b/src/core/tree/kdTree/KDTreeEntity.ts similarity index 100% rename from src/engine/core/tree/kdTree/KDTreeEntity.ts rename to src/core/tree/kdTree/KDTreeEntity.ts diff --git a/src/engine/core/tree/kdTree/KDTreeNode.ts b/src/core/tree/kdTree/KDTreeNode.ts similarity index 100% rename from src/engine/core/tree/kdTree/KDTreeNode.ts rename to src/core/tree/kdTree/KDTreeNode.ts diff --git a/src/engine/core/tree/kdTree/KDTreeSpace.ts b/src/core/tree/kdTree/KDTreeSpace.ts similarity index 100% rename from src/engine/core/tree/kdTree/KDTreeSpace.ts rename to src/core/tree/kdTree/KDTreeSpace.ts diff --git a/src/engine/textures/DefaultRes.ts b/src/engine/textures/DefaultRes.ts deleted file mode 100644 index 69de0a77..00000000 --- a/src/engine/textures/DefaultRes.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { Engine3D } from '../Engine3D'; -import { BRDFLUTGenerate } from '../gfx/generate/BrdfLUTGenerate'; -import { Uint8ArrayTexture } from './Uint8ArrayTexture'; -import { Texture } from "../gfx/graphics/webGpu/core/texture/Texture"; -import { HDRTextureCube } from './HDRTextureCube'; - -/** - * default internal texture - * @internal - * @group Texture - */ -class _DefaultRes { - /** - * normal texture - */ - public normalTexture: Uint8ArrayTexture; - public maskTexture: Uint8ArrayTexture; - public whiteTexture: Uint8ArrayTexture; - public blackTexture: Uint8ArrayTexture; - public redTexture: Uint8ArrayTexture; - public blueTexture: Uint8ArrayTexture; - public greenTexture: Uint8ArrayTexture; - public yellowTexture: Uint8ArrayTexture; - public grayTexture: Uint8ArrayTexture; - public defaultTextureKVMap: { [name: string]: Texture } = {}; - public defaultTextureVKMap: Map = new Map(); - public defaultSky: HDRTextureCube; - /** - * create a texture - * @param width width of texture - * @param height height of texture - * @param r component-red - * @param g component-green - * @param b component-blue - * @param a component-alpha(0 for transparent,1 for opaque) - * @param name name string - * @returns - */ - public createTexture(width: number, height: number, r: number, g: number, b: number, a: number, name?: string) { - let w = 32; - let h = 32; - let textureData = new Uint8Array(w * h * 4); - this.fillColor(textureData, width, height, r, g, b, a); - let texture = new Uint8ArrayTexture(); - texture.name = name; - texture.create(16, 16, textureData, true); - if (name) { - this.recordTexture(name, texture); - } - return texture; - } - - public recordTexture(name: string, texture: Texture) { - this.defaultTextureKVMap[name] = texture; - this.defaultTextureVKMap.set(texture, name); - } - - /** - * fill slod color to this texture - * @param array data of texture - * @param w width of texture - * @param h height of texture - * @param r component-red - * @param g component-green - * @param b component-blue - * @param a component-alpha(0 for transparent,1 for opaque) - */ - public fillColor(array: any, w: number, h: number, r: number, g: number, b: number, a: number) { - for (let i = 0; i < w; i++) { - for (let j = 0; j < h; j++) { - let pixelIndex = j * w + i; - array[pixelIndex * 4 + 0] = r; - array[pixelIndex * 4 + 1] = g; - array[pixelIndex * 4 + 2] = b; - array[pixelIndex * 4 + 3] = a; - } - } - } - - /** - * Initialize a common texture object. Provide a universal solid color texture object. - */ - public async initCommon() { - defaultRes.normalTexture = defaultRes.createTexture(32, 32, 255 * 0.5, 255 * 0.5, 255.0, 255.0, 'default-normalTexture'); - defaultRes.maskTexture = defaultRes.createTexture(32, 32, 255, 255 * 0.5, 0.0, 255.0, 'default-maskTexture'); - defaultRes.whiteTexture = defaultRes.createTexture(32, 32, 255, 255, 255, 255, 'default-whiteTexture'); - defaultRes.blackTexture = defaultRes.createTexture(32, 32, 0, 0, 0, 255.0, 'default-blackTexture'); - defaultRes.redTexture = defaultRes.createTexture(32, 32, 255, 0, 0, 255.0, 'default-redTexture'); - defaultRes.blueTexture = defaultRes.createTexture(32, 32, 0, 0, 255, 255.0, 'default-blueTexture'); - defaultRes.greenTexture = defaultRes.createTexture(32, 32, 0, 255, 0, 255, 'default-greenTexture'); - defaultRes.yellowTexture = defaultRes.createTexture(32, 32, 0, 255, 255, 255.0, 'default-yellowTexture'); - defaultRes.grayTexture = defaultRes.createTexture(32, 32, 128, 128, 128, 255.0, 'default-grayTexture'); - - let brdf = new BRDFLUTGenerate(); - let texture = brdf.generateBRDFLUTTexture(); - let BRDFLUT = texture.name = 'BRDFLUT'; - Engine3D.res.addTexture(BRDFLUT, texture); - this.recordTexture(BRDFLUT, texture); - - defaultRes.defaultSky = new HDRTextureCube(); - defaultRes.defaultSky.createFromTexture(128, defaultRes.blackTexture); - } -} - -/** - * @internal - * default internal texture - * @group Texture - */ -export let defaultRes = new _DefaultRes(); diff --git a/src/engine/event/CEvent.ts b/src/event/CEvent.ts similarity index 95% rename from src/engine/event/CEvent.ts rename to src/event/CEvent.ts index 1eeaa660..a127526c 100644 --- a/src/engine/event/CEvent.ts +++ b/src/event/CEvent.ts @@ -1,123 +1,123 @@ -import { View3D } from '../core/View3D'; -import { Object3D } from '../core/entities/Object3D'; -import { TouchData } from '../io/TouchData'; -import { CEventListener } from './CEventListener'; -/** - * Basic class of Event - * @group Events - */ -export class CEvent { - /** - * Event target, it's usually event dispatcher - */ - public target: Object3D; - - /** - * Current event target, it's current bubble object - */ - public currentTarget: CEventListener; - - /** - * event type, it's registered string of key - */ - public type: string; - - /** - * extra data.Used for the transmission process of events, carrying data - */ - public data: any; - - /** - * - * The param data when event is registered - */ - public param: any; - - /** - * - * the time when event is - */ - public time: number = 0; - - /** - * - *the delay time when event is dispatched. - */ - public delay: number = 0; - - /** - * - * mouse code, see @MouseCode {@link MouseCode} - */ - public mouseCode: number = 0; - - /** - * Is Ctrl key pressed when the event occurs - */ - public ctrlKey: boolean; - - /** - * Is Alt key pressed when the event occurs - */ - public altKey: boolean; - - /** - * Is Shift key pressed when the event occurs - */ - public shiftKey: boolean; - - /** - * Collection of finger touch points, which registered - */ - public targetTouches: Array; - - /** - * Collection of finger touch points changed - */ - public changedTouches: Array; - - /** - * Collection of finger touch points - */ - public touches: Array; - - private _stopImmediatePropagation: boolean = false; - - /** - * binded view3D object in event. - */ - public view: View3D; - - /** - * - * Create a new event, with type and data - * @param eventType {any} eventType - * @param data {any} param - */ - constructor(eventType: string = null, data: any = null) { - this.type = eventType; - this.data = data; - } - /** - * - * Prevent bubbling of all event listeners in subsequent nodes of the current node in the event flow. - */ - public stopImmediatePropagation() { - this._stopImmediatePropagation = true; - } - - /** - * @internal - * set stopImmediatePropagation as false - */ - public reset() { - this._stopImmediatePropagation = false; - } - - /** - * Returns stopImmediatePropagation value - */ - public get isStopImmediatePropagation(): boolean { - return this._stopImmediatePropagation; - } -} +import { View3D } from '../core/View3D'; +import { Object3D } from '../core/entities/Object3D'; +import { TouchData } from '../io/TouchData'; +import { CEventListener } from './CEventListener'; +/** + * Basic class of Event + * @group Events + */ +export class CEvent { + /** + * Event target, it's usually event dispatcher + */ + public target: Object3D; + + /** + * Current event target, it's current bubble object + */ + public currentTarget: CEventListener; + + /** + * event type, it's registered string of key + */ + public type: string; + + /** + * extra data.Used for the transmission process of events, carrying data + */ + public data: any; + + /** + * + * The param data when event is registered + */ + public param: any; + + /** + * + * the time when event is + */ + public time: number = 0; + + /** + * + *the delay time when event is dispatched. + */ + public delay: number = 0; + + /** + * + * mouse code, see @MouseCode {@link MouseCode} + */ + public mouseCode: number = 0; + + /** + * Is Ctrl key pressed when the event occurs + */ + public ctrlKey: boolean; + + /** + * Is Alt key pressed when the event occurs + */ + public altKey: boolean; + + /** + * Is Shift key pressed when the event occurs + */ + public shiftKey: boolean; + + /** + * Collection of finger touch points, which registered + */ + public targetTouches: Array; + + /** + * Collection of finger touch points changed + */ + public changedTouches: Array; + + /** + * Collection of finger touch points + */ + public touches: Array; + + private _stopImmediatePropagation: boolean = false; + + /** + * binded view3D object in event. + */ + public view: View3D; + + /** + * + * Create a new event, with type and data + * @param eventType {any} eventType + * @param data {any} param + */ + constructor(eventType: string = null, data: any = null) { + this.type = eventType; + this.data = data; + } + /** + * + * Prevent bubbling of all event listeners in subsequent nodes of the current node in the event flow. + */ + public stopImmediatePropagation() { + this._stopImmediatePropagation = true; + } + + /** + * @internal + * set stopImmediatePropagation as false + */ + public reset() { + this._stopImmediatePropagation = false; + } + + /** + * Returns stopImmediatePropagation value + */ + public get isStopImmediatePropagation(): boolean { + return this._stopImmediatePropagation; + } +} diff --git a/src/engine/event/CEventDispatcher.ts b/src/event/CEventDispatcher.ts similarity index 95% rename from src/engine/event/CEventDispatcher.ts rename to src/event/CEventDispatcher.ts index 3ed52d44..f9f68891 100644 --- a/src/engine/event/CEventDispatcher.ts +++ b/src/event/CEventDispatcher.ts @@ -1,210 +1,210 @@ -import { CEvent } from './CEvent'; -import { CEventListener } from './CEventListener'; - -/** - * Basic class of event diapatcher. - * It includes the implementation of functions such as event registration, - * deregistration, distribution, and unregister. - * @group Events - */ -export class CEventDispatcher { - /** - * @internal - */ - protected listeners: any = {}; - /** - * @internal - */ - public data: any; - /** - * - * Dispatch an event to all registered objects with a specific type of listener. - * @param event3D the event is dispatched. - */ - public dispatchEvent(event: CEvent) { - var list: any = this.listeners[event.type]; - if (list != null) { - list = list.slice(); - for (var i: number = 0; i < list.length; i++) { - var listener: CEventListener = list[i]; - if (listener.handler) { - try { - event.param = listener.param; - event.currentTarget = listener; - if (!listener.thisObject) { - // log("nullListener thisObject"); - } - listener.handler.call(listener.thisObject, event); - } catch (error) { - // if (window.//console) { - //console.error(error.stack); - // } - } - if (event.isStopImmediatePropagation) { - break; - } - } - } - } - } - - /** - * - * release all registered event. - */ - public dispose() { - for (var key in this.listeners) { - var list: any = this.listeners[key]; - while (list.length > 0) { - var listener: CEventListener = list[0]; - listener.handler = null; - listener.thisObject = null; - list.splice(0, 1); - } - } - } - - /** - * - * register an event listener to event distancher. - * @param type {string} event type. - * @param callback {Function} The callback function that handles events. - * This function must accept an Event3D object as its unique parameter and cannot return any result. - * for example:function(evt:Event3D):void。 - * @param thisObject {any} Current registration object, it'll call callback function。 - * @param param {any} the data binded to registered event, the default value is null。 - * @param priority {number} The priority of callback function execution, with a larger set value having priority to call - * @returns {number} Returns register event id - */ - public addEventListener(type: string | number, callback: Function, thisObject: any, param: any = null, priority: number = 0): number { - if (this.listeners[type] == null) { - this.listeners[type] = []; - } - - if (!this.hasEventListener(type, callback, thisObject)) { - var listener: CEventListener = new CEventListener(type, thisObject, callback, param, priority); - listener.id = ++CEventListener.event_id_count; - listener.current = this; - this.listeners[type].push(listener); - this.listeners[type].sort(function (listener1: CEventListener, listener2: CEventListener) { - return listener2.priority - listener1.priority; - }); - - return listener.id; - } - - for (let i = 0; i < this.listeners[type].length; i++) { - let listener: CEventListener = this.listeners[type][i]; - if (listener.equalCurrentListener(type, callback, thisObject, param)) { - return listener.id; - } - } - - return 0; - } - - /** - * - * Remove Event Listening - * @param type {string} event type - * @param callback {Function} callback function of event register - * @param thisObject {any} The current registered object. - */ - public removeEventListener(type: string | number, callback: Function, thisObject: any): void { - if (this.hasEventListener(type, callback, thisObject)) { - for (var i: number = 0; i < this.listeners[type].length; i++) { - var listener: CEventListener = this.listeners[type][i]; - if (listener.equalCurrentListener(type, callback, thisObject, listener.param)) { - listener.handler = null; - listener.thisObject = null; - this.listeners[type].splice(i, 1); - return; - } - } - } - } - - /** - * - * Remove an event Listening with id - * @param register event id, see {@link addEventListener} - * Returns true when removed success. - */ - public removeEventListenerAt(id: number): boolean { - for (var key in this.listeners) { - for (var i: number = 0; i < this.listeners[key].length; i++) { - var listener = this.listeners[key][i]; - if (listener.id == id) { - listener.handler = null; - listener.thisObject = null; - this.listeners[key].splice(i, 1); - return true; - } - } - } - return false; - } - - /** - * - * Specify a event type to remove all related event listeners - * eventType event type, set null to remove all event listeners - */ - public removeAllEventListener(eventType: string | number = null): void { - let listener: CEventListener; - - if (eventType) { - if (this.listeners[eventType]) { - for (var i: number = 0; i < this.listeners[eventType].length; i++) { - listener = this.listeners[eventType][i]; - listener.dispose(); - this.listeners[eventType].splice(i, 1); - } - - delete this.listeners[eventType]; - } - } else { - for (let key in this.listeners) { - for (var i: number = 0; i < this.listeners[key].length; i++) { - listener = this.listeners[key][i]; - listener.dispose(); - this.listeners[key].splice(i, 1); - } - - delete this.listeners[key]; - } - } - } - - /** - * - * whether the target presence of a listener with event type. - * @param type {string} event type. - * @returns {boolean} Returns a boolean. - */ - public containEventListener(type: string): boolean { - if (this.listeners[type] == null) return false; - return this.listeners[type].length > 0; - } - - /** - * - * whether the target presence of a listener with event type. it associate more registration parameters. - * @param type {string} event name. - * @param callback {Function} callback function of event register. - * @param thisObject {any} The registered object. - * @returns {boolean} Returns a boolean. - */ - public hasEventListener(type: string | number, callback: Function = null, thisObject: any = null): boolean { - if (this.listeners[type] == null) return false; - if (thisObject && callback) { - for (var i: number = 0; i < this.listeners[type].length; i++) { - var listener: CEventListener = this.listeners[type][i]; - if (listener.equalCurrentListener(type, callback, thisObject, listener.param)) { - return true; - } - } - } - return false; - } -} +import { CEvent } from './CEvent'; +import { CEventListener } from './CEventListener'; + +/** + * Basic class of event diapatcher. + * It includes the implementation of functions such as event registration, + * deregistration, distribution, and unregister. + * @group Events + */ +export class CEventDispatcher { + /** + * @internal + */ + protected listeners: any = {}; + /** + * @internal + */ + public data: any; + /** + * + * Dispatch an event to all registered objects with a specific type of listener. + * @param event3D the event is dispatched. + */ + public dispatchEvent(event: CEvent) { + var list: any = this.listeners[event.type]; + if (list != null) { + list = list.slice(); + for (var i: number = 0; i < list.length; i++) { + var listener: CEventListener = list[i]; + if (listener.handler) { + try { + event.param = listener.param; + event.currentTarget = listener; + if (!listener.thisObject) { + // log("nullListener thisObject"); + } + listener.handler.call(listener.thisObject, event); + } catch (error) { + // if (window.//console) { + //console.error(error.stack); + // } + } + if (event.isStopImmediatePropagation) { + break; + } + } + } + } + } + + /** + * + * release all registered event. + */ + public dispose() { + for (var key in this.listeners) { + var list: any = this.listeners[key]; + while (list.length > 0) { + var listener: CEventListener = list[0]; + listener.handler = null; + listener.thisObject = null; + list.splice(0, 1); + } + } + } + + /** + * + * register an event listener to event distancher. + * @param type {string} event type. + * @param callback {Function} The callback function that handles events. + * This function must accept an Event3D object as its unique parameter and cannot return any result. + * for example: function(evt:Event3D):void. + * @param thisObject {any} Current registration object, it'll call callback function. + * @param param {any} the data binded to registered event, the default value is null. + * @param priority {number} The priority of callback function execution, with a larger set value having priority to call + * @returns {number} Returns register event id + */ + public addEventListener(type: string | number, callback: Function, thisObject: any, param: any = null, priority: number = 0): number { + if (this.listeners[type] == null) { + this.listeners[type] = []; + } + + if (!this.hasEventListener(type, callback, thisObject)) { + var listener: CEventListener = new CEventListener(type, thisObject, callback, param, priority); + listener.id = ++CEventListener.event_id_count; + listener.current = this; + this.listeners[type].push(listener); + this.listeners[type].sort(function (listener1: CEventListener, listener2: CEventListener) { + return listener2.priority - listener1.priority; + }); + + return listener.id; + } + + for (let i = 0; i < this.listeners[type].length; i++) { + let listener: CEventListener = this.listeners[type][i]; + if (listener.equalCurrentListener(type, callback, thisObject, param)) { + return listener.id; + } + } + + return 0; + } + + /** + * + * Remove Event Listening + * @param type {string} event type + * @param callback {Function} callback function of event register + * @param thisObject {any} The current registered object. + */ + public removeEventListener(type: string | number, callback: Function, thisObject: any): void { + if (this.hasEventListener(type, callback, thisObject)) { + for (var i: number = 0; i < this.listeners[type].length; i++) { + var listener: CEventListener = this.listeners[type][i]; + if (listener.equalCurrentListener(type, callback, thisObject, listener.param)) { + listener.handler = null; + listener.thisObject = null; + this.listeners[type].splice(i, 1); + return; + } + } + } + } + + /** + * + * Remove an event Listening with id + * @param register event id, see {@link addEventListener} + * Returns true when removed success. + */ + public removeEventListenerAt(id: number): boolean { + for (var key in this.listeners) { + for (var i: number = 0; i < this.listeners[key].length; i++) { + var listener = this.listeners[key][i]; + if (listener.id == id) { + listener.handler = null; + listener.thisObject = null; + this.listeners[key].splice(i, 1); + return true; + } + } + } + return false; + } + + /** + * + * Specify a event type to remove all related event listeners + * eventType event type, set null to remove all event listeners + */ + public removeAllEventListener(eventType: string | number = null): void { + let listener: CEventListener; + + if (eventType) { + if (this.listeners[eventType]) { + for (var i: number = 0; i < this.listeners[eventType].length; i++) { + listener = this.listeners[eventType][i]; + listener.dispose(); + this.listeners[eventType].splice(i, 1); + } + + delete this.listeners[eventType]; + } + } else { + for (let key in this.listeners) { + for (var i: number = 0; i < this.listeners[key].length; i++) { + listener = this.listeners[key][i]; + listener.dispose(); + this.listeners[key].splice(i, 1); + } + + delete this.listeners[key]; + } + } + } + + /** + * + * whether the target presence of a listener with event type. + * @param type {string} event type. + * @returns {boolean} Returns a boolean. + */ + public containEventListener(type: string): boolean { + if (this.listeners[type] == null) return false; + return this.listeners[type].length > 0; + } + + /** + * + * whether the target presence of a listener with event type. it associate more registration parameters. + * @param type {string} event name. + * @param callback {Function} callback function of event register. + * @param thisObject {any} The registered object. + * @returns {boolean} Returns a boolean. + */ + public hasEventListener(type: string | number, callback: Function = null, thisObject: any = null): boolean { + if (this.listeners[type] == null) return false; + if (thisObject && callback) { + for (var i: number = 0; i < this.listeners[type].length; i++) { + var listener: CEventListener = this.listeners[type][i]; + if (listener.equalCurrentListener(type, callback, thisObject, listener.param)) { + return true; + } + } + } + return false; + } +} diff --git a/src/engine/event/CEventListener.ts b/src/event/CEventListener.ts similarity index 96% rename from src/engine/event/CEventListener.ts rename to src/event/CEventListener.ts index c5f17328..833d7b94 100644 --- a/src/engine/event/CEventListener.ts +++ b/src/event/CEventListener.ts @@ -1,61 +1,61 @@ -/** - * The EventListener class is used to add or remove event listeners. - * @internal - * @group Events - */ -export class CEventListener { - /** - * @private - */ - public static event_id_count = 0; - - /** - * - * Record a id. When registering a listening event, the value will increase automatically - */ - public id: number = 0; - - /** - * - * Returns current event dispatcher - */ - public current: any; - - /** - * - * @param type {string} event type - * @param thisObject {any} the object is registerd - * @param handler {Function} The callback function that handles events. - * @param param {any} Parameters bound when registering events - * @param priority {number} The priority of callback function execution, with a larger set value having priority to call - */ - constructor(public type: string | number = null, public thisObject: any = null, public handler: Function = null, public param: any = null, public priority: number = 0) { } - - /** - * - * Compare whether two events are the same - * @param type {string} event type - * @param handler {Function} The callback function that handles events. - * @param thisObject {any} the object is registerd - * @param param {any} Parameters bound when registering events - * @returns {boolean} Returns a boolean - */ - public equalCurrentListener(type: string | number, handler: Function, thisObject: any, param: any): boolean { - if (this.type == type && this.thisObject == thisObject && this.handler == handler && this.param == param) { - return true; - } - return false; - } - - /** - * - * release all registered event. - */ - - public dispose() { - this.handler = null; - this.thisObject = null; - this.param = null; - this.priority = 0; - } -} +/** + * The EventListener class is used to add or remove event listeners. + * @internal + * @group Events + */ +export class CEventListener { + /** + * @private + */ + public static event_id_count = 0; + + /** + * + * Record a id. When registering a listening event, the value will increase automatically + */ + public id: number = 0; + + /** + * + * Returns current event dispatcher + */ + public current: any; + + /** + * + * @param type {string} event type + * @param thisObject {any} the object is registerd + * @param handler {Function} The callback function that handles events. + * @param param {any} Parameters bound when registering events + * @param priority {number} The priority of callback function execution, with a larger set value having priority to call + */ + constructor(public type: string | number = null, public thisObject: any = null, public handler: Function = null, public param: any = null, public priority: number = 0) { } + + /** + * + * Compare whether two events are the same + * @param type {string} event type + * @param handler {Function} The callback function that handles events. + * @param thisObject {any} the object is registerd + * @param param {any} Parameters bound when registering events + * @returns {boolean} Returns a boolean + */ + public equalCurrentListener(type: string | number, handler: Function, thisObject: any, param: any): boolean { + if (this.type == type && this.thisObject == thisObject && this.handler == handler && this.param == param) { + return true; + } + return false; + } + + /** + * + * release all registered event. + */ + + public dispose() { + this.handler = null; + this.thisObject = null; + this.param = null; + this.priority = 0; + } +} diff --git a/src/engine/event/CResizeEvent.ts b/src/event/CResizeEvent.ts similarity index 95% rename from src/engine/event/CResizeEvent.ts rename to src/event/CResizeEvent.ts index e3ee17f0..11f938db 100644 --- a/src/engine/event/CResizeEvent.ts +++ b/src/event/CResizeEvent.ts @@ -1,13 +1,13 @@ -import { CEvent } from './CEvent'; -/** - * size change event when canvas resized - * @internal - * @group Events - */ -export class CResizeEvent extends CEvent { - /** - * - * RESIZE:enum event type - */ - static RESIZE: string = 'resize'; -} +import { CEvent } from './CEvent'; +/** + * size change event when canvas resized + * @internal + * @group Events + */ +export class CResizeEvent extends CEvent { + /** + * + * RESIZE:enum event type + */ + static RESIZE: string = 'resize'; +} diff --git a/src/engine/event/KeyCode.ts b/src/event/KeyCode.ts similarity index 94% rename from src/engine/event/KeyCode.ts rename to src/event/KeyCode.ts index 3cb5c69f..3c0e249f 100644 --- a/src/engine/event/KeyCode.ts +++ b/src/event/KeyCode.ts @@ -1,112 +1,112 @@ -/** - * Represents a unique identifier corresponding to a keyboard button. see {@link KeyboardEvent.keyCode} - * @group Events - */ -export enum KeyCode { - Key_BackSpace = 8, - Key_Tab = 9, - Key_Clear = 12, - Key_Enter = 13, - Key_Shift_L = 16, - Key_Control_L = 17, - Key_Alt_L = 18, - Key_Pause = 19, - Key_CapsLock = 20, - Key_Escape = 21, - Key_Esc = 27, - Key_Space = 32, - Key_Prior = 33, - Key_Next = 34, - Key_End = 35, - Key_Home = 36, - Key_Left = 37, - Key_Up = 38, - Key_Right = 39, - Key_Down = 40, - Key_Select = 41, - Key_Print = 42, - Key_Execute = 43, - Key_Insert = 45, - Key_Delete = 46, - Key_Help = 47, - Key_0 = 48, - Key_1 = 49, - Key_2 = 50, - Key_3 = 51, - Key_4 = 52, - Key_5 = 53, - Key_6 = 54, - Key_7 = 55, - Key_8 = 56, - Key_9 = 57, - - Key_A = 65, - Key_B = 66, - Key_C = 67, - Key_D = 68, - Key_E = 69, - Key_F = 70, - Key_G = 71, - Key_H = 72, - Key_I = 73, - Key_J = 74, - Key_K = 75, - Key_L = 76, - Key_M = 77, - Key_N = 78, - Key_O = 79, - Key_P = 80, - Key_Q = 81, - Key_R = 82, - Key_S = 83, - Key_T = 84, - Key_U = 85, - Key_V = 86, - Key_W = 87, - Key_X = 88, - Key_Y = 89, - Key_Z = 90, - Key_KP_0 = 96, - Key_KP_1 = 97, - Key_KP_2 = 98, - Key_KP_3 = 99, - Key_KP_4 = 100, - Key_KP_5 = 101, - Key_KP_6 = 102, - Key_KP_7 = 103, - Key_KP_8 = 104, - Key_KP_9 = 105, - Key_Multiply = 106, - Key_Add = 107, - Key_Separator = 108, - Key_Subtract = 109, - Key_Decimal = 110, - Key_Divide = 111, - Key_F1 = 112, - Key_F2 = 113, - Key_F3 = 114, - Key_F4 = 115, - Key_F5 = 116, - Key_F6 = 117, - Key_F7 = 118, - Key_F8 = 119, - Key_F9 = 120, - Key_F10 = 121, - Key_F11 = 122, - Key_F12 = 123, - Key_F13 = 124, - Key_F14 = 125, - Key_F15 = 126, - Key_F16 = 127, - Key_F17 = 128, - Key_F18 = 129, - Key_F19 = 130, - Key_F20 = 131, - Key_F21 = 132, - Key_F22 = 133, - Key_F23 = 134, - Key_F24 = 135, - - Key_Num_Lock = 136, - Key_Scroll_Lock = 137, -} +/** + * Represents a unique identifier corresponding to a keyboard button. see {@link KeyboardEvent.keyCode} + * @group Events + */ +export enum KeyCode { + Key_BackSpace = 8, + Key_Tab = 9, + Key_Clear = 12, + Key_Enter = 13, + Key_Shift_L = 16, + Key_Control_L = 17, + Key_Alt_L = 18, + Key_Pause = 19, + Key_CapsLock = 20, + Key_Escape = 21, + Key_Esc = 27, + Key_Space = 32, + Key_Prior = 33, + Key_Next = 34, + Key_End = 35, + Key_Home = 36, + Key_Left = 37, + Key_Up = 38, + Key_Right = 39, + Key_Down = 40, + Key_Select = 41, + Key_Print = 42, + Key_Execute = 43, + Key_Insert = 45, + Key_Delete = 46, + Key_Help = 47, + Key_0 = 48, + Key_1 = 49, + Key_2 = 50, + Key_3 = 51, + Key_4 = 52, + Key_5 = 53, + Key_6 = 54, + Key_7 = 55, + Key_8 = 56, + Key_9 = 57, + + Key_A = 65, + Key_B = 66, + Key_C = 67, + Key_D = 68, + Key_E = 69, + Key_F = 70, + Key_G = 71, + Key_H = 72, + Key_I = 73, + Key_J = 74, + Key_K = 75, + Key_L = 76, + Key_M = 77, + Key_N = 78, + Key_O = 79, + Key_P = 80, + Key_Q = 81, + Key_R = 82, + Key_S = 83, + Key_T = 84, + Key_U = 85, + Key_V = 86, + Key_W = 87, + Key_X = 88, + Key_Y = 89, + Key_Z = 90, + Key_KP_0 = 96, + Key_KP_1 = 97, + Key_KP_2 = 98, + Key_KP_3 = 99, + Key_KP_4 = 100, + Key_KP_5 = 101, + Key_KP_6 = 102, + Key_KP_7 = 103, + Key_KP_8 = 104, + Key_KP_9 = 105, + Key_Multiply = 106, + Key_Add = 107, + Key_Separator = 108, + Key_Subtract = 109, + Key_Decimal = 110, + Key_Divide = 111, + Key_F1 = 112, + Key_F2 = 113, + Key_F3 = 114, + Key_F4 = 115, + Key_F5 = 116, + Key_F6 = 117, + Key_F7 = 118, + Key_F8 = 119, + Key_F9 = 120, + Key_F10 = 121, + Key_F11 = 122, + Key_F12 = 123, + Key_F13 = 124, + Key_F14 = 125, + Key_F15 = 126, + Key_F16 = 127, + Key_F17 = 128, + Key_F18 = 129, + Key_F19 = 130, + Key_F20 = 131, + Key_F21 = 132, + Key_F22 = 133, + Key_F23 = 134, + Key_F24 = 135, + + Key_Num_Lock = 136, + Key_Scroll_Lock = 137, +} diff --git a/src/engine/event/MouseCode.ts b/src/event/MouseCode.ts similarity index 92% rename from src/engine/event/MouseCode.ts rename to src/event/MouseCode.ts index dabc3640..1255454e 100644 --- a/src/engine/event/MouseCode.ts +++ b/src/event/MouseCode.ts @@ -1,26 +1,26 @@ -/** - * Mouse Key Code - * @group Events - */ -export enum MouseCode { - /** - * - * key code of mouse left - * - */ - MOUSE_LEFT = 0, - - /** - * - * key code of mouse middle - * - */ - MOUSE_MID = 1, - - /** - * - * key code of mouse right - * - */ - MOUSE_RIGHT = 2, -} +/** + * Mouse Key Code + * @group Events + */ +export enum MouseCode { + /** + * + * key code of mouse left + * + */ + MOUSE_LEFT = 0, + + /** + * + * key code of mouse middle + * + */ + MOUSE_MID = 1, + + /** + * + * key code of mouse right + * + */ + MOUSE_RIGHT = 2, +} diff --git a/src/engine/event/eventConst/KeyEvent.ts b/src/event/eventConst/KeyEvent.ts similarity index 100% rename from src/engine/event/eventConst/KeyEvent.ts rename to src/event/eventConst/KeyEvent.ts diff --git a/src/engine/event/eventConst/LoaderEvent.ts b/src/event/eventConst/LoaderEvent.ts similarity index 100% rename from src/engine/event/eventConst/LoaderEvent.ts rename to src/event/eventConst/LoaderEvent.ts diff --git a/src/engine/event/eventConst/Object3DEvent.ts b/src/event/eventConst/Object3DEvent.ts similarity index 100% rename from src/engine/event/eventConst/Object3DEvent.ts rename to src/event/eventConst/Object3DEvent.ts diff --git a/src/engine/event/eventConst/PointerEvent3D.ts b/src/event/eventConst/PointerEvent3D.ts similarity index 100% rename from src/engine/event/eventConst/PointerEvent3D.ts rename to src/event/eventConst/PointerEvent3D.ts diff --git a/src/engine/event/eventConst/UIEvent.ts b/src/event/eventConst/UIEvent.ts similarity index 100% rename from src/engine/event/eventConst/UIEvent.ts rename to src/event/eventConst/UIEvent.ts diff --git a/src/gfx/data/IrradianceVolume.ts b/src/gfx/data/IrradianceVolume.ts new file mode 100644 index 00000000..6094cdb6 --- /dev/null +++ b/src/gfx/data/IrradianceVolume.ts @@ -0,0 +1,56 @@ +import { StorageGPUBuffer } from "../graphics/webGpu/core/buffer/StorageGPUBuffer"; + +/** + * @internal + * @group Post + */ +export class IrradianceVolume { + private debugX: number = 0; + private debugY: number = 0; + private debugZ: number = 0; + public probesBufferData: Float32Array; //offset xyz frame + public probesBuffer: StorageGPUBuffer; + public isVolumeFrameChange: boolean = true; + public irradianceVolumeBuffer: StorageGPUBuffer; + + public constructor() { + this.irradianceVolumeBuffer = new StorageGPUBuffer(80); + this.fillIrradianceData(); + } + + private fillIrradianceData(): void { + this.irradianceVolumeBuffer.setFloat("orientationIndex", 0); + this.irradianceVolumeBuffer.setFloat("hysteresis", 0); + this.irradianceVolumeBuffer.setFloat("OctRTSideSize", 0); + this.irradianceVolumeBuffer.setFloat("OctRTMaxSize", 0); + this.irradianceVolumeBuffer.setFloat("startX", 0); + this.irradianceVolumeBuffer.setFloat("startY", 0); + this.irradianceVolumeBuffer.setFloat("startZ", 0); + this.irradianceVolumeBuffer.setFloat("ProbeSpace", 0); + this.irradianceVolumeBuffer.setFloat("probeXCount", 0); + this.irradianceVolumeBuffer.setFloat("probeYCount", 0); + this.irradianceVolumeBuffer.setFloat("probeZCount", 0); + this.irradianceVolumeBuffer.setFloat("maxDistance", 0); + this.irradianceVolumeBuffer.setFloat("depthSharpness", 0); + this.irradianceVolumeBuffer.setFloat("ProbeSourceTextureSize", 0); + this.irradianceVolumeBuffer.setFloat("ProbeSize", 0); + this.irradianceVolumeBuffer.setFloat("bounceIntensity", 0); + this.irradianceVolumeBuffer.setFloat("probeRoughness", 0); + + this.irradianceVolumeBuffer.setFloat("normalBias", 0); + this.irradianceVolumeBuffer.setFloat("irradianceChebyshevBias", 0); + this.irradianceVolumeBuffer.setFloat("rayNumber", 0); + this.irradianceVolumeBuffer.setFloat("irradianceDistanceBias", 0); + this.irradianceVolumeBuffer.setFloat("indirectIntensity", 0); + this.irradianceVolumeBuffer.setFloat("ddgiGamma", 0); + this.irradianceVolumeBuffer.setFloat("lerpHysteresis", 0); + + this.irradianceVolumeBuffer.setFloat("debugX", this.debugX); + this.irradianceVolumeBuffer.setFloat("debugY", this.debugY); + this.irradianceVolumeBuffer.setFloat("debugZ", this.debugZ); + + this.irradianceVolumeBuffer.apply(); + } + + +} diff --git a/src/engine/gfx/generate/BrdfLUTGenerate.ts b/src/gfx/generate/BrdfLUTGenerate.ts similarity index 100% rename from src/engine/gfx/generate/BrdfLUTGenerate.ts rename to src/gfx/generate/BrdfLUTGenerate.ts diff --git a/src/engine/gfx/generate/PassGenerate.ts b/src/gfx/generate/PassGenerate.ts similarity index 96% rename from src/engine/gfx/generate/PassGenerate.ts rename to src/gfx/generate/PassGenerate.ts index a84d21e0..a36ccb92 100644 --- a/src/engine/gfx/generate/PassGenerate.ts +++ b/src/gfx/generate/PassGenerate.ts @@ -1,5 +1,4 @@ import { RenderNode } from '../../components/renderer/RenderNode'; -import { GLTFParser } from '../../loader/parser/gltf/GLTFParser'; import { MaterialBase } from '../../materials/MaterialBase'; import { CastPointShadowMaterialPass } from '../../materials/multiPass/CastPointShadowMaterialPass'; import { CastShadowMaterialPass } from '../../materials/multiPass/CastShadowMaterialPass'; @@ -8,6 +7,7 @@ import { GBufferPass } from '../../materials/multiPass/GBufferPass'; import { SkyGBufferPass } from '../../materials/multiPass/SkyGBufferPass'; import { RendererMaskUtil, RendererMask } from '../renderJob/passRenderer/state/RendererMask'; import { RendererType } from '../renderJob/passRenderer/state/RendererType'; +import { GLTFType } from '../../loader/parser/gltf/GLTFType'; /** * @internal @@ -63,8 +63,8 @@ export class PassGenerate { public static createShadowPass(renderNode: RenderNode, material: MaterialBase) { let use_skeleton = RendererMaskUtil.hasMask(renderNode.rendererMask, RendererMask.SkinnedMesh); let useTangent = renderNode.geometry.hasAttribute('TANGENT'); - let useMorphTargets = renderNode.geometry.hasAttribute(GLTFParser.MORPH_POSITION_PREFIX + '0'); - let useMorphNormals = renderNode.geometry.hasAttribute(GLTFParser.MORPH_NORMAL_PREFIX + '0'); + let useMorphTargets = renderNode.geometry.hasAttribute(GLTFType.MORPH_POSITION_PREFIX + '0'); + let useMorphNormals = renderNode.geometry.hasAttribute(GLTFType.MORPH_NORMAL_PREFIX + '0'); let shadowMaterialPass = material.renderShader.getPassShader(RendererType.SHADOW); if (!shadowMaterialPass) { @@ -132,8 +132,8 @@ export class PassGenerate { // let baseMat = renderNode.materials[0]; // reflectionPass.baseMap = baseMat.baseMap; // let useTangent = renderNode.geometry.hasVertexAttribute('TANGENT'); - // let useMorphTargets = renderNode.geometry.hasVertexAttribute(GLTFParser.MORPH_POSITION_PREFIX + '0'); - // let useMorphNormals = renderNode.geometry.hasVertexAttribute(GLTFParser.MORPH_NORMAL_PREFIX + '0'); + // let useMorphTargets = renderNode.geometry.hasVertexAttribute(GLTFType.MORPH_POSITION_PREFIX + '0'); + // let useMorphNormals = renderNode.geometry.hasVertexAttribute(GLTFType.MORPH_NORMAL_PREFIX + '0'); // let use_skeleton = RendererMaskUtil.hasMask(renderNode.rendererMask, RendererMask.SkinnedMesh); @@ -172,8 +172,8 @@ export class PassGenerate { let baseMat = renderNode.materials[0]; depthMaterialPass.baseMap = baseMat.baseMap; let useTangent = renderNode.geometry.hasAttribute('TANGENT'); - let useMorphTargets = renderNode.geometry.hasAttribute(GLTFParser.MORPH_POSITION_PREFIX + '0'); - let useMorphNormals = renderNode.geometry.hasAttribute(GLTFParser.MORPH_NORMAL_PREFIX + '0'); + let useMorphTargets = renderNode.geometry.hasAttribute(GLTFType.MORPH_POSITION_PREFIX + '0'); + let useMorphNormals = renderNode.geometry.hasAttribute(GLTFType.MORPH_NORMAL_PREFIX + '0'); let use_skeleton = RendererMaskUtil.hasMask(renderNode.rendererMask, RendererMask.SkinnedMesh); diff --git a/src/engine/gfx/generate/convert/BlurEffectCreator.ts b/src/gfx/generate/convert/BlurEffectCreator.ts similarity index 100% rename from src/engine/gfx/generate/convert/BlurEffectCreator.ts rename to src/gfx/generate/convert/BlurEffectCreator.ts diff --git a/src/engine/gfx/generate/convert/ErpImage2CubeMap.ts b/src/gfx/generate/convert/ErpImage2CubeMap.ts similarity index 100% rename from src/engine/gfx/generate/convert/ErpImage2CubeMap.ts rename to src/gfx/generate/convert/ErpImage2CubeMap.ts diff --git a/src/engine/gfx/generate/convert/IBLEnvMapCreator.ts b/src/gfx/generate/convert/IBLEnvMapCreator.ts similarity index 100% rename from src/engine/gfx/generate/convert/IBLEnvMapCreator.ts rename to src/gfx/generate/convert/IBLEnvMapCreator.ts diff --git a/src/engine/gfx/generate/convert/MergeRGBACreator.ts b/src/gfx/generate/convert/MergeRGBACreator.ts similarity index 100% rename from src/engine/gfx/generate/convert/MergeRGBACreator.ts rename to src/gfx/generate/convert/MergeRGBACreator.ts diff --git a/src/engine/gfx/generate/convert/TextureCubeStdCreator.ts b/src/gfx/generate/convert/TextureCubeStdCreator.ts similarity index 100% rename from src/engine/gfx/generate/convert/TextureCubeStdCreator.ts rename to src/gfx/generate/convert/TextureCubeStdCreator.ts diff --git a/src/engine/gfx/generate/convert/TextureCubeUtils.ts b/src/gfx/generate/convert/TextureCubeUtils.ts similarity index 100% rename from src/engine/gfx/generate/convert/TextureCubeUtils.ts rename to src/gfx/generate/convert/TextureCubeUtils.ts diff --git a/src/engine/gfx/graphics/webGpu/CanvasConfig.ts b/src/gfx/graphics/webGpu/CanvasConfig.ts similarity index 94% rename from src/engine/gfx/graphics/webGpu/CanvasConfig.ts rename to src/gfx/graphics/webGpu/CanvasConfig.ts index e95a3699..ba70c9b5 100644 --- a/src/engine/gfx/graphics/webGpu/CanvasConfig.ts +++ b/src/gfx/graphics/webGpu/CanvasConfig.ts @@ -1,4 +1,3 @@ -import { Scene3D } from '../../../core/Scene3D'; /** * config data for canvas diff --git a/src/engine/gfx/graphics/webGpu/Context3D.ts b/src/gfx/graphics/webGpu/Context3D.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/Context3D.ts rename to src/gfx/graphics/webGpu/Context3D.ts diff --git a/src/engine/gfx/graphics/webGpu/WebGPUConst.ts b/src/gfx/graphics/webGpu/WebGPUConst.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/WebGPUConst.ts rename to src/gfx/graphics/webGpu/WebGPUConst.ts diff --git a/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts b/src/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts similarity index 98% rename from src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts rename to src/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts index c7a6ccc3..24859b4d 100644 --- a/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts +++ b/src/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup.ts @@ -15,7 +15,7 @@ export class GlobalBindGroup { // public static probeEntries: ProbeEntries; public static modelMatrixBindGroup: MatrixBindGroup; - public static initCommon() { + public static init() { this.modelMatrixBindGroup = new MatrixBindGroup(); this._cameraBindGroups = new Map(); this._lightEntriesMap = new Map(); diff --git a/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout.ts b/src/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout.ts rename to src/gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout.ts diff --git a/src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts b/src/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts rename to src/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts diff --git a/src/engine/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts b/src/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts rename to src/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts diff --git a/src/engine/gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup.ts b/src/gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup.ts rename to src/gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup.ts diff --git a/src/engine/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts b/src/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts similarity index 92% rename from src/engine/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts rename to src/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts index 71a0711d..c75de7d4 100644 --- a/src/engine/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts +++ b/src/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts @@ -6,6 +6,7 @@ import { Engine3D } from "../../../../../../Engine3D"; import { LightData } from "../../../../../../components/lights/LightData"; import { View3D } from "../../../../../../core/View3D"; import { MemoryInfo } from "../../../../../../core/pool/memory/MemoryInfo"; +import { IrradianceVolume } from "../../../../../data/IrradianceVolume"; import { EntityCollect } from "../../../../../renderJob/collect/EntityCollect"; import { StorageGPUBuffer } from "../../buffer/StorageGPUBuffer"; @@ -15,6 +16,7 @@ import { StorageGPUBuffer } from "../../buffer/StorageGPUBuffer"; */ export class LightEntries { public storageGPUBuffer: StorageGPUBuffer; + public irradianceVolume: IrradianceVolume; private _lightList: MemoryInfo[] = []; constructor() { @@ -23,6 +25,8 @@ export class LightEntries { GPUBufferUsage.COPY_SRC ); + this.irradianceVolume = new IrradianceVolume(); + for (let i = 0; i < Engine3D.setting.light.maxLight; i++) { let memory = this.storageGPUBuffer.memory.allocation_node(LightData.lightSize * 4); this._lightList.push(memory); diff --git a/src/gfx/graphics/webGpu/core/buffer/ArrayBufferData.ts b/src/gfx/graphics/webGpu/core/buffer/ArrayBufferData.ts new file mode 100644 index 00000000..71334cd8 --- /dev/null +++ b/src/gfx/graphics/webGpu/core/buffer/ArrayBufferData.ts @@ -0,0 +1 @@ +export type ArrayBufferData = Uint8Array | Uint16Array | Uint32Array | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array \ No newline at end of file diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer.ts b/src/gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer.ts similarity index 80% rename from src/engine/gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer.ts rename to src/gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer.ts index cf93521b..f02d3e09 100644 --- a/src/engine/gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer.ts +++ b/src/gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer.ts @@ -1,4 +1,5 @@ import { GPUBufferBase } from './GPUBufferBase'; +import { GPUBufferType } from './GPUBufferType'; /** * Storage class buffer for calculating shaders @@ -8,6 +9,7 @@ import { GPUBufferBase } from './GPUBufferBase'; export class ComputeGPUBuffer extends GPUBufferBase { constructor(size: number, data?: Float32Array) { super(); + this.bufferType = GPUBufferType.ComputeGPUBuffer; this.createBuffer(GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, size, data); } } diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts b/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts similarity index 93% rename from src/engine/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts rename to src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts index f10e54c7..b3269c3b 100644 --- a/src/engine/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts +++ b/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts @@ -1,5 +1,5 @@ -import { MemoryDO } from "../../../../../core/pool/memory/MemoryDO"; -import { MemoryInfo } from "../../../../../core/pool/memory/MemoryInfo"; +import { ArrayBufferData } from "./ArrayBufferData"; +import { GPUBufferType } from "./GPUBufferType"; import { Color } from "../../../../../math/Color"; import { Matrix4 } from "../../../../../math/Matrix4"; import { Quaternion } from "../../../../../math/Quaternion"; @@ -7,16 +7,19 @@ import { Vector2 } from "../../../../../math/Vector2"; import { Vector3 } from "../../../../../math/Vector3"; import { Vector4 } from "../../../../../math/Vector4"; import { Struct } from "../../../../../util/struct/Struct"; -import { GPUContext } from "../../../../renderJob/GPUContext"; + import { webGPUContext } from "../../Context3D"; +import { MemoryDO } from "../../../../../core/pool/memory/MemoryDO"; +import { MemoryInfo } from "../../../../../core/pool/memory/MemoryInfo"; +import { GPUContext } from "../../../../renderJob/GPUContext"; -export type ArrayBufferData = Uint8Array | Uint16Array | Uint32Array | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array /** * @internal * @group GFX */ export class GPUBufferBase { + public bufferType: GPUBufferType; public buffer: GPUBuffer; public memory: MemoryDO; public memoryNodes: Map; @@ -25,7 +28,6 @@ export class GPUBufferBase { public byteSize: number; public usage: GPUBufferUsageFlags; public visibility: number = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; - private _readBuffer: GPUBuffer; constructor() { @@ -358,16 +360,17 @@ export class GPUBufferBase { } private async read() { - this._readFlag = true; - let command = GPUContext.beginCommandEncoder(); - command.copyBufferToBuffer(this.buffer, 0, this._readBuffer, 0, this.memory.shareDataBuffer.byteLength); - GPUContext.endCommandEncoder(command); - - await this._readBuffer.mapAsync(GPUMapMode.READ); - const copyArrayBuffer = this._readBuffer.getMappedRange(); - this.outFloat32Array.set(new Float32Array(copyArrayBuffer), 0); - // this.memory.shareDataBuffer.set(new Float32Array(copyArrayBuffer), 0); - this._readBuffer.unmap(); - this._readFlag = false; + // this._readFlag = true; + + // let command = context.beginCommandEncoder(); + // command.copyBufferToBuffer(this.buffer, 0, this._readBuffer, 0, this.memory.shareDataBuffer.byteLength); + // GPUContext.endCommandEncoder(command); + + // await this._readBuffer.mapAsync(GPUMapMode.READ); + // const copyArrayBuffer = this._readBuffer.getMappedRange(); + // this.outFloat32Array.set(new Float32Array(copyArrayBuffer), 0); + // // this.memory.shareDataBuffer.set(new Float32Array(copyArrayBuffer), 0); + // this._readBuffer.unmap(); + // this._readFlag = false; } } diff --git a/src/gfx/graphics/webGpu/core/buffer/GPUBufferType.ts b/src/gfx/graphics/webGpu/core/buffer/GPUBufferType.ts new file mode 100644 index 00000000..3b4b799f --- /dev/null +++ b/src/gfx/graphics/webGpu/core/buffer/GPUBufferType.ts @@ -0,0 +1,9 @@ +export enum GPUBufferType { + IndicesGPUBuffer, + VertexGPUBuffer, + UniformGPUBuffer, + StorageGPUBuffer, + ComputeGPUBuffer, + MaterialDataUniformGPUBuffer, + StructStorageGPUBuffer +} \ No newline at end of file diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer.ts b/src/gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer.ts similarity index 86% rename from src/engine/gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer.ts rename to src/gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer.ts index 5cab421f..cde486b4 100644 --- a/src/engine/gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer.ts +++ b/src/gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer.ts @@ -1,6 +1,8 @@ import { MemoryInfo } from '../../../../../core/pool/memory/MemoryInfo'; import { webGPUContext } from '../../Context3D'; -import { ArrayBufferData, GPUBufferBase } from './GPUBufferBase'; +import { ArrayBufferData } from './ArrayBufferData'; +import { GPUBufferBase } from './GPUBufferBase'; +import { GPUBufferType } from './GPUBufferType'; /** * The buffer use at geometry indices @@ -12,6 +14,7 @@ export class IndicesGPUBuffer extends GPUBufferBase { public indicesNode: MemoryInfo; constructor(data?: ArrayBufferData) { super(); + this.bufferType = GPUBufferType.IndicesGPUBuffer; this.createIndicesBuffer(GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.INDEX | GPUBufferUsage.INDIRECT, data); } diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts b/src/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts similarity index 94% rename from src/engine/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts rename to src/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts index 76facef3..ee60cfec 100644 --- a/src/engine/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts +++ b/src/gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer.ts @@ -1,3 +1,4 @@ +import { GPUBufferType } from './GPUBufferType'; import { UniformNode } from '../uniforms/UniformNode'; import { GPUBufferBase } from './GPUBufferBase'; /** @@ -9,6 +10,7 @@ export class MaterialDataUniformGPUBuffer extends GPUBufferBase { private _onChange: boolean = true; constructor() { super(); + this.bufferType = GPUBufferType.MaterialDataUniformGPUBuffer; } /** diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/StorageGPUBuffer.ts b/src/gfx/graphics/webGpu/core/buffer/StorageGPUBuffer.ts similarity index 71% rename from src/engine/gfx/graphics/webGpu/core/buffer/StorageGPUBuffer.ts rename to src/gfx/graphics/webGpu/core/buffer/StorageGPUBuffer.ts index 36b09e42..d728a408 100644 --- a/src/engine/gfx/graphics/webGpu/core/buffer/StorageGPUBuffer.ts +++ b/src/gfx/graphics/webGpu/core/buffer/StorageGPUBuffer.ts @@ -1,4 +1,6 @@ -import { ArrayBufferData, GPUBufferBase } from './GPUBufferBase'; +import { ArrayBufferData } from './ArrayBufferData'; +import { GPUBufferBase } from './GPUBufferBase'; +import { GPUBufferType } from './GPUBufferType'; /** * The buffer of the storage class * written in the computer shader or CPU Coder @@ -8,6 +10,7 @@ import { ArrayBufferData, GPUBufferBase } from './GPUBufferBase'; export class StorageGPUBuffer extends GPUBufferBase { constructor(size: number, usage: number = 0, data?: ArrayBufferData) { super(); + this.bufferType = GPUBufferType.StorageGPUBuffer; this.createBuffer(GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | usage, size, data); // this.createBuffer(GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST, size, data); } diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer.ts b/src/gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer.ts similarity index 84% rename from src/engine/gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer.ts rename to src/gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer.ts index b3cff78a..0c2e14f5 100644 --- a/src/engine/gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer.ts +++ b/src/gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer.ts @@ -1,5 +1,6 @@ import { Struct } from '../../../../../util/struct/Struct'; import { GPUBufferBase } from './GPUBufferBase'; +import { GPUBufferType } from './GPUBufferType'; /** * Structure storage class buffer, convenient for initializing gpubuffers of structure types * written in the computer shader or CPU Coder @@ -9,6 +10,7 @@ import { GPUBufferBase } from './GPUBufferBase'; export class StructStorageGPUBuffer extends GPUBufferBase { constructor(struct: { new(): T }, count: number, usage: number = 0) { super(); + this.bufferType = GPUBufferType.StructStorageGPUBuffer; this.createBufferByStruct(GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | usage, struct, count); } } diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/UniformGPUBuffer.ts b/src/gfx/graphics/webGpu/core/buffer/UniformGPUBuffer.ts similarity index 84% rename from src/engine/gfx/graphics/webGpu/core/buffer/UniformGPUBuffer.ts rename to src/gfx/graphics/webGpu/core/buffer/UniformGPUBuffer.ts index d2b34fa8..1ee4860a 100644 --- a/src/engine/gfx/graphics/webGpu/core/buffer/UniformGPUBuffer.ts +++ b/src/gfx/graphics/webGpu/core/buffer/UniformGPUBuffer.ts @@ -1,3 +1,4 @@ +import { GPUBufferType } from './GPUBufferType'; import { GPUBufferBase } from './GPUBufferBase'; /** * CPU write, GPU read-only transmission buffer @@ -8,6 +9,7 @@ import { GPUBufferBase } from './GPUBufferBase'; export class UniformGPUBuffer extends GPUBufferBase { constructor(size: number, data?: Float32Array) { super(); + this.bufferType = GPUBufferType.UniformGPUBuffer; this.createBuffer(GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC, size, data); } diff --git a/src/engine/gfx/graphics/webGpu/core/buffer/VertexGPUBuffer.ts b/src/gfx/graphics/webGpu/core/buffer/VertexGPUBuffer.ts similarity index 88% rename from src/engine/gfx/graphics/webGpu/core/buffer/VertexGPUBuffer.ts rename to src/gfx/graphics/webGpu/core/buffer/VertexGPUBuffer.ts index e1984534..30dcb0f7 100644 --- a/src/engine/gfx/graphics/webGpu/core/buffer/VertexGPUBuffer.ts +++ b/src/gfx/graphics/webGpu/core/buffer/VertexGPUBuffer.ts @@ -1,6 +1,7 @@ import { MemoryInfo } from '../../../../../core/pool/memory/MemoryInfo'; import { webGPUContext } from '../../Context3D'; -import { ArrayBufferData, GPUBufferBase } from './GPUBufferBase'; +import { GPUBufferBase } from './GPUBufferBase'; +import { GPUBufferType } from './GPUBufferType'; /** * The buffer use at geometry indices @@ -12,6 +13,7 @@ export class VertexGPUBuffer extends GPUBufferBase { public node: MemoryInfo; constructor(size: number) { super(); + this.bufferType = GPUBufferType.VertexGPUBuffer; this.createVertexBuffer(GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.VERTEX, size); } diff --git a/src/engine/gfx/graphics/webGpu/core/texture/ITexture.ts b/src/gfx/graphics/webGpu/core/texture/ITexture.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/texture/ITexture.ts rename to src/gfx/graphics/webGpu/core/texture/ITexture.ts diff --git a/src/engine/gfx/graphics/webGpu/core/texture/Texture.ts b/src/gfx/graphics/webGpu/core/texture/Texture.ts similarity index 98% rename from src/engine/gfx/graphics/webGpu/core/texture/Texture.ts rename to src/gfx/graphics/webGpu/core/texture/Texture.ts index 1679b6ab..9dc523fd 100644 --- a/src/engine/gfx/graphics/webGpu/core/texture/Texture.ts +++ b/src/gfx/graphics/webGpu/core/texture/Texture.ts @@ -1,6 +1,6 @@ -import { webGPUContext } from "../../Context3D"; -import { GPUAddressMode } from "../../WebGPUConst"; -import { TextureMipmapGenerator } from "./TextureMipmapGenerator"; +import { GPUAddressMode } from '../../WebGPUConst'; +import { TextureMipmapGenerator } from './TextureMipmapGenerator'; +import { webGPUContext } from '../../Context3D'; /** * Texture diff --git a/src/engine/gfx/graphics/webGpu/core/texture/TextureCube.ts b/src/gfx/graphics/webGpu/core/texture/TextureCube.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/texture/TextureCube.ts rename to src/gfx/graphics/webGpu/core/texture/TextureCube.ts diff --git a/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapCompute.ts b/src/gfx/graphics/webGpu/core/texture/TextureMipmapCompute.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapCompute.ts rename to src/gfx/graphics/webGpu/core/texture/TextureMipmapCompute.ts diff --git a/src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapGenerator.ts b/src/gfx/graphics/webGpu/core/texture/TextureMipmapGenerator.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/texture/TextureMipmapGenerator.ts rename to src/gfx/graphics/webGpu/core/texture/TextureMipmapGenerator.ts diff --git a/src/engine/gfx/graphics/webGpu/core/uniforms/UniformNode.ts b/src/gfx/graphics/webGpu/core/uniforms/UniformNode.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/core/uniforms/UniformNode.ts rename to src/gfx/graphics/webGpu/core/uniforms/UniformNode.ts diff --git a/src/engine/gfx/graphics/webGpu/descriptor/RTDescriptor.ts b/src/gfx/graphics/webGpu/descriptor/RTDescriptor.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/descriptor/RTDescriptor.ts rename to src/gfx/graphics/webGpu/descriptor/RTDescriptor.ts diff --git a/src/engine/gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator.ts b/src/gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator.ts rename to src/gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/ComputeShader.ts b/src/gfx/graphics/webGpu/shader/ComputeShader.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/ComputeShader.ts rename to src/gfx/graphics/webGpu/shader/ComputeShader.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/RenderShader.ts b/src/gfx/graphics/webGpu/shader/RenderShader.ts similarity index 95% rename from src/engine/gfx/graphics/webGpu/shader/RenderShader.ts rename to src/gfx/graphics/webGpu/shader/RenderShader.ts index 90ca4cca..01deac09 100644 --- a/src/engine/gfx/graphics/webGpu/shader/RenderShader.ts +++ b/src/gfx/graphics/webGpu/shader/RenderShader.ts @@ -8,13 +8,12 @@ import { MaterialBase } from "../../../../materials/MaterialBase"; import { MaterialPass } from "../../../../materials/MaterialPass"; import { Color } from "../../../../math/Color"; import { Vector4 } from "../../../../math/Vector4"; -import { defaultRes } from "../../../../textures/DefaultRes"; + import { GPUContext } from "../../../renderJob/GPUContext"; import { GlobalBindGroupLayout } from "../core/bindGroups/GlobalBindGroupLayout"; import { GPUBufferBase } from "../core/buffer/GPUBufferBase"; -import { MaterialDataUniformGPUBuffer } from "../core/buffer/MaterialDataUniformGPUBuffer"; -import { Texture } from "../core/texture/Texture"; import { UniformNode } from "../core/uniforms/UniformNode"; +import { Texture } from "../core/texture/Texture"; import { webGPUContext } from "../Context3D"; import { ShaderConverter } from "./converter/ShaderConverter"; import { ShaderBase } from "./ShaderBase"; @@ -24,6 +23,10 @@ import { ShaderReflection, ShaderReflectionVarInfo } from "./value/ShaderReflect import { ShaderState } from "./value/ShaderState"; import { RendererPassState } from "../../../renderJob/passRenderer/state/RendererPassState"; import { RendererType } from "../../../renderJob/passRenderer/state/RendererType"; +import { GPUBufferType } from "../core/buffer/GPUBufferType"; + +import { MaterialDataUniformGPUBuffer } from "../core/buffer/MaterialDataUniformGPUBuffer"; +import { ShaderUtil } from "./util/ShaderUtil"; export class RenderShader extends ShaderBase { public useRz: boolean = false; @@ -72,8 +75,7 @@ export class RenderShader extends ShaderBase { protected _textureGroup: number = -1; protected _textureChange: boolean = false; - private static _renderShaderModulePool: Map = new Map(); - private static _renderShader: Map = new Map(); + private _vs_limit = []; private _fs_limit = []; private _cs_limit = []; @@ -87,11 +89,11 @@ export class RenderShader extends ShaderBase { this.fsName = fs.toLowerCase(); if (!(this.vsName in ShaderLib)) { - console.error(`Shader Not Register, Please Register Shader!`, this.vsName); + console.error(`Shader Not Register, Please Register Shader!`, this.vsName); } if (!(this.fsName in ShaderLib)) { - console.error(`Shader Not Register, Please Register Shader!`, this.fsName); + console.error(`Shader Not Register, Please Register Shader!`, this.fsName); } if (ShaderLib[this.vsName]) { @@ -204,7 +206,8 @@ export class RenderShader extends ShaderBase { */ public static createShader(vs: string, fs: string): string { let shader = new RenderShader(vs, fs); - RenderShader._renderShader.set(shader.instanceID, shader); + ShaderUtil.renderShader.set(shader.instanceID, shader); + return shader.instanceID; } @@ -213,10 +216,10 @@ export class RenderShader extends ShaderBase { * @param instanceID instance ID of the RenderShader */ public static destroyShader(instanceID: string) { - if (RenderShader._renderShader.has(instanceID)) { - let shader = RenderShader._renderShader.get(instanceID); + if (ShaderUtil.renderShader.has(instanceID)) { + let shader = ShaderUtil.renderShader.get(instanceID); shader.destroy(); - RenderShader._renderShader.delete(instanceID) + ShaderUtil.renderShader.delete(instanceID) } } @@ -226,7 +229,7 @@ export class RenderShader extends ShaderBase { * @returns RenderShader object */ public static getShader(instanceID: string) { - return RenderShader._renderShader.get(instanceID); + return ShaderUtil.renderShader.get(instanceID); } /** @@ -308,7 +311,7 @@ export class RenderShader extends ShaderBase { } /** - * Apply render shader state value + * Apply render shader state value * @param geometry * @param materialPass * @param rendererPassState @@ -479,7 +482,7 @@ export class RenderShader extends ShaderBase { key += `${k}=${this.defineValue[k]},`; } - let shaderModule = RenderShader._renderShaderModulePool.get(key); + let shaderModule = ShaderUtil.renderShaderModulePool.get(key); if (!shaderModule) { shader = this.applyPostDefine(shader, renderPassState); @@ -494,7 +497,7 @@ export class RenderShader extends ShaderBase { console.log(e); } }); - RenderShader._renderShaderModulePool.set(key, shaderModule); + ShaderUtil.renderShaderModulePool.set(key, shaderModule); } switch (stage) { @@ -551,7 +554,7 @@ export class RenderShader extends ShaderBase { case `sampler`: { let textureName = info.varName.replace(`Sampler`, ``); - let texture = this.textures[textureName] ? this.textures[textureName] : defaultRes.redTexture; + let texture = this.textures[textureName] ? this.textures[textureName] : Engine3D.res.redTexture; let entry: GPUBindGroupLayoutEntry = { binding: info.binding, visibility: texture.visibility, @@ -565,7 +568,7 @@ export class RenderShader extends ShaderBase { case `sampler_comparison`: { let textureName = info.varName.replace(`Sampler`, ``); - let texture = this.textures[textureName] ? this.textures[textureName] : defaultRes.redTexture; + let texture = this.textures[textureName] ? this.textures[textureName] : Engine3D.res.redTexture; let entry: GPUBindGroupLayoutEntry = { binding: info.binding, visibility: texture.visibility, @@ -584,7 +587,7 @@ export class RenderShader extends ShaderBase { case `texture_depth_cube`: case `texture_depth_cube_array`: { - let texture = this.textures[info.varName] ? this.textures[info.varName] : defaultRes.redTexture; + let texture = this.textures[info.varName] ? this.textures[info.varName] : Engine3D.res.redTexture; let entry: GPUBindGroupLayoutEntry = { binding: info.binding, visibility: texture.visibility, @@ -600,7 +603,7 @@ export class RenderShader extends ShaderBase { break; case `texture_external`: { - let texture = this.textures[info.varName] ? this.textures[info.varName] : defaultRes.redTexture; + let texture = this.textures[info.varName] ? this.textures[info.varName] : Engine3D.res.redTexture; let entry: GPUBindGroupLayoutEntry = { binding: info.binding, visibility: texture.visibility, @@ -613,7 +616,7 @@ export class RenderShader extends ShaderBase { break; default: { - let texture = this.textures[info.varName] ? this.textures[info.varName] : defaultRes.redTexture; + let texture = this.textures[info.varName] ? this.textures[info.varName] : Engine3D.res.redTexture; let entry: GPUBindGroupLayoutEntry = { binding: info.binding, visibility: texture.visibility, @@ -643,7 +646,7 @@ export class RenderShader extends ShaderBase { if (refs.varType == `uniform`) { let buffer = this._bufferDic.get(refs.varName); if (buffer) { - if (buffer instanceof MaterialDataUniformGPUBuffer) { + if (buffer.bufferType == GPUBufferType.MaterialDataUniformGPUBuffer) { let uniforms: UniformNode[] = []; for (let i = 0; i < refs.dataFields.length; i++) { const field = refs.dataFields[i]; @@ -691,7 +694,7 @@ export class RenderShader extends ShaderBase { let textureName = refs.varName.replace(`Sampler`, ``); let texture = this.textures[textureName]; if (!texture) { - texture = defaultRes.blackTexture; + texture = Engine3D.res.blackTexture; this.setTexture(textureName, texture); } if (texture) { @@ -720,7 +723,7 @@ export class RenderShader extends ShaderBase { } else { let texture = this.textures[refs.varName]; if (!texture) { - texture = defaultRes.whiteTexture; + texture = Engine3D.res.whiteTexture; this.setTexture(refs.varName, texture); } if (texture) { @@ -908,6 +911,8 @@ export class RenderShader extends ShaderBase { this.shaderState.splitTexture = this.shaderReflection.useSplit; } + + ; } diff --git a/src/engine/gfx/graphics/webGpu/shader/ShaderBase.ts b/src/gfx/graphics/webGpu/shader/ShaderBase.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/ShaderBase.ts rename to src/gfx/graphics/webGpu/shader/ShaderBase.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/ShaderStage.ts b/src/gfx/graphics/webGpu/shader/ShaderStage.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/ShaderStage.ts rename to src/gfx/graphics/webGpu/shader/ShaderStage.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/GLSLLexer.ts b/src/gfx/graphics/webGpu/shader/converter/GLSLLexer.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/converter/GLSLLexer.ts rename to src/gfx/graphics/webGpu/shader/converter/GLSLLexer.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/GLSLLexerToken.ts b/src/gfx/graphics/webGpu/shader/converter/GLSLLexerToken.ts similarity index 87% rename from src/engine/gfx/graphics/webGpu/shader/converter/GLSLLexerToken.ts rename to src/gfx/graphics/webGpu/shader/converter/GLSLLexerToken.ts index 3906db88..69e35b39 100644 --- a/src/engine/gfx/graphics/webGpu/shader/converter/GLSLLexerToken.ts +++ b/src/gfx/graphics/webGpu/shader/converter/GLSLLexerToken.ts @@ -221,65 +221,65 @@ export enum TokenType { UINT, // built-in type: uint[] UINT_ARRAY, - // built-in type:bool + // built-in type: bool BOOL, - // built-in type:bool[] + // built-in type: bool[] BOOL_ARRAY, - // built-in type:float + // built-in type: float FLOAT, - // built-in type:float[] + // built-in type: float[] FLOAT_ARRAY, - // built-in type:double + // built-in type: double DOUBLE, - // built-in type:double[] + // built-in type: double[] DOUBLE_ARRAY, - // built-in type:vec2 + // built-in type: vec2 VEC2, - // built-in type:vec2[] + // built-in type: vec2[] VEC2_ARRAY, - // built-in type:vec3 + // built-in type: vec3 VEC3, - // built-in type:vec3[] + // built-in type: vec3[] VEC3_ARRAY, - // built-in type:vec4 + // built-in type: vec4 VEC4, - // built-in type:vec4[] + // built-in type: vec4[] VEC4_ARRAY, - // built-in type:bvec2 + // built-in type: bvec2 BVEC2, - // built-in type:bvec2[] + // built-in type: bvec2[] BVEC2_ARRAY, - // built-in type:bvec3 + // built-in type: bvec3 BVEC3, - // built-in type:bvec3[] + // built-in type: bvec3[] BVEC3_ARRAY, - // built-in type:bvec4 + // built-in type: bvec4 BVEC4, - // built-in type:bvec4[] + // built-in type: bvec4[] BVEC4_ARRAY, - // built-in type:ivec2 + // built-in type: ivec2 IVEC2, - // built-in type:ivec2[] + // built-in type: ivec2[] IVEC2_ARRAY, - // built-in type:ivec3 + // built-in type: ivec3 IVEC3, - // built-in type:ivec3[] + // built-in type: ivec3[] IVEC3_ARRAY, - // built-in type:ivec4 + // built-in type: ivec4 IVEC4, - // built-in type:ivec4[] + // built-in type: ivec4[] IVEC4_ARRAY, - // built-in type:uvec2 + // built-in type: uvec2 UVEC2, - // built-in type:uvec2[] + // built-in type: uvec2[] UVEC2_ARRAY, - // built-in type:uvec3 + // built-in type: uvec3 UVEC3, - // built-in type:uvec3[] + // built-in type: uvec3[] UVEC3_ARRAY, - // built-in type:uvec4 + // built-in type: uvec4 UVEC4, - // built-in type:uvec4[] + // built-in type: uvec4[] UVEC4_ARRAY, // built-in type: mat2x2 MAT2x2, @@ -333,15 +333,15 @@ export enum TokenType { SAMPLER_1D_SHADOW, // built-in type: sampler2DShadow SAMPLER_2D_SHADOW, - // built-in type:texture1D + // built-in type: texture1D TEXTURE_1D, - // built-in type:texture1DArray + // built-in type: texture1DArray TEXTURE_1D_ARRAY, - // built-in type:texture2D + // built-in type: texture2D TEXTURE_2D, - // built-in type:texture2DArray + // built-in type: texture2DArray TEXTURE_2D_ARRAY, - // built-in type:texture3D + // built-in type: texture3D TEXTURE_3D, // built-in type: textureCube TEXTURE_CUBE, diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/GLSLPreprocessor.ts b/src/gfx/graphics/webGpu/shader/converter/GLSLPreprocessor.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/converter/GLSLPreprocessor.ts rename to src/gfx/graphics/webGpu/shader/converter/GLSLPreprocessor.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/GLSLSyntax.ts b/src/gfx/graphics/webGpu/shader/converter/GLSLSyntax.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/converter/GLSLSyntax.ts rename to src/gfx/graphics/webGpu/shader/converter/GLSLSyntax.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/Reader.ts b/src/gfx/graphics/webGpu/shader/converter/Reader.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/converter/Reader.ts rename to src/gfx/graphics/webGpu/shader/converter/Reader.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/ShaderConverter.ts b/src/gfx/graphics/webGpu/shader/converter/ShaderConverter.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/converter/ShaderConverter.ts rename to src/gfx/graphics/webGpu/shader/converter/ShaderConverter.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/StatementNode.ts b/src/gfx/graphics/webGpu/shader/converter/StatementNode.ts similarity index 99% rename from src/engine/gfx/graphics/webGpu/shader/converter/StatementNode.ts rename to src/gfx/graphics/webGpu/shader/converter/StatementNode.ts index 7151bbab..e410074c 100644 --- a/src/engine/gfx/graphics/webGpu/shader/converter/StatementNode.ts +++ b/src/gfx/graphics/webGpu/shader/converter/StatementNode.ts @@ -946,7 +946,7 @@ export class SN_Expression extends StatementNode { throw 'An unexpected character'; } } else if (currToken.isOperation()) { - // ++a、--a + // ++a, --a if (currToken.Type == TokenType.INC || currToken.Type == TokenType.DEC) { let op = currToken; r.skipToken(1); @@ -1325,7 +1325,7 @@ export class SN_TernaryOperation extends StatementNode { /** * @internal - * Statement node:Expression of select(a.b) + * Statement node: Expression of select(a.b) * @group GFX */ export class SN_SelectOperation extends StatementNode { @@ -1357,7 +1357,7 @@ export class SN_SelectOperation extends StatementNode { /** * @internal - * Statement node:Expression of index(a[b]) + * Statement node: Expression of index(a[b]) * @group GFX */ export class SN_IndexOperation extends StatementNode { @@ -1585,7 +1585,7 @@ export class SN_CodeBlock extends StatementNode { /** * @internal - * Statement node:precision + * Statement node: precision * @group GFX */ export class SN_Precision extends StatementNode { diff --git a/src/engine/gfx/graphics/webGpu/shader/converter/WGSLTranslator.ts b/src/gfx/graphics/webGpu/shader/converter/WGSLTranslator.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/converter/WGSLTranslator.ts rename to src/gfx/graphics/webGpu/shader/converter/WGSLTranslator.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/util/MorePassParser.ts b/src/gfx/graphics/webGpu/shader/util/MorePassParser.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/util/MorePassParser.ts rename to src/gfx/graphics/webGpu/shader/util/MorePassParser.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/util/Preprocessor.ts b/src/gfx/graphics/webGpu/shader/util/Preprocessor.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/util/Preprocessor.ts rename to src/gfx/graphics/webGpu/shader/util/Preprocessor.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/util/ShaderUtil.ts b/src/gfx/graphics/webGpu/shader/util/ShaderUtil.ts similarity index 54% rename from src/engine/gfx/graphics/webGpu/shader/util/ShaderUtil.ts rename to src/gfx/graphics/webGpu/shader/util/ShaderUtil.ts index eb9ca3bb..eb9aca29 100644 --- a/src/engine/gfx/graphics/webGpu/shader/util/ShaderUtil.ts +++ b/src/gfx/graphics/webGpu/shader/util/ShaderUtil.ts @@ -1,3 +1,5 @@ +import { RenderShader } from "../RenderShader"; + export type VertexPart = { name: string; vertex_in_struct: string; @@ -18,12 +20,11 @@ export type FragmentPart = { } export class ShaderUtil { - /** - * - * @param vsName - * @param shaderParts - */ - public static createShader(vertexParts: VertexPart, fragmentShader: FragmentPart) { + public static renderShaderModulePool: Map; + public static renderShader: Map; + public static init() { + this.renderShaderModulePool = new Map(); + this.renderShader = new Map(); } } diff --git a/src/engine/gfx/graphics/webGpu/shader/value/ConstValue.ts b/src/gfx/graphics/webGpu/shader/value/ConstValue.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/value/ConstValue.ts rename to src/gfx/graphics/webGpu/shader/value/ConstValue.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/value/DefineValue.ts b/src/gfx/graphics/webGpu/shader/value/DefineValue.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/value/DefineValue.ts rename to src/gfx/graphics/webGpu/shader/value/DefineValue.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/value/ShaderReflectionInfo.ts b/src/gfx/graphics/webGpu/shader/value/ShaderReflectionInfo.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/value/ShaderReflectionInfo.ts rename to src/gfx/graphics/webGpu/shader/value/ShaderReflectionInfo.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/value/ShaderState.ts b/src/gfx/graphics/webGpu/shader/value/ShaderState.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/value/ShaderState.ts rename to src/gfx/graphics/webGpu/shader/value/ShaderState.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/value/ShaderValue.ts b/src/gfx/graphics/webGpu/shader/value/ShaderValue.ts similarity index 100% rename from src/engine/gfx/graphics/webGpu/shader/value/ShaderValue.ts rename to src/gfx/graphics/webGpu/shader/value/ShaderValue.ts diff --git a/src/engine/gfx/graphics/webGpu/shader/value/UniformValue.ts b/src/gfx/graphics/webGpu/shader/value/UniformValue.ts similarity index 85% rename from src/engine/gfx/graphics/webGpu/shader/value/UniformValue.ts rename to src/gfx/graphics/webGpu/shader/value/UniformValue.ts index 3f62b4f5..9fa71976 100644 --- a/src/engine/gfx/graphics/webGpu/shader/value/UniformValue.ts +++ b/src/gfx/graphics/webGpu/shader/value/UniformValue.ts @@ -1,4 +1,3 @@ -import { LightBase } from '../../../../../components/lights/LightBase'; import { Color } from '../../../../../math/Color'; import { Vector2 } from '../../../../../math/Vector2'; import { Vector3 } from '../../../../../math/Vector3'; diff --git a/src/engine/gfx/renderJob/GPUContext.ts b/src/gfx/renderJob/GPUContext.ts similarity index 72% rename from src/engine/gfx/renderJob/GPUContext.ts rename to src/gfx/renderJob/GPUContext.ts index 75361633..c829f28a 100644 --- a/src/engine/gfx/renderJob/GPUContext.ts +++ b/src/gfx/renderJob/GPUContext.ts @@ -1,16 +1,11 @@ import { Camera3D } from "../../core/Camera3D"; -import { View3D } from "../../core/View3D"; -import { ViewQuad } from "../../core/ViewQuad"; import { GeometryBase } from "../../core/geometry/GeometryBase"; import { ProfilerUtil } from "../../util/ProfilerUtil"; import { webGPUContext } from "../graphics/webGpu/Context3D"; import { GlobalBindGroup } from "../graphics/webGpu/core/bindGroups/GlobalBindGroup"; -import { Texture } from "../graphics/webGpu/core/texture/Texture"; import { ComputeShader } from "../graphics/webGpu/shader/ComputeShader"; import { RenderShader } from "../graphics/webGpu/shader/RenderShader"; import { RendererPassState } from "./passRenderer/state/RendererPassState"; -import { RendererType } from "./passRenderer/state/RendererType"; - /** * WebGPU api use context @@ -213,69 +208,6 @@ export class GPUContext { } - /** - * By inputting a map to viewQuad and setting corresponding - * processing shaders, the corresponding results are output for off-screen rendering - * Can also be directly used as the final display rendering result rendering canvas - * @param viewQuad - * @see ViewQuad - * @param scene3D - * @see Scene3D - * @param command - */ - public static renderTarget(view: View3D, viewQuad: ViewQuad, command: GPUCommandEncoder) { - let camera = view.camera; - let encoder = GPUContext.beginRenderPass(command, viewQuad.rendererPassState); - GPUContext.bindCamera(encoder, camera); - viewQuad.quadRenderer.nodeUpdate(view, RendererType.COLOR, viewQuad.rendererPassState, null); - viewQuad.quadRenderer.renderPass2(view, RendererType.COLOR, viewQuad.rendererPassState, null, encoder); - GPUContext.endPass(encoder); - } - - /** - * Output to screen through screen based shading - * @param viewQuad - * @see ViewQuad - * @param scene3D - * @see Scene3D - * @param command - * @param colorTexture - */ - public static renderToViewQuad(view: View3D, viewQuad: ViewQuad, command: GPUCommandEncoder, colorTexture: Texture) { - let camera = view.camera; - viewQuad.colorTexture = colorTexture; - let encoder = GPUContext.beginRenderPass(command, viewQuad.rendererPassState); - GPUContext.bindCamera(encoder, camera); - - // viewQuad.x = view.viewPort.x; - // viewQuad.y = view.viewPort.y; - // viewQuad.scaleX = view.viewPort.width; - // viewQuad.scaleY = view.viewPort.height; - // viewQuad.transform.updateWorldMatrix(true); - // encoder.setViewport( - // view.viewPort.x * webGPUContext.presentationSize[0], - // view.viewPort.y * webGPUContext.presentationSize[1], - // view.viewPort.width * webGPUContext.presentationSize[0], - // view.viewPort.height * webGPUContext.presentationSize[1], - // 0.0, 1.0); - // encoder.setScissorRect( - // view.viewPort.x * webGPUContext.presentationSize[0], - // view.viewPort.y * webGPUContext.presentationSize[0], - // view.viewPort.width * webGPUContext.presentationSize[0], - // view.viewPort.height * webGPUContext.presentationSize[1], - // ); - - // encoder.setScissorRect(view.viewPort.x, view.viewPort.y, 300, 150); - // encoder.setViewport(view.viewPort.x, view.viewPort.y, view.viewPort.width / (view.viewPort.width / view.viewPort.height), view.viewPort.height, 0.0, 1.0); - // encoder.setScissorRect(view.viewPort.x, view.viewPort.y, view.viewPort.width, view.viewPort.height); - - // encoder.setViewport(camera.viewPort.x, camera.viewPort.y, camera.viewPort.width, camera.viewPort.height, 0.0, 1.0); - // encoder.setScissorRect(camera.viewPort.x, camera.viewPort.y, camera.viewPort.width, camera.viewPort.height); - - viewQuad.quadRenderer.nodeUpdate(view, RendererType.COLOR, viewQuad.rendererPassState, null); - viewQuad.quadRenderer.renderPass2(view, RendererType.COLOR, viewQuad.rendererPassState, null, encoder); - GPUContext.endPass(encoder); - } /** * Perform the final calculation and submit the Shader to the GPU diff --git a/src/engine/gfx/renderJob/collect/CollectInfo.ts b/src/gfx/renderJob/collect/CollectInfo.ts similarity index 100% rename from src/engine/gfx/renderJob/collect/CollectInfo.ts rename to src/gfx/renderJob/collect/CollectInfo.ts diff --git a/src/gfx/renderJob/collect/ComponentCollect.ts b/src/gfx/renderJob/collect/ComponentCollect.ts new file mode 100644 index 00000000..b72536bb --- /dev/null +++ b/src/gfx/renderJob/collect/ComponentCollect.ts @@ -0,0 +1,44 @@ +import { IComponent } from "../../../components/IComponent"; +import { Object3D } from "../../../core/entities/Object3D"; + +export class ComponentCollect { + + /** + * @internal + */ + public static componentsUpdateList: Map; + + /** + * @internal + */ + public static componentsLateUpdateList: Map; + + /** + * @internal + */ + public static componentsBeforeUpdateList: Map; + + /** + * @internal + */ + public static componentsComputeList: Map; + + /** + * @internal + */ + public static waitStartComponent: Map; + + /** + * @internal + */ + public static graphicComponent: Map; + + public static init() { + ComponentCollect.componentsUpdateList = new Map(); + ComponentCollect.componentsLateUpdateList = new Map(); + ComponentCollect.componentsBeforeUpdateList = new Map(); + ComponentCollect.componentsComputeList = new Map(); + ComponentCollect.waitStartComponent = new Map(); + ComponentCollect.graphicComponent = new Map(); + } +} diff --git a/src/engine/gfx/renderJob/collect/EntityBatchCollect.ts b/src/gfx/renderJob/collect/EntityBatchCollect.ts similarity index 100% rename from src/engine/gfx/renderJob/collect/EntityBatchCollect.ts rename to src/gfx/renderJob/collect/EntityBatchCollect.ts diff --git a/src/engine/gfx/renderJob/collect/EntityCollect.ts b/src/gfx/renderJob/collect/EntityCollect.ts similarity index 91% rename from src/engine/gfx/renderJob/collect/EntityCollect.ts rename to src/gfx/renderJob/collect/EntityCollect.ts index bf4eba4f..4ee5f637 100644 --- a/src/engine/gfx/renderJob/collect/EntityCollect.ts +++ b/src/gfx/renderJob/collect/EntityCollect.ts @@ -1,19 +1,20 @@ -import { LightBase } from '../../../components/lights/LightBase'; + +import { ILight } from '../../../components/lights/ILight'; import { RenderNode } from '../../../components/renderer/RenderNode'; -import { SkyRenderer } from '../../../components/renderer/SkyRenderer'; import { Scene3D } from '../../../core/Scene3D'; import { RenderLayerUtil, RenderLayer } from '../config/RenderLayer'; import { Graphic3DBatchRenderer } from '../passRenderer/graphic/Graphic3DBatchRenderer'; +import { RendererMask } from '../passRenderer/state/RendererMask'; import { CollectInfo } from './CollectInfo'; import { EntityBatchCollect } from './EntityBatchCollect'; -import { RenderGroup } from './RenderGroup'; + /** * @internal * @group Post */ export class EntityCollect { // private static _sceneRenderList: Map; - private _sceneLights: Map; + private _sceneLights: Map; private _source_opaqueRenderNodes: Map; private _source_transparentRenderNodes: Map; @@ -32,7 +33,7 @@ export class EntityCollect { giLightingChange: true } - public sky: SkyRenderer; + public sky: RenderNode; private _collectInfo: CollectInfo; @@ -46,7 +47,7 @@ export class EntityCollect { constructor() { // this._sceneRenderList = new Map(); - this._sceneLights = new Map(); + this._sceneLights = new Map(); this._source_opaqueRenderNodes = new Map(); this._source_transparentRenderNodes = new Map(); @@ -80,7 +81,8 @@ export class EntityCollect { public addRenderNode(root: Scene3D, renderNode: RenderNode) { if (!root) return; - if (renderNode instanceof SkyRenderer) { + + if (renderNode.hasMask(RendererMask.Sky)) { this.sky = renderNode; } else if (renderNode instanceof Graphic3DBatchRenderer) { if (this._graphics.indexOf(renderNode) == -1) { @@ -123,7 +125,7 @@ export class EntityCollect { } public removeRenderNode(root: Scene3D, renderNode: RenderNode) { - if (renderNode instanceof SkyRenderer) { + if (renderNode.hasMask(RendererMask.Sky)) { this.sky = null; } else if (!RenderLayerUtil.hasMask(renderNode.object3D.renderLayer, RenderLayer.None)) { @@ -138,7 +140,7 @@ export class EntityCollect { } } - public addLight(root: Scene3D, light: LightBase) { + public addLight(root: Scene3D, light: ILight) { if (!this._sceneLights.has(root)) { this._sceneLights.set(root, [light]); } else { @@ -148,7 +150,7 @@ export class EntityCollect { } } - public removeLight(root: Scene3D, light: LightBase) { + public removeLight(root: Scene3D, light: ILight) { if (this._sceneLights.has(root)) { let list = this._sceneLights.get(root); let index = list.indexOf(light); @@ -157,7 +159,7 @@ export class EntityCollect { } } } - public getLights(root: Scene3D): LightBase[] { + public getLights(root: Scene3D): ILight[] { let list = this._sceneLights.get(root); return list ? list : []; } diff --git a/src/engine/gfx/renderJob/collect/RenderGroup.ts b/src/gfx/renderJob/collect/RenderGroup.ts similarity index 100% rename from src/engine/gfx/renderJob/collect/RenderGroup.ts rename to src/gfx/renderJob/collect/RenderGroup.ts diff --git a/src/engine/gfx/renderJob/collect/ShadowLightsCollect.ts b/src/gfx/renderJob/collect/ShadowLightsCollect.ts similarity index 82% rename from src/engine/gfx/renderJob/collect/ShadowLightsCollect.ts rename to src/gfx/renderJob/collect/ShadowLightsCollect.ts index 4da99259..6cf8c71c 100644 --- a/src/engine/gfx/renderJob/collect/ShadowLightsCollect.ts +++ b/src/gfx/renderJob/collect/ShadowLightsCollect.ts @@ -1,9 +1,9 @@ import { Engine3D } from '../../../Engine3D'; -import { DirectLight } from '../../../components/lights/DirectLight'; -import { LightBase } from '../../../components/lights/LightBase'; +import { ILight } from '../../../components/lights/ILight'; + import { LightType } from '../../../components/lights/LightData'; import { Scene3D } from '../../../core/Scene3D'; -import { View3D } from '../../../core/View3D'; + import { CameraUtil } from '../../../util/CameraUtil'; import { UUID } from '../../../util/Global'; /** @@ -12,15 +12,15 @@ import { UUID } from '../../../util/Global'; */ export class ShadowLightsCollect { - public static directionLightList: Map; - public static pointLightList: Map; + public static directionLightList: Map; + public static pointLightList: Map; public static init() { - this.directionLightList = new Map(); - this.pointLightList = new Map(); + this.directionLightList = new Map(); + this.pointLightList = new Map(); } - static getShadowLightList(light: LightBase) { + static getShadowLightList(light: ILight) { if (!light.transform.view3D) return null; if (light.lightData.lightType == LightType.DirectionLight) { let list = this.directionLightList.get(light.transform.view3D.scene); @@ -82,7 +82,7 @@ export class ShadowLightsCollect { return list; } - static addShadowLight(light: LightBase) { + static addShadowLight(light: ILight) { if (!light.transform.view3D) return null; if (light.lightData.lightType == LightType.DirectionLight) { let list = this.directionLightList.get(light.transform.view3D.scene); @@ -90,11 +90,11 @@ export class ShadowLightsCollect { list = []; this.directionLightList.set(light.transform.view3D.scene, list); } - if (light instanceof DirectLight && !light.shadowCamera) { - light.shadowCamera = CameraUtil.createCamera3DObject(null, 'shadowCamera'); - light.shadowCamera.name = UUID(); - light.shadowCamera.isShadowCamera = true; - light.shadowCamera.orthoOffCenter( + if (light.lightData.lightType == LightType.DirectionLight && !light['shadowCamera']) { + light['shadowCamera'] = CameraUtil.createCamera3DObject(null, 'shadowCamera'); + light['shadowCamera'].name = UUID(); + light['shadowCamera'].isShadowCamera = true; + light['shadowCamera'].orthoOffCenter( Engine3D.setting.shadow.shadowBound, -Engine3D.setting.shadow.shadowBound, Engine3D.setting.shadow.shadowBound, @@ -103,12 +103,12 @@ export class ShadowLightsCollect { 50000, ); } - let has = list.indexOf(light as DirectLight) == -1; + let has = list.indexOf(light) == -1; if (has) { if (list.length < 8) { light.lightData.castShadowIndex = list.length; } - list.push(light as DirectLight); + list.push(light); } return list; } else if (light.lightData.lightType == LightType.PointLight) { @@ -142,12 +142,12 @@ export class ShadowLightsCollect { } } - public static removeShadowLight(light: LightBase) { + public static removeShadowLight(light: ILight) { if (!light.transform.view3D) return null; if (light.lightData.lightType == LightType.DirectionLight) { let list = this.directionLightList.get(light.transform.view3D.scene); if (list) { - let index = list.indexOf(light as DirectLight); + let index = list.indexOf(light); if (index != -1) { list.splice(index, 1); } diff --git a/src/engine/gfx/renderJob/config/RTResourceConfig.ts b/src/gfx/renderJob/config/RTResourceConfig.ts similarity index 100% rename from src/engine/gfx/renderJob/config/RTResourceConfig.ts rename to src/gfx/renderJob/config/RTResourceConfig.ts diff --git a/src/engine/gfx/renderJob/config/RenderLayer.ts b/src/gfx/renderJob/config/RenderLayer.ts similarity index 100% rename from src/engine/gfx/renderJob/config/RenderLayer.ts rename to src/gfx/renderJob/config/RenderLayer.ts diff --git a/src/engine/gfx/renderJob/frame/GBufferFrame.ts b/src/gfx/renderJob/frame/GBufferFrame.ts similarity index 100% rename from src/engine/gfx/renderJob/frame/GBufferFrame.ts rename to src/gfx/renderJob/frame/GBufferFrame.ts diff --git a/src/engine/gfx/renderJob/frame/ProbeGBufferFrame.ts b/src/gfx/renderJob/frame/ProbeGBufferFrame.ts similarity index 100% rename from src/engine/gfx/renderJob/frame/ProbeGBufferFrame.ts rename to src/gfx/renderJob/frame/ProbeGBufferFrame.ts diff --git a/src/engine/gfx/renderJob/frame/RTFrame.ts b/src/gfx/renderJob/frame/RTFrame.ts similarity index 100% rename from src/engine/gfx/renderJob/frame/RTFrame.ts rename to src/gfx/renderJob/frame/RTFrame.ts diff --git a/src/engine/gfx/renderJob/frame/RTResourceMap.ts b/src/gfx/renderJob/frame/RTResourceMap.ts similarity index 96% rename from src/engine/gfx/renderJob/frame/RTResourceMap.ts rename to src/gfx/renderJob/frame/RTResourceMap.ts index b2a0eed9..3ed7f278 100644 --- a/src/engine/gfx/renderJob/frame/RTResourceMap.ts +++ b/src/gfx/renderJob/frame/RTResourceMap.ts @@ -1,6 +1,5 @@ import { ViewQuad } from '../../../core/ViewQuad'; -import { defaultRes } from '../../../textures/DefaultRes'; -import { Uint16Texture } from '../../../textures/Uint16Texture'; + import { VirtualTexture } from '../../../textures/VirtualTexture'; import { UniformNode } from '../../graphics/webGpu/core/uniforms/UniformNode'; import { RTDescriptor } from '../../graphics/webGpu/descriptor/RTDescriptor'; diff --git a/src/engine/gfx/renderJob/jobs/ForwardRenderJob.ts b/src/gfx/renderJob/jobs/ForwardRenderJob.ts similarity index 97% rename from src/engine/gfx/renderJob/jobs/ForwardRenderJob.ts rename to src/gfx/renderJob/jobs/ForwardRenderJob.ts index 9a04cf75..6be26740 100644 --- a/src/engine/gfx/renderJob/jobs/ForwardRenderJob.ts +++ b/src/gfx/renderJob/jobs/ForwardRenderJob.ts @@ -1,7 +1,7 @@ import { Engine3D } from '../../../Engine3D'; import { View3D } from '../../../core/View3D'; import { GlobalBindGroup } from '../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; -import { ColorPassRenderer } from '../color/ColorPassRenderer'; +import { ColorPassRenderer } from '../passRenderer/color/ColorPassRenderer'; import { GBufferFrame } from '../frame/GBufferFrame'; import { RendererJob } from './RendererJob'; /** diff --git a/src/engine/gfx/renderJob/jobs/RenderMap.ts b/src/gfx/renderJob/jobs/RenderMap.ts similarity index 100% rename from src/engine/gfx/renderJob/jobs/RenderMap.ts rename to src/gfx/renderJob/jobs/RenderMap.ts diff --git a/src/engine/gfx/renderJob/jobs/RendererJob.ts b/src/gfx/renderJob/jobs/RendererJob.ts similarity index 92% rename from src/engine/gfx/renderJob/jobs/RendererJob.ts rename to src/gfx/renderJob/jobs/RendererJob.ts index 0b9e470a..b79ba779 100644 --- a/src/engine/gfx/renderJob/jobs/RendererJob.ts +++ b/src/gfx/renderJob/jobs/RendererJob.ts @@ -1,11 +1,10 @@ -import { ComponentBase } from '../../../components/ComponentBase'; import { Scene3D } from '../../../core/Scene3D'; import { View3D } from '../../../core/View3D'; import { Engine3D } from '../../../Engine3D'; import { PickFire } from '../../../io/PickFire'; import { GlobalBindGroup } from '../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; import { ShadowLightsCollect } from '../collect/ShadowLightsCollect'; -import { ColorPassRenderer } from '../color/ColorPassRenderer'; +import { ColorPassRenderer } from '../passRenderer/color/ColorPassRenderer'; import { GBufferFrame } from '../frame/GBufferFrame'; import { GPUContext } from '../GPUContext'; import { OcclusionSystem } from '../occlusion/OcclusionSystem'; @@ -17,6 +16,7 @@ import { PreDepthPassRenderer } from '../passRenderer/preDepth/PreDepthPassRende import { RendererMap } from './RenderMap'; import { PostRenderer } from '../passRenderer/post/PostRenderer'; import { PostBase } from '../post/PostBase'; +import { ComponentCollect } from '../collect/ComponentCollect'; /** * render jobs @@ -198,7 +198,7 @@ export class RendererJob { /****** * auto update component list *****/ - ComponentBase.componentsBeforeUpdateList.forEach((v, k) => { + ComponentCollect.componentsBeforeUpdateList.forEach((v, k) => { if (k.enable) v(); }); @@ -211,12 +211,12 @@ export class RendererJob { renderLoop(); } - ComponentBase.componentsUpdateList.forEach((v, k) => { + ComponentCollect.componentsUpdateList.forEach((v, k) => { if (k.enable) v(); }); let command = GPUContext.beginCommandEncoder(); - ComponentBase.componentsComputeList.forEach((v, k) => { + ComponentCollect.componentsComputeList.forEach((v, k) => { if (k.enable) v(view, command); }); GPUContext.endCommandEncoder(command); @@ -229,7 +229,7 @@ export class RendererJob { view.scene.envMapChange = false; - ComponentBase.componentsLateUpdateList.forEach((v, k) => { + ComponentCollect.componentsLateUpdateList.forEach((v, k) => { if (k.enable) v(); }); @@ -257,9 +257,8 @@ export class RendererJob { let passList = this.rendererMap.getAllPassRenderer(); for (let i = 0; i < passList.length; i++) { const renderer = passList[i]; - renderer.clusterLightingRender = this.clusterLightingRender; renderer.beforeCompute(view, this.occlusionSystem); - renderer.render(view, this.occlusionSystem); + renderer.render(view, this.occlusionSystem, this.clusterLightingRender.clusterLightingBuffer); renderer.lateCompute(view, this.occlusionSystem); } } diff --git a/src/engine/gfx/renderJob/occlusion/OcclusionSystem.ts b/src/gfx/renderJob/occlusion/OcclusionSystem.ts similarity index 100% rename from src/engine/gfx/renderJob/occlusion/OcclusionSystem.ts rename to src/gfx/renderJob/occlusion/OcclusionSystem.ts diff --git a/src/engine/gfx/renderJob/passRenderer/RenderContext.ts b/src/gfx/renderJob/passRenderer/RenderContext.ts similarity index 100% rename from src/engine/gfx/renderJob/passRenderer/RenderContext.ts rename to src/gfx/renderJob/passRenderer/RenderContext.ts diff --git a/src/engine/gfx/renderJob/passRenderer/RendererBase.ts b/src/gfx/renderJob/passRenderer/RendererBase.ts similarity index 92% rename from src/engine/gfx/renderJob/passRenderer/RendererBase.ts rename to src/gfx/renderJob/passRenderer/RendererBase.ts index 63329edd..7190bc54 100644 --- a/src/engine/gfx/renderJob/passRenderer/RendererBase.ts +++ b/src/gfx/renderJob/passRenderer/RendererBase.ts @@ -17,6 +17,7 @@ import { RendererPassState } from "./state/RendererPassState"; import { RendererType } from "./state/RendererType"; import { RenderContext } from "./RenderContext"; import { ClusterLightingRender } from "./cluster/ClusterLightingRender"; +import { ClusterLightingBuffer } from "./cluster/ClusterLightingBuffer"; /** @@ -27,7 +28,6 @@ export class RendererBase extends CEventDispatcher { public rendererPassState: RendererPassState; public splitRendererPassState: RendererPassState; public useRenderBundle: boolean = false; - public clusterLightingRender: ClusterLightingRender; public debugViewQuads: ViewQuad[]; public debugTextures: Texture[]; @@ -74,7 +74,7 @@ export class RendererBase extends CEventDispatcher { public beforeCompute(view: View3D, occlusionSystem: OcclusionSystem) { } public lateCompute(view: View3D, occlusionSystem: OcclusionSystem) { } - public render(view: View3D, occlusionSystem: OcclusionSystem, maskTr: boolean = false) { + public render(view: View3D, occlusionSystem: OcclusionSystem, clusterLightingBuffer: ClusterLightingBuffer, maskTr: boolean = false) { GPUContext.cleanCache(); let camera = view.camera; @@ -97,7 +97,7 @@ export class RendererBase extends CEventDispatcher { if (!maskTr && EntityCollect.instance.sky) { GPUContext.bindCamera(renderPassEncoder, camera); - EntityCollect.instance.sky.renderPass2(view, this._rendererType, this.rendererPassState, this.clusterLightingRender, renderPassEncoder); + EntityCollect.instance.sky.renderPass2(view, this._rendererType, this.rendererPassState, clusterLightingBuffer, renderPassEncoder); } this.drawRenderNodes(view, renderPassEncoder, command, collectInfo.opaqueList, occlusionSystem); @@ -134,7 +134,7 @@ export class RendererBase extends CEventDispatcher { protected renderTr(encoder: GPURenderPassEncoder, command: GPUCommandEncoder, collectInfo: CollectInfo, scene: Scene3D, occlusionSystem: OcclusionSystem) { } - protected renderBundleOp(view: View3D, collectInfo: CollectInfo, occlusionSystem: OcclusionSystem) { + protected renderBundleOp(view: View3D, collectInfo: CollectInfo, occlusionSystem: OcclusionSystem, clusterLightingBuffer?: ClusterLightingBuffer) { let entityBatchCollect = EntityCollect.instance.getOpRenderGroup(view.scene); if (entityBatchCollect) { let bundlerList = []; @@ -143,7 +143,7 @@ export class RendererBase extends CEventDispatcher { bundlerList.push(v.bundleMap.get(this._rendererType)); } else { let renderBundleEncoder = GPUContext.recordBundleEncoder(this.rendererPassState.renderBundleEncoderDescriptor); - this.recordRenderBundleNode(view, renderBundleEncoder, v.renderNodes); + this.recordRenderBundleNode(view, renderBundleEncoder, v.renderNodes, clusterLightingBuffer); let newBundle = renderBundleEncoder.finish(); v.bundleMap.set(this._rendererType, newBundle); bundlerList.push(newBundle); @@ -154,7 +154,7 @@ export class RendererBase extends CEventDispatcher { return []; } - protected renderBundleTr(view: View3D, collectInfo: CollectInfo, occlusionSystem: OcclusionSystem) { + protected renderBundleTr(view: View3D, collectInfo: CollectInfo, occlusionSystem: OcclusionSystem, clusterLightingBuffer?: ClusterLightingBuffer) { let entityBatchCollect = EntityCollect.instance.getTrRenderGroup(view.scene); if (entityBatchCollect) { let bundlerList = []; @@ -163,7 +163,7 @@ export class RendererBase extends CEventDispatcher { bundlerList.push(v.bundleMap.get(this._rendererType)); } else { let renderBundleEncoder = GPUContext.recordBundleEncoder(this.rendererPassState.renderBundleEncoderDescriptor); - this.recordRenderBundleNode(view, renderBundleEncoder, v.renderNodes); + this.recordRenderBundleNode(view, renderBundleEncoder, v.renderNodes, clusterLightingBuffer); let newBundle = renderBundleEncoder.finish(); v.bundleMap.set(this._rendererType, newBundle); bundlerList.push(newBundle); @@ -174,7 +174,7 @@ export class RendererBase extends CEventDispatcher { return []; } - protected recordRenderBundleNode(view: View3D, encoder, nodes: RenderNode[]) { + protected recordRenderBundleNode(view: View3D, encoder, nodes: RenderNode[], clusterLightingBuffer?: ClusterLightingBuffer) { GPUContext.bindCamera(encoder, view.camera); GPUContext.bindGeometryBuffer(encoder, nodes[0].geometry); for (let i = 0; i < nodes.length; ++i) { @@ -182,11 +182,11 @@ export class RendererBase extends CEventDispatcher { let matrixIndex = renderNode.transform.worldMatrix.index; if (!renderNode.transform.enable) continue; - renderNode.recordRenderPass2(view, this._rendererType, this.rendererPassState, this.clusterLightingRender, encoder); + renderNode.recordRenderPass2(view, this._rendererType, this.rendererPassState, clusterLightingBuffer, encoder); } } - protected drawRenderNodes(view: View3D, encoder: GPURenderPassEncoder, command: GPUCommandEncoder, nodes: RenderNode[], occlusionSystem: OcclusionSystem) { + protected drawRenderNodes(view: View3D, encoder: GPURenderPassEncoder, command: GPUCommandEncoder, nodes: RenderNode[], occlusionSystem: OcclusionSystem, clusterLightingBuffer?: ClusterLightingBuffer) { GPUContext.bindCamera(encoder, view.camera); for (let i = Engine3D.setting.render.drawOpMin; i < Math.min(nodes.length, Engine3D.setting.render.drawOpMax); ++i) { let renderNode = nodes[i]; @@ -196,7 +196,7 @@ export class RendererBase extends CEventDispatcher { continue; if (!renderNode.enable) continue; - renderNode.renderPass2(view, this._rendererType, this.rendererPassState, this.clusterLightingRender, encoder); + renderNode.renderPass2(view, this._rendererType, this.rendererPassState, clusterLightingBuffer, encoder); } } @@ -227,7 +227,4 @@ export class RendererBase extends CEventDispatcher { this.debugViewQuads.push(viewQuad); } } - - - } diff --git a/src/gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer.ts b/src/gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer.ts new file mode 100644 index 00000000..a59c258f --- /dev/null +++ b/src/gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer.ts @@ -0,0 +1,37 @@ +import { ComputeGPUBuffer } from "../../../graphics/webGpu/core/buffer/ComputeGPUBuffer"; +import { UniformGPUBuffer } from "../../../graphics/webGpu/core/buffer/UniformGPUBuffer"; + +export class ClusterLightingBuffer { + + public clusterBuffer: ComputeGPUBuffer; + public lightAssignBuffer: ComputeGPUBuffer; + public assignTableBuffer: ComputeGPUBuffer; + public clustersUniformBuffer: UniformGPUBuffer; + + constructor(numClusters: number, maxNumLightsPerCluster: number) { + this.clusterBuffer = new ComputeGPUBuffer(numClusters * /*two vec4*/ 2 * /*vec4*/4); + this.clustersUniformBuffer = new UniformGPUBuffer(10); + this.clustersUniformBuffer.visibility = GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; + + this.lightAssignBuffer = new ComputeGPUBuffer(numClusters * maxNumLightsPerCluster); + this.lightAssignBuffer.visibility = GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; + this.assignTableBuffer = new ComputeGPUBuffer(numClusters * 4); // it has start and count + this.assignTableBuffer.visibility = GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; + } + + public update(width: number, height: number, clusterPix: number, clusterTileX: number, clusterTileY: number, clusterTileZ: number, maxNumLights: number, maxNumLightsPerCluster: number, near: number, far: number) { + this.clustersUniformBuffer.setFloat('clusterTileX', clusterTileX); + this.clustersUniformBuffer.setFloat('clusterTileY', clusterTileY); + this.clustersUniformBuffer.setFloat('clusterTileZ', clusterTileZ); + this.clustersUniformBuffer.setFloat('numLights', maxNumLights); + this.clustersUniformBuffer.setFloat('maxNumLightsPerCluster', maxNumLightsPerCluster); + + this.clustersUniformBuffer.setFloat('near', near); + this.clustersUniformBuffer.setFloat('far', far); + + this.clustersUniformBuffer.setFloat('screenWidth', width); + this.clustersUniformBuffer.setFloat('screenHeight', height); + this.clustersUniformBuffer.setFloat('clusterPix', clusterPix); + this.clustersUniformBuffer.apply(); + } +} \ No newline at end of file diff --git a/src/engine/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts b/src/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts similarity index 62% rename from src/engine/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts rename to src/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts index cce8ef61..9f91c364 100644 --- a/src/engine/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts +++ b/src/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts @@ -1,11 +1,8 @@ import ClusterBoundsSource_cs from '../../../../assets/shader/cluster/ClusterBoundsSource_cs.wgsl?raw'; import ClusterLighting_cs from '../../../../assets/shader/cluster/ClusterLighting_cs.wgsl?raw'; -import { LightBase } from '../../../../components/lights/LightBase'; import { View3D } from '../../../../core/View3D'; import { GlobalBindGroup } from '../../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; -import { ComputeGPUBuffer } from '../../../graphics/webGpu/core/buffer/ComputeGPUBuffer'; -import { UniformGPUBuffer } from '../../../graphics/webGpu/core/buffer/UniformGPUBuffer'; import { ComputeShader } from '../../../graphics/webGpu/shader/ComputeShader'; import { webGPUContext } from '../../../graphics/webGpu/Context3D'; import { EntityCollect } from '../../collect/EntityCollect'; @@ -13,6 +10,8 @@ import { GPUContext } from '../../GPUContext'; import { OcclusionSystem } from '../../occlusion/OcclusionSystem'; import { RendererBase } from '../RendererBase'; import { RendererType } from '../state/RendererType'; +import { ILight } from '../../../../components/lights/ILight'; +import { ClusterLightingBuffer } from './ClusterLightingBuffer'; /** * @internal * @group Post @@ -24,10 +23,7 @@ export class ClusterLightingRender extends RendererBase { public maxNumLights = 128; public maxNumLightsPerCluster = 100; public clusterPix = 1; - public clusterBuffer: ComputeGPUBuffer; - public lightAssignBuffer: ComputeGPUBuffer; - public assignTableBuffer: ComputeGPUBuffer; - public clustersUniformBuffer: UniformGPUBuffer; + public clusterLightingBuffer: ClusterLightingBuffer; private _clusterGenerateCompute: ComputeShader; private _clusterLightingCompute: ComputeShader; @@ -50,41 +46,22 @@ export class ClusterLightingRender extends RendererBase { let near = camera.near; let far = camera.far; - this.clusterBuffer = new ComputeGPUBuffer(numClusters * /*two vec4*/ 2 * /*vec4*/4); - this.clustersUniformBuffer = new UniformGPUBuffer(10); - this.clustersUniformBuffer.visibility = GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; - - this.clustersUniformBuffer.setFloat('clusterTileX', this.clusterTileX); - this.clustersUniformBuffer.setFloat('clusterTileY', this.clusterTileY); - this.clustersUniformBuffer.setFloat('clusterTileZ', this.clusterTileZ); - this.clustersUniformBuffer.setFloat('numLights', this.maxNumLights); - this.clustersUniformBuffer.setFloat('maxNumLightsPerCluster', this.maxNumLightsPerCluster); - - this.clustersUniformBuffer.setFloat('near', near); - this.clustersUniformBuffer.setFloat('far', far); - - this.clustersUniformBuffer.setFloat('screenWidth', size[0]); - this.clustersUniformBuffer.setFloat('screenHeight', size[1]); - this.clustersUniformBuffer.setFloat('clusterPix', this.clusterPix); - this.clustersUniformBuffer.apply(); + this.clusterLightingBuffer = new ClusterLightingBuffer(numClusters, this.maxNumLightsPerCluster); + this.clusterLightingBuffer.update(size[0], size[1], this.clusterPix, this.clusterTileX, this.clusterTileY, this.clusterTileZ, this.maxNumLights, this.maxNumLightsPerCluster, near, far); let standBindGroup = GlobalBindGroup.getCameraGroup(camera); this._clusterGenerateCompute.setUniformBuffer(`globalUniform`, standBindGroup.uniformGPUBuffer); this._clusterLightingCompute.setUniformBuffer(`globalUniform`, standBindGroup.uniformGPUBuffer); - this._clusterGenerateCompute.setUniformBuffer(`clustersUniform`, this.clustersUniformBuffer); - this._clusterGenerateCompute.setStorageBuffer(`clusterBuffer`, this.clusterBuffer); + this._clusterGenerateCompute.setUniformBuffer(`clustersUniform`, this.clusterLightingBuffer.clustersUniformBuffer); + this._clusterGenerateCompute.setStorageBuffer(`clusterBuffer`, this.clusterLightingBuffer.clusterBuffer); let lightBuffer = GlobalBindGroup.getLightEntries(view.scene); - this.lightAssignBuffer = new ComputeGPUBuffer(numClusters * this.maxNumLightsPerCluster); - this.lightAssignBuffer.visibility = GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; - this.assignTableBuffer = new ComputeGPUBuffer(numClusters * 4); // it has start and count - this.assignTableBuffer.visibility = GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; this._clusterLightingCompute.setStorageBuffer(`models`, GlobalBindGroup.modelMatrixBindGroup.matrixBufferDst); - this._clusterLightingCompute.setUniformBuffer(`clustersUniform`, this.clustersUniformBuffer); - this._clusterLightingCompute.setStorageBuffer(`clusterBuffer`, this.clusterBuffer); + this._clusterLightingCompute.setUniformBuffer(`clustersUniform`, this.clusterLightingBuffer.clustersUniformBuffer); + this._clusterLightingCompute.setStorageBuffer(`clusterBuffer`, this.clusterLightingBuffer.clusterBuffer); this._clusterLightingCompute.setStorageBuffer(`lightBuffer`, lightBuffer.storageGPUBuffer); - this._clusterLightingCompute.setStorageBuffer(`lightAssignBuffer`, this.lightAssignBuffer); - this._clusterLightingCompute.setStorageBuffer(`assignTable`, this.assignTableBuffer); + this._clusterLightingCompute.setStorageBuffer(`lightAssignBuffer`, this.clusterLightingBuffer.lightAssignBuffer); + this._clusterLightingCompute.setStorageBuffer(`assignTable`, this.clusterLightingBuffer.assignTableBuffer); this.debug(view); } @@ -95,13 +72,12 @@ export class ClusterLightingRender extends RendererBase { let near = camera.near; let far = camera.far; - let lights: LightBase[] = EntityCollect.instance.getLights(scene); + let lights: ILight[] = EntityCollect.instance.getLights(scene); let size = webGPUContext.presentationSize; // this.clustersUniformBuffer.setFloat('screenWidth', size[0] ); // this.clustersUniformBuffer.setFloat('screenHeight', size[1] ); - this.clustersUniformBuffer.setFloat('numLights', lights.length); - - this.clustersUniformBuffer.apply(); + this.clusterLightingBuffer.clustersUniformBuffer.setFloat('numLights', lights.length); + this.clusterLightingBuffer.clustersUniformBuffer.apply(); this._clusterGenerateCompute.workerSizeX = this.clusterTileZ; this._clusterLightingCompute.workerSizeX = this.clusterTileZ; diff --git a/src/engine/gfx/renderJob/color/ColorPassRenderer.ts b/src/gfx/renderJob/passRenderer/color/ColorPassRenderer.ts similarity index 78% rename from src/engine/gfx/renderJob/color/ColorPassRenderer.ts rename to src/gfx/renderJob/passRenderer/color/ColorPassRenderer.ts index 89ac1341..47f2b418 100644 --- a/src/engine/gfx/renderJob/color/ColorPassRenderer.ts +++ b/src/gfx/renderJob/passRenderer/color/ColorPassRenderer.ts @@ -1,13 +1,14 @@ -import { Engine3D } from "../../../Engine3D"; -import { RenderNode } from "../../../components/renderer/RenderNode"; -import { View3D } from "../../../core/View3D"; -import { ProfilerUtil } from "../../../util/ProfilerUtil"; -import { GPUContext } from "../GPUContext"; -import { EntityCollect } from "../collect/EntityCollect"; -import { OcclusionSystem } from "../occlusion/OcclusionSystem"; -import { RenderContext } from "../passRenderer/RenderContext"; -import { RendererBase } from "../passRenderer/RendererBase"; -import { RendererType } from "../passRenderer/state/RendererType"; +import { Engine3D } from "../../../../Engine3D"; +import { RenderNode } from "../../../../components/renderer/RenderNode"; +import { View3D } from "../../../../core/View3D"; +import { ProfilerUtil } from "../../../../util/ProfilerUtil"; +import { GPUContext } from "../../GPUContext"; +import { EntityCollect } from "../../collect/EntityCollect"; +import { OcclusionSystem } from "../../occlusion/OcclusionSystem"; +import { RenderContext } from "../RenderContext"; +import { RendererBase } from "../RendererBase"; +import { ClusterLightingBuffer } from "../cluster/ClusterLightingBuffer"; +import { RendererType } from "../state/RendererType"; /** @@ -22,7 +23,7 @@ export class ColorPassRenderer extends RendererBase { this.passType = RendererType.COLOR; } - public render(view: View3D, occlusionSystem: OcclusionSystem, maskTr: boolean = false) { + public render(view: View3D, occlusionSystem: OcclusionSystem, clusterLightingBuffer?: ClusterLightingBuffer, maskTr: boolean = false) { // return ; this.renderContext.clean(); @@ -67,11 +68,11 @@ export class ColorPassRenderer extends RendererBase { if (!maskTr && EntityCollect.instance.sky) { GPUContext.bindCamera(renderPassEncoder, camera); - EntityCollect.instance.sky.renderPass2(view, this._rendererType, this.rendererPassState, this.clusterLightingRender, renderPassEncoder); + EntityCollect.instance.sky.renderPass2(view, this._rendererType, this.rendererPassState, clusterLightingBuffer, renderPassEncoder); } GPUContext.bindCamera(renderPassEncoder, camera); - this.drawNodes(view, this.renderContext, collectInfo.opaqueList, occlusionSystem); + this.drawNodes(view, this.renderContext, collectInfo.opaqueList, occlusionSystem, clusterLightingBuffer); this.renderContext.endRenderPass(); ProfilerUtil.end("ColorPass Draw Opaque"); } @@ -90,15 +91,15 @@ export class ColorPassRenderer extends RendererBase { if (!maskTr) { GPUContext.bindCamera(renderPassEncoder, camera); - this.drawNodes(view, this.renderContext, collectInfo.transparentList, occlusionSystem); + this.drawNodes(view, this.renderContext, collectInfo.transparentList, occlusionSystem, clusterLightingBuffer); } let graphicsList = EntityCollect.instance.getGraphicList(); for (let i = 0; i < graphicsList.length; i++) { const graphic3DRenderNode = graphicsList[i]; let matrixIndex = graphic3DRenderNode.transform.worldMatrix.index; - graphic3DRenderNode.nodeUpdate(view, this._rendererType, this.splitRendererPassState, this.clusterLightingRender); - graphic3DRenderNode.renderPass2(view, this._rendererType, this.splitRendererPassState, this.clusterLightingRender, renderPassEncoder); + graphic3DRenderNode.nodeUpdate(view, this._rendererType, this.splitRendererPassState, clusterLightingBuffer); + graphic3DRenderNode.renderPass2(view, this._rendererType, this.splitRendererPassState, clusterLightingBuffer, renderPassEncoder); } this.renderContext.endRenderPass(); @@ -108,14 +109,14 @@ export class ColorPassRenderer extends RendererBase { ProfilerUtil.end("colorPass Renderer"); } - public drawNodes(view: View3D, renderContext: RenderContext, nodes: RenderNode[], occlusionSystem: OcclusionSystem) { + public drawNodes(view: View3D, renderContext: RenderContext, nodes: RenderNode[], occlusionSystem: OcclusionSystem, clusterLightingBuffer: ClusterLightingBuffer) { { for (let i = Engine3D.setting.render.drawOpMin; i < Math.min(nodes.length, Engine3D.setting.render.drawOpMax); ++i) { let renderNode = nodes[i]; if (!renderNode.transform.enable) continue; if (!renderNode.enable) continue; - renderNode.nodeUpdate(view, this._rendererType, this.rendererPassState, this.clusterLightingRender); + renderNode.nodeUpdate(view, this._rendererType, this.rendererPassState, clusterLightingBuffer); renderNode.renderPass(view, this.passType, this.renderContext); } } diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts b/src/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts similarity index 93% rename from src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts rename to src/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts index 2944b3ee..083411af 100644 --- a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts +++ b/src/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts @@ -10,6 +10,7 @@ import { ClusterLightingRender } from "../cluster/ClusterLightingRender"; import { Graphic3DFixedRenderPipeline } from "./Graphic3DFixedRenderPipeline"; import { GraphicConfig } from "./GraphicConfig"; import { Graphics3DShape } from "./Graphics3DShape"; +import { ClusterLightingBuffer } from "../cluster/ClusterLightingBuffer"; /** * @internal @@ -62,7 +63,7 @@ export class Graphic3DBatchRenderer extends RenderNode { this.shapes.set(uuid, data); } - protected init() { + public init() { super.init(); this.castGI = false; this.castShadow = false; @@ -81,7 +82,7 @@ export class Graphic3DBatchRenderer extends RenderNode { this._readyPipeline = true; } - public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingRender?: ClusterLightingRender) { + public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingBuffer?: ClusterLightingBuffer) { // if(!this.enable || passType != RendererType.COLOR ) return ; if (this.mDirtyData) { this.mRenderPipeline.reset(); @@ -93,7 +94,7 @@ export class Graphic3DBatchRenderer extends RenderNode { return; } - public renderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingRender: ClusterLightingRender, encoder: GPURenderPassEncoder, useBundle: boolean = false) { + public renderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingBuffer: ClusterLightingBuffer, encoder: GPURenderPassEncoder, useBundle: boolean = false) { // if(!this.enable || passType != RendererType.COLOR ) return ; this.mRenderPipeline.render(rendererPassState, encoder); } diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts b/src/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts similarity index 100% rename from src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts rename to src/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts b/src/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts similarity index 100% rename from src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts rename to src/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts b/src/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts similarity index 100% rename from src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts rename to src/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DRender.ts b/src/gfx/renderJob/passRenderer/graphic/Graphic3DRender.ts similarity index 100% rename from src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DRender.ts rename to src/gfx/renderJob/passRenderer/graphic/Graphic3DRender.ts diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/GraphicConfig.ts b/src/gfx/renderJob/passRenderer/graphic/GraphicConfig.ts similarity index 100% rename from src/engine/gfx/renderJob/passRenderer/graphic/GraphicConfig.ts rename to src/gfx/renderJob/passRenderer/graphic/GraphicConfig.ts diff --git a/src/engine/gfx/renderJob/passRenderer/graphic/Graphics3DShape.ts b/src/gfx/renderJob/passRenderer/graphic/Graphics3DShape.ts similarity index 100% rename from src/engine/gfx/renderJob/passRenderer/graphic/Graphics3DShape.ts rename to src/gfx/renderJob/passRenderer/graphic/Graphics3DShape.ts diff --git a/src/engine/gfx/renderJob/passRenderer/post/PostRenderer.ts b/src/gfx/renderJob/passRenderer/post/PostRenderer.ts similarity index 89% rename from src/engine/gfx/renderJob/passRenderer/post/PostRenderer.ts rename to src/gfx/renderJob/passRenderer/post/PostRenderer.ts index ac310c98..275a61f1 100644 --- a/src/engine/gfx/renderJob/passRenderer/post/PostRenderer.ts +++ b/src/gfx/renderJob/passRenderer/post/PostRenderer.ts @@ -60,11 +60,11 @@ export class PostRenderer extends RendererBase { } let lastTexture = GPUContext.lastRenderPassState.getLastRenderTexture(); - GPUContext.renderToViewQuad(view, this.finalQuadView, command, lastTexture); + this.finalQuadView.renderToViewQuad(view, this.finalQuadView, command, lastTexture); { if (this.debugViewQuads.length) { let debugIndex = Engine3D.setting.render.debugQuad; - if (debugIndex >= 0) GPUContext.renderToViewQuad(view, this.debugViewQuads[debugIndex], command, this.debugTextures[debugIndex]); + if (debugIndex >= 0) this.debugViewQuads[debugIndex].renderToViewQuad(view, this.debugViewQuads[debugIndex], command, this.debugTextures[debugIndex]); } } GPUContext.endCommandEncoder(command); diff --git a/src/engine/gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer.ts b/src/gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer.ts similarity index 100% rename from src/engine/gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer.ts rename to src/gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer.ts diff --git a/src/engine/gfx/renderJob/passRenderer/preDepth/ZCullingCompute.ts b/src/gfx/renderJob/passRenderer/preDepth/ZCullingCompute.ts similarity index 100% rename from src/engine/gfx/renderJob/passRenderer/preDepth/ZCullingCompute.ts rename to src/gfx/renderJob/passRenderer/preDepth/ZCullingCompute.ts diff --git a/src/engine/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts b/src/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts similarity index 97% rename from src/engine/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts rename to src/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts index 93732fb2..af9683cb 100644 --- a/src/engine/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts +++ b/src/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts @@ -1,9 +1,7 @@ -import { LightBase } from '../../../../components/lights/LightBase'; import { LightType } from '../../../../components/lights/LightData'; import { ShadowLightsCollect } from '../../collect/ShadowLightsCollect'; import { Camera3D } from '../../../../core/Camera3D'; import { CubeCamera } from '../../../../core/CubeCamera'; -import { Scene3D } from '../../../../core/Scene3D'; import { Engine3D } from '../../../../Engine3D'; import { VirtualTexture } from '../../../../textures/VirtualTexture'; import { GPUTextureFormat } from '../../../graphics/webGpu/WebGPUConst'; @@ -22,6 +20,7 @@ import { RTDescriptor } from '../../../graphics/webGpu/descriptor/RTDescriptor'; import { WebGPUDescriptorCreator } from '../../../graphics/webGpu/descriptor/WebGPUDescriptorCreator'; import { RendererPassState } from '../state/RendererPassState'; import { RendererType } from '../state/RendererType'; +import { ILight } from '../../../../components/lights/ILight'; type CubeShadowMapInfo = { cubeCamera: CubeCamera, @@ -36,7 +35,7 @@ type CubeShadowMapInfo = { export class PointLightShadowRenderer extends RendererBase { public shadowPassCount: number; private _forceUpdate = false; - private _shadowCameraDic: Map; + private _shadowCameraDic: Map; public shadowCamera: Camera3D; public cubeTextureArray: DepthCubeArrayTexture; public colorTexture: VirtualTexture; @@ -46,14 +45,14 @@ export class PointLightShadowRenderer extends RendererBase { this.passType = RendererType.POINT_SHADOW; // this.shadowSize = Engine3D.setting.shadow.pointShadowSize; - this._shadowCameraDic = new Map(); + this._shadowCameraDic = new Map(); this.cubeTextureArray = new DepthCubeArrayTexture(this.shadowSize, this.shadowSize, 8); this.colorTexture = new VirtualTexture(this.shadowSize, this.shadowSize, GPUTextureFormat.bgra8unorm, false); } - public getShadowCamera(view: View3D, lightBase: LightBase): CubeShadowMapInfo { + public getShadowCamera(view: View3D, lightBase: ILight): CubeShadowMapInfo { let cubeShadowMapInfo: CubeShadowMapInfo; if (this._shadowCameraDic.has(lightBase)) { cubeShadowMapInfo = this._shadowCameraDic.get(lightBase); diff --git a/src/engine/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts b/src/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts similarity index 96% rename from src/engine/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts rename to src/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts index 383868f3..6a37b927 100644 --- a/src/engine/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts +++ b/src/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts @@ -19,6 +19,7 @@ import { OcclusionSystem } from "../../occlusion/OcclusionSystem"; import { RendererPassState } from "../state/RendererPassState"; import { RendererType } from "../state/RendererType"; import { RendererBase } from "../RendererBase"; +import { ClusterLightingBuffer } from "../cluster/ClusterLightingBuffer"; /** * @internal @@ -203,7 +204,7 @@ export class ShadowMapPassRenderer extends RendererBase { } - protected recordShadowRenderBundleNode(view: View3D, shadowCamera: Camera3D, encoder, nodes: RenderNode[]) { + protected recordShadowRenderBundleNode(view: View3D, shadowCamera: Camera3D, encoder, nodes: RenderNode[], clusterLightingBuffer?: ClusterLightingBuffer) { GPUContext.bindCamera(encoder, shadowCamera); GPUContext.bindGeometryBuffer(encoder, nodes[0].geometry); for (let i = 0; i < nodes.length; ++i) { @@ -211,11 +212,11 @@ export class ShadowMapPassRenderer extends RendererBase { let matrixIndex = renderNode.transform.worldMatrix.index; if (!renderNode.transform.enable) continue; - renderNode.recordRenderPass2(view, this._rendererType, this.rendererPassState, this.clusterLightingRender, encoder); + renderNode.recordRenderPass2(view, this._rendererType, this.rendererPassState, clusterLightingBuffer, encoder); } } - protected drawShadowRenderNodes(view: View3D, shadowCamera: Camera3D, encoder: GPURenderPassEncoder, nodes: RenderNode[]) { + protected drawShadowRenderNodes(view: View3D, shadowCamera: Camera3D, encoder: GPURenderPassEncoder, nodes: RenderNode[], clusterLightingBuffer?: ClusterLightingBuffer) { GPUContext.bindCamera(encoder, shadowCamera); for (let i = Engine3D.setting.render.drawOpMin; i < Math.min(nodes.length, Engine3D.setting.render.drawOpMax); ++i) { let renderNode = nodes[i]; @@ -225,7 +226,7 @@ export class ShadowMapPassRenderer extends RendererBase { continue; if (!renderNode.enable) continue; - renderNode.renderPass2(view, this._rendererType, this.rendererPassState, this.clusterLightingRender, encoder); + renderNode.renderPass2(view, this._rendererType, this.rendererPassState, clusterLightingBuffer, encoder); } } } diff --git a/src/engine/gfx/renderJob/passRenderer/state/RendererMask.ts b/src/gfx/renderJob/passRenderer/state/RendererMask.ts similarity index 95% rename from src/engine/gfx/renderJob/passRenderer/state/RendererMask.ts rename to src/gfx/renderJob/passRenderer/state/RendererMask.ts index cfb50d30..9c02ab28 100644 --- a/src/engine/gfx/renderJob/passRenderer/state/RendererMask.ts +++ b/src/gfx/renderJob/passRenderer/state/RendererMask.ts @@ -29,6 +29,6 @@ export class RendererMaskUtil { } public static hasMask(m1: RendererMask, m2: RendererMask): boolean { - return (m1 & m2) != 0; + return (m1 & m2) == m2; } } diff --git a/src/engine/gfx/renderJob/passRenderer/state/RendererPassState.ts b/src/gfx/renderJob/passRenderer/state/RendererPassState.ts similarity index 91% rename from src/engine/gfx/renderJob/passRenderer/state/RendererPassState.ts rename to src/gfx/renderJob/passRenderer/state/RendererPassState.ts index ea80fae5..46ee9a45 100644 --- a/src/engine/gfx/renderJob/passRenderer/state/RendererPassState.ts +++ b/src/gfx/renderJob/passRenderer/state/RendererPassState.ts @@ -1,5 +1,6 @@ +import { Engine3D } from "../../../../Engine3D"; import { Camera3D } from "../../../../core/Camera3D"; -import { defaultRes } from "../../../../textures/DefaultRes"; + import { VirtualTexture } from "../../../../textures/VirtualTexture"; import { Texture } from "../../../graphics/webGpu/core/texture/Texture"; import { RTDescriptor } from "../../../graphics/webGpu/descriptor/RTDescriptor"; @@ -36,9 +37,9 @@ export class RendererPassState { getLastRenderTexture() { if (this.renderTargets) { - return this.renderTargets.length > 0 ? this.renderTargets[0] : defaultRes.redTexture; + return this.renderTargets.length > 0 ? this.renderTargets[0] : Engine3D.res.redTexture; } else { - return defaultRes.redTexture + return Engine3D.res.redTexture } } } diff --git a/src/engine/gfx/renderJob/passRenderer/state/RendererType.ts b/src/gfx/renderJob/passRenderer/state/RendererType.ts similarity index 100% rename from src/engine/gfx/renderJob/passRenderer/state/RendererType.ts rename to src/gfx/renderJob/passRenderer/state/RendererType.ts diff --git a/src/engine/gfx/renderJob/post/DepthOfFieldPost.ts b/src/gfx/renderJob/post/DepthOfFieldPost.ts similarity index 99% rename from src/engine/gfx/renderJob/post/DepthOfFieldPost.ts rename to src/gfx/renderJob/post/DepthOfFieldPost.ts index 111d37a2..068e7605 100644 --- a/src/engine/gfx/renderJob/post/DepthOfFieldPost.ts +++ b/src/gfx/renderJob/post/DepthOfFieldPost.ts @@ -18,7 +18,7 @@ import { RTResourceConfig } from '../config/RTResourceConfig'; import { GBufferFrame } from '../frame/GBufferFrame'; import { RTFrame } from '../frame/RTFrame'; /** - * depth of field effect。 + * depth of field effect. * A common post-processing effect that simulates the focusing characteristics of a camera lens. * ``` * //Configure parameters related to depth of field diff --git a/src/engine/gfx/renderJob/post/FXAAPost.ts b/src/gfx/renderJob/post/FXAAPost.ts similarity index 89% rename from src/engine/gfx/renderJob/post/FXAAPost.ts rename to src/gfx/renderJob/post/FXAAPost.ts index 56cfb16a..2d8a7482 100644 --- a/src/engine/gfx/renderJob/post/FXAAPost.ts +++ b/src/gfx/renderJob/post/FXAAPost.ts @@ -14,14 +14,6 @@ import { View3D } from '../../../core/View3D'; * A deformation anti-aliasing method that pays more attention to performance. * It only needs one pass to get the result. FXAA focuses on fast visual anti-aliasing effect, * rather than pursuing perfect real anti-aliasing effect. - * ``` - * let cfg = {@link Engine3D.setting.render.postProcessing.fxaa}; - * let view = new View3D(); - view.scene = this.scene; - view.camera = mainCamera; - - * Engine3D.startRender(renderJob); - *``` * @group Post Effects */ export class FXAAPost extends PostBase { diff --git a/src/engine/gfx/renderJob/post/GTAOPost.ts b/src/gfx/renderJob/post/GTAOPost.ts similarity index 100% rename from src/engine/gfx/renderJob/post/GTAOPost.ts rename to src/gfx/renderJob/post/GTAOPost.ts diff --git a/src/engine/gfx/renderJob/post/GlobalFog.ts b/src/gfx/renderJob/post/GlobalFog.ts similarity index 93% rename from src/engine/gfx/renderJob/post/GlobalFog.ts rename to src/gfx/renderJob/post/GlobalFog.ts index 99422b83..63d4024e 100644 --- a/src/engine/gfx/renderJob/post/GlobalFog.ts +++ b/src/gfx/renderJob/post/GlobalFog.ts @@ -13,16 +13,6 @@ import { View3D } from '../../../core/View3D'; import { GBufferFrame } from '../frame/GBufferFrame'; /** * screen space fog - * ``` - * //setting - * let cfg = {@link Engine3D.setting.render.postProcessing.globalFog}; - * let view = new View3D(); - view.scene = this.scene; - view.camera = mainCamera; - - * - * Engine3D.startRender(renderJob); - *``` * @group Post Effects */ export class GlobalFog extends PostBase { @@ -143,7 +133,7 @@ export class GlobalFog extends PostBase { render(view: View3D, command: GPUCommandEncoder) { const renderShader = this.viewQuad.material.renderShader; renderShader.setTexture('colorMap', this.getOutTexture()); - GPUContext.renderTarget(view, this.viewQuad, command); + this.viewQuad.renderTarget(view, this.viewQuad, command); } } diff --git a/src/engine/gfx/renderJob/post/HDRBloomPost.ts b/src/gfx/renderJob/post/HDRBloomPost.ts similarity index 83% rename from src/engine/gfx/renderJob/post/HDRBloomPost.ts rename to src/gfx/renderJob/post/HDRBloomPost.ts index 9a8621af..c75e78ca 100644 --- a/src/engine/gfx/renderJob/post/HDRBloomPost.ts +++ b/src/gfx/renderJob/post/HDRBloomPost.ts @@ -12,15 +12,6 @@ import { View3D } from '../../../core/View3D'; /** * HDR Bloom effect * ``` - * //setting - * let cfg = {@link Engine3D.setting.render.postProcessing.bloom}; - * let view = new View3D(); - view.scene = this.scene; - view.camera = mainCamera; - - * - * Engine3D.startRender(renderJob); - *``` * @group Post Effects */ export class HDRBloomPost extends PostBase { @@ -135,7 +126,7 @@ export class HDRBloomPost extends PostBase { { let colorTexture = this.getOutTexture(); { - GPUContext.renderToViewQuad(view, this.brightnessView, command, colorTexture); + this.brightnessView.renderToViewQuad(view, this.brightnessView, command, colorTexture); } { let tex = this.brightnessView.rendererPassState.renderTargets[0]; @@ -146,13 +137,13 @@ export class HDRBloomPost extends PostBase { ql.material.renderShader.setUniformFloat(`horizontal`, 0.5); ql.material.renderShader.setUniformFloat(`vScale`, i * this.blurX); - GPUContext.renderToViewQuad(view, ql, command, tex); + ql.renderToViewQuad(view, ql, command, tex); tex = ql.rendererPassState.renderTargets[0]; qr.material.renderShader.setUniformFloat(`horizontal`, 2.0); qr.material.renderShader.setUniformFloat(`hScale`, i * this.blurY); - GPUContext.renderToViewQuad(view, qr, command, tex); + qr.renderToViewQuad(view, qr, command, tex); tex = qr.rendererPassState.renderTargets[0]; } } @@ -165,12 +156,7 @@ export class HDRBloomPost extends PostBase { shader.setTexture(`blurTex4`, this.blurList[3].qr.rendererPassState.renderTargets[0]); shader.setTexture(`blurTex5`, this.blurList[4].qr.rendererPassState.renderTargets[0]); - // this.compositeView.material.blurTex5[1] = this.blurList[0].qr.rendererPassState.renderTargets[0]; - // this.compositeView.material.textures[2] = this.blurList[1].qr.rendererPassState.renderTargets[0]; - // this.compositeView.material.textures[3] = this.blurList[2].qr.rendererPassState.renderTargets[0]; - // this.compositeView.material.textures[4] = this.blurList[3].qr.rendererPassState.renderTargets[0]; - // this.compositeView.material.textures[5] = this.blurList[4].qr.rendererPassState.renderTargets[0]; - GPUContext.renderToViewQuad(view, this.compositeView, command, colorTexture); + this.compositeView.renderToViewQuad(view, this.compositeView, command, colorTexture); } } // GPUContext.endCommandEncoder(command); diff --git a/src/engine/gfx/renderJob/post/OutlinePost.ts b/src/gfx/renderJob/post/OutlinePost.ts similarity index 96% rename from src/engine/gfx/renderJob/post/OutlinePost.ts rename to src/gfx/renderJob/post/OutlinePost.ts index 5a914537..92c73700 100644 --- a/src/engine/gfx/renderJob/post/OutlinePost.ts +++ b/src/gfx/renderJob/post/OutlinePost.ts @@ -85,11 +85,9 @@ export class OutlinePostData { } } -export let outlinePostData: OutlinePostData = new OutlinePostData(); - /** * post effect out line - * OutlinePostManager, + * OutlinePostManager, * ``` * //setting * let cfg = {@link Engine3D.setting.render.postProcessing.outline}; @@ -141,8 +139,11 @@ export class OutlinePost extends PostBase { oldOutlineColor: StorageGPUBuffer; rtFrame: RTFrame; + outlineData: OutlinePostData; + constructor() { super(); + this.outlineData = new OutlinePostData(); } /** @@ -280,12 +281,12 @@ export class OutlinePost extends PostBase { this.weightBuffer = new StorageGPUBuffer(this.lowTexSize.x * this.lowTexSize.y * 4, GPUBufferUsage.COPY_SRC); this.oldOutlineColor = new StorageGPUBuffer(this.lowTexSize.x * this.lowTexSize.y * 4, GPUBufferUsage.COPY_SRC); - this.slotsArray = new Float32Array(outlinePostData.SlotCount * 4); + this.slotsArray = new Float32Array(this.outlineData.SlotCount * 4); this.slotsBuffer = new StorageGPUBuffer(this.slotsArray.length); this.slotsBuffer.setFloat32Array('slotsArray', this.slotsArray); this.slotsBuffer.apply(); - this.entitiesArray = new Float32Array(outlinePostData.SlotCount * outlinePostData.MaxEntities); + this.entitiesArray = new Float32Array(this.outlineData.SlotCount * this.outlineData.MaxEntities); this.entitiesBuffer = new StorageGPUBuffer(this.entitiesArray.length); this.entitiesBuffer.setFloat32Array('entitiesArray', this.entitiesArray); this.slotsBuffer.apply(); @@ -296,10 +297,10 @@ export class OutlinePost extends PostBase { private fetchData: { dirty: boolean; slots: OutlinePostSlot[] }; private fetchOutlineData(): void { - outlinePostData.fetchData(this.fetchData); + this.outlineData.fetchData(this.fetchData); if (this.fetchData.dirty) { - let slotCount = outlinePostData.SlotCount; - let maxEntities = outlinePostData.MaxEntities; + let slotCount = this.outlineData.SlotCount; + let maxEntities = this.outlineData.MaxEntities; for (let i = 0; i < slotCount; i++) { let offset = 4 * i; let slot = this.fetchData.slots[i]; diff --git a/src/engine/gfx/renderJob/post/PostBase.ts b/src/gfx/renderJob/post/PostBase.ts similarity index 96% rename from src/engine/gfx/renderJob/post/PostBase.ts rename to src/gfx/renderJob/post/PostBase.ts index 7b66d20c..0ba36633 100644 --- a/src/engine/gfx/renderJob/post/PostBase.ts +++ b/src/gfx/renderJob/post/PostBase.ts @@ -70,9 +70,9 @@ export class PostBase { */ public render(view: View3D, command: GPUCommandEncoder) { this.compute(view); - this.rtViewQuad.forEach((v, k) => { + this.rtViewQuad.forEach((viewQuad, k) => { let lastTexture = GPUContext.lastRenderPassState.getLastRenderTexture(); - GPUContext.renderToViewQuad(view, v, command, lastTexture); + viewQuad.renderToViewQuad(view, viewQuad, command, lastTexture); }); } diff --git a/src/engine/gfx/renderJob/post/SSRPost.ts b/src/gfx/renderJob/post/SSRPost.ts similarity index 98% rename from src/engine/gfx/renderJob/post/SSRPost.ts rename to src/gfx/renderJob/post/SSRPost.ts index 1cda19e1..af4e84ac 100644 --- a/src/engine/gfx/renderJob/post/SSRPost.ts +++ b/src/gfx/renderJob/post/SSRPost.ts @@ -23,6 +23,7 @@ import { RTFrame } from '../frame/RTFrame'; import { GBufferFrame } from '../frame/GBufferFrame'; import { SSRSetting } from '../../../setting/post/SSRSetting'; import { View3D } from '../../../core/View3D'; +import { SkyRenderer } from '../../../components/renderer/SkyRenderer'; /** * Screen space reflection * ``` @@ -170,7 +171,9 @@ export class SSRPost extends PostBase { this.SSR_RayTraceCompute.setSamplerTexture("zBufferTexture", rtFrame.getPositionMap()); this.SSR_RayTraceCompute.setSamplerTexture(RTResourceConfig.normalBufferTex_NAME, rtFrame.attachments[2]); this.SSR_RayTraceCompute.setSamplerTexture(RTResourceConfig.materialBufferTex_NAME, rtFrame.attachments[3]); - this.SSR_RayTraceCompute.setSamplerTexture(`prefilterMap`, EntityCollect.instance.sky.map); + + if (EntityCollect.instance.sky instanceof SkyRenderer) + this.SSR_RayTraceCompute.setSamplerTexture(`prefilterMap`, EntityCollect.instance.sky.map); this.SSR_RayTraceCompute.workerSizeX = Math.ceil(this.isRetTexture.width / 8); this.SSR_RayTraceCompute.workerSizeY = Math.ceil(this.isRetTexture.height / 8); diff --git a/src/engine/gfx/renderJob/post/TAAPost.ts b/src/gfx/renderJob/post/TAAPost.ts similarity index 100% rename from src/engine/gfx/renderJob/post/TAAPost.ts rename to src/gfx/renderJob/post/TAAPost.ts diff --git a/src/index.ts b/src/index.ts index ef2d8dd8..ecf6a3fb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,377 @@ -let foo = 1 -export { foo } \ No newline at end of file +export * from "./Engine3D" +export * from "./assets/Res" +export * from "./assets/shader/ShaderLib" +export * from "./assets/shader/anim/SkeletonAnimation_shader" +export * from "./assets/shader/compute/BlurEffectCreator_compute" +export * from "./assets/shader/core/pass/CastShadowPass_wgsl" +export * from "./assets/shader/core/pass/ZPassShader_vs" +export * from "./assets/shader/core/struct/LightStructFrag" +export * from "./assets/shader/core/struct/VertexAttributes" +export * from "./assets/shader/glsl/Quad_glsl" +export * from "./assets/shader/glsl/Sky_glsl" +export * from "./assets/shader/glsl/post/LUT_glsl" +export * from "./assets/shader/lighting/LightingFunction_frag" +export * from "./assets/shader/lighting/UnLit_frag" +export * from "./assets/shader/materials/ColorLitShader" +export * from "./assets/shader/materials/Lambert_shader" +export * from "./assets/shader/materials/PavementShader" +export * from "./assets/shader/materials/PointShadowDebug" +export * from "./assets/shader/materials/program/ClusterDebug_frag" +export * from "./assets/shader/materials/sky/AtmosphericScatteringSky_shader" +export * from "./assets/shader/materials/sky/CubeSky_Shader" +export * from "./assets/shader/materials/uniforms/MaterialUniform" +export * from "./assets/shader/materials/uniforms/PhysicMaterialUniform_frag" +export * from "./assets/shader/materials/uniforms/UnLitMaterialUniform_frag" +export * from "./assets/shader/materials/uniforms/VideoUniform_frag" +export * from "./assets/shader/math/MathShader" +export * from "./assets/shader/post/Bloom_shader" +export * from "./assets/shader/post/GlobalFog_shader" +export * from "./assets/shader/quad/Quad_shader" +export * from "./components/AtmosphericComponent" +export * from "./components/BillboardComponent" +export * from "./components/ColliderComponent" +export * from "./components/ComponentBase" +export * from "./components/SkeletonAnimationComponent" +export * from "./components/Transform" +export * from "./components/anim/OAnimationEvent" +export * from "./components/anim/curveAnim/curveAnim/AnimationMonitor" +export * from "./components/anim/curveAnim/curveAnim/AttributeAnimCurve" +export * from "./components/anim/curveAnim/curveAnim/PropertyAnimClip" +export * from "./components/anim/curveAnim/curveAnim/PropertyAnimation" +export * from "./components/anim/curveAnim/curveAnim/PropertyAnimationEvent" +export * from "./components/anim/curveAnim/curveAnim/PropertyHelp" +export * from "./components/anim/morphAnim/MorphTargetBlender" +export * from "./components/anim/morphAnim/MorphTargetData" +export * from "./components/anim/morphAnim/MorphTargetFrame" +export * from "./components/anim/morphAnim/MorphTargetKey" +export * from "./components/anim/morphAnim/MorphTarget_shader" +export * from "./components/anim/skeletonAnim/Joint" +export * from "./components/anim/skeletonAnim/JointPose" +export * from "./components/anim/skeletonAnim/Skeleton" +export * from "./components/anim/skeletonAnim/SkeletonAnimationClip" +export * from "./components/anim/skeletonAnim/SkeletonAnimationClipState" +export * from "./components/anim/skeletonAnim/SkeletonAnimationCompute" +export * from "./components/anim/skeletonAnim/SkeletonPose" +export * from "./components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs" +export * from "./components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs" +export * from "./components/anim/skeletonAnim/shader/compute_skeleton_blend" +export * from "./components/anim/skeletonAnim/shader/compute_skeleton_transform" +export * from "./components/audio/AudioListener" +export * from "./components/audio/PositionAudio" +export * from "./components/audio/StaticAudio" +export * from "./components/controller/CameraControllerBase" +export * from "./components/controller/FirstPersonCameraController" +export * from "./components/controller/FlyCameraController" +export * from "./components/controller/HoverCameraController" +export * from "./components/controller/OrbitController" +export * from "./components/controller/ThirdPersonCameraController" +export * from "./components/lights/DirectLight" +export * from "./components/lights/GILighting" +export * from "./components/lights/IESProfiles" +export * from "./components/lights/LightBase" +export * from "./components/lights/LightData" +export * from "./components/lights/PointLight" +export * from "./components/lights/SpotLight" +export * from "./components/post/PostProcessingComponent" +export * from "./components/renderer/InstanceDrawComponent" +export * from "./components/renderer/MaterialComponent" +export * from "./components/renderer/MeshComponent" +export * from "./components/renderer/MeshRenderer" +export * from "./components/renderer/RenderNode" +export * from "./components/renderer/SkinnedMeshRenderer" +export * from "./components/renderer/SkyRenderer" +export * from "./components/shape/BoxColliderShape" +export * from "./components/shape/CapsuleColliderShape" +export * from "./components/shape/ColliderShape" +export * from "./components/shape/MeshColliderShape" +export * from "./components/shape/SphereColliderShape" +export * from "./core/Camera3D" +export * from "./core/CameraType" +export * from "./core/CubeCamera" +export * from "./core/PointShadowCubeCamera" +export * from "./core/Scene3D" +export * from "./core/View3D" +export * from "./core/ViewQuad" +export * from "./core/bound/BoundingBox" +export * from "./core/bound/BoundingSphere" +export * from "./core/bound/Frustum" +export * from "./core/bound/IBound" +export * from "./core/entities/Entity" +export * from "./core/entities/InstancedMesh" +export * from "./core/entities/Object3D" +export * from "./core/geometry/GeometryBase" +export * from "./core/geometry/GeometryIndicesBuffer" +export * from "./core/geometry/GeometryVertexBuffer" +export * from "./core/geometry/GeometryVertexType" +export * from "./core/geometry/VertexAttribute" +export * from "./core/geometry/VertexAttributeData" +export * from "./core/geometry/VertexAttributeName" +export * from "./core/geometry/VertexAttributeSize" +export * from "./core/geometry/VertexAttributeStride" +export * from "./core/geometry/VertexFormat" +export * from "./core/pool/ObjectPool" +export * from "./core/pool/memory/MatrixDO" +export * from "./core/pool/memory/MemoryDO" +export * from "./core/pool/memory/MemoryInfo" +export * from "./core/tree/kdTree/IKDTreeUserData" +export * from "./core/tree/kdTree/KDTreeEntity" +export * from "./core/tree/kdTree/KDTreeNode" +export * from "./core/tree/kdTree/KDTreeSpace" +export * from "./event/CEvent" +export * from "./event/CEventDispatcher" +export * from "./event/CEventListener" +export * from "./event/CResizeEvent" +export * from "./event/KeyCode" +export * from "./event/MouseCode" +export * from "./event/eventConst/KeyEvent" +export * from "./event/eventConst/LoaderEvent" +export * from "./event/eventConst/Object3DEvent" +export * from "./event/eventConst/PointerEvent3D" +export * from "./event/eventConst/UIEvent" +export * from "./gfx/generate/BrdfLUTGenerate" +export * from "./gfx/generate/PassGenerate" +export * from "./gfx/generate/convert/BlurEffectCreator" +export * from "./gfx/generate/convert/ErpImage2CubeMap" +export * from "./gfx/generate/convert/IBLEnvMapCreator" +export * from "./gfx/generate/convert/MergeRGBACreator" +export * from "./gfx/generate/convert/TextureCubeStdCreator" +export * from "./gfx/generate/convert/TextureCubeUtils" +export * from "./gfx/graphics/webGpu/CanvasConfig" +export * from "./gfx/graphics/webGpu/Context3D" +export * from "./gfx/graphics/webGpu/WebGPUConst" +export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout" +export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/groups/LightEntries" +export * from "./gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferBase" +export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferType" +export * from "./gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/StorageGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/UniformGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/VertexGPUBuffer" +export * from "./gfx/graphics/webGpu/core/texture/ITexture" +export * from "./gfx/graphics/webGpu/core/texture/Texture" +export * from "./gfx/graphics/webGpu/core/texture/TextureCube" +export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapCompute" +export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapGenerator" +export * from "./gfx/graphics/webGpu/core/uniforms/UniformNode" +export * from "./gfx/graphics/webGpu/descriptor/RTDescriptor" +export * from "./gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator" +export * from "./gfx/graphics/webGpu/shader/ComputeShader" +export * from "./gfx/graphics/webGpu/shader/RenderShader" +export * from "./gfx/graphics/webGpu/shader/ShaderBase" +export * from "./gfx/graphics/webGpu/shader/ShaderStage" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexer" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexerToken" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLPreprocessor" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLSyntax" +export * from "./gfx/graphics/webGpu/shader/converter/Reader" +export * from "./gfx/graphics/webGpu/shader/converter/ShaderConverter" +export * from "./gfx/graphics/webGpu/shader/converter/StatementNode" +export * from "./gfx/graphics/webGpu/shader/converter/WGSLTranslator" +export * from "./gfx/graphics/webGpu/shader/util/MorePassParser" +export * from "./gfx/graphics/webGpu/shader/util/Preprocessor" +export * from "./gfx/graphics/webGpu/shader/util/ShaderUtil" +export * from "./gfx/graphics/webGpu/shader/value/ConstValue" +export * from "./gfx/graphics/webGpu/shader/value/DefineValue" +export * from "./gfx/graphics/webGpu/shader/value/ShaderReflectionInfo" +export * from "./gfx/graphics/webGpu/shader/value/ShaderState" +export * from "./gfx/graphics/webGpu/shader/value/ShaderValue" +export * from "./gfx/graphics/webGpu/shader/value/UniformValue" +export * from "./gfx/renderJob/GPUContext" +export * from "./gfx/renderJob/collect/CollectInfo" +export * from "./gfx/renderJob/collect/EntityBatchCollect" +export * from "./gfx/renderJob/collect/EntityCollect" +export * from "./gfx/renderJob/collect/RenderGroup" +export * from "./gfx/renderJob/collect/ShadowLightsCollect" +export * from "./gfx/renderJob/config/RTResourceConfig" +export * from "./gfx/renderJob/config/RenderLayer" +export * from "./gfx/renderJob/frame/GBufferFrame" +export * from "./gfx/renderJob/frame/ProbeGBufferFrame" +export * from "./gfx/renderJob/frame/RTFrame" +export * from "./gfx/renderJob/frame/RTResourceMap" +export * from "./gfx/renderJob/jobs/ForwardRenderJob" +export * from "./gfx/renderJob/jobs/RenderMap" +export * from "./gfx/renderJob/jobs/RendererJob" +export * from "./gfx/renderJob/occlusion/OcclusionSystem" +export * from "./gfx/renderJob/passRenderer/RenderContext" +export * from "./gfx/renderJob/passRenderer/RendererBase" +export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingRender" +export * from "./gfx/renderJob/passRenderer/color/ColorPassRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DRender" +export * from "./gfx/renderJob/passRenderer/graphic/GraphicConfig" +export * from "./gfx/renderJob/passRenderer/graphic/Graphics3DShape" +export * from "./gfx/renderJob/passRenderer/post/PostRenderer" +export * from "./gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer" +export * from "./gfx/renderJob/passRenderer/preDepth/ZCullingCompute" +export * from "./gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer" +export * from "./gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer" +export * from "./gfx/renderJob/passRenderer/state/RendererMask" +export * from "./gfx/renderJob/passRenderer/state/RendererPassState" +export * from "./gfx/renderJob/passRenderer/state/RendererType" +export * from "./gfx/renderJob/post/DepthOfFieldPost" +export * from "./gfx/renderJob/post/FXAAPost" +export * from "./gfx/renderJob/post/GTAOPost" +export * from "./gfx/renderJob/post/GlobalFog" +export * from "./gfx/renderJob/post/HDRBloomPost" +export * from "./gfx/renderJob/post/OutlinePost" +export * from "./gfx/renderJob/post/PostBase" +export * from "./gfx/renderJob/post/SSRPost" +export * from "./gfx/renderJob/post/TAAPost" +export * from "./io/InputSystem" +export * from "./io/PickFire" +export * from "./io/PickResult" +export * from "./io/RayCastMeshDetail" +export * from "./io/TouchData" +export * from "./io/picker/PickCompute" +export * from "./loader/FileLoader" +export * from "./loader/LoaderBase" +export * from "./loader/LoaderData" +export * from "./loader/LoaderFunctions" +export * from "./loader/LoaderManager" +export * from "./loader/parser/B3DMParser" +export * from "./loader/parser/I3DMParser" +export * from "./loader/parser/OBJParser" +export * from "./loader/parser/ParserBase" +export * from "./loader/parser/RGBEParser" +export * from "./loader/parser/b3dm/B3DMLoader" +export * from "./loader/parser/b3dm/B3DMLoaderBase" +export * from "./loader/parser/b3dm/FeatureTable" +export * from "./loader/parser/b3dm/arrayToString" +export * from "./loader/parser/b3dm/readMagicBytes" +export * from "./loader/parser/gltf/GLBParser" +export * from "./loader/parser/gltf/GLTFInfo" +export * from "./loader/parser/gltf/GLTFParser" +export * from "./loader/parser/gltf/GLTFSubParser" +export * from "./loader/parser/gltf/GLTFSubParserCamera" +export * from "./loader/parser/gltf/GLTFSubParserConverter" +export * from "./loader/parser/gltf/GLTFSubParserMaterial" +export * from "./loader/parser/gltf/GLTFSubParserMesh" +export * from "./loader/parser/gltf/GLTFSubParserSkeleton" +export * from "./loader/parser/gltf/GLTFSubParserSkin" +export * from "./loader/parser/gltf/TypeArray" +export * from "./loader/parser/gltf/extends/KHR_draco_mesh_compression" +export * from "./loader/parser/gltf/extends/KHR_lights_punctual" +export * from "./loader/parser/gltf/extends/KHR_materials_clearcoat" +export * from "./loader/parser/gltf/extends/KHR_materials_emissive_strength" +export * from "./loader/parser/gltf/extends/KHR_materials_ior" +export * from "./loader/parser/gltf/extends/KHR_materials_sheen" +export * from "./loader/parser/gltf/extends/KHR_materials_specular" +export * from "./loader/parser/gltf/extends/KHR_materials_transmission" +export * from "./loader/parser/gltf/extends/KHR_materials_unlit" +export * from "./loader/parser/gltf/extends/KHR_materials_variants" +export * from "./loader/parser/gltf/extends/KHR_materials_volume" +export * from "./loader/parser/gltf/extends/KHR_mesh_quantization" +export * from "./loader/parser/gltf/extends/KHR_texture_basisu" +export * from "./loader/parser/gltf/extends/KHR_texture_transform" +export * from "./loader/parser/i3dm/I3DMLoader" +export * from "./loader/parser/i3dm/I3DMLoaderBase" +export * from "./loader/parser/tileRenderer/TileSet" +export * from "./loader/parser/tileRenderer/TilesRenderer" +export * from "./materials/BlendMode" +export * from "./materials/ColorLitMaterial" +export * from "./materials/GlassMaterial" +export * from "./materials/LambertMaterial" +export * from "./materials/LitMaterial" +export * from "./materials/MaterialBase" +export * from "./materials/MaterialPass" +export * from "./materials/MaterialRegister" +export * from "./materials/PavementMaterial" +export * from "./materials/PhysicMaterial" +export * from "./materials/PointMaterial" +export * from "./materials/SkyMaterial" +export * from "./materials/UnLitMaterial" +export * from "./materials/effectPass/OutLinePass" +export * from "./materials/multiPass/CastPointShadowMaterialPass" +export * from "./materials/multiPass/CastShadowMaterialPass" +export * from "./materials/multiPass/DepthMaterialPass" +export * from "./materials/multiPass/GBufferPass" +export * from "./materials/multiPass/SkyGBufferPass" +export * from "./math/AnimationCurve" +export * from "./math/Bezier2D" +export * from "./math/Bezier3D" +export * from "./math/Color" +export * from "./math/HaltonSeq" +export * from "./math/Line" +export * from "./math/MathUtil" +export * from "./math/Matrix3" +export * from "./math/Matrix4" +export * from "./math/Orientation3D" +export * from "./math/ParticleMath" +export * from "./math/ParticleSystemCurves" +export * from "./math/Plane" +export * from "./math/PolynomialCurve" +export * from "./math/Polynomials" +export * from "./math/Quaternion" +export * from "./math/Rand" +export * from "./math/Random" +export * from "./math/Ray" +export * from "./math/Rect" +export * from "./math/TimeInterpolator" +export * from "./math/Triangle" +export * from "./math/UV" +export * from "./math/Vector2" +export * from "./math/Vector3" +export * from "./math/Vector4" +export * from "./setting/EngineSetting" +export * from "./setting/GlobalIlluminationSetting" +export * from "./setting/LightSetting" +export * from "./setting/MaterialSetting" +export * from "./setting/OcclusionQuerySetting" +export * from "./setting/PickSetting" +export * from "./setting/RenderSetting" +export * from "./setting/ShadowSetting" +export * from "./setting/SkySetting" +export * from "./setting/post/BloomSetting" +export * from "./setting/post/DepthOfViewSetting" +export * from "./setting/post/GTAOSetting" +export * from "./setting/post/GlobalFogSetting" +export * from "./setting/post/OutlineSetting" +export * from "./setting/post/SSRSetting" +export * from "./setting/post/TAASetting" +export * from "./shape/BoxGeometry" +export * from "./shape/CylinderGeometry" +export * from "./shape/PlaneGeometry" +export * from "./shape/SphereGeometry" +export * from "./shape/TorusGeometry" +export * from "./textures/AtmosphericScatteringSky" +export * from "./textures/BitmapTexture2D" +export * from "./textures/BitmapTexture2DArray" +export * from "./textures/BitmapTextureCube" +export * from "./textures/Depth2DTextureArray" +export * from "./textures/DepthCubeArrayTexture" +export * from "./textures/DepthCubeTexture" +export * from "./textures/Float16ArrayTexture" +export * from "./textures/Float32ArrayTexture" +export * from "./textures/HDRTexture" +export * from "./textures/HDRTextureCube" +export * from "./textures/LDRTextureCube" +export * from "./textures/SolidColorSky" +export * from "./textures/Uint16Texture" +export * from "./textures/Uint8ArrayTexture" +export * from "./textures/VirtualTexture" +export * from "./util/AxisObject" +export * from "./util/BytesStream" +export * from "./util/CameraUtil" +export * from "./util/Convert" +export * from "./util/GeometryUtil" +export * from "./util/Global" +export * from "./util/KelvinUtil" +export * from "./util/Object3DUtil" +export * from "./util/ProfilerUtil" +export * from "./util/StringUtil" +export * from "./util/Time" +export * from "./util/Vector3Ex" +export * from "./util/ZSorterUtil" +export * from "./util/struct/Struct" +export * from "./util/struct/StructValue" +export * from "./util/struct/Vector3Struct" diff --git a/src/engine/io/InputSystem.ts b/src/io/InputSystem.ts similarity index 99% rename from src/engine/io/InputSystem.ts rename to src/io/InputSystem.ts index 74518cf6..9b9fcd15 100644 --- a/src/engine/io/InputSystem.ts +++ b/src/io/InputSystem.ts @@ -447,7 +447,7 @@ export class InputSystem extends CEventDispatcher { * @param startY {Number} * @param endX {Number} * @param endY {Number} - * @returns result {number} 1:up,2:down,3:left,4:right,0:not move + * @returns result {number} 1: up, 2: down, 3: left, 4: right, 0: not move */ public GetSlideDirection(startX: number, startY: number, endX: number, endY: number): number { var dy = startY - endY; diff --git a/src/engine/io/PickFire.ts b/src/io/PickFire.ts similarity index 100% rename from src/engine/io/PickFire.ts rename to src/io/PickFire.ts diff --git a/src/engine/io/PickResult.ts b/src/io/PickResult.ts similarity index 100% rename from src/engine/io/PickResult.ts rename to src/io/PickResult.ts diff --git a/src/engine/io/RayCastMeshDetail.ts b/src/io/RayCastMeshDetail.ts similarity index 100% rename from src/engine/io/RayCastMeshDetail.ts rename to src/io/RayCastMeshDetail.ts diff --git a/src/engine/io/TouchData.ts b/src/io/TouchData.ts similarity index 98% rename from src/engine/io/TouchData.ts rename to src/io/TouchData.ts index 4936a3ce..3aa23d0f 100644 --- a/src/engine/io/TouchData.ts +++ b/src/io/TouchData.ts @@ -1,5 +1,5 @@ /** - * the param of touch event。 + * the param of touch event. * Save as the basic data for touch events in touch event. see InputSystem. * @internal * @group IO diff --git a/src/engine/io/picker/PickCompute.ts b/src/io/picker/PickCompute.ts similarity index 100% rename from src/engine/io/picker/PickCompute.ts rename to src/io/picker/PickCompute.ts diff --git a/src/engine/loader/FileLoader.ts b/src/loader/FileLoader.ts similarity index 100% rename from src/engine/loader/FileLoader.ts rename to src/loader/FileLoader.ts diff --git a/src/engine/loader/LoaderBase.ts b/src/loader/LoaderBase.ts similarity index 100% rename from src/engine/loader/LoaderBase.ts rename to src/loader/LoaderBase.ts diff --git a/src/engine/loader/LoaderData.ts b/src/loader/LoaderData.ts similarity index 100% rename from src/engine/loader/LoaderData.ts rename to src/loader/LoaderData.ts diff --git a/src/engine/loader/LoaderFunctions.ts b/src/loader/LoaderFunctions.ts similarity index 100% rename from src/engine/loader/LoaderFunctions.ts rename to src/loader/LoaderFunctions.ts diff --git a/src/engine/loader/LoaderManager.ts b/src/loader/LoaderManager.ts similarity index 100% rename from src/engine/loader/LoaderManager.ts rename to src/loader/LoaderManager.ts diff --git a/src/engine/loader/parser/B3DMParser.ts b/src/loader/parser/B3DMParser.ts similarity index 100% rename from src/engine/loader/parser/B3DMParser.ts rename to src/loader/parser/B3DMParser.ts diff --git a/src/engine/loader/parser/I3DMParser.ts b/src/loader/parser/I3DMParser.ts similarity index 100% rename from src/engine/loader/parser/I3DMParser.ts rename to src/loader/parser/I3DMParser.ts diff --git a/src/engine/loader/parser/OBJParser.ts b/src/loader/parser/OBJParser.ts similarity index 99% rename from src/engine/loader/parser/OBJParser.ts rename to src/loader/parser/OBJParser.ts index c5241277..2510e3f4 100644 --- a/src/engine/loader/parser/OBJParser.ts +++ b/src/loader/parser/OBJParser.ts @@ -8,6 +8,7 @@ import { StringUtil } from '../../util/StringUtil'; import { FileLoader } from '../FileLoader'; import { ParserBase } from './ParserBase'; + type MatData = { name?: string, Kd?: string[], diff --git a/src/engine/loader/parser/ParserBase.ts b/src/loader/parser/ParserBase.ts similarity index 100% rename from src/engine/loader/parser/ParserBase.ts rename to src/loader/parser/ParserBase.ts diff --git a/src/engine/loader/parser/RGBEParser.ts b/src/loader/parser/RGBEParser.ts similarity index 100% rename from src/engine/loader/parser/RGBEParser.ts rename to src/loader/parser/RGBEParser.ts diff --git a/src/engine/loader/parser/b3dm/B3DMLoader.ts b/src/loader/parser/b3dm/B3DMLoader.ts similarity index 94% rename from src/engine/loader/parser/b3dm/B3DMLoader.ts rename to src/loader/parser/b3dm/B3DMLoader.ts index 3ccdff43..5f780367 100644 --- a/src/engine/loader/parser/b3dm/B3DMLoader.ts +++ b/src/loader/parser/b3dm/B3DMLoader.ts @@ -1,5 +1,5 @@ -import { B3DMLoaderBase } from "./B3DMLoaderBase"; -import { B3DMParseUtil } from "../B3DMParser"; +import {B3DMLoaderBase} from "./B3DMLoaderBase"; +import {B3DMParseUtil} from "../B3DMParser"; import { Transform } from "../../../components/Transform"; import { Matrix4 } from "../../../math/Matrix4"; import { Orientation3D } from "../../../math/Orientation3D"; @@ -24,7 +24,7 @@ export class B3DMLoader extends B3DMLoaderBase { let model = await glbLoader.parseBinary(this.gltfBuffer); - let { batchTable, featureTable } = b3dm; + let {batchTable, featureTable} = b3dm; const rtcCenter = featureTable.getData('RTC_CENTER'); if (rtcCenter) { diff --git a/src/engine/loader/parser/b3dm/B3DMLoaderBase.ts b/src/loader/parser/b3dm/B3DMLoaderBase.ts similarity index 100% rename from src/engine/loader/parser/b3dm/B3DMLoaderBase.ts rename to src/loader/parser/b3dm/B3DMLoaderBase.ts diff --git a/src/engine/loader/parser/b3dm/FeatureTable.ts b/src/loader/parser/b3dm/FeatureTable.ts similarity index 100% rename from src/engine/loader/parser/b3dm/FeatureTable.ts rename to src/loader/parser/b3dm/FeatureTable.ts diff --git a/src/engine/loader/parser/b3dm/arrayToString.ts b/src/loader/parser/b3dm/arrayToString.ts similarity index 100% rename from src/engine/loader/parser/b3dm/arrayToString.ts rename to src/loader/parser/b3dm/arrayToString.ts diff --git a/src/engine/loader/parser/b3dm/readMagicBytes.ts b/src/loader/parser/b3dm/readMagicBytes.ts similarity index 100% rename from src/engine/loader/parser/b3dm/readMagicBytes.ts rename to src/loader/parser/b3dm/readMagicBytes.ts diff --git a/src/engine/loader/parser/gltf/GLBParser.ts b/src/loader/parser/gltf/GLBParser.ts similarity index 92% rename from src/engine/loader/parser/gltf/GLBParser.ts rename to src/loader/parser/gltf/GLBParser.ts index de629e4e..5de78620 100644 --- a/src/engine/loader/parser/gltf/GLBParser.ts +++ b/src/loader/parser/gltf/GLBParser.ts @@ -91,10 +91,10 @@ export class GLBParser extends ParserBase { const buffer = this._gltf.buffers[bufferView.buffer]; let dataBuffer = new Uint8Array(buffer.dbuffer, bufferView.byteOffset, bufferView.byteLength); let imgData = new Blob([dataBuffer], { type: image.mimeType }); - let dTexture = new BitmapTexture2D(); - await dTexture.loadFromBlob(imgData); - dTexture.name = image.name; - this._gltf.resources[image.name] = dTexture; + let dtexture = new BitmapTexture2D(); + await dtexture.loadFromBlob(imgData); + dtexture.name = image.name; + this._gltf.resources[image.name] = dtexture; } } @@ -123,10 +123,10 @@ export class GLBParser extends ParserBase { const buffer = this._gltf.buffers[bufferView.buffer]; let dataBuffer = new Uint8Array(buffer.dbuffer, bufferView.byteOffset, bufferView.byteLength); let imgData = new Blob([dataBuffer], { type: image.mimeType }); - let dTexture = new BitmapTexture2D(); - await dTexture.loadFromBlob(imgData); - dTexture.name = image.name; - this._gltf.resources[image.name] = dTexture; + let dtexture = new BitmapTexture2D(); + await dtexture.loadFromBlob(imgData); + dtexture.name = image.name; + this._gltf.resources[image.name] = dtexture; } } diff --git a/src/engine/loader/parser/gltf/GLTFInfo.ts b/src/loader/parser/gltf/GLTFInfo.ts similarity index 97% rename from src/engine/loader/parser/gltf/GLTFInfo.ts rename to src/loader/parser/gltf/GLTFInfo.ts index 0006e695..72801b98 100644 --- a/src/engine/loader/parser/gltf/GLTFInfo.ts +++ b/src/loader/parser/gltf/GLTFInfo.ts @@ -46,7 +46,7 @@ export class GLTF_Info { sampler: number; source: number; name: string; - dTexture: any; + dtexture: any; }[]; cameras: any; skins: any; @@ -55,8 +55,8 @@ export class GLTF_Info { uri: string; name: string; isParsed: any; - dSampler: any; - dImage: any; + dsampler: any; + dimage: any; mimeType: string; bufferView: number; }[]; diff --git a/src/engine/loader/parser/gltf/GLTFParser.ts b/src/loader/parser/gltf/GLTFParser.ts similarity index 76% rename from src/engine/loader/parser/gltf/GLTFParser.ts rename to src/loader/parser/gltf/GLTFParser.ts index 49340271..2fdff3ff 100644 --- a/src/engine/loader/parser/gltf/GLTFParser.ts +++ b/src/loader/parser/gltf/GLTFParser.ts @@ -26,7 +26,7 @@ export class GLTFParser extends ParserBase { //await this.load_gltf_textures(); let subParser = new GLTFSubParser(); let nodes = await subParser.parse(this.initUrl, this._gltf, this._gltf.scene); - subParser.destroy(); + subParser.destory(); subParser = null if (nodes) { this.data = nodes.rootNode; @@ -48,45 +48,7 @@ export class GLTFParser extends ParserBase { throw new Error('Method not implemented.'); } - public static readonly GLTF_NODE_INDEX_PROPERTY: 'GLTF_NODE_INDEX'; - public static readonly BASE_COLOR_UNIFORM = 'u_baseColorFactor'; - - public static readonly BASE_COLOR_TEXTURE_UNIFORM = 'u_baseColorSampler'; - - public static readonly METALROUGHNESS_UNIFORM = 'u_metallicRoughnessValues'; - - public static readonly METALROUGHNESS_TEXTURE_UNIFORM = 'u_metallicRoughnessSampler'; - - public static readonly NORMAL_TEXTURE_UNIFORM = 'u_normalSampler'; - - public static readonly NORMAL_SCALE_UNIFORM = 'u_normalScale'; - - public static readonly EMISSIVE_TEXTURE_UNIFORM = 'u_emissiveSampler'; - - public static readonly EMISSIVE_FACTOR_UNIFORM = 'u_emissiveFactor'; - - public static readonly OCCLUSION_TEXTURE_UNIFORM = 'u_occlusionSampler'; - - public static readonly OCCLUSION_FACTOR_UNIFORM = 'u_occlusionFactor'; - - public static readonly MAX_MORPH_TARGETS = 8; - - public static readonly MORPH_POSITION_PREFIX = 'a_morphPositions_'; - - public static readonly MORPH_NORMAL_PREFIX = 'a_morphNormals_'; - - public static readonly MORPH_TANGENT_PREFIX = 'a_morphTangents_'; - - public static readonly MORPH_WEIGHT_UNIFORM = 'u_morphWeights'; - - public static readonly SCENE_ROOT_SKELETON = 'SCENE_ROOT'; - - public static readonly IDENTITY_INVERSE_BIND_MATRICES = 'IDENTITY_IBM'; - - public static readonly JOINT_MATRICES_UNIFORM = 'u_jointMatrix'; - - public static readonly ALPHA_CUTOFF_UNIFORM = 'u_alphaCutoff'; private static _counter = 0; public static getMeshNameCounter() { @@ -135,15 +97,15 @@ export class GLTFParser extends ParserBase { return `MORPH_TARGET_NUM ${targetNum}`; } - public static getMorphTargetPositionDefine() { + public static getMorphtargetPositionDefine() { return 'HAS_MORPH_POSITION'; } - public static getMorphTargetNormalDefine() { + public static getMorphtargetNormalDefine() { return 'HAS_MORPH_NORMAL'; } - public static getMorphTargetTangentDefine() { + public static getMorphtargetTangentDefine() { return 'HAS_MORPH_TANGENT'; } diff --git a/src/engine/loader/parser/gltf/GLTFSubParser.ts b/src/loader/parser/gltf/GLTFSubParser.ts similarity index 57% rename from src/engine/loader/parser/gltf/GLTFSubParser.ts rename to src/loader/parser/gltf/GLTFSubParser.ts index 9a945f04..18f48dda 100644 --- a/src/engine/loader/parser/gltf/GLTFSubParser.ts +++ b/src/loader/parser/gltf/GLTFSubParser.ts @@ -1,33 +1,10 @@ import { Skeleton } from '../../../components/anim/skeletonAnim/Skeleton'; -import { SkeletonAnimationComponent } from '../../../components/SkeletonAnimationComponent'; -import { SkeletonAnimationClip } from '../../../components/anim/skeletonAnim/SkeletonAnimationClip'; -import { DirectLight } from '../../../components/lights/DirectLight'; -import { PointLight } from '../../../components/lights/PointLight'; -import { SpotLight } from '../../../components/lights/SpotLight'; -import { MeshRenderer } from '../../../components/renderer/MeshRenderer'; -import { SkinnedMeshRenderer } from '../../../components/renderer/SkinnedMeshRenderer'; import { Object3D } from '../../../core/entities/Object3D'; -import { GeometryBase } from '../../../core/geometry/GeometryBase'; -import { VertexAttributeName } from '../../../core/geometry/VertexAttributeName'; -import { Engine3D } from '../../../Engine3D'; -import { BlendMode } from '../../../materials/BlendMode'; -import { MaterialBase } from '../../../materials/MaterialBase'; -import { PhysicMaterial } from '../../../materials/PhysicMaterial'; -import { Color } from '../../../math/Color'; -import { RADIANS_TO_DEGREES } from '../../../math/MathUtil'; -import { Quaternion } from '../../../math/Quaternion'; -import { defaultRes } from '../../../textures/DefaultRes'; -import { UUID } from '../../../util/Global'; import { StringUtil } from '../../../util/StringUtil'; -import { KHR_materials_clearcoat } from './extends/KHR_materials_clearcoat'; -import { KHR_materials_unlit } from './extends/KHR_materials_unlit'; import { GLTF_Info, GLTF_Node } from './GLTFInfo'; -import { GLTFParser } from './GLTFParser'; import { getTypedArrayTypeFromGLType } from './TypeArray'; import { KHR_draco_mesh_compression } from './extends/KHR_draco_mesh_compression'; -import { KHR_materials_emissive_strength } from './extends/KHR_materials_emissive_strength'; import { BitmapTexture2D } from '../../../textures/BitmapTexture2D'; -import { LitMaterial } from '../../../materials/LitMaterial'; import { GLTFSubParserCamera } from './GLTFSubParserCamera'; import { GLTFSubParserMesh } from './GLTFSubParserMesh'; import { GLTFSubParserMaterial } from './GLTFSubParserMaterial'; @@ -56,16 +33,12 @@ export class GLTFSubParser { } public get version() { - if (this.version) - return this.version; + if (this.version) return this.version; else if (this.gltf) { - if (!this.gltf.asset) - return this.errorMiss('asset'); + if (!this.gltf.asset) return this.errorMiss('asset'); this._version = this.gltf.asset.version; - - if (this.gltf.asset.minVersion) - this._version += `\r minVersion${this.gltf.asset.minVersion}`; + if (this.gltf.asset.minVersion) this._version += `\r minVersion${this.gltf.asset.minVersion}`; return this.version; } @@ -74,7 +47,7 @@ export class GLTFSubParser { return null; } - public async parse(initUrl: string, gltf: GLTF_Info, sceneId: number) { + public async parse(initUrl: string, gltf, sceneId) { this.gltf = gltf; this.initUrl = initUrl; const { version, generator } = this.gltf.asset; @@ -93,12 +66,12 @@ export class GLTFSubParser { return await this.convertToNode(result); } - public destroy() { + public destory() { KHR_draco_mesh_compression.unload(this.gltf) this.gltf = null } - private async parseScene(sceneId: number) { + private async parseScene(sceneId) { const loadScene = sceneId || this.gltf.scene || 0; const scene = this.gltf.scenes[loadScene]; @@ -117,7 +90,7 @@ export class GLTFSubParser { return result; } - private async parseNode(nodeId: number) { + private async parseNode(nodeId) { const node = this.gltf.nodes[nodeId]; if (!node) return this.errorMiss('node', nodeId); @@ -170,14 +143,14 @@ export class GLTFSubParser { throw new Error(e + info); } - private parseCamera(cameraId: number) { + private parseCamera(cameraId) { if (!this._cameraParser) { this._cameraParser = new GLTFSubParserCamera(this.gltf); } return this._cameraParser.parse(cameraId); } - private async parseMesh(meshId: number) { + private async parseMesh(meshId) { if (!this._meshParser) { this._meshParser = new GLTFSubParserMesh(this); } @@ -186,31 +159,31 @@ export class GLTFSubParser { public async parseTexture(index: number) { let textureInfo = this.gltf.textures[index]; - if (textureInfo && !textureInfo.dTexture) { + if (textureInfo && !textureInfo.dtexture) { if (textureInfo && textureInfo.source != null) { let image = this.gltf.images[textureInfo.source]; if (image.uri) { let name = image.uri; name = StringUtil.getURLName(name); - textureInfo.dTexture = this.gltf.resources[name]; + textureInfo.dtexture = this.gltf.resources[name]; } else if (image.bufferView) { let buffer = this.parseBufferView(image.bufferView); let bitmapTexture = new BitmapTexture2D(); let img = new Blob([buffer], { type: image.mimeType }); await bitmapTexture.loadFromBlob(img); - textureInfo.dTexture = bitmapTexture; + textureInfo.dtexture = bitmapTexture; } else { - textureInfo.dTexture = this.gltf.resources[image.name]; + textureInfo.dtexture = this.gltf.resources[image.name]; } } else if (textureInfo.name) { let name = StringUtil.getURLName(textureInfo.name); - textureInfo.dTexture = this.gltf.resources[name]; + textureInfo.dtexture = this.gltf.resources[name]; } } - if (!textureInfo.dTexture) { + if (!textureInfo.dtexture) { console.log("miss texture , please check texture!", index, textureInfo); } - return textureInfo.dTexture; + return textureInfo.dtexture; } public async parseMaterial(materialId) { @@ -222,6 +195,87 @@ export class GLTFSubParser { private parseAnimations() { const result = []; + // const animations = this.gltf.animations; + // if (animations) + // for (let i = 0; i < animations.length; i++) { + // const animation = animations[i]; + // const { name, channels, samplers } = animation; + // const clips = []; + // if (channels && samplers) + // for (let j = 0; j < channels.length; j++) { + // const channel = channels[j]; + // const sampler = samplers[channel.sampler]; + // if (!sampler) { + + // this.errorMiss(`animations[${i}].channels[${j}].sampler`, channel.sampler); + // continue; + + // } + + // const input = this.parseAccessor(sampler.input).data; + // const outputData = this.parseAccessor(sampler.output); + // const output = outputData.data; + // const numComponents = outputData.numComponents; + // const interpolation = sampler.interpolation || 'LINEAR'; + // const gltfNodeIdx = channel.target.node; + // const path = channel.target.path; + + // if (!input || !output) continue; + + // let combinedOutput = output; + // if (numComponents !== 1 || input.length !== output.length) { + + // const numComp = output.length / input.length; + // combinedOutput = []; + // for (let k = 0; k < input.length; k++) + // combinedOutput.push(output.slice(numComp * k, numComp * (k + 1))); + + // } + + // let nodeProperty = path; + // const extras = {}; + // switch (path) { + + // case 'translation': + // nodeProperty = 'position'; + // break; + // case 'rotation': + // nodeProperty = 'quaternion'; + // break; + // case 'scale': + // nodeProperty = 'scale'; + // break; + // case 'weights': + // nodeProperty = 'weights'; + // // extras.uniformName = GLTFParser.MORPH_WEIGHT_UNIFORM; + // break; + // default: + // console.error(`unsupported animation sampler path ${path}`); + // nodeProperty = false; + // } + + // if (!nodeProperty) continue; + + // const clip = { + // times: input, + // values: combinedOutput, + // findFlag: GLTFParser.GLTF_NODE_INDEX_PROPERTY, + // findValue: gltfNodeIdx, + // targetProp: nodeProperty, + // method: interpolation, + // extras, + // }; + + // clips.push(clip); + + // } + + // result.push({ + // name: name || String(i), + // clips, + // }); + + // } return result; } @@ -232,7 +286,7 @@ export class GLTFSubParser { return this._converter.convertNodeToObject3D(nodeInfo, parentNode); } - public parseSkeleton(skeletonID: number) { + public parseSkeleton(skeletonID) { if (!this._skeletonParser) { this._skeletonParser = new GLTFSubParserSkeleton(this); } @@ -246,10 +300,10 @@ export class GLTFSubParser { return this._skeletonParser.parseSkeletonAnimation(skeleton, animation); } - private async traverse(parentNode, nodeInfos) { + private async trivarse(parentNode, nodeInfos) { for (let i = 0; i < nodeInfos.length; i++) { const node = await this.parseObject3D(nodeInfos[i], parentNode); - await this.traverse(node, nodeInfos[i].children); + await this.trivarse(node, nodeInfos[i].children); } } @@ -261,9 +315,151 @@ export class GLTFSubParser { const textures = []; const skins = []; const cameras = []; - await this.traverse(rootNode, nodes); + await this.trivarse(rootNode, nodes); let animas; + // apply skins + // if ( skins.length ) { + + // const handlers = []; // help uglify use different name + // for ( let i = 0; i < skins.length; i ++ ) { + + // const { + // joints, skeleton, inverseBindMatrices, models, + // } = skins[ i ]; + + // const jointNum = joints.length; + // const globalJointTransformNodes = []; + // for ( let j = 0; j < jointNum; j ++ ) + // globalJointTransformNodes[ j ] = rootNode.findInChildren( GLTFParser.GLTF_NODE_INDEX_PROPERTY, joints[ j ] ); + + // let skeletonNode; + // if ( skeleton !== GLTFParser.SCENE_ROOT_SKELETON ) + // skeletonNode = rootNode.findInChildren( GLTFParser.GLTF_NODE_INDEX_PROPERTY, skeleton ); + // else + // skeletonNode = rootNode; + // skins[ i ].skeletonNode = skeletonNode; // do not know how to use it + + // const frag = new Array( 16 ); + // const fragWorld = new Array( 16 ); + // handlers[ i ] = function updateJointUniformFunc() { + + // for ( let k = 0; k < models.length; k ++ ) { + + // const model = models[ k ]; + // const globalTransformNode = model.node; + // let jointMats = []; + // Matrix4.invert( fragWorld, globalTransformNode.transform.getWorldMatrix() ); + + // for ( let n = 0; n < jointNum; n ++ ) { + + // Matrix4.mult( frag, fragWorld, globalJointTransformNodes[ n ].transform.getWorldMatrix() ); + // if ( inverseBindMatrices[ n ] !== GLTFParser.IDENTITY_INVERSE_BIND_MATRICES ) + // Matrix4.mult( frag, frag, inverseBindMatrices[ n ] ); + // jointMats = jointMats.concat( frag ); + + // } + + // const uniformObj = {}; + // uniformObj[ GLTFParser.JOINT_MATRICES_UNIFORM ] = jointMats; + // model.setUniformObj( uniformObj ); + + // } + + // }; + + // rootNode.afterUpdateMatrix.push( { + // type: 'skin', skinName: skins[ i ].name, handler: handlers[ i ], trigerNodes: [ skeletonNode, ...globalJointTransformNodes ], + // } ); + + // } + + // } + + // // animations + // for ( let i = 0; i < animations.length; i ++ ) { + + // const { clips } = animations[ i ]; + // let animateMaxTime = Number.NEGATIVE_INFINITY; + // let animateMinTime = Number.POSITIVE_INFINITY; + // for ( let j = 0; j < clips.length; j ++ ) { + + // const { + // findFlag, findValue, targetProp, times, extras, // method, + // } = clips[ j ]; + + // const node = rootNode.findInChildren( findFlag, findValue ); + // let targetNodes = [ node ]; + // if ( ! node.model && node.gltfPrimitives ) + // targetNodes = node.gltfPrimitives; + + // let setTarget; + // let resetTarget; + // if ( targetProp === 'weights' ) { + + // const resetObj = {}; + // resetObj[ GLTFParser.MORPH_WEIGHT_UNIFORM ] = targetNodes[ 0 ].model.uniformObj[ GLTFParser.MORPH_WEIGHT_UNIFORM ]; + // resetTarget = function () { + + // targetNodes.forEach( ( n ) => { + + // n.model.setUniformObj( resetObj ); + + // } ); + + // }; + + // setTarget = function ( v ) { + + // const uniformobj = {}; + // uniformobj[ extras.uniformName ] = v; + + // targetNodes.forEach( ( n ) => { + + // n.model.setUniformObj( uniformobj ); + + // } ); + + // }; + + // } else { + + // const defaultValues = []; + // for ( let m = 0; m < targetNodes.length; m ++ ) + // defaultValues[ m ] = targetNodes[ m ][ targetProp ]; + + // resetTarget = function () { + + // for ( let m = 0; m < targetNodes.length; m ++ ) + // targetNodes[ m ][ targetProp ] = defaultValues[ m ]; + + // }; + + // setTarget = function ( v ) { + + // targetNodes.forEach( ( n ) => { + + // n[ targetProp ] = v; // eslint-disable-line + + // } ); + + // }; + + // } + + // animateMinTime = animateMinTime < times[ 0 ] ? animateMinTime : times[ 0 ]; + // animateMaxTime = animateMaxTime > times[ times.length - 1 ] ? animateMaxTime : times[ times.length - 1 ]; + + // Object.assign( clips[ j ], { setTarget, resetTarget } ); + + // } + + // Object.assign( animations[ i ], { animateMinTime, animateMaxTime } ); + + // } + + // animas = { animations, type: 'gltf' }; + return { rootNode, textures, @@ -272,14 +468,14 @@ export class GLTFSubParser { }; } - private parseSkin(skinId: number) { + private parseSkin(skinId) { if (!this._skinParser) { this._skinParser = new GLTFSubParserSkin(this); } return this._skinParser.parse(skinId); } - public parseAccessor(accessorId: number) { + public parseAccessor(accessorId) { const accessor = this.gltf.accessors[accessorId]; if (!accessor) return this.errorMiss('accessor', accessorId); @@ -379,7 +575,7 @@ export class GLTFSubParser { return typedArray; } - public parseBufferView(bufferViewId: number) { + public parseBufferView(bufferViewId) { const bufferView = this.gltf.bufferViews[bufferViewId]; if (!bufferView) return this.errorMiss('bufferView', bufferViewId); @@ -398,7 +594,7 @@ export class GLTFSubParser { return bufferView.dbufferView; } - private parseBuffer(bufferId: number) { + private parseBuffer(bufferId) { const buffer = this.gltf.buffers[bufferId]; if (!buffer) return this.errorMiss('buffer', bufferId); diff --git a/src/engine/loader/parser/gltf/GLTFSubParserCamera.ts b/src/loader/parser/gltf/GLTFSubParserCamera.ts similarity index 97% rename from src/engine/loader/parser/gltf/GLTFSubParserCamera.ts rename to src/loader/parser/gltf/GLTFSubParserCamera.ts index 2e482357..1b96cb69 100644 --- a/src/engine/loader/parser/gltf/GLTFSubParserCamera.ts +++ b/src/loader/parser/gltf/GLTFSubParserCamera.ts @@ -10,7 +10,7 @@ export class GLTFSubParserCamera { this.gltf = gltf; } - public parse(cameraId: number) { + public parse(cameraId) { const camera = this.gltf.cameras[cameraId]; if (!camera) diff --git a/src/engine/loader/parser/gltf/GLTFSubParserConverter.ts b/src/loader/parser/gltf/GLTFSubParserConverter.ts similarity index 98% rename from src/engine/loader/parser/gltf/GLTFSubParserConverter.ts rename to src/loader/parser/gltf/GLTFSubParserConverter.ts index 1cc0a4d8..041a2757 100644 --- a/src/engine/loader/parser/gltf/GLTFSubParserConverter.ts +++ b/src/loader/parser/gltf/GLTFSubParserConverter.ts @@ -15,11 +15,11 @@ import { PhysicMaterial } from "../../../materials/PhysicMaterial"; import { Color } from "../../../math/Color"; import { RADIANS_TO_DEGREES } from "../../../math/MathUtil"; import { Quaternion } from "../../../math/Quaternion"; -import { defaultRes } from "../../../textures/DefaultRes"; import { UUID } from "../../../util/Global"; import { GLTF_Info, GLTF_Node } from "./GLTFInfo"; import { GLTFParser } from "./GLTFParser"; import { GLTFSubParser } from "./GLTFSubParser"; +import { GLTFType } from "./GLTFType"; import { KHR_materials_clearcoat } from "./extends/KHR_materials_clearcoat"; import { KHR_materials_emissive_strength } from "./extends/KHR_materials_emissive_strength"; import { KHR_materials_unlit } from "./extends/KHR_materials_unlit"; @@ -38,7 +38,7 @@ export class GLTFSubParserConverter { public async convertNodeToObject3D(nodeInfo: GLTF_Node, parentNode): Promise { const node = new Object3D(); node.name = nodeInfo.name; - node[GLTFParser.GLTF_NODE_INDEX_PROPERTY] = nodeInfo.nodeId; + node[GLTFType.GLTF_NODE_INDEX_PROPERTY] = nodeInfo.nodeId; nodeInfo['nodeObj'] = node; if (nodeInfo.matrix) { @@ -234,8 +234,8 @@ export class GLTFSubParserConverter { if (emissiveFactor && (emissiveFactor[0] > 0 || emissiveFactor[1] > 0 || emissiveFactor[2] > 0)) { if (physicMaterial.emissiveMap) { - if (physicMaterial.emissiveMap == defaultRes.blackTexture) { - physicMaterial.emissiveMap = defaultRes.whiteTexture; + if (physicMaterial.emissiveMap == Engine3D.res.blackTexture) { + physicMaterial.emissiveMap = Engine3D.res.whiteTexture; } } let emissiveFactorA = emissiveFactor[3] ? emissiveFactor[3] : 1.0; diff --git a/src/engine/loader/parser/gltf/GLTFSubParserMaterial.ts b/src/loader/parser/gltf/GLTFSubParserMaterial.ts similarity index 93% rename from src/engine/loader/parser/gltf/GLTFSubParserMaterial.ts rename to src/loader/parser/gltf/GLTFSubParserMaterial.ts index 266596dc..975dc3e8 100644 --- a/src/engine/loader/parser/gltf/GLTFSubParserMaterial.ts +++ b/src/loader/parser/gltf/GLTFSubParserMaterial.ts @@ -1,5 +1,5 @@ +import { Engine3D } from "../../../Engine3D"; import { Vector4 } from "../../../math/Vector4"; -import { defaultRes } from "../../../textures/DefaultRes"; import { GLTF_Info } from "./GLTFInfo"; import { GLTFParser } from "./GLTFParser"; import { GLTFSubParser } from "./GLTFSubParser"; @@ -16,7 +16,7 @@ export class GLTFSubParserMaterial { this.subParser = subParser; } - public async parse(materialId: number) { + public async parse(materialId) { let material; if (materialId == undefined) { material = GLTFParser.defaultMaterial; @@ -76,7 +76,7 @@ export class GLTFSubParserMaterial { if (texture) { dmaterial.baseColorTexture = texture; } else { - dmaterial.baseColorTexture = defaultRes.redTexture; + dmaterial.baseColorTexture = Engine3D.res.redTexture; } } @@ -85,7 +85,7 @@ export class GLTFSubParserMaterial { if (texture) { dmaterial.metallicRoughnessTexture = texture; } else { - dmaterial.metallicRoughnessTexture = defaultRes.blackTexture; + dmaterial.metallicRoughnessTexture = Engine3D.res.blackTexture; } } } else { @@ -117,7 +117,7 @@ export class GLTFSubParserMaterial { if (texture) { dmaterial.normalTexture = texture; } else { - dmaterial.normalTexture = defaultRes.normalTexture; + dmaterial.normalTexture = Engine3D.res.normalTexture; } } @@ -137,7 +137,7 @@ export class GLTFSubParserMaterial { if (texture) { dmaterial.emissiveTexture = texture; } else { - dmaterial.emissiveTexture = defaultRes.blackTexture; + dmaterial.emissiveTexture = Engine3D.res.blackTexture; } } diff --git a/src/engine/loader/parser/gltf/GLTFSubParserMesh.ts b/src/loader/parser/gltf/GLTFSubParserMesh.ts similarity index 94% rename from src/engine/loader/parser/gltf/GLTFSubParserMesh.ts rename to src/loader/parser/gltf/GLTFSubParserMesh.ts index 02f1133b..172be370 100644 --- a/src/engine/loader/parser/gltf/GLTFSubParserMesh.ts +++ b/src/loader/parser/gltf/GLTFSubParserMesh.ts @@ -2,6 +2,7 @@ import { VertexAttributeName } from "../../../core/geometry/VertexAttributeName" import { GLTF_Info } from "./GLTFInfo"; import { GLTFParser } from "./GLTFParser"; import { GLTFSubParser } from "./GLTFSubParser"; +import { GLTFType } from "./GLTFType"; import { KHR_draco_mesh_compression } from "./extends/KHR_draco_mesh_compression"; /** @@ -16,7 +17,7 @@ export class GLTFSubParserMesh { this.subParser = subParser; } - public async parse(meshId: number) { + public async parse(meshId) { const mesh = this.gltf.meshes[meshId]; if (!mesh) @@ -159,15 +160,15 @@ export class GLTFSubParserMesh { let attribName; switch (attribute) { case 'POSITION': - attribName = GLTFParser.MORPH_POSITION_PREFIX + j; + attribName = GLTFType.MORPH_POSITION_PREFIX + j; hasPositions = true; break; case 'NORMAL': - attribName = GLTFParser.MORPH_NORMAL_PREFIX + j; + attribName = GLTFType.MORPH_NORMAL_PREFIX + j; hasNormals = true; break; case 'TANGENT': - attribName = GLTFParser.MORPH_TANGENT_PREFIX + j; + attribName = GLTFType.MORPH_TANGENT_PREFIX + j; hasTangents = true; break; default: @@ -180,9 +181,9 @@ export class GLTFSubParserMesh { }); } - if (hasPositions) dprimitive.defines.push(GLTFParser.getMorphTargetPositionDefine()); - if (hasNormals) dprimitive.defines.push(GLTFParser.getMorphTargetNormalDefine()); - if (hasTangents) dprimitive.defines.push(GLTFParser.getMorphTargetTangentDefine()); + if (hasPositions) dprimitive.defines.push(GLTFParser.getMorphtargetPositionDefine()); + if (hasNormals) dprimitive.defines.push(GLTFParser.getMorphtargetNormalDefine()); + if (hasTangents) dprimitive.defines.push(GLTFParser.getMorphtargetTangentDefine()); dprimitive.weights = mesh.weights || new Array(targets.length).fill(0); } diff --git a/src/engine/loader/parser/gltf/GLTFSubParserSkeleton.ts b/src/loader/parser/gltf/GLTFSubParserSkeleton.ts similarity index 99% rename from src/engine/loader/parser/gltf/GLTFSubParserSkeleton.ts rename to src/loader/parser/gltf/GLTFSubParserSkeleton.ts index e60eb3ac..eb8f0fdc 100644 --- a/src/engine/loader/parser/gltf/GLTFSubParserSkeleton.ts +++ b/src/loader/parser/gltf/GLTFSubParserSkeleton.ts @@ -13,7 +13,7 @@ export class GLTFSubParserSkeleton { this.subParser = subParser; } - public parse(skeletonID: number): Skeleton { + public parse(skeletonID): Skeleton { let skeleton: Skeleton = new Skeleton(); this.buildSkeleton(skeleton, undefined, skeletonID); return skeleton; diff --git a/src/engine/loader/parser/gltf/GLTFSubParserSkin.ts b/src/loader/parser/gltf/GLTFSubParserSkin.ts similarity index 94% rename from src/engine/loader/parser/gltf/GLTFSubParserSkin.ts rename to src/loader/parser/gltf/GLTFSubParserSkin.ts index 0a90e69c..acf171a4 100644 --- a/src/engine/loader/parser/gltf/GLTFSubParserSkin.ts +++ b/src/loader/parser/gltf/GLTFSubParserSkin.ts @@ -1,6 +1,7 @@ import { GLTF_Info } from "./GLTFInfo"; import { GLTFParser } from "./GLTFParser"; import { GLTFSubParser } from "./GLTFSubParser"; +import { GLTFType } from "./GLTFType"; export class GLTFSubParserSkin { protected gltf: GLTF_Info; @@ -11,7 +12,7 @@ export class GLTFSubParserSkin { this.subParser = subParser; } - public parse(skinId: number) { + public parse(skinId) { const skin = this.gltf.skins[skinId]; if (!skin) @@ -53,7 +54,7 @@ export class GLTFSubParserSkin { dskin.skeleton = rootNodeId; } // dskin.skeleton = skeleton === undefined ? GLTFParser.SCENE_ROOT_SKELETON : skeleton; - dskin.inverseBindMatrices = GLTFParser.IDENTITY_INVERSE_BIND_MATRICES; + dskin.inverseBindMatrices = GLTFType.IDENTITY_INVERSE_BIND_MATRICES; if (inverseBindMatrices !== undefined) { const accessor = this.parseAccessor(inverseBindMatrices); diff --git a/src/loader/parser/gltf/GLTFType.ts b/src/loader/parser/gltf/GLTFType.ts new file mode 100644 index 00000000..8ed1aa2c --- /dev/null +++ b/src/loader/parser/gltf/GLTFType.ts @@ -0,0 +1,41 @@ +export class GLTFType { + public static readonly GLTF_NODE_INDEX_PROPERTY: 'GLTF_NODE_INDEX'; + + public static readonly BASE_COLOR_UNIFORM = 'u_baseColorFactor'; + + public static readonly BASE_COLOR_TEXTURE_UNIFORM = 'u_baseColorSampler'; + + public static readonly METALROUGHNESS_UNIFORM = 'u_metallicRoughnessValues'; + + public static readonly METALROUGHNESS_TEXTURE_UNIFORM = 'u_metallicRoughnessSampler'; + + public static readonly NORMAL_TEXTURE_UNIFORM = 'u_normalSampler'; + + public static readonly NORMAL_SCALE_UNIFORM = 'u_normalScale'; + + public static readonly EMISSIVE_TEXTURE_UNIFORM = 'u_emissiveSampler'; + + public static readonly EMISSIVE_FACTOR_UNIFORM = 'u_emissiveFactor'; + + public static readonly OCCLUSION_TEXTURE_UNIFORM = 'u_occlusionSampler'; + + public static readonly OCCLUSION_FACTOR_UNIFORM = 'u_occlusionFactor'; + + public static readonly MAX_MORPH_TARGETS = 8; + + public static readonly MORPH_POSITION_PREFIX = 'a_morphPositions_'; + + public static readonly MORPH_NORMAL_PREFIX = 'a_morphNormals_'; + + public static readonly MORPH_TANGENT_PREFIX = 'a_morphTangents_'; + + public static readonly MORPH_WEIGHT_UNIFORM = 'u_morphWeights'; + + public static readonly SCENE_ROOT_SKELETON = 'SCENE_ROOT'; + + public static readonly IDENTITY_INVERSE_BIND_MATRICES = 'IDENTITY_IBM'; + + public static readonly JOINT_MATRICES_UNIFORM = 'u_jointMatrix'; + + public static readonly ALPHA_CUTOFF_UNIFORM = 'u_alphaCutoff'; +} \ No newline at end of file diff --git a/src/engine/loader/parser/gltf/TypeArray.ts b/src/loader/parser/gltf/TypeArray.ts similarity index 100% rename from src/engine/loader/parser/gltf/TypeArray.ts rename to src/loader/parser/gltf/TypeArray.ts diff --git a/src/engine/loader/parser/gltf/extends/KHR_draco_mesh_compression.ts b/src/loader/parser/gltf/extends/KHR_draco_mesh_compression.ts similarity index 100% rename from src/engine/loader/parser/gltf/extends/KHR_draco_mesh_compression.ts rename to src/loader/parser/gltf/extends/KHR_draco_mesh_compression.ts diff --git a/src/engine/loader/parser/gltf/extends/KHR_lights_punctual.ts b/src/loader/parser/gltf/extends/KHR_lights_punctual.ts similarity index 100% rename from src/engine/loader/parser/gltf/extends/KHR_lights_punctual.ts rename to src/loader/parser/gltf/extends/KHR_lights_punctual.ts diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_clearcoat.ts b/src/loader/parser/gltf/extends/KHR_materials_clearcoat.ts similarity index 100% rename from src/engine/loader/parser/gltf/extends/KHR_materials_clearcoat.ts rename to src/loader/parser/gltf/extends/KHR_materials_clearcoat.ts diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_emissive_strength.ts b/src/loader/parser/gltf/extends/KHR_materials_emissive_strength.ts similarity index 73% rename from src/engine/loader/parser/gltf/extends/KHR_materials_emissive_strength.ts rename to src/loader/parser/gltf/extends/KHR_materials_emissive_strength.ts index 4964eb3e..e47d6cb9 100644 --- a/src/engine/loader/parser/gltf/extends/KHR_materials_emissive_strength.ts +++ b/src/loader/parser/gltf/extends/KHR_materials_emissive_strength.ts @@ -1,14 +1,14 @@ //https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_emissive_strength -import { defaultRes } from "../../../../textures/DefaultRes"; +import { Engine3D } from "../../../../Engine3D"; export class KHR_materials_emissive_strength { public static apply(gltf: any, dmaterial: any, tMaterial: any) { let extensions = dmaterial.extensions; if (extensions && extensions[`KHR_materials_emissive_strength`]) { tMaterial.emissiveIntensity = extensions[`KHR_materials_emissive_strength`].emissiveStrength * 0.5; - if (tMaterial.emissiveMap == defaultRes.blackTexture) { - tMaterial.emissiveMap = defaultRes.whiteTexture; + if (tMaterial.emissiveMap == Engine3D.res.blackTexture) { + tMaterial.emissiveMap = Engine3D.res.whiteTexture; } } else { tMaterial.emissiveIntensity = 1; diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_ior.ts b/src/loader/parser/gltf/extends/KHR_materials_ior.ts similarity index 100% rename from src/engine/loader/parser/gltf/extends/KHR_materials_ior.ts rename to src/loader/parser/gltf/extends/KHR_materials_ior.ts diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_sheen.ts b/src/loader/parser/gltf/extends/KHR_materials_sheen.ts similarity index 100% rename from src/engine/loader/parser/gltf/extends/KHR_materials_sheen.ts rename to src/loader/parser/gltf/extends/KHR_materials_sheen.ts diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_specular.ts b/src/loader/parser/gltf/extends/KHR_materials_specular.ts similarity index 100% rename from src/engine/loader/parser/gltf/extends/KHR_materials_specular.ts rename to src/loader/parser/gltf/extends/KHR_materials_specular.ts diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_transmission.ts b/src/loader/parser/gltf/extends/KHR_materials_transmission.ts similarity index 100% rename from src/engine/loader/parser/gltf/extends/KHR_materials_transmission.ts rename to src/loader/parser/gltf/extends/KHR_materials_transmission.ts diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_unlit.ts b/src/loader/parser/gltf/extends/KHR_materials_unlit.ts similarity index 100% rename from src/engine/loader/parser/gltf/extends/KHR_materials_unlit.ts rename to src/loader/parser/gltf/extends/KHR_materials_unlit.ts diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_variants.ts b/src/loader/parser/gltf/extends/KHR_materials_variants.ts similarity index 100% rename from src/engine/loader/parser/gltf/extends/KHR_materials_variants.ts rename to src/loader/parser/gltf/extends/KHR_materials_variants.ts diff --git a/src/engine/loader/parser/gltf/extends/KHR_materials_volume.ts b/src/loader/parser/gltf/extends/KHR_materials_volume.ts similarity index 100% rename from src/engine/loader/parser/gltf/extends/KHR_materials_volume.ts rename to src/loader/parser/gltf/extends/KHR_materials_volume.ts diff --git a/src/engine/loader/parser/gltf/extends/KHR_mesh_quantization.ts b/src/loader/parser/gltf/extends/KHR_mesh_quantization.ts similarity index 100% rename from src/engine/loader/parser/gltf/extends/KHR_mesh_quantization.ts rename to src/loader/parser/gltf/extends/KHR_mesh_quantization.ts diff --git a/src/engine/loader/parser/gltf/extends/KHR_texture_basisu.ts b/src/loader/parser/gltf/extends/KHR_texture_basisu.ts similarity index 100% rename from src/engine/loader/parser/gltf/extends/KHR_texture_basisu.ts rename to src/loader/parser/gltf/extends/KHR_texture_basisu.ts diff --git a/src/engine/loader/parser/gltf/extends/KHR_texture_transform.ts b/src/loader/parser/gltf/extends/KHR_texture_transform.ts similarity index 100% rename from src/engine/loader/parser/gltf/extends/KHR_texture_transform.ts rename to src/loader/parser/gltf/extends/KHR_texture_transform.ts diff --git a/src/engine/loader/parser/i3dm/I3DMLoader.ts b/src/loader/parser/i3dm/I3DMLoader.ts similarity index 100% rename from src/engine/loader/parser/i3dm/I3DMLoader.ts rename to src/loader/parser/i3dm/I3DMLoader.ts diff --git a/src/engine/loader/parser/i3dm/I3DMLoaderBase.ts b/src/loader/parser/i3dm/I3DMLoaderBase.ts similarity index 100% rename from src/engine/loader/parser/i3dm/I3DMLoaderBase.ts rename to src/loader/parser/i3dm/I3DMLoaderBase.ts diff --git a/src/engine/loader/parser/tileRenderer/TileSet.ts b/src/loader/parser/tileRenderer/TileSet.ts similarity index 100% rename from src/engine/loader/parser/tileRenderer/TileSet.ts rename to src/loader/parser/tileRenderer/TileSet.ts diff --git a/src/engine/loader/parser/tileRenderer/TilesRenderer.ts b/src/loader/parser/tileRenderer/TilesRenderer.ts similarity index 100% rename from src/engine/loader/parser/tileRenderer/TilesRenderer.ts rename to src/loader/parser/tileRenderer/TilesRenderer.ts diff --git a/src/engine/materials/BlendMode.ts b/src/materials/BlendMode.ts similarity index 100% rename from src/engine/materials/BlendMode.ts rename to src/materials/BlendMode.ts diff --git a/src/engine/materials/ColorLitMaterial.ts b/src/materials/ColorLitMaterial.ts similarity index 87% rename from src/engine/materials/ColorLitMaterial.ts rename to src/materials/ColorLitMaterial.ts index 035432b5..401c393d 100644 --- a/src/engine/materials/ColorLitMaterial.ts +++ b/src/materials/ColorLitMaterial.ts @@ -1,7 +1,8 @@ +import { Engine3D } from '../Engine3D'; import { ShaderLib } from '../assets/shader/ShaderLib'; import { ColorLitShader } from '../assets/shader/materials/ColorLitShader'; import { Color } from '../math/Color'; -import { defaultRes } from '../textures/DefaultRes'; + import { PhysicMaterial } from './PhysicMaterial'; /** * ColorLitMaterial @@ -35,8 +36,8 @@ export class ColorLitMaterial extends PhysicMaterial { shaderState.acceptGI = true; shaderState.useLight = true; - shader.setTexture("normalMap", defaultRes.normalTexture); - shader.setTexture("emissiveMap", defaultRes.blackTexture); + shader.setTexture("normalMap", Engine3D.res.normalTexture); + shader.setTexture("emissiveMap", Engine3D.res.blackTexture); } clone(): this { diff --git a/src/engine/materials/GlassMaterial.ts b/src/materials/GlassMaterial.ts similarity index 93% rename from src/engine/materials/GlassMaterial.ts rename to src/materials/GlassMaterial.ts index fcb0d4a8..d885fe48 100644 --- a/src/engine/materials/GlassMaterial.ts +++ b/src/materials/GlassMaterial.ts @@ -2,7 +2,7 @@ import { ShaderLib } from '../assets/shader/ShaderLib'; import GlassShader from '../assets/shader/materials/GlassShader.wgsl?raw'; import { Engine3D } from '../Engine3D'; import { Vector4 } from '../math/Vector4'; -import { defaultRes } from '../textures/DefaultRes'; + import { PhysicMaterial } from './PhysicMaterial'; import { registerMaterial } from './MaterialRegister'; /** @@ -35,13 +35,13 @@ export class GlassMaterial extends PhysicMaterial { let bdrflutTex = Engine3D.res.getTexture(`BRDFLUT`); this.brdfLUT = bdrflutTex; - this.baseMap = defaultRes.whiteTexture; - this.normalMap = defaultRes.normalTexture; + this.baseMap = Engine3D.res.whiteTexture; + this.normalMap = Engine3D.res.normalTexture; // this.aoMap = defaultTexture.whiteTexture; // this.maskMap = defaultTexture.maskTexture; // this.maskMap = defaultTexture.grayTexture; // shader.setDefine(`USE_ARMC`, false); - this.emissiveMap = defaultRes.blackTexture; + this.emissiveMap = Engine3D.res.blackTexture; } diff --git a/src/engine/materials/LambertMaterial.ts b/src/materials/LambertMaterial.ts similarity index 91% rename from src/engine/materials/LambertMaterial.ts rename to src/materials/LambertMaterial.ts index a663a4a0..6418d8ad 100644 --- a/src/engine/materials/LambertMaterial.ts +++ b/src/materials/LambertMaterial.ts @@ -1,10 +1,11 @@ import { Lambert_shader } from '../assets/shader/materials/Lambert_shader'; import { ShaderLib } from '../assets/shader/ShaderLib'; +import { Engine3D } from '../Engine3D'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { Color } from '../math/Color'; import { Vector4 } from '../math/Vector4'; -import { defaultRes } from '../textures/DefaultRes'; + import { MaterialBase } from './MaterialBase'; import { registerMaterial } from "./MaterialRegister"; @@ -39,9 +40,9 @@ export class LambertMaterial extends MaterialBase { shaderState.useLight = true; // default value - this.baseMap = defaultRes.whiteTexture; - this.emissiveMap = defaultRes.blackTexture; - this.baseMap = defaultRes.grayTexture; + this.baseMap = Engine3D.res.whiteTexture; + this.emissiveMap = Engine3D.res.blackTexture; + this.baseMap = Engine3D.res.grayTexture; } /** diff --git a/src/engine/materials/LitMaterial.ts b/src/materials/LitMaterial.ts similarity index 93% rename from src/engine/materials/LitMaterial.ts rename to src/materials/LitMaterial.ts index be8a37f1..ff4164da 100644 --- a/src/engine/materials/LitMaterial.ts +++ b/src/materials/LitMaterial.ts @@ -1,6 +1,6 @@ import { Engine3D } from '../Engine3D'; import { Vector4 } from '../math/Vector4'; -import { defaultRes } from '../textures/DefaultRes'; + import { registerMaterial } from './MaterialRegister'; import { PhysicMaterial } from './PhysicMaterial'; /** @@ -33,13 +33,13 @@ export class LitMaterial extends PhysicMaterial { let bdrflutTex = Engine3D.res.getTexture(`BRDFLUT`); this.brdfLUT = bdrflutTex; - this.baseMap = defaultRes.whiteTexture; - this.normalMap = defaultRes.normalTexture; + this.baseMap = Engine3D.res.whiteTexture; + this.normalMap = Engine3D.res.normalTexture; // this.aoMap = defaultTexture.whiteTexture; // this.maskMap = defaultTexture.maskTexture; // this.maskMap = defaultTexture.grayTexture; // shader.setDefine(`USE_ARMC`, false); - this.emissiveMap = defaultRes.blackTexture; + this.emissiveMap = Engine3D.res.blackTexture; // this.alphaCutoff = 0.5; diff --git a/src/engine/materials/MaterialBase.ts b/src/materials/MaterialBase.ts similarity index 100% rename from src/engine/materials/MaterialBase.ts rename to src/materials/MaterialBase.ts diff --git a/src/engine/materials/MaterialPass.ts b/src/materials/MaterialPass.ts similarity index 100% rename from src/engine/materials/MaterialPass.ts rename to src/materials/MaterialPass.ts diff --git a/src/engine/materials/MaterialRegister.ts b/src/materials/MaterialRegister.ts similarity index 71% rename from src/engine/materials/MaterialRegister.ts rename to src/materials/MaterialRegister.ts index 858f4e11..4544db69 100644 --- a/src/engine/materials/MaterialRegister.ts +++ b/src/materials/MaterialRegister.ts @@ -31,10 +31,10 @@ export type MaterialClassName = | 'PointMaterial' | 'none'; -export let materialClassToName: Map, MaterialClassName> = new Map, MaterialClassName>(); -export let materialNameToClass: Map> = new Map>(); +// export let materialClassToName: Map, MaterialClassName> = new Map, MaterialClassName>(); +// export let materialNameToClass: Map> = new Map>(); export function registerMaterial(name: MaterialClassName, cls: Ctor): void { - materialClassToName.set(cls, name); - materialNameToClass.set(name, cls); + // materialClassToName.set(cls, name); + // materialNameToClass.set(name, cls); } \ No newline at end of file diff --git a/src/engine/materials/PavementMaterial.ts b/src/materials/PavementMaterial.ts similarity index 88% rename from src/engine/materials/PavementMaterial.ts rename to src/materials/PavementMaterial.ts index 5555dfee..80e4ea7c 100644 --- a/src/engine/materials/PavementMaterial.ts +++ b/src/materials/PavementMaterial.ts @@ -2,9 +2,10 @@ import { ShaderLib } from '../assets/shader/ShaderLib'; import { PavementShader } from '../assets/shader/materials/PavementShader'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { Color } from '../math/Color'; -import { defaultRes } from '../textures/DefaultRes'; + import { PhysicMaterial } from './PhysicMaterial'; import { registerMaterial } from "../materials/MaterialRegister"; +import { Engine3D } from '../Engine3D'; /** * PavementMaterial * @group Material @@ -36,11 +37,11 @@ export class PavementMaterial extends PhysicMaterial { shaderState.receiveEnv = true; shaderState.acceptGI = true; shaderState.useLight = true; - shader.setTexture("normalMap", defaultRes.normalTexture); - shader.setTexture("emissiveMap", defaultRes.blackTexture); + shader.setTexture("normalMap", Engine3D.res.normalTexture); + shader.setTexture("emissiveMap", Engine3D.res.blackTexture); // default value - this.baseMap = defaultRes.whiteTexture; + this.baseMap = Engine3D.res.whiteTexture; this.transparent = true; } diff --git a/src/engine/materials/PhysicMaterial.ts b/src/materials/PhysicMaterial.ts similarity index 98% rename from src/engine/materials/PhysicMaterial.ts rename to src/materials/PhysicMaterial.ts index 89b7fcd5..6aa96a96 100644 --- a/src/engine/materials/PhysicMaterial.ts +++ b/src/materials/PhysicMaterial.ts @@ -1,7 +1,8 @@ +import { Engine3D } from '../Engine3D'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { Color } from '../math/Color'; import { Vector4 } from '../math/Vector4'; -import { defaultRes } from '../textures/DefaultRes'; + import { MaterialBase } from './MaterialBase'; import { registerMaterial } from "./MaterialRegister"; @@ -196,7 +197,7 @@ export class PhysicMaterial extends MaterialBase { public set aoMap(value: Texture) { if (!value) return; this.renderShader.setTexture(`aoMap`, value); - if (value != defaultRes.whiteTexture) { + if (value != Engine3D.res.whiteTexture) { this.renderShader.setDefine(`USE_AOTEX`, true); } } diff --git a/src/engine/materials/PointMaterial.ts b/src/materials/PointMaterial.ts similarity index 94% rename from src/engine/materials/PointMaterial.ts rename to src/materials/PointMaterial.ts index b66c0018..4353148f 100644 --- a/src/engine/materials/PointMaterial.ts +++ b/src/materials/PointMaterial.ts @@ -1,10 +1,11 @@ +import { Engine3D } from '../Engine3D'; import { ShaderLib } from '../assets/shader/ShaderLib'; import { PointShadowDebug } from '../assets/shader/materials/PointShadowDebug'; import UnLit from '../assets/shader/materials/UnLit.wgsl?raw'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { Color } from '../math/Color'; import { Vector4 } from '../math/Vector4'; -import { defaultRes } from '../textures/DefaultRes'; + import { MaterialBase } from './MaterialBase'; import { registerMaterial } from "./MaterialRegister"; @@ -35,7 +36,7 @@ export class PointMaterial extends MaterialBase { shaderState.useLight = false; // default value - this.baseMap = defaultRes.whiteTexture; + this.baseMap = Engine3D.res.whiteTexture; } /** diff --git a/src/engine/materials/SkyMaterial.ts b/src/materials/SkyMaterial.ts similarity index 100% rename from src/engine/materials/SkyMaterial.ts rename to src/materials/SkyMaterial.ts diff --git a/src/engine/materials/UnLitMaterial.ts b/src/materials/UnLitMaterial.ts similarity index 94% rename from src/engine/materials/UnLitMaterial.ts rename to src/materials/UnLitMaterial.ts index 7b99143c..e596040c 100644 --- a/src/engine/materials/UnLitMaterial.ts +++ b/src/materials/UnLitMaterial.ts @@ -1,9 +1,10 @@ +import { Engine3D } from '../Engine3D'; import { ShaderLib } from '../assets/shader/ShaderLib'; import UnLit from '../assets/shader/materials/UnLit.wgsl?raw'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { Color } from '../math/Color'; import { Vector4 } from '../math/Vector4'; -import { defaultRes } from '../textures/DefaultRes'; + import { MaterialBase } from './MaterialBase'; import { registerMaterial } from "./MaterialRegister"; @@ -36,7 +37,7 @@ export class UnLitMaterial extends MaterialBase { shader.setUniformColor("ccc", new Color(1.0, 0.0, 0.0, 1.0)); // default value - this.baseMap = defaultRes.whiteTexture; + this.baseMap = Engine3D.res.whiteTexture; } /** diff --git a/src/engine/materials/effectPass/OutLinePass.ts b/src/materials/effectPass/OutLinePass.ts similarity index 93% rename from src/engine/materials/effectPass/OutLinePass.ts rename to src/materials/effectPass/OutLinePass.ts index 5ff2c8d3..71068e6a 100644 --- a/src/engine/materials/effectPass/OutLinePass.ts +++ b/src/materials/effectPass/OutLinePass.ts @@ -2,9 +2,10 @@ import { MaterialPass } from "../MaterialPass"; import OutlineShaderPass from "../../assets/shader/materials/OutlinePass.wgsl?raw" import { GPUCompareFunction } from "../../gfx/graphics/webGpu/WebGPUConst"; -import { defaultRes } from "../../textures/DefaultRes"; + import { Color } from "../../math/Color"; import { ShaderLib } from "../../assets/shader/ShaderLib"; +import { Engine3D } from "../../Engine3D"; export class OutLinePass extends MaterialPass { constructor(lineWeight: number = 10) { @@ -26,7 +27,7 @@ export class OutLinePass extends MaterialPass { shaderState.depthCompare = GPUCompareFunction.always; // shaderState.blendMode = BlendMode.ADD ; - shader.setTexture("baseMap", defaultRes.whiteTexture); + shader.setTexture("baseMap", Engine3D.res.whiteTexture); } private _lineWeight: number = 0; diff --git a/src/engine/materials/multiPass/CastPointShadowMaterialPass.ts b/src/materials/multiPass/CastPointShadowMaterialPass.ts similarity index 100% rename from src/engine/materials/multiPass/CastPointShadowMaterialPass.ts rename to src/materials/multiPass/CastPointShadowMaterialPass.ts diff --git a/src/engine/materials/multiPass/CastShadowMaterialPass.ts b/src/materials/multiPass/CastShadowMaterialPass.ts similarity index 100% rename from src/engine/materials/multiPass/CastShadowMaterialPass.ts rename to src/materials/multiPass/CastShadowMaterialPass.ts diff --git a/src/engine/materials/multiPass/DepthMaterialPass.ts b/src/materials/multiPass/DepthMaterialPass.ts similarity index 100% rename from src/engine/materials/multiPass/DepthMaterialPass.ts rename to src/materials/multiPass/DepthMaterialPass.ts diff --git a/src/engine/materials/multiPass/GBufferPass.ts b/src/materials/multiPass/GBufferPass.ts similarity index 93% rename from src/engine/materials/multiPass/GBufferPass.ts rename to src/materials/multiPass/GBufferPass.ts index 2c6b43e2..393af896 100644 --- a/src/engine/materials/multiPass/GBufferPass.ts +++ b/src/materials/multiPass/GBufferPass.ts @@ -1,11 +1,12 @@ import { ShaderLib } from '../../assets/shader/ShaderLib'; import { Texture } from '../../gfx/graphics/webGpu/core/texture/Texture'; import { Color } from '../../math/Color'; -import { defaultRes } from '../../textures/DefaultRes'; + import { BlendMode } from '../BlendMode'; import { MaterialBase } from '../MaterialBase'; import { registerMaterial } from "../MaterialRegister"; import GBuffer_shader from '../../assets/shader/core/pass/GBuffer_shader.wgsl?raw'; +import { Engine3D } from '../../Engine3D'; /** * @internal @@ -35,7 +36,7 @@ export class GBufferPass extends MaterialBase { this.renderShader.setUniformFloat(`alphaCutoff`, 1); this.blendMode = BlendMode.NONE; - this.renderShader.setTexture(`normalMap`, defaultRes.normalTexture); + this.renderShader.setTexture(`normalMap`, Engine3D.res.normalTexture); } public set shadowMap(texture: Texture) { } diff --git a/src/engine/materials/multiPass/SkyGBufferPass.ts b/src/materials/multiPass/SkyGBufferPass.ts similarity index 100% rename from src/engine/materials/multiPass/SkyGBufferPass.ts rename to src/materials/multiPass/SkyGBufferPass.ts diff --git a/src/engine/math/AnimationCurve.ts b/src/math/AnimationCurve.ts similarity index 96% rename from src/engine/math/AnimationCurve.ts rename to src/math/AnimationCurve.ts index 95340f51..0d6dac9d 100644 --- a/src/engine/math/AnimationCurve.ts +++ b/src/math/AnimationCurve.ts @@ -1,307 +1,307 @@ -import { PingPong, RepeatSE } from './MathUtil'; - -/** - * Time Warp Mode - * @PingPong value min -> max -> min - * @Repeat value = value % repeatSpace - * @Clamp value = max(min( value , 1 ) , 0 ) - */ -export enum WrapTimeMode { - PingPong = 0, - Repeat = 1, - Clamp = 2, -} - -/** - * @group Math - */ -export class Keyframe { - public serializedVersion: string = '2'; - public time: number; - public value: number; - public inSlope: number = 0; - public outSlope: number = 0; - public tangentMode: number = 0; - - constructor(time: number = 0, value: number = 0) { - this.time = time; - this.value = value; - } - - public unSerialized(data: any) { - this.serializedVersion = data['serializedVersion']; - this.time = data['time']; - this.value = data['value']; - this.tangentMode = data['tangentMode']; - this.inSlope = data['inSlope'] == 'Infinity' ? NaN : data['inSlope']; - this.outSlope = data['outSlope'] == 'Infinity' ? NaN : data['outSlope']; - } - - public unSerialized2(data: any) { - this.serializedVersion = data['serializedVersion']; - this.time = data['time']; - this.value = data['value']; - this.tangentMode = data['tangentMode']; - this.inSlope = data['inTangent'] == 'Infinity' ? NaN : data['inTangent']; - this.outSlope = data['outTangent'] == 'Infinity' ? NaN : data['outTangent']; - } -} - -/** - * @internal - * @group Math - */ -export class FrameCache { - public index: number; //= lhsIndex; - public time: number; // = lhs.time + timeOffset; - public timeEnd: number; // = rhs.time + timeOffset; - public coeff: number[] = []; //= lhsIndex; -} - -/** - * Animation Cureve - * has frame list data - * @group Math - */ -export class AnimationCurve { - private _totalTime: number = 1; - - private _cache: FrameCache = new FrameCache(); - - private _cacheOut: { lhsIndex: number; rhsIndex: number } = { - lhsIndex: 0, - rhsIndex: 0, - }; - - private _InvalidateCache: boolean = false; - - public curve: Keyframe[] = []; - - public serializedVersion: number; - - public preWarpMode: number; - - public postWarpMode: number; - - public rotationOrder: number; - - constructor(frames?: Keyframe[], preWarpMode: WrapTimeMode = WrapTimeMode.Repeat, postWarpMode: WrapTimeMode = WrapTimeMode.Repeat) { - if (frames) for (let i = 0; i < frames.length; i++) { - const frame = frames[i]; - this.addKeyFrame(frame); - } - this.preWarpMode = preWarpMode; - this.postWarpMode = postWarpMode; - } - - /** - * return this curve use total time - */ - public get totalTime() { - return this._totalTime; - } - - /** - * get curve first keframe time - */ - public get first(): Keyframe { - return this.curve[0]; - } - - /** - * get curve last keyframe time - */ - public get last(): Keyframe { - return this.curve[this.curve.length - 1]; - } - - /** - * add keyFrame to curve keyframe last and calcTotalTime - * @param keyFrame {@link Keyframe} sea: one key frame data - */ - public addKeyFrame(keyFrame: Keyframe) { - if (this.curve.indexOf(keyFrame) == -1) { - this.curve.push(keyFrame); - } - this.calcTotalTime(); - } - - /** - * remove keyframe form this curve - * @param keyFrame {@link Keyframe} - */ - public removeKeyFrame(keyFrame: Keyframe) { - let index = this.curve.indexOf(keyFrame); - if (index != -1) { - this.curve.splice(index, 1); - } - - this.calcTotalTime(); - } - - /** - * calculate keyframe list in to timeline - * @param cache {@link FrameCache} - * @param lhsIndex left frame index - * @param rhsIndex right frame index - * @param timeOffset offset time default 0.0 - */ - public calculateCacheData(cache: FrameCache, lhsIndex: number, rhsIndex: number, timeOffset: number = 0) { - let m_Curve = this.curve; - let lhs = m_Curve[lhsIndex]; - let rhs = m_Curve[rhsIndex]; - // DebugAssertIf (timeOffset < -0.001F || timeOffset - 0.001F > rhs.time - lhs.time); - cache.index = lhsIndex; - cache.time = lhs.time + timeOffset; - cache.timeEnd = rhs.time + timeOffset; - cache.index = lhsIndex; - - let dx, length; - let dy; - let m1, m2, d1, d2; - - dx = rhs.time - lhs.time; - dx = Math.max(dx, 0.0001); - dy = rhs.value - lhs.value; - length = 1.0 / (dx * dx); - - m1 = lhs.outSlope; - m2 = rhs.inSlope; - d1 = m1 * dx; - d2 = m2 * dx; - - cache.coeff[0] = ((d1 + d2 - dy - dy) * length) / dx; - cache.coeff[1] = (dy + dy + dy - d1 - d1 - d2) * length; - cache.coeff[2] = m1; - cache.coeff[3] = lhs.value; - this.setupStepped(cache.coeff, lhs, rhs); - } - - /** - * get caculate frames value - * @param time - * @returns - */ - public getValue(time: number): number { - time = this.wrapTime(time); - - this.findCurve(time, this._cacheOut); - - this.calculateCacheData(this._cache, this._cacheOut.lhsIndex, this._cacheOut.rhsIndex, 0); - - return this.evaluateCache(this._cache, time); - } - - /** - * get has Keyframe list count - * @returns int - */ - public getKeyCount(): number { - return this.curve.length; - } - - /** - * Get a Keyframe Data by Index - * @param index must int - * @returns Keyframe {@link Keyframe} - */ - public getKey(index: number): Keyframe { - return this.curve[index]; - } - - public unSerialized(data: any): this { - this.preWarpMode = data['m_PreInfinity']; - this.postWarpMode = data['m_PostInfinity']; - this.rotationOrder = data['m_RotationOrder']; - - let len = data['m_Curve'].length; - for (let i = 0; i < len; i++) { - this.curve[i] = new Keyframe(); - this.curve[i].unSerialized(data['m_Curve'][i.toString()]); - } - this.calcTotalTime(); - return this; - } - - public unSerialized2(data: Object): this { - this.preWarpMode = data['preWrapMode']; - this.postWarpMode = data['postWrapMode']; - - let keyFrames = data['keyFrames'] || data['keys']; - let len = keyFrames.length; - for (let i = 0; i < len; i++) { - this.curve[i] = new Keyframe(); - this.curve[i].unSerialized2(keyFrames[i.toString()]); - } - this.calcTotalTime(); - return this; - } - - private wrapTime(curveT: number) { - let m_Curve = this.curve; - let begTime = m_Curve[0].time; - let endTime = m_Curve[m_Curve.length - 1].time; - - if (curveT < begTime) { - if (this.preWarpMode == WrapTimeMode.Clamp) curveT = begTime; - else if (this.preWarpMode == WrapTimeMode.PingPong) curveT = PingPong(curveT, begTime, endTime); - else curveT = RepeatSE(curveT, begTime, endTime); - } else if (curveT > endTime) { - if (this.postWarpMode == WrapTimeMode.Clamp) curveT = endTime; - else if (this.postWarpMode == WrapTimeMode.PingPong) curveT = PingPong(curveT, begTime, endTime); - else curveT = RepeatSE(curveT, begTime, endTime); - } - return curveT; - } - - private evaluateCache(cache: FrameCache, curveT: number): number { - let t = curveT - cache.time; - let output = t * (t * (t * cache.coeff[0] + cache.coeff[1]) + cache.coeff[2]) + cache.coeff[3]; - return output; - } - - private findCurve(time: number, out: { lhsIndex: number; rhsIndex: number }) { - let frames = this.curve; - for (let i = 1; i < frames.length; i++) { - let left = frames[i - 1]; - let right = frames[i]; - if (left.time <= time && right.time > time) { - out.lhsIndex = i - 1; - out.rhsIndex = i; - } - } - } - - private setupStepped(coeff: number[], lhs: Keyframe, rhs: Keyframe) { - if (isNaN(lhs.outSlope) || isNaN(rhs.inSlope)) { - coeff[0] = 0.0; - coeff[1] = 0.0; - coeff[2] = 0.0; - coeff[3] = lhs.value; - } - } - - private invalidateCache() { - this._InvalidateCache = true; - } - - private calcTotalTime() { - let maxTime = 0; - for (let curve of this.curve) { - maxTime = Math.max(maxTime, curve.time); - } - this._totalTime = maxTime; - } - - public static scaleCurveValue(curve: AnimationCurve, scale: number) { - if (!curve._InvalidateCache) { - for (let i = 0; i < curve.curve.length; i++) { - let c = curve.curve[i]; - c.value *= scale; - c.inSlope *= scale; - c.outSlope *= scale; - } - } - curve.invalidateCache(); - } -} +import { PingPong, RepeatSE } from './MathUtil'; + +/** + * Time Warp Mode + * @PingPong value min -> max -> min + * @Repeat value = value % repeatSpace + * @Clamp value = max(min( value , 1 ) , 0 ) + */ +export enum WrapTimeMode { + PingPong = 0, + Repeat = 1, + Clamp = 2, +} + +/** + * @group Math + */ +export class Keyframe { + public serializedVersion: string = '2'; + public time: number; + public value: number; + public inSlope: number = 0; + public outSlope: number = 0; + public tangentMode: number = 0; + + constructor(time: number = 0, value: number = 0) { + this.time = time; + this.value = value; + } + + public unSerialized(data: any) { + this.serializedVersion = data['serializedVersion']; + this.time = data['time']; + this.value = data['value']; + this.tangentMode = data['tangentMode']; + this.inSlope = data['inSlope'] == 'Infinity' ? NaN : data['inSlope']; + this.outSlope = data['outSlope'] == 'Infinity' ? NaN : data['outSlope']; + } + + public unSerialized2(data: any) { + this.serializedVersion = data['serializedVersion']; + this.time = data['time']; + this.value = data['value']; + this.tangentMode = data['tangentMode']; + this.inSlope = data['inTangent'] == 'Infinity' ? NaN : data['inTangent']; + this.outSlope = data['outTangent'] == 'Infinity' ? NaN : data['outTangent']; + } +} + +/** + * @internal + * @group Math + */ +export class FrameCache { + public index: number; //= lhsIndex; + public time: number; // = lhs.time + timeOffset; + public timeEnd: number; // = rhs.time + timeOffset; + public coeff: number[] = []; //= lhsIndex; +} + +/** + * Animation Cureve + * has frame list data + * @group Math + */ +export class AnimationCurve { + private _totalTime: number = 1; + + private _cache: FrameCache = new FrameCache(); + + private _cacheOut: { lhsIndex: number; rhsIndex: number } = { + lhsIndex: 0, + rhsIndex: 0, + }; + + private _InvalidateCache: boolean = false; + + public curve: Keyframe[] = []; + + public serializedVersion: number; + + public preWarpMode: number; + + public postWarpMode: number; + + public rotationOrder: number; + + constructor(frames?: Keyframe[], preWarpMode: WrapTimeMode = WrapTimeMode.Repeat, postWarpMode: WrapTimeMode = WrapTimeMode.Repeat) { + if (frames) for (let i = 0; i < frames.length; i++) { + const frame = frames[i]; + this.addKeyFrame(frame); + } + this.preWarpMode = preWarpMode; + this.postWarpMode = postWarpMode; + } + + /** + * return this curve use total time + */ + public get totalTime() { + return this._totalTime; + } + + /** + * get curve first keframe time + */ + public get first(): Keyframe { + return this.curve[0]; + } + + /** + * get curve last keyframe time + */ + public get last(): Keyframe { + return this.curve[this.curve.length - 1]; + } + + /** + * add keyFrame to curve keyframe last and calcTotalTime + * @param keyFrame {@link Keyframe} sea: one key frame data + */ + public addKeyFrame(keyFrame: Keyframe) { + if (this.curve.indexOf(keyFrame) == -1) { + this.curve.push(keyFrame); + } + this.calcTotalTime(); + } + + /** + * remove keyframe form this curve + * @param keyFrame {@link Keyframe} + */ + public removeKeyFrame(keyFrame: Keyframe) { + let index = this.curve.indexOf(keyFrame); + if (index != -1) { + this.curve.splice(index, 1); + } + + this.calcTotalTime(); + } + + /** + * calculate keyframe list in to timeline + * @param cache {@link FrameCache} + * @param lhsIndex left frame index + * @param rhsIndex right frame index + * @param timeOffset offset time default 0.0 + */ + public calculateCacheData(cache: FrameCache, lhsIndex: number, rhsIndex: number, timeOffset: number = 0) { + let m_Curve = this.curve; + let lhs = m_Curve[lhsIndex]; + let rhs = m_Curve[rhsIndex]; + // DebugAssertIf (timeOffset < -0.001F || timeOffset - 0.001F > rhs.time - lhs.time); + cache.index = lhsIndex; + cache.time = lhs.time + timeOffset; + cache.timeEnd = rhs.time + timeOffset; + cache.index = lhsIndex; + + let dx, length; + let dy; + let m1, m2, d1, d2; + + dx = rhs.time - lhs.time; + dx = Math.max(dx, 0.0001); + dy = rhs.value - lhs.value; + length = 1.0 / (dx * dx); + + m1 = lhs.outSlope; + m2 = rhs.inSlope; + d1 = m1 * dx; + d2 = m2 * dx; + + cache.coeff[0] = ((d1 + d2 - dy - dy) * length) / dx; + cache.coeff[1] = (dy + dy + dy - d1 - d1 - d2) * length; + cache.coeff[2] = m1; + cache.coeff[3] = lhs.value; + this.setupStepped(cache.coeff, lhs, rhs); + } + + /** + * get caculate frames value + * @param time + * @returns + */ + public getValue(time: number): number { + time = this.wrapTime(time); + + this.findCurve(time, this._cacheOut); + + this.calculateCacheData(this._cache, this._cacheOut.lhsIndex, this._cacheOut.rhsIndex, 0); + + return this.evaluateCache(this._cache, time); + } + + /** + * get has Keyframe list count + * @returns int + */ + public getKeyCount(): number { + return this.curve.length; + } + + /** + * Get a Keyframe Data by Index + * @param index must int + * @returns Keyframe {@link Keyframe} + */ + public getKey(index: number): Keyframe { + return this.curve[index]; + } + + public unSerialized(data: any): this { + this.preWarpMode = data['m_PreInfinity']; + this.postWarpMode = data['m_PostInfinity']; + this.rotationOrder = data['m_RotationOrder']; + + let len = data['m_Curve'].length; + for (let i = 0; i < len; i++) { + this.curve[i] = new Keyframe(); + this.curve[i].unSerialized(data['m_Curve'][i.toString()]); + } + this.calcTotalTime(); + return this; + } + + public unSerialized2(data: Object): this { + this.preWarpMode = data['preWrapMode']; + this.postWarpMode = data['postWrapMode']; + + let keyFrames = data['keyFrames'] || data['keys']; + let len = keyFrames.length; + for (let i = 0; i < len; i++) { + this.curve[i] = new Keyframe(); + this.curve[i].unSerialized2(keyFrames[i.toString()]); + } + this.calcTotalTime(); + return this; + } + + private wrapTime(curveT: number) { + let m_Curve = this.curve; + let begTime = m_Curve[0].time; + let endTime = m_Curve[m_Curve.length - 1].time; + + if (curveT < begTime) { + if (this.preWarpMode == WrapTimeMode.Clamp) curveT = begTime; + else if (this.preWarpMode == WrapTimeMode.PingPong) curveT = PingPong(curveT, begTime, endTime); + else curveT = RepeatSE(curveT, begTime, endTime); + } else if (curveT > endTime) { + if (this.postWarpMode == WrapTimeMode.Clamp) curveT = endTime; + else if (this.postWarpMode == WrapTimeMode.PingPong) curveT = PingPong(curveT, begTime, endTime); + else curveT = RepeatSE(curveT, begTime, endTime); + } + return curveT; + } + + private evaluateCache(cache: FrameCache, curveT: number): number { + let t = curveT - cache.time; + let output = t * (t * (t * cache.coeff[0] + cache.coeff[1]) + cache.coeff[2]) + cache.coeff[3]; + return output; + } + + private findCurve(time: number, out: { lhsIndex: number; rhsIndex: number }) { + let frames = this.curve; + for (let i = 1; i < frames.length; i++) { + let left = frames[i - 1]; + let right = frames[i]; + if (left.time <= time && right.time > time) { + out.lhsIndex = i - 1; + out.rhsIndex = i; + } + } + } + + private setupStepped(coeff: number[], lhs: Keyframe, rhs: Keyframe) { + if (isNaN(lhs.outSlope) || isNaN(rhs.inSlope)) { + coeff[0] = 0.0; + coeff[1] = 0.0; + coeff[2] = 0.0; + coeff[3] = lhs.value; + } + } + + private invalidateCache() { + this._InvalidateCache = true; + } + + private calcTotalTime() { + let maxTime = 0; + for (let curve of this.curve) { + maxTime = Math.max(maxTime, curve.time); + } + this._totalTime = maxTime; + } + + public static scaleCurveValue(curve: AnimationCurve, scale: number) { + if (!curve._InvalidateCache) { + for (let i = 0; i < curve.curve.length; i++) { + let c = curve.curve[i]; + c.value *= scale; + c.inSlope *= scale; + c.outSlope *= scale; + } + } + curve.invalidateCache(); + } +} diff --git a/src/engine/math/Bezier2D.ts b/src/math/Bezier2D.ts similarity index 96% rename from src/engine/math/Bezier2D.ts rename to src/math/Bezier2D.ts index ecb3681c..5ce18982 100644 --- a/src/engine/math/Bezier2D.ts +++ b/src/math/Bezier2D.ts @@ -1,95 +1,95 @@ -import { MathUtil } from './MathUtil'; -import { Vector2 } from './Vector2'; -/** - * 2D Bezier Curve - * @group Math - */ -export class Bezier2D { - - private _points: Vector2[]; - - private _cacheValue: Vector2; - - /** - * instance bezier class - */ - constructor(vec2Ds: Vector2[] = []) { - this.points = vec2Ds; - this._cacheValue = new Vector2(); - } - - /** - * get all bezier 2d points - */ - public get points(): Vector2[] { - return this._points; - } - - /** - * set bezier 2d point[x,y] list must great 4 - */ - public set points(value: Vector2[]) { - this._points = value; - } - - /** - * get point2d at curve - * @param v 0.0 ~ 1.0 - * @returns return point2D at curve - */ - public getValue(v: number): Vector2 { - if (v < 0) v = 0; - if (v > 1) v = 1; - - let len = this.points.length - 1; - let ci = Math.floor(len * v); - let ni = ci + 1; - let w = MathUtil.fract((len + 1) * v); - if (ni >= len) { - ni = ci; - w = 0; - } - - this._cacheValue.x = this.points[ci].x + (this.points[ni].x - this.points[ci].x) * w; - this._cacheValue.y = this.points[ci].y + (this.points[ni].y - this.points[ci].y) * w; - return this._cacheValue; - } - - /** - * caclute bezier curve points at line [ 0.0 , 1.0 ] - * @param anchorpoints bezier anchor - * @param pointsAmount point count - * @returns get a bezier curve [Bezier2D] - */ - public static createBezierPoints(anchorpoints: Vector2[], pointsAmount: number): Bezier2D { - var bezier2d: Bezier2D = new Bezier2D(); - for (var i = 0; i < pointsAmount; i++) { - var point = Bezier2D.multiPointBezier(anchorpoints, i / pointsAmount); - bezier2d.points.push(point); - } - return bezier2d; - } - - private static multiPointBezier(points: Vector2[], t: number) { - var len = points.length; - var x = 0, - y = 0; - var erxiangshi = function (start: number, end: number) { - var cs = 1, - bcs = 1; - while (end > 0) { - cs *= start; - bcs *= end; - start--; - end--; - } - return cs / bcs; - }; - for (var i = 0; i < len; i++) { - var point = points[i]; - x += point.x * Math.pow(1 - t, len - 1 - i) * Math.pow(t, i) * erxiangshi(len - 1, i); - y += point.y * Math.pow(1 - t, len - 1 - i) * Math.pow(t, i) * erxiangshi(len - 1, i); - } - return new Vector2(x, y); - } -} +import { MathUtil } from './MathUtil'; +import { Vector2 } from './Vector2'; +/** + * 2D Bezier Curve + * @group Math + */ +export class Bezier2D { + + private _points: Vector2[]; + + private _cacheValue: Vector2; + + /** + * instance bezier class + */ + constructor(vec2Ds: Vector2[] = []) { + this.points = vec2Ds; + this._cacheValue = new Vector2(); + } + + /** + * get all bezier 2d points + */ + public get points(): Vector2[] { + return this._points; + } + + /** + * set bezier 2d point[x,y] list must great 4 + */ + public set points(value: Vector2[]) { + this._points = value; + } + + /** + * get point2d at curve + * @param v 0.0 ~ 1.0 + * @returns return point2D at curve + */ + public getValue(v: number): Vector2 { + if (v < 0) v = 0; + if (v > 1) v = 1; + + let len = this.points.length - 1; + let ci = Math.floor(len * v); + let ni = ci + 1; + let w = MathUtil.fract((len + 1) * v); + if (ni >= len) { + ni = ci; + w = 0; + } + + this._cacheValue.x = this.points[ci].x + (this.points[ni].x - this.points[ci].x) * w; + this._cacheValue.y = this.points[ci].y + (this.points[ni].y - this.points[ci].y) * w; + return this._cacheValue; + } + + /** + * caclute bezier curve points at line [ 0.0 , 1.0 ] + * @param anchorpoints bezier anchor + * @param pointsAmount point count + * @returns get a bezier curve [Bezier2D] + */ + public static createBezierPoints(anchorpoints: Vector2[], pointsAmount: number): Bezier2D { + var bezier2d: Bezier2D = new Bezier2D(); + for (var i = 0; i < pointsAmount; i++) { + var point = Bezier2D.multiPointBezier(anchorpoints, i / pointsAmount); + bezier2d.points.push(point); + } + return bezier2d; + } + + private static multiPointBezier(points: Vector2[], t: number) { + var len = points.length; + var x = 0, + y = 0; + var erxiangshi = function (start: number, end: number) { + var cs = 1, + bcs = 1; + while (end > 0) { + cs *= start; + bcs *= end; + start--; + end--; + } + return cs / bcs; + }; + for (var i = 0; i < len; i++) { + var point = points[i]; + x += point.x * Math.pow(1 - t, len - 1 - i) * Math.pow(t, i) * erxiangshi(len - 1, i); + y += point.y * Math.pow(1 - t, len - 1 - i) * Math.pow(t, i) * erxiangshi(len - 1, i); + } + return new Vector2(x, y); + } +} diff --git a/src/engine/math/Bezier3D.ts b/src/math/Bezier3D.ts similarity index 96% rename from src/engine/math/Bezier3D.ts rename to src/math/Bezier3D.ts index a869392e..c8bf8e0a 100644 --- a/src/engine/math/Bezier3D.ts +++ b/src/math/Bezier3D.ts @@ -1,122 +1,122 @@ -import { Vector3 } from './Vector3'; -/** - * 3D Bezier Curve - * @group Math - */ -export class Bezier3D { - private static tmp_points: Vector3[] = []; - - /** - * get cubic curve point value form t at bezier data - * @param t interval value - * @param p0 start point - * @param c1 left control point - * @param c2 right control point - * @param p3 end point - * @returns cubic curve point - */ - public static calculateCubicBezierPoint(t: number, p0: Vector3, c1: Vector3, c2: Vector3, p3: Vector3): Vector3 { - if (t > 1) t = 1; - if (t < 0) t = 0; - let u = 1 - t; - let uu = u * u; - let uuu = u * u * u; - let tt = t * t; - let ttt = t * t * t; - let p = p0.mul(uuu); - let tp1 = c1.mul(3); - tp1 = tp1.mul(t); - tp1 = tp1.mul(uu); - - let tp2 = c2.mul(3); - tp2 = tp2.mul(tt); - tp2 = tp2.mul(u); - - let tp3 = p3.mul(ttt); - p = p.add(tp1); - p = p.add(tp2); - p = p.add(tp3); - return p; - } - - /** - * get curve point form three point bezier curve - * @param t interval value - * @param p0 start point - * @param c1 contrl point - * @param p1 end point - * @returns get bezier point at curve - */ - public static bezierPoint(t: number, p0: Vector3, c1: Vector3, p1: Vector3): Vector3 { - if (t > 1) t = 1; - if (t < 0) t = 0; - let u = 1 - t; - let uu = u * u; - let tt = t * t; - - let pp0 = p0.mul(uu); - - let cc1 = c1.mul(2); - cc1.scaleBy(u); - cc1.scaleBy(t); - - let pp1 = p1.mul(tt); - - pp0 = pp0.add(cc1); - pp0 = pp0.add(pp1); - - return pp0; - } - - private static calculateCubicBezierPoints(t: number, ps: Vector3[], skip: number): Vector3 { - if (t > 1) t = 1; - if (t < 0) t = 0; - let u = 1 - t; - let uu = u * u; - let uuu = u * u * u; - let tt = t * t; - let ttt = t * t * t; - let p = ps[skip].mul(uuu); - let tp1 = ps[skip + 1].mul(3); - tp1 = tp1.mul(t); - tp1 = tp1.mul(uu); - - let tp2 = ps[skip + 2].mul(3); - tp2 = tp2.mul(tt); - tp2 = tp2.mul(u); - - let tp3 = ps[skip + 3].mul(ttt); - p = p.add(tp1); - p = p.add(tp2); - p = p.add(tp3); - - return p; - } - - private static bezierPathValue(t: number, points: Vector3[]): Vector3 { - if (t > 1) t = 1; - if (t < 0) t = 0; - let count = points.length; - let tmp_points = this.tmp_points; - tmp_points.length = 0; - - for (let i = 1; i < count; ++i) { - for (let j = 0; j < count - i; ++j) { - if (i == 1) { - let v = new Vector3(); - v.x = points[j].x * (1 - t) + points[j + 1].x * t; - v.y = points[j].y * (1 - t) + points[j + 1].y * t; - v.z = points[j].z * (1 - t) + points[j + 1].z * t; - this.tmp_points.push(v); - continue; - } - let v2 = new Vector3(); - v2.x = tmp_points[j].x * (1 - t) + tmp_points[j + 1].x * t; - v2.y = tmp_points[j].y * (1 - t) + tmp_points[j + 1].y * t; - v2.z = tmp_points[j].z * (1 - t) + tmp_points[j + 1].z * t; - tmp_points.push(v2); - } - } - return tmp_points[0]; - } -} +import { Vector3 } from './Vector3'; +/** + * 3D Bezier Curve + * @group Math + */ +export class Bezier3D { + private static tmp_points: Vector3[] = []; + + /** + * get cubic curve point value form t at bezier data + * @param t interval value + * @param p0 start point + * @param c1 left control point + * @param c2 right control point + * @param p3 end point + * @returns cubic curve point + */ + public static calculateCubicBezierPoint(t: number, p0: Vector3, c1: Vector3, c2: Vector3, p3: Vector3): Vector3 { + if (t > 1) t = 1; + if (t < 0) t = 0; + let u = 1 - t; + let uu = u * u; + let uuu = u * u * u; + let tt = t * t; + let ttt = t * t * t; + let p = p0.mul(uuu); + let tp1 = c1.mul(3); + tp1 = tp1.mul(t); + tp1 = tp1.mul(uu); + + let tp2 = c2.mul(3); + tp2 = tp2.mul(tt); + tp2 = tp2.mul(u); + + let tp3 = p3.mul(ttt); + p = p.add(tp1); + p = p.add(tp2); + p = p.add(tp3); + return p; + } + + /** + * get curve point form three point bezier curve + * @param t interval value + * @param p0 start point + * @param c1 contrl point + * @param p1 end point + * @returns get bezier point at curve + */ + public static bezierPoint(t: number, p0: Vector3, c1: Vector3, p1: Vector3): Vector3 { + if (t > 1) t = 1; + if (t < 0) t = 0; + let u = 1 - t; + let uu = u * u; + let tt = t * t; + + let pp0 = p0.mul(uu); + + let cc1 = c1.mul(2); + cc1.scaleBy(u); + cc1.scaleBy(t); + + let pp1 = p1.mul(tt); + + pp0 = pp0.add(cc1); + pp0 = pp0.add(pp1); + + return pp0; + } + + private static calculateCubicBezierPoints(t: number, ps: Vector3[], skip: number): Vector3 { + if (t > 1) t = 1; + if (t < 0) t = 0; + let u = 1 - t; + let uu = u * u; + let uuu = u * u * u; + let tt = t * t; + let ttt = t * t * t; + let p = ps[skip].mul(uuu); + let tp1 = ps[skip + 1].mul(3); + tp1 = tp1.mul(t); + tp1 = tp1.mul(uu); + + let tp2 = ps[skip + 2].mul(3); + tp2 = tp2.mul(tt); + tp2 = tp2.mul(u); + + let tp3 = ps[skip + 3].mul(ttt); + p = p.add(tp1); + p = p.add(tp2); + p = p.add(tp3); + + return p; + } + + private static bezierPathValue(t: number, points: Vector3[]): Vector3 { + if (t > 1) t = 1; + if (t < 0) t = 0; + let count = points.length; + let tmp_points = this.tmp_points; + tmp_points.length = 0; + + for (let i = 1; i < count; ++i) { + for (let j = 0; j < count - i; ++j) { + if (i == 1) { + let v = new Vector3(); + v.x = points[j].x * (1 - t) + points[j + 1].x * t; + v.y = points[j].y * (1 - t) + points[j + 1].y * t; + v.z = points[j].z * (1 - t) + points[j + 1].z * t; + this.tmp_points.push(v); + continue; + } + let v2 = new Vector3(); + v2.x = tmp_points[j].x * (1 - t) + tmp_points[j + 1].x * t; + v2.y = tmp_points[j].y * (1 - t) + tmp_points[j + 1].y * t; + v2.z = tmp_points[j].z * (1 - t) + tmp_points[j + 1].z * t; + tmp_points.push(v2); + } + } + return tmp_points[0]; + } +} diff --git a/src/engine/math/Color.ts b/src/math/Color.ts similarity index 96% rename from src/engine/math/Color.ts rename to src/math/Color.ts index 361763de..5bb72bc8 100644 --- a/src/engine/math/Color.ts +++ b/src/math/Color.ts @@ -1,440 +1,440 @@ -/** - * RGBA Color Object - * @group Math - */ -export class Color { - - /** - * red color - */ - public static COLOR_RED: Color = new Color(1, 0, 0, 1); - - /** - * green color - */ - public static COLOR_GREEN: Color = new Color(0, 1, 0, 1); - - /** - * blue color - */ - public static COLOR_BLUE: Color = new Color(0, 0, 1, 1); - - /** - * white color - */ - public static COLOR_WHITE: Color = new Color(1, 1, 1, 1); - - /** - * cache - * @internal - */ - public static COLOR_0: Color = new Color(); - /** - * cache - * @internal - */ - public static COLOR_1: Color = new Color(); - /** - * cache - * @internal - */ - public static COLOR_2: Color = new Color(); - - /** - * @internal - */ - private static HEX_CHARACTERS = 'a-f\\d'; - - /** - * @internal - */ - private static MATCH_3OR4_HEX = `#?[${Color.HEX_CHARACTERS}]{3}[${Color.HEX_CHARACTERS}]?`; - /** - * @internal - */ - private static MATCH_6OR8_HEX = `#?[${Color.HEX_CHARACTERS}]{6}([${Color.HEX_CHARACTERS}]{2})?`; - /** - * @internal - */ - private static NON_HEX_CHARS = new RegExp(`[^#${Color.HEX_CHARACTERS}]`, 'gi'); - /** - * @internal - */ - private static VALID_HEX_SIZE = new RegExp(`^${Color.MATCH_3OR4_HEX}$|^${Color.MATCH_6OR8_HEX}$`, 'i'); - - /** - * red channel - */ - public r: number = 0; - - /** - * green channel - */ - public g: number = 0; - - /** - * blue channel - */ - public b: number = 0; - - /** - * alpha channel - */ - public a: number = 0; - - /** - * create new color instance - * @param r red channel - * @param g green channel - * @param b blue channel - * @param a alpha channel - */ - constructor(r: number = 1.0, g: number = 1.0, b: number = 1.0, a: number = 1.0) { - this.setTo(r, g, b, a); - } - - /*** - * convert to hdr color , channel a is intensity - */ - convertToHDRRGB(): Color { - this.r = this.r * Math.pow(2.4, this.a); - this.g = this.g * Math.pow(2.4, this.a); - this.b = this.b * Math.pow(2.4, this.a); - return this; - } - - /** - * unSerialized color by data - * @param data - * @returns - */ - public unSerialized(data: any): this { - this.r = data['r']; - this.g = data['g']; - this.b = data['b']; - this.a = data['a']; - return this; - } - - /** - * update this color rgb form hexadecimal no alpha - * @param value - */ - public hexToRGB(value: number) { - //this.a = ((value >> 24) & 0xff ) / 255; - this.r = ((value >> 16) & 0xff) / 255; - this.g = ((value >> 8) & 0xff) / 255; - this.b = (value & 0xff) / 255; - } - - /** - * update this color rgb form hexadecimal has alpha - * @param value - */ - public hexToRGBA(value: number) { - this.a = ((value >> 24) & 0xff) / 255; - this.r = ((value >> 16) & 0xff) / 255; - this.g = ((value >> 8) & 0xff) / 255; - this.b = (value & 0xff) / 255; - } - - /** - * random on color - * @returns - */ - public static random(base: number = 1.0): Color { - let color = new Color(); - color.a = base; - color.r = base * Math.random(); - color.g = base * Math.random(); - color.b = base * Math.random(); - return color; - } - - /** - * set rgba to this color - * @param r red channel - * @param g green channel - * @param b blue channel - * @param a alpha channel - */ - public setTo(r: number, g: number, b: number, a: number) { - this.r = Math.max(r, 0.0); - this.g = Math.max(g, 0.0); - this.b = Math.max(b, 0.0); - this.a = Math.max(a, 0.0); - } - - /** - * update this color rgba form hexadecimal - * @param hex hex string。 - */ - public setHex(hex: string) { - if (typeof hex !== 'string' || Color.NON_HEX_CHARS.test(hex) || !Color.VALID_HEX_SIZE.test(hex)) { - throw new TypeError('Expected a valid hex string'); - } - hex = hex.replace(/^#/, ''); - let alphaFromHex = 1; - - if (hex.length === 8) { - alphaFromHex = Number.parseInt(hex.slice(6, 8), 16) / 255; - hex = hex.slice(0, 6); - } - - if (hex.length === 4) { - alphaFromHex = Number.parseInt(hex.slice(3, 4).repeat(2), 16) / 255; - hex = hex.slice(0, 3); - } - - if (hex.length === 3) { - hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; - } - - const number = Number.parseInt(hex, 16); - const red = number >> 16; - const green = (number >> 8) & 255; - const blue = number & 255; - const alpha = alphaFromHex; - this.a = alpha; - this.r = red / 255; - this.g = green / 255; - this.b = blue / 255; - } - - /** - * convert this color to hex string code - * @returns - */ - public getHex(): string { - let getHexStr = (n: number) => { - n *= 255.0; - let str = n.toString(16); - if (str.length === 1) { - str = '0' + str; - } - return str; - }; - let hex = getHexStr(this.r) + getHexStr(this.g) + getHexStr(this.b) + getHexStr(this.a); - return hex; - } - - /** - * get rgb to array - */ - public get rgb(): number[] { - return [(this.r * 255) >>> 0, (this.g * 255) >>> 0, (this.b * 255) >>> 0]; - } - - /** - * set rgb by array - */ - public set rgb(c: number[]) { - this.setTo(c[0] / 255, c[1] / 255, c[2] / 255, this.a); - } - - /** - * get rgba to array - */ - public get rgba(): number[] { - return [(this.r * 255) >>> 0, (this.g * 255) >>> 0, (this.b * 255) >>> 0, (this.a * 255) >>> 0]; - } - - /** - * set rgb by array - */ - public set rgba(c: number[]) { - this.setTo(c[0] / 255, c[1] / 255, c[2] / 255, c[3] / 255); - } - - /** - * clone this color - * @returns - */ - public clone(): Color { - return new Color().copyForm(this); - } - - /** - * copy color form source color - * @returns - */ - public copyForm(src: Color): this { - this.r = src.r; - this.g = src.g; - this.b = src.b; - this.a = src.a; - return this; - } - - /** - * copy color form array - * @param arr [ 255 , 255 , 255 , 255 ] - * @param scalar - * @returns - */ - public copyFormArray(arr: number[], scalar: number = 255) { - this.r = arr[0] / scalar; - this.g = arr[1] / scalar; - this.b = arr[2] / scalar; - this.a = arr[3] / scalar; - return this; - } - - /** - * update this color rgb form hexadecimal no alpha - * @param hexColor rgb color - * @param dst ref out color - */ - public static hexRGBColor(hexColor: number, dst: Color = null): Color { - dst = dst || new Color(); - dst.hexToRGB(hexColor); - return dst; - } - - - - public static PRIMARY = 0x3f51b5; // - public static PRIMARYDARK = 0x303f9f; // - public static ACCENT = 0xff4081; // - - public static WHITE = 0xffffff; - public static IVORY = 0xfffff0; - public static LIGHTYELLOW = 0xffffe0; - public static YELLOW = 0xffff00; - public static SNOW = 0xfffafa; - public static FLORALWHITE = 0xfffaf0; - public static LEMONCHIFFON = 0xfffacd; - public static CORNSILK = 0xfff8dc; - public static SEASHELL = 0xfff5ee; - public static LAVENDERBLUSH = 0xfff0f5; - public static PAPAYAWHIP = 0xffefd5; - public static BLANCHEDALMOND = 0xffebcd; - public static MISTYROSE = 0xffe4e1; - public static BISQUE = 0xffe4c4; - public static MOCCASIN = 0xffe4b5; - public static NAVAJOWHITE = 0xffdead; - public static PEACHPUFF = 0xffdab9; - public static GOLD = 0xffd700; - public static PINK = 0xffc0cb; - public static LIGHTPINK = 0xffb6c1; - public static ORANGE = 0xffa500; - public static LIGHTSALMON = 0xffa07a; - public static DARKORANGE = 0xff8c00; - public static CORAL = 0xff7f50; - public static HOTPINK = 0xff69b4; - public static TOMATO = 0xff6347; - public static ORANGERED = 0xff4500; - public static DEEPPINK = 0xff1493; - public static FUCHSIA = 0xff00ff; - public static MAGENTA = 0xff00ff; - public static RED = 0xff0000; - public static OLDLACE = 0xfdf5e6; - public static LIGHTGOLDENRODYELLOW = 0xfafad2; - public static LINEN = 0xfaf0e6; - public static ANTIQUEWHITE = 0xfaebd7; - public static SALMON = 0xfa8072; - public static GHOSTWHITE = 0xf8f8ff; - public static MINTCREAM = 0xf5fffa; - public static WHITESMOKE = 0xf5f5f5; - public static BEIGE = 0xf5f5dc; - public static WHEAT = 0xf5deb3; - public static SANDYBROWN = 0xf4a460; - public static AZURE = 0xf0ffff; - public static HONEYDEW = 0xf0fff0; - public static ALICEBLUE = 0xf0f8ff; - public static KHAKI = 0xf0e68c; - public static LIGHTCORAL = 0xf08080; - public static PALEGOLDENROD = 0xeee8aa; - public static VIOLET = 0xee82ee; - public static DARKSALMON = 0xe9967a; - public static LAVENDER = 0xe6e6fa; - public static LIGHTCYAN = 0xe0ffff; - public static BURLYWOOD = 0xdeb887; - public static PLUM = 0xdda0dd; - public static GAINSBORO = 0xdcdcdc; - public static CRIMSON = 0xdc143c; - public static PALEVIOLETRED = 0xdb7093; - - public static GOLDENROD = 0xdaa520; - public static ORCHID = 0xda70d6; - public static THISTLE = 0xd8bfd8; - public static LIGHTGREY = 0xd3d3d3; - public static TAN = 0xd2b48c; - public static CHOCOLATE = 0xd2691e; - public static PERU = 0xcd853f; - public static INDIANRED = 0xcd5c5c; - public static MEDIUMVIOLETRED = 0xc71585; - public static SILVER = 0xc0c0c0; - public static DARKKHAKI = 0xbdb76b; - public static ROSYBROWN = 0xbc8f8f; - public static MEDIUMORCHID = 0xba55d3; - public static DARKGOLDENROD = 0xb8860b; - public static FIREBRICK = 0xb22222; - public static POWDERBLUE = 0xb0e0e6; - public static LIGHTSTEELBLUE = 0xb0c4de; - public static PALETURQUOISE = 0xafeeee; - public static GREENYELLOW = 0xadff2f; - public static LIGHTBLUE = 0xadd8e6; - public static DARKGRAY = 0xa9a9a9; - public static BROWN = 0xa52a2a; - public static SIENNA = 0xa0522d; - public static DARKORCHID = 0x9932cc; - public static PALEGREEN = 0x98fb98; - public static DARKVIOLET = 0x9400d3; - public static MEDIUMPURPLE = 0x9370db; - public static LIGHTGREEN = 0x90ee90; - public static DARKSEAGREEN = 0x8fbc8f; - public static SADDLEBROWN = 0x8b4513; - public static DARKMAGENTA = 0x8b008b; - public static DARKRED = 0x8b0000; - public static BLUEVIOLET = 0x8a2be2; - public static LIGHTSKYBLUE = 0x87cefa; - public static SKYBLUE = 0x87ceeb; - public static GRAY = 0x808080; - public static OLIVE = 0x808000; - public static PURPLE = 0x800080; - public static MAROON = 0x800000; - public static AQUAMARINE = 0x7fffd4; - public static CHARTREUSE = 0x7fff00; - public static LAWNGREEN = 0x7cfc00; - public static MEDIUMSLATEBLUE = 0x7b68ee; - public static LIGHTSLATEGRAY = 0x778899; - public static SLATEGRAY = 0x708090; - public static OLIVEDRAB = 0x6b8e23; - public static SLATEBLUE = 0x6a5acd; - public static DIMGRAY = 0x696969; - public static MEDIUMAQUAMARINE = 0x66cdaa; - public static CORNFLOWERBLUE = 0x6495ed; - public static CADETBLUE = 0x5f9ea0; - public static DARKOLIVEGREEN = 0x556b2f; - public static INDIGO = 0x4b0082; - public static MEDIUMTURQUOISE = 0x48d1cc; - public static DARKSLATEBLUE = 0x483d8b; - public static STEELBLUE = 0x4682b4; - public static ROYALBLUE = 0x4169e1; - public static TURQUOISE = 0x40e0d0; - public static MEDIUMSEAGREEN = 0x3cb371; - public static LIMEGREEN = 0x32cd32; - public static DARKSLATEGRAY = 0x2f4f4f; - public static SEAGREEN = 0x2e8b57; - public static FORESTGREEN = 0x228b22; - public static LIGHTSEAGREEN = 0x20b2aa; - public static DODGERBLUE = 0x1e90ff; - public static MIDNIGHTBLUE = 0x191970; - public static AQUA = 0x00ffff; - public static CYAN = 0x00ffff; - public static SPRINGGREEN = 0x00ff7f; - public static LIME = 0x00ff00; - public static MEDIUMSPRINGGREEN = 0x00fa9a; - public static DARKTURQUOISE = 0x00ced1; - public static DEEPSKYBLUE = 0x00bfff; - public static DARKCYAN = 0x008b8b; - public static TEAL = 0x008080; - public static GREEN = 0x008000; - public static DARKGREEN = 0x006400; - public static BLUE = 0x0000ff; - public static MEDIUMBLUE = 0x0000cd; - public static DARKBLUE = 0x00008b; - public static NAVY = 0x000080; - public static BLACK = 0x000000; +/** + * RGBA Color Object + * @group Math + */ +export class Color { + + /** + * red color + */ + public static COLOR_RED: Color = new Color(1, 0, 0, 1); + + /** + * green color + */ + public static COLOR_GREEN: Color = new Color(0, 1, 0, 1); + + /** + * blue color + */ + public static COLOR_BLUE: Color = new Color(0, 0, 1, 1); + + /** + * white color + */ + public static COLOR_WHITE: Color = new Color(1, 1, 1, 1); + + /** + * cache + * @internal + */ + public static COLOR_0: Color = new Color(); + /** + * cache + * @internal + */ + public static COLOR_1: Color = new Color(); + /** + * cache + * @internal + */ + public static COLOR_2: Color = new Color(); + + /** + * @internal + */ + private static HEX_CHARACTERS = 'a-f\\d'; + + /** + * @internal + */ + private static MATCH_3OR4_HEX = `#?[${Color.HEX_CHARACTERS}]{3}[${Color.HEX_CHARACTERS}]?`; + /** + * @internal + */ + private static MATCH_6OR8_HEX = `#?[${Color.HEX_CHARACTERS}]{6}([${Color.HEX_CHARACTERS}]{2})?`; + /** + * @internal + */ + private static NON_HEX_CHARS = new RegExp(`[^#${Color.HEX_CHARACTERS}]`, 'gi'); + /** + * @internal + */ + private static VALID_HEX_SIZE = new RegExp(`^${Color.MATCH_3OR4_HEX}$|^${Color.MATCH_6OR8_HEX}$`, 'i'); + + /** + * red channel + */ + public r: number = 0; + + /** + * green channel + */ + public g: number = 0; + + /** + * blue channel + */ + public b: number = 0; + + /** + * alpha channel + */ + public a: number = 0; + + /** + * create new color instance + * @param r red channel + * @param g green channel + * @param b blue channel + * @param a alpha channel + */ + constructor(r: number = 1.0, g: number = 1.0, b: number = 1.0, a: number = 1.0) { + this.setTo(r, g, b, a); + } + + /*** + * convert to hdr color , channel a is intensity + */ + convertToHDRRGB(): Color { + this.r = this.r * Math.pow(2.4, this.a); + this.g = this.g * Math.pow(2.4, this.a); + this.b = this.b * Math.pow(2.4, this.a); + return this; + } + + /** + * unSerialized color by data + * @param data + * @returns + */ + public unSerialized(data: any): this { + this.r = data['r']; + this.g = data['g']; + this.b = data['b']; + this.a = data['a']; + return this; + } + + /** + * update this color rgb form hexadecimal no alpha + * @param value + */ + public hexToRGB(value: number) { + //this.a = ((value >> 24) & 0xff ) / 255; + this.r = ((value >> 16) & 0xff) / 255; + this.g = ((value >> 8) & 0xff) / 255; + this.b = (value & 0xff) / 255; + } + + /** + * update this color rgb form hexadecimal has alpha + * @param value + */ + public hexToRGBA(value: number) { + this.a = ((value >> 24) & 0xff) / 255; + this.r = ((value >> 16) & 0xff) / 255; + this.g = ((value >> 8) & 0xff) / 255; + this.b = (value & 0xff) / 255; + } + + /** + * random on color + * @returns + */ + public static random(base: number = 1.0): Color { + let color = new Color(); + color.a = base; + color.r = base * Math.random(); + color.g = base * Math.random(); + color.b = base * Math.random(); + return color; + } + + /** + * set rgba to this color + * @param r red channel + * @param g green channel + * @param b blue channel + * @param a alpha channel + */ + public setTo(r: number, g: number, b: number, a: number) { + this.r = Math.max(r, 0.0); + this.g = Math.max(g, 0.0); + this.b = Math.max(b, 0.0); + this.a = Math.max(a, 0.0); + } + + /** + * update this color rgba form hexadecimal + * @param hex hex string. + */ + public setHex(hex: string) { + if (typeof hex !== 'string' || Color.NON_HEX_CHARS.test(hex) || !Color.VALID_HEX_SIZE.test(hex)) { + throw new TypeError('Expected a valid hex string'); + } + hex = hex.replace(/^#/, ''); + let alphaFromHex = 1; + + if (hex.length === 8) { + alphaFromHex = Number.parseInt(hex.slice(6, 8), 16) / 255; + hex = hex.slice(0, 6); + } + + if (hex.length === 4) { + alphaFromHex = Number.parseInt(hex.slice(3, 4).repeat(2), 16) / 255; + hex = hex.slice(0, 3); + } + + if (hex.length === 3) { + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; + } + + const number = Number.parseInt(hex, 16); + const red = number >> 16; + const green = (number >> 8) & 255; + const blue = number & 255; + const alpha = alphaFromHex; + this.a = alpha; + this.r = red / 255; + this.g = green / 255; + this.b = blue / 255; + } + + /** + * convert this color to hex string code + * @returns + */ + public getHex(): string { + let getHexStr = (n: number) => { + n *= 255.0; + let str = n.toString(16); + if (str.length === 1) { + str = '0' + str; + } + return str; + }; + let hex = getHexStr(this.r) + getHexStr(this.g) + getHexStr(this.b) + getHexStr(this.a); + return hex; + } + + /** + * get rgb to array + */ + public get rgb(): number[] { + return [(this.r * 255) >>> 0, (this.g * 255) >>> 0, (this.b * 255) >>> 0]; + } + + /** + * set rgb by array + */ + public set rgb(c: number[]) { + this.setTo(c[0] / 255, c[1] / 255, c[2] / 255, this.a); + } + + /** + * get rgba to array + */ + public get rgba(): number[] { + return [(this.r * 255) >>> 0, (this.g * 255) >>> 0, (this.b * 255) >>> 0, (this.a * 255) >>> 0]; + } + + /** + * set rgb by array + */ + public set rgba(c: number[]) { + this.setTo(c[0] / 255, c[1] / 255, c[2] / 255, c[3] / 255); + } + + /** + * clone this color + * @returns + */ + public clone(): Color { + return new Color().copyForm(this); + } + + /** + * copy color form source color + * @returns + */ + public copyForm(src: Color): this { + this.r = src.r; + this.g = src.g; + this.b = src.b; + this.a = src.a; + return this; + } + + /** + * copy color form array + * @param arr [ 255 , 255 , 255 , 255 ] + * @param scalar + * @returns + */ + public copyFormArray(arr: number[], scalar: number = 255) { + this.r = arr[0] / scalar; + this.g = arr[1] / scalar; + this.b = arr[2] / scalar; + this.a = arr[3] / scalar; + return this; + } + + /** + * update this color rgb form hexadecimal no alpha + * @param hexColor rgb color + * @param dst ref out color + */ + public static hexRGBColor(hexColor: number, dst: Color = null): Color { + dst = dst || new Color(); + dst.hexToRGB(hexColor); + return dst; + } + + + + public static PRIMARY = 0x3f51b5; // + public static PRIMARYDARK = 0x303f9f; // + public static ACCENT = 0xff4081; // + + public static WHITE = 0xffffff; + public static IVORY = 0xfffff0; + public static LIGHTYELLOW = 0xffffe0; + public static YELLOW = 0xffff00; + public static SNOW = 0xfffafa; + public static FLORALWHITE = 0xfffaf0; + public static LEMONCHIFFON = 0xfffacd; + public static CORNSILK = 0xfff8dc; + public static SEASHELL = 0xfff5ee; + public static LAVENDERBLUSH = 0xfff0f5; + public static PAPAYAWHIP = 0xffefd5; + public static BLANCHEDALMOND = 0xffebcd; + public static MISTYROSE = 0xffe4e1; + public static BISQUE = 0xffe4c4; + public static MOCCASIN = 0xffe4b5; + public static NAVAJOWHITE = 0xffdead; + public static PEACHPUFF = 0xffdab9; + public static GOLD = 0xffd700; + public static PINK = 0xffc0cb; + public static LIGHTPINK = 0xffb6c1; + public static ORANGE = 0xffa500; + public static LIGHTSALMON = 0xffa07a; + public static DARKORANGE = 0xff8c00; + public static CORAL = 0xff7f50; + public static HOTPINK = 0xff69b4; + public static TOMATO = 0xff6347; + public static ORANGERED = 0xff4500; + public static DEEPPINK = 0xff1493; + public static FUCHSIA = 0xff00ff; + public static MAGENTA = 0xff00ff; + public static RED = 0xff0000; + public static OLDLACE = 0xfdf5e6; + public static LIGHTGOLDENRODYELLOW = 0xfafad2; + public static LINEN = 0xfaf0e6; + public static ANTIQUEWHITE = 0xfaebd7; + public static SALMON = 0xfa8072; + public static GHOSTWHITE = 0xf8f8ff; + public static MINTCREAM = 0xf5fffa; + public static WHITESMOKE = 0xf5f5f5; + public static BEIGE = 0xf5f5dc; + public static WHEAT = 0xf5deb3; + public static SANDYBROWN = 0xf4a460; + public static AZURE = 0xf0ffff; + public static HONEYDEW = 0xf0fff0; + public static ALICEBLUE = 0xf0f8ff; + public static KHAKI = 0xf0e68c; + public static LIGHTCORAL = 0xf08080; + public static PALEGOLDENROD = 0xeee8aa; + public static VIOLET = 0xee82ee; + public static DARKSALMON = 0xe9967a; + public static LAVENDER = 0xe6e6fa; + public static LIGHTCYAN = 0xe0ffff; + public static BURLYWOOD = 0xdeb887; + public static PLUM = 0xdda0dd; + public static GAINSBORO = 0xdcdcdc; + public static CRIMSON = 0xdc143c; + public static PALEVIOLETRED = 0xdb7093; + + public static GOLDENROD = 0xdaa520; + public static ORCHID = 0xda70d6; + public static THISTLE = 0xd8bfd8; + public static LIGHTGREY = 0xd3d3d3; + public static TAN = 0xd2b48c; + public static CHOCOLATE = 0xd2691e; + public static PERU = 0xcd853f; + public static INDIANRED = 0xcd5c5c; + public static MEDIUMVIOLETRED = 0xc71585; + public static SILVER = 0xc0c0c0; + public static DARKKHAKI = 0xbdb76b; + public static ROSYBROWN = 0xbc8f8f; + public static MEDIUMORCHID = 0xba55d3; + public static DARKGOLDENROD = 0xb8860b; + public static FIREBRICK = 0xb22222; + public static POWDERBLUE = 0xb0e0e6; + public static LIGHTSTEELBLUE = 0xb0c4de; + public static PALETURQUOISE = 0xafeeee; + public static GREENYELLOW = 0xadff2f; + public static LIGHTBLUE = 0xadd8e6; + public static DARKGRAY = 0xa9a9a9; + public static BROWN = 0xa52a2a; + public static SIENNA = 0xa0522d; + public static DARKORCHID = 0x9932cc; + public static PALEGREEN = 0x98fb98; + public static DARKVIOLET = 0x9400d3; + public static MEDIUMPURPLE = 0x9370db; + public static LIGHTGREEN = 0x90ee90; + public static DARKSEAGREEN = 0x8fbc8f; + public static SADDLEBROWN = 0x8b4513; + public static DARKMAGENTA = 0x8b008b; + public static DARKRED = 0x8b0000; + public static BLUEVIOLET = 0x8a2be2; + public static LIGHTSKYBLUE = 0x87cefa; + public static SKYBLUE = 0x87ceeb; + public static GRAY = 0x808080; + public static OLIVE = 0x808000; + public static PURPLE = 0x800080; + public static MAROON = 0x800000; + public static AQUAMARINE = 0x7fffd4; + public static CHARTREUSE = 0x7fff00; + public static LAWNGREEN = 0x7cfc00; + public static MEDIUMSLATEBLUE = 0x7b68ee; + public static LIGHTSLATEGRAY = 0x778899; + public static SLATEGRAY = 0x708090; + public static OLIVEDRAB = 0x6b8e23; + public static SLATEBLUE = 0x6a5acd; + public static DIMGRAY = 0x696969; + public static MEDIUMAQUAMARINE = 0x66cdaa; + public static CORNFLOWERBLUE = 0x6495ed; + public static CADETBLUE = 0x5f9ea0; + public static DARKOLIVEGREEN = 0x556b2f; + public static INDIGO = 0x4b0082; + public static MEDIUMTURQUOISE = 0x48d1cc; + public static DARKSLATEBLUE = 0x483d8b; + public static STEELBLUE = 0x4682b4; + public static ROYALBLUE = 0x4169e1; + public static TURQUOISE = 0x40e0d0; + public static MEDIUMSEAGREEN = 0x3cb371; + public static LIMEGREEN = 0x32cd32; + public static DARKSLATEGRAY = 0x2f4f4f; + public static SEAGREEN = 0x2e8b57; + public static FORESTGREEN = 0x228b22; + public static LIGHTSEAGREEN = 0x20b2aa; + public static DODGERBLUE = 0x1e90ff; + public static MIDNIGHTBLUE = 0x191970; + public static AQUA = 0x00ffff; + public static CYAN = 0x00ffff; + public static SPRINGGREEN = 0x00ff7f; + public static LIME = 0x00ff00; + public static MEDIUMSPRINGGREEN = 0x00fa9a; + public static DARKTURQUOISE = 0x00ced1; + public static DEEPSKYBLUE = 0x00bfff; + public static DARKCYAN = 0x008b8b; + public static TEAL = 0x008080; + public static GREEN = 0x008000; + public static DARKGREEN = 0x006400; + public static BLUE = 0x0000ff; + public static MEDIUMBLUE = 0x0000cd; + public static DARKBLUE = 0x00008b; + public static NAVY = 0x000080; + public static BLACK = 0x000000; } \ No newline at end of file diff --git a/src/engine/math/HaltonSeq.ts b/src/math/HaltonSeq.ts similarity index 100% rename from src/engine/math/HaltonSeq.ts rename to src/math/HaltonSeq.ts diff --git a/src/engine/math/Line.ts b/src/math/Line.ts similarity index 100% rename from src/engine/math/Line.ts rename to src/math/Line.ts diff --git a/src/engine/math/MathUtil.ts b/src/math/MathUtil.ts similarity index 100% rename from src/engine/math/MathUtil.ts rename to src/math/MathUtil.ts diff --git a/src/engine/math/Matrix3.ts b/src/math/Matrix3.ts similarity index 100% rename from src/engine/math/Matrix3.ts rename to src/math/Matrix3.ts diff --git a/src/engine/math/Matrix4.ts b/src/math/Matrix4.ts similarity index 100% rename from src/engine/math/Matrix4.ts rename to src/math/Matrix4.ts diff --git a/src/engine/math/Orientation3D.ts b/src/math/Orientation3D.ts similarity index 100% rename from src/engine/math/Orientation3D.ts rename to src/math/Orientation3D.ts diff --git a/src/math/ParticleMath.ts b/src/math/ParticleMath.ts new file mode 100644 index 00000000..b8791794 --- /dev/null +++ b/src/math/ParticleMath.ts @@ -0,0 +1,28 @@ +/** + * @internal + */ +export enum ParticleSystemRandomnessIds { + // Curves + kParticleSystemClampVelocityCurveId = 0x13371337, + kParticleSystemForceCurveId = 0x12460f3b, + kParticleSystemRotationCurveId = 0x6aed452e, + kParticleSystemRotationBySpeedCurveId = 0xdec4aea1, + kParticleSystemStartSpeedCurveId = 0x96aa4de3, + kParticleSystemSizeCurveId = 0x8d2c8431, + kParticleSystemSizeBySpeedCurveId = 0xf3857f6f, + kParticleSystemVelocityCurveId = 0xe0fbd834, + kParticleSystemUVCurveId = 0x13740583, + + // Gradient + kParticleSystemColorGradientId = 0x591bc05c, + kParticleSystemColorByVelocityGradientId = 0x40eb95e4, + + // Misc + kParticleSystemMeshSelectionId = 0xbc524e5f, + kParticleSystemUVRowSelectionId = 0xaf502044, +} + +/** + * @internal + */ +export const kPI = 3.1415926535897932384626433832795028841971693993751; diff --git a/src/math/ParticleSystemCurves.ts b/src/math/ParticleSystemCurves.ts new file mode 100644 index 00000000..9978dfaa --- /dev/null +++ b/src/math/ParticleSystemCurves.ts @@ -0,0 +1,235 @@ +import { AnimationCurve, FrameCache } from './AnimationCurve'; +import { lerp } from './MathUtil'; +import { Polynomial, PolynomialCurve } from './PolynomialCurve'; +import { quadraticPolynomialRootsGeneric } from './Polynomials'; +import { Vector2 } from './Vector2'; + +/** + * @internal + */ +export enum ParticleSystemCurveEvalMode { + kEMScalar, + kEMOptimized, + kEMOptimizedMinMax, + kEMSlow, +} + +/** + * @internal + */ +export enum MinMaxCurveState { + kMMCScalar = 0, + kMMCCurve = 1, + kMMCTwoCurves = 2, + kMMCTwoConstants = 3, +} + +// export class MinMaxOptimizedPolyCurves +// { +// public Integrate(){}; +// public DoubleIntegrate(){}; +// public FindMinMaxIntegrated():Vector2{ return null }; +// public FindMinMaxDoubleIntegrated():Vector2{ return null }; + +// public max:OptimizedPolynomialCurve; +// public min:OptimizedPolynomialCurve; +// } +/** + * @internal + * @group Math + */ +export class MinMaxAnimationCurves { + // public SupportsProcedural (); + public max: AnimationCurve; + public min: AnimationCurve; +} + +/** + * @internal + * @group Math + */ +export class MinMaxPolyCurves { + public max: PolynomialCurve; + public min: PolynomialCurve; + + public integrate() { + this.max.integrate(); + this.min.integrate(); + } + + public doubleIntegrate() { + this.max.doubleIntegrate(); + this.min.doubleIntegrate(); + } + + public findMinMaxIntegrated(): Vector2 { + return null; + } + + public findMinMaxDoubleIntegrated(): Vector2 { + return null; + } +} + +/** + * @internal + * @group Math + */ +export class MinMaxCurve { + public minMaxState: MinMaxCurveState; // see enum MinMaxCurveState + public minCurve: AnimationCurve; + public maxCurve: AnimationCurve; + private _scalar = 1; // Since scalar is baked into the optimized curve we use the setter function to modify it. + private _minScalar: number; + constructor(scalarValue: number = 1) { + this._scalar = scalarValue; + this.minMaxState = MinMaxCurveState.kMMCScalar; + this.minCurve = new AnimationCurve(); + this.maxCurve = new AnimationCurve(); + } + + public setScalar(value) { + this._scalar = value; + } + + public getScalar() { + return this._scalar; + } + + public static evaluateSlow(curve: MinMaxCurve, t, factor) { + let v = curve.maxCurve.getValue(t) * curve.getScalar(); + if (curve.minMaxState == MinMaxCurveState.kMMCTwoCurves) { + return lerp(curve.minCurve.getValue(t) * curve.getScalar(), v, factor); + } + else return v; + } + + public static evaluate(curve: MinMaxCurve, t, randomValue = 1.0): number { + if (curve.minMaxState == MinMaxCurveState.kMMCScalar) { + return curve.getScalar(); + } + + let v = curve.maxCurve.getValue(t) * curve.getScalar(); + if (curve.minMaxState == MinMaxCurveState.kMMCCurve) { + return lerp(curve.minCurve.getValue(t) * curve.getScalar(), v, randomValue); + } + if (curve.minMaxState == MinMaxCurveState.kMMCTwoConstants) { + return lerp(curve._minScalar, curve._scalar, randomValue); + } + if (curve.minMaxState == MinMaxCurveState.kMMCTwoCurves) { + return lerp(curve.minCurve.getValue(t) * curve.getScalar(), v, 1 * Math.random()); + } + return this.evaluateSlow(curve, t, 1); + } + + public unSerialized(data: any) { + this.minMaxState = data['minMaxState']; + this._scalar = data['scalar']; + this._minScalar = data['minScalar']; + this.maxCurve.unSerialized(data['maxCurve']); + this.minCurve.unSerialized(data['minCurve']); + } +} + +/** + * @internal + * @group Math + */ +export class ValueSpread { + public value = 0; + public mode: number = 0; + public spread: number = 0; + public speed: MinMaxCurve = new MinMaxCurve(); + + public unSerialized(data: any) { + this.value = data['value']; + this.mode = data['mode']; + this.spread = data['spread']; + this.speed.unSerialized(data['speed']); + } +} + +// export class DualMinMax3DPolyCurves +// { +// public optX:MinMaxOptimizedPolyCurves; +// public optY:MinMaxOptimizedPolyCurves; +// public optZ:MinMaxOptimizedPolyCurves; +// public x:MinMaxPolyCurves; +// public y:MinMaxPolyCurves; +// public z:MinMaxPolyCurves; +// }; +/** + * @internal + */ +export function curvesSupportProcedural(editorCurves: MinMaxAnimationCurves, minMaxState: number): boolean { + let isValid = PolynomialCurve.isValidCurve(editorCurves.max); + if (minMaxState != MinMaxCurveState.kMMCTwoCurves && minMaxState != MinMaxCurveState.kMMCTwoConstants) { + return isValid; + } + else { + return isValid && PolynomialCurve.isValidCurve(editorCurves.min); + } +} + +/** + * @internal + */ +export function buildCurves(polyCurves: MinMaxPolyCurves, editorCurves: MinMaxAnimationCurves, scalar, minMaxState) { + polyCurves.max.buildCurve(editorCurves.max, scalar); + if (minMaxState != MinMaxCurveState.kMMCTwoCurves && minMaxState != MinMaxCurveState.kMMCTwoConstants) { + polyCurves.min.buildCurve(editorCurves.max, scalar); + } + else { + polyCurves.min.buildCurve(editorCurves.min, scalar); + } +} + +/** + * @internal + */ +export function calculateCurveRangesValue(minMaxValue: Vector2, curve: AnimationCurve) { + let keyCount = curve.getKeyCount(); + if (keyCount == 0) { + return; + } + + if (keyCount == 1) { + calculateMinMax(minMaxValue, curve.getKey(0).value); + } else { + let segmentCount = keyCount - 1; + calculateMinMax(minMaxValue, curve.getKey(0).value); + for (let i = 0; i < segmentCount; i++) { + let cache: FrameCache = new FrameCache(); + curve.calculateCacheData(cache, i, i + 1, 0.0); + + // Differentiate polynomial + let a = 3.0 * cache.coeff[0]; + let b = 2.0 * cache.coeff[1]; + let c = 1.0 * cache.coeff[2]; + + let start = curve.getKey(i).time; + let end = curve.getKey(i + 1).time; + + let roots = []; + let numRoots = quadraticPolynomialRootsGeneric(a, b, c, { r0: roots[0], r1: roots[1] }); + for (let r = 0; r < numRoots; r++) { + if (roots[r] >= 0.0 && roots[r] + start < end) { + calculateMinMax(minMaxValue, Polynomial.EvalSegment(roots[r], cache.coeff)); + } + } + calculateMinMax(minMaxValue, Polynomial.EvalSegment(end - start, cache.coeff)); + } + } +} + + + + + +/** + * @internal + */ +export function calculateMinMax(minmax: Vector2, value: number) { + minmax.x = Math.min(minmax.x, value); + minmax.y = Math.max(minmax.y, value); +} diff --git a/src/engine/math/Plane.ts b/src/math/Plane.ts similarity index 100% rename from src/engine/math/Plane.ts rename to src/math/Plane.ts diff --git a/src/engine/math/PolynomialCurve.ts b/src/math/PolynomialCurve.ts similarity index 97% rename from src/engine/math/PolynomialCurve.ts rename to src/math/PolynomialCurve.ts index 47b1730a..458373e3 100644 --- a/src/engine/math/PolynomialCurve.ts +++ b/src/math/PolynomialCurve.ts @@ -1,255 +1,255 @@ -import { AnimationCurve, FrameCache } from './AnimationCurve'; -import { cubicPolynomialRootsGeneric } from './Polynomials'; -import { Vector2 } from './Vector2'; - -/** - * @internal - * @group Math - */ -export class Polynomial { - public coeff: number[] = []; - public static EvalSegment(t: number, coeff: number[]) { - return t * (t * (t * coeff[0] + coeff[1]) + coeff[2]) + coeff[3]; - } -} - -/** - * @internal - * @group Math - */ -export class PolynomialCurve { - private static kMaxNumSegments = 8; - public segments: Polynomial[] = []; - public integrationCache: number[] = []; - public doubleIntegrationCache: number[] = []; - public times: number[] = []; - public segmentCount: number; - - constructor() { - this.segments[PolynomialCurve.kMaxNumSegments] = new Polynomial(); - this.integrationCache[PolynomialCurve.kMaxNumSegments] = 0; - this.doubleIntegrationCache[PolynomialCurve.kMaxNumSegments] = 0; - this.times[PolynomialCurve.kMaxNumSegments] = 0; - } - - public calculateMinMax(minmax: Vector2, value) { - minmax.x = Math.min(minmax.x, value); - minmax.y = Math.max(minmax.y, value); - } - - public findMinMaxDoubleIntegrated(): Vector2 { - let result = Vector2.ZERO.clone(); - let numSteps = 20; - let delta = 1.0 / numSteps; - let acc = delta; - for (let i = 0; i < numSteps; i++) { - this.calculateMinMax(result, this.evaluateDoubleIntegrated(acc)); - acc += delta; - } - return result; - } - - // Find the maximum of the integrated curve (x: min, y: max) - public findMinMaxIntegrated(): Vector2 { - let result = Vector2.ZERO.clone(); - let prevTimeValue = 0.0; - - let start: [] = []; - let end: [] = []; - for (let i = 0; i < this.segmentCount; i++) { - // Differentiate coefficients - let a = 4.0 * this.segments[i].coeff[0]; - let b = 3.0 * this.segments[i].coeff[1]; - let c = 2.0 * this.segments[i].coeff[2]; - let d = 1.0 * this.segments[i].coeff[3]; - - let roots: number[] = []; - let numRoots = cubicPolynomialRootsGeneric(roots, a, b, c, d); - for (let r = 0; r < numRoots; r++) { - let root = roots[r] + start[i]; - if (root >= start[i] && root < end[i]) { - this.calculateMinMax(result, this.evaluateIntegrated(root)); - } - } - - // TODO: Don't use eval integrated, use eval segment (and integrate in loop) - this.calculateMinMax(result, this.evaluateIntegrated(end[i])); - prevTimeValue = this.times[i]; - } - return result; - } - - public generateIntegrationCache(curve: PolynomialCurve) { - curve.integrationCache[0] = 0.0; - let prevTimeValue0 = curve.times[0]; - let prevTimeValue1 = 0.0; - for (let i = 1; i < curve.segmentCount; i++) { - let coeff = curve.segments[i - 1].coeff; - integrateSegment(coeff); - let time = prevTimeValue0 - prevTimeValue1; - curve.integrationCache[i] = curve.integrationCache[i - 1] + Polynomial.EvalSegment(time, coeff) * time; - prevTimeValue1 = prevTimeValue0; - prevTimeValue0 = curve.times[i]; - } - } - - public generateDoubleIntegrationCache(curve: PolynomialCurve) { - let sum = 0.0; - let prevTimeValue = 0.0; - for (let i = 0; i < curve.segmentCount; i++) { - curve.doubleIntegrationCache[i] = sum; - let time = curve.times[i] - prevTimeValue; - time = Math.max(time, 0.0); - sum += Polynomial.EvalSegment(time, curve.segments[i].coeff) * time * time + curve.integrationCache[i] * time; - prevTimeValue = curve.times[i]; - } - } - - // Integrates a velocity curve to be a position curve. - // You have to call EvaluateIntegrated to evaluate the curve - public integrate() { - this.generateIntegrationCache(this); - for (let i = 0; i < this.segmentCount; i++) { - integrateSegment(this.segments[i].coeff); - } - } - - // Integrates a velocity curve to be a position curve. - // You have to call EvaluateDoubleIntegrated to evaluate the curve - public doubleIntegrate() { - this.generateIntegrationCache(this); - for (let i = 0; i < this.segmentCount; i++) { - doubleIntegrateSegment(this.segments[i].coeff); - } - this.generateDoubleIntegrationCache(this); - } - - // Evaluates if it is possible to represent animation curve as PolynomialCurve - static isValidCurve(editorCurve: AnimationCurve): boolean { - let keyCount = editorCurve.getKeyCount(); - let segmentCount = keyCount - 1; - if (editorCurve.getKey(0).time != 0.0) { - segmentCount++; - } - if (editorCurve.getKey(keyCount - 1).time != 1.0) { - segmentCount++; - } - return segmentCount <= PolynomialCurve.kMaxNumSegments; - } - - public evaluateDoubleIntegrated(t) { - let prevTimeValue = 0.0; - for (let i = 0; i < this.segmentCount; i++) { - if (t <= this.times[i]) { - let time = t - prevTimeValue; - return this.doubleIntegrationCache[i] + this.integrationCache[i] * time + Polynomial.EvalSegment(time, this.segments[i].coeff) * time * time; - } - prevTimeValue = this.times[i]; - } - return 1.0; - } - - // Evaluate integrated Polynomial curve. - // Example: position = EvaluateIntegrated (normalizedTime) * startEnergy - // Use Integrate function to for example turn a velocity curve into a position curve. - // Expects that t is in the 0...1 range. - public evaluateIntegrated(t) { - let prevTimeValue = 0.0; - for (let i = 0; i < this.segmentCount; i++) { - if (t <= this.times[i]) { - let time = t - prevTimeValue; - return this.integrationCache[i] + Polynomial.EvalSegment(time, this.segments[i].coeff) * time; - } - prevTimeValue = this.times[i]; - } - return 1.0; - } - - // Evaluate the curve - // extects that t is in the 0...1 range - public evaluate(t): number { - let prevTimeValue = 0.0; - for (let i = 0; i < this.segmentCount; i++) { - if (t <= this.times[i]) { - return Polynomial.EvalSegment(t - prevTimeValue, this.segments[i].coeff); - - } - prevTimeValue = this.times[i]; - } - return 1.0; - } - - public buildCurve(editorCurve: AnimationCurve, scale: number) { - let keyCount = editorCurve.getKeyCount(); - this.segmentCount = 1; - - let kMaxTime = 1.01; - this.segments.length = 0; - this.integrationCache.length = 0; - this.doubleIntegrationCache.length = 0; - this.times.length = 0; - this.times[0] = kMaxTime; - - // Handle corner case 1 & 0 keyframes - if (keyCount == 0) { - } else if (keyCount == 1) { - this.segments[0] = new Polynomial(); - this.segments[0].coeff[3] = editorCurve.getKey(0).value * scale; - } else { - this.segmentCount = keyCount - 1; - let segmentOffset = 0; - - // Add extra key to start if it doesn't match up - if (editorCurve.getKey(0).time != 0.0) { - this.segments[0].coeff[3] = editorCurve.getKey(0).value; - this.times[0] = editorCurve.getKey(0).time; - segmentOffset = 1; - } - - for (let i = 0; i < this.segmentCount; i++) { - let cache: FrameCache; - editorCurve.calculateCacheData(cache, i, i + 1, 0.0); - this.segments[i + segmentOffset].coeff = cache.coeff.concat(); - this.times[i + segmentOffset] = editorCurve.getKey(i + 1).time; - } - this.segmentCount += segmentOffset; - - // Add extra key to start if it doesn't match up - if (editorCurve.getKey(keyCount - 1).time != 1.0) { - this.segments[this.segmentCount].coeff[3] = editorCurve.getKey(keyCount - 1).value; - this.segmentCount++; - } - - // Fixup last key time value - this.times[this.segmentCount - 1] = kMaxTime; - - for (let i = 0; i < this.segmentCount; i++) { - this.segments[i].coeff[0] *= scale; - this.segments[i].coeff[1] *= scale; - this.segments[i].coeff[2] *= scale; - this.segments[i].coeff[3] *= scale; - } - } - return true; - } -} - -/** - * @internal - */ -export function doubleIntegrateSegment(coeff) { - coeff[0] /= 20.0; - coeff[1] /= 12.0; - coeff[2] /= 6.0; - coeff[3] /= 2.0; -} - -/** - * @internal - */ -export function integrateSegment(coeff) { - coeff[0] /= 4.0; - coeff[1] /= 3.0; - coeff[2] /= 2.0; - coeff[3] /= 1.0; -} +import { AnimationCurve, FrameCache } from './AnimationCurve'; +import { cubicPolynomialRootsGeneric } from './Polynomials'; +import { Vector2 } from './Vector2'; + +/** + * @internal + * @group Math + */ +export class Polynomial { + public coeff: number[] = []; + public static EvalSegment(t: number, coeff: number[]) { + return t * (t * (t * coeff[0] + coeff[1]) + coeff[2]) + coeff[3]; + } +} + +/** + * @internal + * @group Math + */ +export class PolynomialCurve { + private static kMaxNumSegments = 8; + public segments: Polynomial[] = []; + public integrationCache: number[] = []; + public doubleIntegrationCache: number[] = []; + public times: number[] = []; + public segmentCount: number; + + constructor() { + this.segments[PolynomialCurve.kMaxNumSegments] = new Polynomial(); + this.integrationCache[PolynomialCurve.kMaxNumSegments] = 0; + this.doubleIntegrationCache[PolynomialCurve.kMaxNumSegments] = 0; + this.times[PolynomialCurve.kMaxNumSegments] = 0; + } + + public calculateMinMax(minmax: Vector2, value) { + minmax.x = Math.min(minmax.x, value); + minmax.y = Math.max(minmax.y, value); + } + + public findMinMaxDoubleIntegrated(): Vector2 { + let result = Vector2.ZERO.clone(); + let numSteps = 20; + let delta = 1.0 / numSteps; + let acc = delta; + for (let i = 0; i < numSteps; i++) { + this.calculateMinMax(result, this.evaluateDoubleIntegrated(acc)); + acc += delta; + } + return result; + } + + // Find the maximum of the integrated curve (x: min, y: max) + public findMinMaxIntegrated(): Vector2 { + let result = Vector2.ZERO.clone(); + let prevTimeValue = 0.0; + + let start: [] = []; + let end: [] = []; + for (let i = 0; i < this.segmentCount; i++) { + // Differentiate coefficients + let a = 4.0 * this.segments[i].coeff[0]; + let b = 3.0 * this.segments[i].coeff[1]; + let c = 2.0 * this.segments[i].coeff[2]; + let d = 1.0 * this.segments[i].coeff[3]; + + let roots: number[] = []; + let numRoots = cubicPolynomialRootsGeneric(roots, a, b, c, d); + for (let r = 0; r < numRoots; r++) { + let root = roots[r] + start[i]; + if (root >= start[i] && root < end[i]) { + this.calculateMinMax(result, this.evaluateIntegrated(root)); + } + } + + // TODO: Don't use eval integrated, use eval segment (and integrate in loop) + this.calculateMinMax(result, this.evaluateIntegrated(end[i])); + prevTimeValue = this.times[i]; + } + return result; + } + + public generateIntegrationCache(curve: PolynomialCurve) { + curve.integrationCache[0] = 0.0; + let prevTimeValue0 = curve.times[0]; + let prevTimeValue1 = 0.0; + for (let i = 1; i < curve.segmentCount; i++) { + let coeff = curve.segments[i - 1].coeff; + integrateSegment(coeff); + let time = prevTimeValue0 - prevTimeValue1; + curve.integrationCache[i] = curve.integrationCache[i - 1] + Polynomial.EvalSegment(time, coeff) * time; + prevTimeValue1 = prevTimeValue0; + prevTimeValue0 = curve.times[i]; + } + } + + public generateDoubleIntegrationCache(curve: PolynomialCurve) { + let sum = 0.0; + let prevTimeValue = 0.0; + for (let i = 0; i < curve.segmentCount; i++) { + curve.doubleIntegrationCache[i] = sum; + let time = curve.times[i] - prevTimeValue; + time = Math.max(time, 0.0); + sum += Polynomial.EvalSegment(time, curve.segments[i].coeff) * time * time + curve.integrationCache[i] * time; + prevTimeValue = curve.times[i]; + } + } + + // Integrates a velocity curve to be a position curve. + // You have to call EvaluateIntegrated to evaluate the curve + public integrate() { + this.generateIntegrationCache(this); + for (let i = 0; i < this.segmentCount; i++) { + integrateSegment(this.segments[i].coeff); + } + } + + // Integrates a velocity curve to be a position curve. + // You have to call EvaluateDoubleIntegrated to evaluate the curve + public doubleIntegrate() { + this.generateIntegrationCache(this); + for (let i = 0; i < this.segmentCount; i++) { + doubleIntegrateSegment(this.segments[i].coeff); + } + this.generateDoubleIntegrationCache(this); + } + + // Evaluates if it is possible to represent animation curve as PolynomialCurve + static isValidCurve(editorCurve: AnimationCurve): boolean { + let keyCount = editorCurve.getKeyCount(); + let segmentCount = keyCount - 1; + if (editorCurve.getKey(0).time != 0.0) { + segmentCount++; + } + if (editorCurve.getKey(keyCount - 1).time != 1.0) { + segmentCount++; + } + return segmentCount <= PolynomialCurve.kMaxNumSegments; + } + + public evaluateDoubleIntegrated(t) { + let prevTimeValue = 0.0; + for (let i = 0; i < this.segmentCount; i++) { + if (t <= this.times[i]) { + let time = t - prevTimeValue; + return this.doubleIntegrationCache[i] + this.integrationCache[i] * time + Polynomial.EvalSegment(time, this.segments[i].coeff) * time * time; + } + prevTimeValue = this.times[i]; + } + return 1.0; + } + + // Evaluate integrated Polynomial curve. + // Example: position = EvaluateIntegrated (normalizedTime) * startEnergy + // Use Integrate function to for example turn a velocity curve into a position curve. + // Expects that t is in the 0...1 range. + public evaluateIntegrated(t) { + let prevTimeValue = 0.0; + for (let i = 0; i < this.segmentCount; i++) { + if (t <= this.times[i]) { + let time = t - prevTimeValue; + return this.integrationCache[i] + Polynomial.EvalSegment(time, this.segments[i].coeff) * time; + } + prevTimeValue = this.times[i]; + } + return 1.0; + } + + // Evaluate the curve + // extects that t is in the 0...1 range + public evaluate(t): number { + let prevTimeValue = 0.0; + for (let i = 0; i < this.segmentCount; i++) { + if (t <= this.times[i]) { + return Polynomial.EvalSegment(t - prevTimeValue, this.segments[i].coeff); + + } + prevTimeValue = this.times[i]; + } + return 1.0; + } + + public buildCurve(editorCurve: AnimationCurve, scale: number) { + let keyCount = editorCurve.getKeyCount(); + this.segmentCount = 1; + + let kMaxTime = 1.01; + this.segments.length = 0; + this.integrationCache.length = 0; + this.doubleIntegrationCache.length = 0; + this.times.length = 0; + this.times[0] = kMaxTime; + + // Handle corner case 1 & 0 keyframes + if (keyCount == 0) { + } else if (keyCount == 1) { + this.segments[0] = new Polynomial(); + this.segments[0].coeff[3] = editorCurve.getKey(0).value * scale; + } else { + this.segmentCount = keyCount - 1; + let segmentOffset = 0; + + // Add extra key to start if it doesn't match up + if (editorCurve.getKey(0).time != 0.0) { + this.segments[0].coeff[3] = editorCurve.getKey(0).value; + this.times[0] = editorCurve.getKey(0).time; + segmentOffset = 1; + } + + for (let i = 0; i < this.segmentCount; i++) { + let cache: FrameCache; + editorCurve.calculateCacheData(cache, i, i + 1, 0.0); + this.segments[i + segmentOffset].coeff = cache.coeff.concat(); + this.times[i + segmentOffset] = editorCurve.getKey(i + 1).time; + } + this.segmentCount += segmentOffset; + + // Add extra key to start if it doesn't match up + if (editorCurve.getKey(keyCount - 1).time != 1.0) { + this.segments[this.segmentCount].coeff[3] = editorCurve.getKey(keyCount - 1).value; + this.segmentCount++; + } + + // Fixup last key time value + this.times[this.segmentCount - 1] = kMaxTime; + + for (let i = 0; i < this.segmentCount; i++) { + this.segments[i].coeff[0] *= scale; + this.segments[i].coeff[1] *= scale; + this.segments[i].coeff[2] *= scale; + this.segments[i].coeff[3] *= scale; + } + } + return true; + } +} + +/** + * @internal + */ +export function doubleIntegrateSegment(coeff) { + coeff[0] /= 20.0; + coeff[1] /= 12.0; + coeff[2] /= 6.0; + coeff[3] /= 2.0; +} + +/** + * @internal + */ +export function integrateSegment(coeff) { + coeff[0] /= 4.0; + coeff[1] /= 3.0; + coeff[2] /= 2.0; + coeff[3] /= 1.0; +} diff --git a/src/engine/math/Polynomials.ts b/src/math/Polynomials.ts similarity index 96% rename from src/engine/math/Polynomials.ts rename to src/math/Polynomials.ts index 4533c869..26622fc8 100644 --- a/src/engine/math/Polynomials.ts +++ b/src/math/Polynomials.ts @@ -1,97 +1,97 @@ -/** - * @internal - * @group Math - */ -export class Polynomials { } - -// Returns the highest root for the cubic x^3 + px^2 + qx + r -/** - * @internal - */ -export function cubicPolynomialRoot(p: number, q: number, r: number) { - let rcp3 = 1.0 / 3.0; - let half = 0.5; - let po3 = p * rcp3; - let po3_2 = po3 * po3; - let po3_3 = po3_2 * po3; - let b = po3_3 - po3 * q * half + r * half; - let a = -po3_2 + q * rcp3; - let a3 = a * a * a; - let det = a3 + b * b; - - if (det >= 0) { - let r0 = Math.sqrt(det) - b; - r0 = r0 > 0 ? Math.pow(r0, rcp3) : -Math.pow(-r0, rcp3); - - return -po3 - a / r0 + r0; - } - - let abs = Math.sqrt(-a3); - let arg = Math.acos(-b / abs); - abs = Math.pow(abs, rcp3); - abs = abs - a / abs; - arg = -po3 + abs * Math.cos(arg * rcp3); - return arg; -} - -// Calculates all real roots of polynomial ax^2 + bx + c (and returns how many) -/** - * @internal - */ -export function quadraticPolynomialRootsGeneric(a, b, c, out: { r0; r1 }) { - let eps = 0.00001; - if (Math.abs(a) < eps) { - if (Math.abs(b) > eps) { - out.r0 = -c / b; - return 1; - } else { - return 0; - } - } - - let disc = b * b - 4 * a * c; - if (disc < 0.0) { - return 0; - } - - let halfRcpA = 0.5 / a; - let sqrtDisc = Math.sqrt(disc); - out.r0 = (sqrtDisc - b) * halfRcpA; - out.r1 = (-sqrtDisc - b) * halfRcpA; - return 2; -} - -// Calculates all the roots for the cubic ax^3 + bx^2 + cx + d. Max num roots is 3. -/** - * @internal - */ -export function cubicPolynomialRootsGeneric(roots: number[], a: number, b: number, c: number, d: number) { - let numRoots = 0; - if (Math.abs(a) >= 0.0001) { - let p = b / a; - let q = c / a; - let r = d / a; - roots[0] = cubicPolynomialRoot(p, q, r); - numRoots++; - - let la = a; - let lb = b + a * roots[0]; - let lc = c + b * roots[0] + a * roots[0] * roots[0]; - numRoots += quadraticPolynomialRootsGeneric(la, lb, lc, { r0: roots[1], r1: roots[2] }); - } else { - numRoots += quadraticPolynomialRootsGeneric(b, c, d, { r0: roots[1], r1: roots[2] }); - } - - return numRoots; -} - -// // Specialized version of QuadraticPolynomialRootsGeneric that returns the largest root -// /** -// * @internal -// */ -// export function quadraticPolynomialRoot(a, b, c) { -// let r0; -// let r1; -// quadraticPolynomialRootsGeneric(a, b, c, { r0: r0, r1: r1 }); -// return r0; -// } +/** + * @internal + * @group Math + */ +export class Polynomials { } + +// Returns the highest root for the cubic x^3 + px^2 + qx + r +/** + * @internal + */ +export function cubicPolynomialRoot(p: number, q: number, r: number) { + let rcp3 = 1.0 / 3.0; + let half = 0.5; + let po3 = p * rcp3; + let po3_2 = po3 * po3; + let po3_3 = po3_2 * po3; + let b = po3_3 - po3 * q * half + r * half; + let a = -po3_2 + q * rcp3; + let a3 = a * a * a; + let det = a3 + b * b; + + if (det >= 0) { + let r0 = Math.sqrt(det) - b; + r0 = r0 > 0 ? Math.pow(r0, rcp3) : -Math.pow(-r0, rcp3); + + return -po3 - a / r0 + r0; + } + + let abs = Math.sqrt(-a3); + let arg = Math.acos(-b / abs); + abs = Math.pow(abs, rcp3); + abs = abs - a / abs; + arg = -po3 + abs * Math.cos(arg * rcp3); + return arg; +} + +// Calculates all real roots of polynomial ax^2 + bx + c (and returns how many) +/** + * @internal + */ +export function quadraticPolynomialRootsGeneric(a, b, c, out: { r0; r1 }) { + let eps = 0.00001; + if (Math.abs(a) < eps) { + if (Math.abs(b) > eps) { + out.r0 = -c / b; + return 1; + } else { + return 0; + } + } + + let disc = b * b - 4 * a * c; + if (disc < 0.0) { + return 0; + } + + let halfRcpA = 0.5 / a; + let sqrtDisc = Math.sqrt(disc); + out.r0 = (sqrtDisc - b) * halfRcpA; + out.r1 = (-sqrtDisc - b) * halfRcpA; + return 2; +} + +// Calculates all the roots for the cubic ax^3 + bx^2 + cx + d. Max num roots is 3. +/** + * @internal + */ +export function cubicPolynomialRootsGeneric(roots: number[], a: number, b: number, c: number, d: number) { + let numRoots = 0; + if (Math.abs(a) >= 0.0001) { + let p = b / a; + let q = c / a; + let r = d / a; + roots[0] = cubicPolynomialRoot(p, q, r); + numRoots++; + + let la = a; + let lb = b + a * roots[0]; + let lc = c + b * roots[0] + a * roots[0] * roots[0]; + numRoots += quadraticPolynomialRootsGeneric(la, lb, lc, { r0: roots[1], r1: roots[2] }); + } else { + numRoots += quadraticPolynomialRootsGeneric(b, c, d, { r0: roots[1], r1: roots[2] }); + } + + return numRoots; +} + +// // Specialized version of QuadraticPolynomialRootsGeneric that returns the largest root +// /** +// * @internal +// */ +// export function quadraticPolynomialRoot(a, b, c) { +// let r0; +// let r1; +// quadraticPolynomialRootsGeneric(a, b, c, { r0: r0, r1: r1 }); +// return r0; +// } diff --git a/src/engine/math/Quaternion.ts b/src/math/Quaternion.ts similarity index 100% rename from src/engine/math/Quaternion.ts rename to src/math/Quaternion.ts diff --git a/src/engine/math/Rand.ts b/src/math/Rand.ts similarity index 100% rename from src/engine/math/Rand.ts rename to src/math/Rand.ts diff --git a/src/engine/math/Random.ts b/src/math/Random.ts similarity index 100% rename from src/engine/math/Random.ts rename to src/math/Random.ts diff --git a/src/engine/math/Ray.ts b/src/math/Ray.ts similarity index 100% rename from src/engine/math/Ray.ts rename to src/math/Ray.ts diff --git a/src/engine/math/Rect.ts b/src/math/Rect.ts similarity index 100% rename from src/engine/math/Rect.ts rename to src/math/Rect.ts diff --git a/src/engine/math/TimeInterpolator.ts b/src/math/TimeInterpolator.ts similarity index 100% rename from src/engine/math/TimeInterpolator.ts rename to src/math/TimeInterpolator.ts diff --git a/src/engine/math/Triangle.ts b/src/math/Triangle.ts similarity index 100% rename from src/engine/math/Triangle.ts rename to src/math/Triangle.ts diff --git a/src/engine/math/UV.ts b/src/math/UV.ts similarity index 100% rename from src/engine/math/UV.ts rename to src/math/UV.ts diff --git a/src/engine/math/Vector2.ts b/src/math/Vector2.ts similarity index 100% rename from src/engine/math/Vector2.ts rename to src/math/Vector2.ts diff --git a/src/engine/math/Vector3.ts b/src/math/Vector3.ts similarity index 99% rename from src/engine/math/Vector3.ts rename to src/math/Vector3.ts index a2f6cc4d..e5bcb71a 100644 --- a/src/engine/math/Vector3.ts +++ b/src/math/Vector3.ts @@ -178,7 +178,7 @@ export class Vector3 { /** - * Creates an instance of a Vector3 object. If you do not specify a。 + * Creates an instance of a Vector3 object. If you do not specify a. * parameter for the constructor, a Vector3 object is created with * the elements (0,0,0,0). * diff --git a/src/engine/math/Vector4.ts b/src/math/Vector4.ts similarity index 100% rename from src/engine/math/Vector4.ts rename to src/math/Vector4.ts diff --git a/src/sample/index.ts b/src/sample/index.ts deleted file mode 100644 index 62bd094f..00000000 --- a/src/sample/index.ts +++ /dev/null @@ -1,77 +0,0 @@ -/******** Load all samples in /src/sample/ ********/ -function Menu() { - // load all modules in /sample - const modules = import.meta.glob(['./*/*.ts', '!./*/_*.ts']) - // create menu - let title = '', list = '' - for (const path in modules) { - const arr = path.split('/') - let _title = arr[1] - let _demo = arr[2].replace(/Sample_|Sample|\.ts/g, '') - if (_title != title) { - list += `

${_title}

` - title = _title - } - list += `${_demo}` - } - const menu = document.createElement('div') - menu.className = 'menu' - menu.innerHTML = list - document.body.appendChild(menu) - - // change sessionStorage.target on click, and reload iframe - menu.addEventListener('click', (e: Event) => { - let button = e.target as HTMLElement - if (!button.id) - return - // remove prev iframe to clear memory - document.querySelector('iframe')?.remove() - let target = button.id - if (target && modules[target]) { - addIframe() - document.querySelector('.active')?.classList.remove('active') - button.classList.add('active') - sessionStorage.top = menu.scrollTop - sessionStorage.target = target - } - }) - - // load target on refresh - if (sessionStorage.target) { - let target = sessionStorage.target - let a = document.querySelector(`[id="${target}"]`) - if (a) { - addIframe() - a.classList.add('active') - menu.scrollTop = sessionStorage.top - } - } else { - document.querySelector('a')?.click() - } - - // create an iframe inside page to load sample - function addIframe() { - const iframe = document.createElement('iframe') as HTMLIFrameElement - iframe.srcdoc = ` - - ` - document.body.appendChild(iframe) - } -} -Menu() - -// auto update index.ts, import all exports from /src/engine/ -const modules = import.meta.glob(['../engine/**/*.ts', '!../engine/**/*-back.ts', '!../engine/**/_*.ts']) -let content = '' -for (let path in modules) - content += `export * from "${path.slice(1, -3)}"\r\n` -import.meta.hot!.send('autoIndex', { content }) \ No newline at end of file diff --git a/src/engine/setting/EngineSetting.ts b/src/setting/EngineSetting.ts similarity index 100% rename from src/engine/setting/EngineSetting.ts rename to src/setting/EngineSetting.ts diff --git a/src/engine/setting/GlobalIlluminationSetting.ts b/src/setting/GlobalIlluminationSetting.ts similarity index 100% rename from src/engine/setting/GlobalIlluminationSetting.ts rename to src/setting/GlobalIlluminationSetting.ts diff --git a/src/engine/setting/LightSetting.ts b/src/setting/LightSetting.ts similarity index 100% rename from src/engine/setting/LightSetting.ts rename to src/setting/LightSetting.ts diff --git a/src/engine/setting/MaterialSetting.ts b/src/setting/MaterialSetting.ts similarity index 100% rename from src/engine/setting/MaterialSetting.ts rename to src/setting/MaterialSetting.ts diff --git a/src/engine/setting/OcclusionQuerySetting.ts b/src/setting/OcclusionQuerySetting.ts similarity index 100% rename from src/engine/setting/OcclusionQuerySetting.ts rename to src/setting/OcclusionQuerySetting.ts diff --git a/src/engine/setting/PickSetting.ts b/src/setting/PickSetting.ts similarity index 100% rename from src/engine/setting/PickSetting.ts rename to src/setting/PickSetting.ts diff --git a/src/engine/setting/RenderSetting.ts b/src/setting/RenderSetting.ts similarity index 100% rename from src/engine/setting/RenderSetting.ts rename to src/setting/RenderSetting.ts diff --git a/src/engine/setting/ShadowSetting.ts b/src/setting/ShadowSetting.ts similarity index 100% rename from src/engine/setting/ShadowSetting.ts rename to src/setting/ShadowSetting.ts diff --git a/src/engine/setting/SkySetting.ts b/src/setting/SkySetting.ts similarity index 100% rename from src/engine/setting/SkySetting.ts rename to src/setting/SkySetting.ts diff --git a/src/engine/setting/post/BloomSetting.ts b/src/setting/post/BloomSetting.ts similarity index 100% rename from src/engine/setting/post/BloomSetting.ts rename to src/setting/post/BloomSetting.ts diff --git a/src/engine/setting/post/DepthOfViewSetting.ts b/src/setting/post/DepthOfViewSetting.ts similarity index 100% rename from src/engine/setting/post/DepthOfViewSetting.ts rename to src/setting/post/DepthOfViewSetting.ts diff --git a/src/engine/setting/post/GTAOSetting.ts b/src/setting/post/GTAOSetting.ts similarity index 88% rename from src/engine/setting/post/GTAOSetting.ts rename to src/setting/post/GTAOSetting.ts index a851ea5e..5af9f1de 100644 --- a/src/engine/setting/post/GTAOSetting.ts +++ b/src/setting/post/GTAOSetting.ts @@ -26,7 +26,7 @@ export type GTAOSetting = { */ multiBounce: boolean; /** - * true:Calculate the position value of GBuffer using f32 to obtain more accurate values (water and other effects may not be supported) + * true: Calculate the position value of GBuffer using f32 to obtain more accurate values (water and other effects may not be supported) * false: We will use the position value of GBuffer in f16 for operations, with a wider coverage */ usePosFloat32: boolean; diff --git a/src/engine/setting/post/GlobalFogSetting.ts b/src/setting/post/GlobalFogSetting.ts similarity index 95% rename from src/engine/setting/post/GlobalFogSetting.ts rename to src/setting/post/GlobalFogSetting.ts index 9031b10a..fbae4be5 100644 --- a/src/engine/setting/post/GlobalFogSetting.ts +++ b/src/setting/post/GlobalFogSetting.ts @@ -12,7 +12,7 @@ export type GlobalFogSetting = { enable: boolean; /** * type of fog: - * 0: linear exponent 2:squar exponent + * 0: linear exponent 2: squar exponent */ fogType: number; /** diff --git a/src/engine/setting/post/OutlineSetting.ts b/src/setting/post/OutlineSetting.ts similarity index 100% rename from src/engine/setting/post/OutlineSetting.ts rename to src/setting/post/OutlineSetting.ts diff --git a/src/engine/setting/post/SSRSetting.ts b/src/setting/post/SSRSetting.ts similarity index 100% rename from src/engine/setting/post/SSRSetting.ts rename to src/setting/post/SSRSetting.ts diff --git a/src/engine/setting/post/TAASetting.ts b/src/setting/post/TAASetting.ts similarity index 100% rename from src/engine/setting/post/TAASetting.ts rename to src/setting/post/TAASetting.ts diff --git a/src/engine/shape/BoxGeometry.ts b/src/shape/BoxGeometry.ts similarity index 100% rename from src/engine/shape/BoxGeometry.ts rename to src/shape/BoxGeometry.ts diff --git a/src/engine/shape/CylinderGeometry.ts b/src/shape/CylinderGeometry.ts similarity index 100% rename from src/engine/shape/CylinderGeometry.ts rename to src/shape/CylinderGeometry.ts diff --git a/src/engine/shape/PlaneGeometry.ts b/src/shape/PlaneGeometry.ts similarity index 100% rename from src/engine/shape/PlaneGeometry.ts rename to src/shape/PlaneGeometry.ts diff --git a/src/engine/shape/SphereGeometry.ts b/src/shape/SphereGeometry.ts similarity index 100% rename from src/engine/shape/SphereGeometry.ts rename to src/shape/SphereGeometry.ts diff --git a/src/engine/shape/TorusGeometry.ts b/src/shape/TorusGeometry.ts similarity index 97% rename from src/engine/shape/TorusGeometry.ts rename to src/shape/TorusGeometry.ts index 77965607..8e516f61 100644 --- a/src/engine/shape/TorusGeometry.ts +++ b/src/shape/TorusGeometry.ts @@ -32,9 +32,9 @@ export class TorusGeometry extends GeometryBase { * * @constructor * @param radius {number} Radius of torus, default value is 0.4 - * @param tube {number} Pipe radius, default value is 0.1。 - * @param radialSegments {number}Number of torus segments, default value is 32。 - * @param tubularSegments {number} Number of pipeline segments, defualt value is 32。 + * @param tube {number} Pipe radius, default value is 0.1. + * @param radialSegments {number}Number of torus segments, default value is 32. + * @param tubularSegments {number} Number of pipeline segments, defualt value is 32. */ constructor(radius: number = 0.4, tube: number = 0.1, radialSegments: number = 32, tubularSegments: number = 32) { super(); diff --git a/src/engine/textures/AtmosphericScatteringSky.ts b/src/textures/AtmosphericScatteringSky.ts similarity index 100% rename from src/engine/textures/AtmosphericScatteringSky.ts rename to src/textures/AtmosphericScatteringSky.ts diff --git a/src/engine/textures/BitmapTexture2D.ts b/src/textures/BitmapTexture2D.ts similarity index 100% rename from src/engine/textures/BitmapTexture2D.ts rename to src/textures/BitmapTexture2D.ts index 93814633..abb0070d 100644 --- a/src/engine/textures/BitmapTexture2D.ts +++ b/src/textures/BitmapTexture2D.ts @@ -1,8 +1,8 @@ -import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; import { LoaderBase } from '../loader/LoaderBase'; import { LoaderFunctions } from '../loader/LoaderFunctions'; import { StringUtil } from '../util/StringUtil'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; /** * bitmap texture diff --git a/src/engine/textures/BitmapTexture2DArray.ts b/src/textures/BitmapTexture2DArray.ts similarity index 99% rename from src/engine/textures/BitmapTexture2DArray.ts rename to src/textures/BitmapTexture2DArray.ts index fb9d4773..db0bebfc 100644 --- a/src/engine/textures/BitmapTexture2DArray.ts +++ b/src/textures/BitmapTexture2DArray.ts @@ -1,9 +1,10 @@ import { GPUFilterMode, GPUTextureFormat } from '../gfx/graphics/webGpu/WebGPUConst'; -import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; -import { ITexture } from '../gfx/graphics/webGpu/core/texture/ITexture'; -import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; + import { BitmapTexture2D } from './BitmapTexture2D'; import { GPUContext } from '../gfx/renderJob/GPUContext'; +import { ITexture } from '../gfx/graphics/webGpu/core/texture/ITexture'; +import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; +import { webGPUContext } from '../gfx/graphics/webGpu/Context3D'; /** * Type BitmapTexture 2D Array , Use in GPU diff --git a/src/engine/textures/BitmapTextureCube.ts b/src/textures/BitmapTextureCube.ts similarity index 100% rename from src/engine/textures/BitmapTextureCube.ts rename to src/textures/BitmapTextureCube.ts diff --git a/src/engine/textures/Depth2DTextureArray.ts b/src/textures/Depth2DTextureArray.ts similarity index 100% rename from src/engine/textures/Depth2DTextureArray.ts rename to src/textures/Depth2DTextureArray.ts diff --git a/src/engine/textures/DepthCubeArrayTexture.ts b/src/textures/DepthCubeArrayTexture.ts similarity index 100% rename from src/engine/textures/DepthCubeArrayTexture.ts rename to src/textures/DepthCubeArrayTexture.ts diff --git a/src/engine/textures/DepthCubeTexture.ts b/src/textures/DepthCubeTexture.ts similarity index 100% rename from src/engine/textures/DepthCubeTexture.ts rename to src/textures/DepthCubeTexture.ts diff --git a/src/engine/textures/Float16ArrayTexture.ts b/src/textures/Float16ArrayTexture.ts similarity index 100% rename from src/engine/textures/Float16ArrayTexture.ts rename to src/textures/Float16ArrayTexture.ts diff --git a/src/engine/textures/Float32ArrayTexture.ts b/src/textures/Float32ArrayTexture.ts similarity index 100% rename from src/engine/textures/Float32ArrayTexture.ts rename to src/textures/Float32ArrayTexture.ts diff --git a/src/engine/textures/HDRTexture.ts b/src/textures/HDRTexture.ts similarity index 100% rename from src/engine/textures/HDRTexture.ts rename to src/textures/HDRTexture.ts diff --git a/src/engine/textures/HDRTextureCube.ts b/src/textures/HDRTextureCube.ts similarity index 100% rename from src/engine/textures/HDRTextureCube.ts rename to src/textures/HDRTextureCube.ts diff --git a/src/engine/textures/LDRTextureCube.ts b/src/textures/LDRTextureCube.ts similarity index 98% rename from src/engine/textures/LDRTextureCube.ts rename to src/textures/LDRTextureCube.ts index 87978e2f..575becb1 100644 --- a/src/engine/textures/LDRTextureCube.ts +++ b/src/textures/LDRTextureCube.ts @@ -8,7 +8,7 @@ import { LoaderFunctions } from "../loader/LoaderFunctions"; import { BitmapTexture2D } from "./BitmapTexture2D"; /** - * LDRTextureCube : create a cube texture, it's low dynamic range texture + * LDRTextureCube: create a cube texture, it's low dynamic range texture * @group Texture */ export class LDRTextureCube extends TextureCube { diff --git a/src/engine/textures/SolidColorSky.ts b/src/textures/SolidColorSky.ts similarity index 81% rename from src/engine/textures/SolidColorSky.ts rename to src/textures/SolidColorSky.ts index bbf4f56e..55db9b36 100644 --- a/src/engine/textures/SolidColorSky.ts +++ b/src/textures/SolidColorSky.ts @@ -1,5 +1,6 @@ +import { Engine3D } from '../Engine3D'; import { Color } from '../math/Color'; -import { defaultRes } from './DefaultRes'; + import { Float16ArrayTexture } from './Float16ArrayTexture'; import { HDRTextureCube } from './HDRTextureCube'; @@ -23,7 +24,7 @@ export class SolidColorSky extends HDRTextureCube { this._skyColor = color; this._internalTexture = new Float16ArrayTexture(); let numbers = []; - defaultRes.fillColor(numbers, this._minSize, this._minSize, this.color.r, this.color.g, this.color.b, this.color.a); + Engine3D.res.fillColor(numbers, this._minSize, this._minSize, this.color.r, this.color.g, this.color.b, this.color.a); this._internalTexture.create(this._minSize, this._minSize, numbers, false); this.createFromTexture(this._minSize, this._internalTexture); return this; @@ -31,7 +32,7 @@ export class SolidColorSky extends HDRTextureCube { private changeColor(color: Color): this { this._skyColor = color; - defaultRes.fillColor(this._internalTexture.floatArray, this._minSize, this._minSize, this.color.r, this.color.g, this.color.b, this.color.a); + Engine3D.res.fillColor(this._internalTexture.floatArray, this._minSize, this._minSize, this.color.r, this.color.g, this.color.b, this.color.a); this._internalTexture.updateTexture(this._minSize, this._minSize, this._internalTexture.floatArray, false); this.uploadTexture(0, this._internalTexture); return this; diff --git a/src/engine/textures/Uint16Texture.ts b/src/textures/Uint16Texture.ts similarity index 100% rename from src/engine/textures/Uint16Texture.ts rename to src/textures/Uint16Texture.ts diff --git a/src/engine/textures/Uint8ArrayTexture.ts b/src/textures/Uint8ArrayTexture.ts similarity index 100% rename from src/engine/textures/Uint8ArrayTexture.ts rename to src/textures/Uint8ArrayTexture.ts diff --git a/src/engine/textures/VirtualTexture.ts b/src/textures/VirtualTexture.ts similarity index 100% rename from src/engine/textures/VirtualTexture.ts rename to src/textures/VirtualTexture.ts diff --git a/src/engine/util/AxisObject.ts b/src/util/AxisObject.ts similarity index 97% rename from src/engine/util/AxisObject.ts rename to src/util/AxisObject.ts index 841a8928..759b87c7 100644 --- a/src/engine/util/AxisObject.ts +++ b/src/util/AxisObject.ts @@ -5,7 +5,7 @@ import { UnLitMaterial } from '../materials/UnLitMaterial'; import { Color } from '../math/Color'; import { Vector3 } from '../math/Vector3'; import { BoxGeometry } from '../shape/BoxGeometry'; -import { defaultRes } from '../textures/DefaultRes'; + /** * @internal diff --git a/src/engine/util/BytesStream.ts b/src/util/BytesStream.ts similarity index 100% rename from src/engine/util/BytesStream.ts rename to src/util/BytesStream.ts diff --git a/src/engine/util/CameraUtil.ts b/src/util/CameraUtil.ts similarity index 100% rename from src/engine/util/CameraUtil.ts rename to src/util/CameraUtil.ts diff --git a/src/engine/util/Convert.ts b/src/util/Convert.ts similarity index 100% rename from src/engine/util/Convert.ts rename to src/util/Convert.ts diff --git a/src/engine/util/GeometryUtil.ts b/src/util/GeometryUtil.ts similarity index 100% rename from src/engine/util/GeometryUtil.ts rename to src/util/GeometryUtil.ts diff --git a/src/engine/util/Global.ts b/src/util/Global.ts similarity index 100% rename from src/engine/util/Global.ts rename to src/util/Global.ts diff --git a/src/engine/util/KelvinUtil.ts b/src/util/KelvinUtil.ts similarity index 100% rename from src/engine/util/KelvinUtil.ts rename to src/util/KelvinUtil.ts diff --git a/src/engine/util/Object3DUtil.ts b/src/util/Object3DUtil.ts similarity index 100% rename from src/engine/util/Object3DUtil.ts rename to src/util/Object3DUtil.ts diff --git a/src/engine/util/ProfilerUtil.ts b/src/util/ProfilerUtil.ts similarity index 100% rename from src/engine/util/ProfilerUtil.ts rename to src/util/ProfilerUtil.ts diff --git a/src/engine/util/StringUtil.ts b/src/util/StringUtil.ts similarity index 100% rename from src/engine/util/StringUtil.ts rename to src/util/StringUtil.ts diff --git a/src/engine/util/Time.ts b/src/util/Time.ts similarity index 100% rename from src/engine/util/Time.ts rename to src/util/Time.ts diff --git a/src/engine/util/Vector3Ex.ts b/src/util/Vector3Ex.ts similarity index 100% rename from src/engine/util/Vector3Ex.ts rename to src/util/Vector3Ex.ts diff --git a/src/engine/util/ZSorterUtil.ts b/src/util/ZSorterUtil.ts similarity index 97% rename from src/engine/util/ZSorterUtil.ts rename to src/util/ZSorterUtil.ts index f57dcb4f..326bf53d 100644 --- a/src/engine/util/ZSorterUtil.ts +++ b/src/util/ZSorterUtil.ts @@ -61,4 +61,4 @@ export class ZSorterUtil { } } -export let zSorterUtil: ZSorterUtil = new ZSorterUtil(); +// export let zSorterUtil: ZSorterUtil = new ZSorterUtil(); diff --git a/src/engine/util/struct/Struct.ts b/src/util/struct/Struct.ts similarity index 100% rename from src/engine/util/struct/Struct.ts rename to src/util/struct/Struct.ts diff --git a/src/engine/util/struct/StructValue.ts b/src/util/struct/StructValue.ts similarity index 100% rename from src/engine/util/struct/StructValue.ts rename to src/util/struct/StructValue.ts diff --git a/src/engine/util/struct/Vector3Struct.ts b/src/util/struct/Vector3Struct.ts similarity index 100% rename from src/engine/util/struct/Vector3Struct.ts rename to src/util/struct/Vector3Struct.ts diff --git a/test/base/base.test.ts b/test/base/base.test.ts index c6596f19..fed99653 100644 --- a/test/base/base.test.ts +++ b/test/base/base.test.ts @@ -1,8 +1,7 @@ -import * as Orillusion from '../../src'; import { test, end } from '../util' await test('Init', async () => { - console.log(Orillusion) + // console.log(Orillusion) }) setTimeout(end, 500) \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index f5e65983..38cccccf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,7 @@ "noEmit": true, "rootDir": "./", "baseUrl": "./", + "outDir": "./js", "paths": { "../*": ["src/*"], "@orillusion/*": ["src/libs/*"], @@ -24,6 +25,6 @@ "allowJs": true, "strict": false }, - "include": ["src", "test"], + "include": ["src", "test", "sample"], "exclude": ["node_modules", "dist", "public"] } \ No newline at end of file From a06ec3e16af102446b20564c28443394475ed34c Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Mon, 1 May 2023 08:07:20 +0800 Subject: [PATCH 067/100] feat: auto indexing exports from /src (#84) watch all `.ts` changes from /src auto update exports in `index.ts` --- vite.config.js | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/vite.config.js b/vite.config.js index 704299dc..8e111653 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,7 +1,7 @@ // vite.config.js import { defineConfig } from 'vite' -import { readFile, writeFile } from 'fs/promises' -import {resolve} from 'path' +import { readFile, writeFile, readdir, lstat } from 'fs/promises' +import { resolve, parse } from 'path' module.exports = defineConfig({ server: { @@ -18,11 +18,39 @@ module.exports = defineConfig({ plugins: [{ name: 'autoIndex', configureServer(server) { - server.ws.on('autoIndex', async (data) => { + const tsFile = /\/src\/.*.ts$/ + async function dir(folder, ts = []) { + let files = await readdir(folder) + for (let f of files) { + let path = resolve(folder, f) + let ls = await lstat(path) + if (ls.isDirectory()) { + await dir(path, ts) + } else if (tsFile.test(path)) { + let name = parse(path).name + if (name !== 'index' && !name.startsWith('_') && !name.endsWith('-back')) + ts.push(path) + } + } + return ts + } + async function autoIndex(file) { + if(file && !tsFile.test(file)) + return + let ts = await dir('./src') + let improts = '' + for (let path of ts) { + improts += `export * from "${path.replace(__dirname + '/src', '.').slice(0, -3)}"\r\n` + } let content = await readFile(resolve(__dirname, './src/index.ts'), 'utf-8') - if(data.content !== content) - writeFile(resolve(__dirname, './src/index.ts'), data.content) - }) + if (improts !== content) { + console.log('[autoIndex] index.ts') + writeFile(resolve(__dirname, './src/index.ts'), improts) + } + } + server.httpServer.on('listening', autoIndex) + server.watcher.on('change', autoIndex) + server.watcher.on('unlink', autoIndex) } }], build: { @@ -33,4 +61,4 @@ module.exports = defineConfig({ }, // minify: 'terser' } -}) +}) \ No newline at end of file From 2a169f7e1e9e7c50ee14e40efe841595c1bfd921 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Mon, 1 May 2023 08:17:16 +0800 Subject: [PATCH 068/100] docs: update README remove note --- README.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index d155d086..88804e0d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,4 @@ ![Cover Art](https://github.com/Orillusion/orillusion-webgpu-samples/blob/main/logo_new.png) - -> **Note:** -> -> Currently, this repo is used to collect feedback on the NPM package of the Orillusion engine. According to all the feedback, we will carry on refining the engine core. Then, we need to set up the regulations for a long-term open source project and all the source code will be put in this repo in the near future, which indicates a brand new journey for Orillusion. - - ## Orillusion [![Test](https://github.com/Orillusion/orillusion/actions/workflows/ci.yml/badge.svg)](https://github.com/Orillusion/orillusion/actions/workflows/ci.yml) @@ -45,7 +39,7 @@ In order to use the engine more conveniently, we support to use native ` + \ No newline at end of file diff --git a/package.json b/package.json index 9c193bd4..524f130d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orillusion/core", - "version": "0.5.0", + "version": "0.6.0", "author": "Orillusion", "description": "Orillusion WebGPU Engine", "main": "./dist/orillusion.umd.js", @@ -25,12 +25,12 @@ "test": "electron test/ci/main.js", "test:ci": "xvfb-maybe -- electron test/ci/main.js", "test:install": "pnpm i electron@npm:electron-nightly@latest xvfb-maybe -O", - "docs": "npm run docs:core && npm run docs:physics && npm run docs:media", + "docs": "npm run docs:core && npm run docs:physics && npm run docs:media && npm run docs:stats", "docs:typedoc": "npx typedoc --plugin typedoc-plugin-markdown --plugin ./script/typedoc-plugin-not-exported.js --tsconfig tsconfig.build.json --gitRevision main --hideBreadcrumbs true --allReflectionsHaveOwnDocument true --readme none --excludeInternal --excludePrivate --excludeProtected --sort source-order --out", "docs:core": "npm run docs:typedoc docs/api src/index.ts", - "docs:physics": "npm run docs:typedoc docs/physics src/libs/physics/index.ts", - "docs:media": "npm run docs:typedoc docs/media-extention src/libs/media-extention/index.ts", - "docs:stats": "npm run docs:typedoc docs/stats src/libs/stats/index.ts" + "docs:physics": "cd packages/physics && npm run docs", + "docs:media": "cd packages/media-extention && npm run docs", + "docs:stats": "cd packages/stats && npm run docs" }, "devDependencies": { "@webgpu/types": "^0.1.30", diff --git a/packages/ammo/ammo.d.ts b/packages/ammo/ammo.d.ts new file mode 100644 index 00000000..ff5363d7 --- /dev/null +++ b/packages/ammo/ammo.d.ts @@ -0,0 +1,1071 @@ +export default Ammo; +/** + * @internal + */ +declare function Ammo(target?: T): Promise; +/** + * Ammo 原生类 by Bullet2 + */ +declare module Ammo { + function destroy(obj: any): void; + function _malloc(size: number): number; + function _free(ptr: number): void; + const HEAP8: Int8Array; + const HEAP16: Int16Array; + const HEAP32: Int32Array; + const HEAPU8: Uint8Array; + const HEAPU16: Uint16Array; + const HEAPU32: Uint32Array; + const HEAPF32: Float32Array; + const HEAPF64: Float64Array; + class btIDebugDraw { + drawLine(from: btVector3, to: btVector3, color: btVector3): void; + drawContactPoint(pointOnB: btVector3, normalOnB: btVector3, distance: number, lifeTime: number, color: btVector3): void; + reportErrorWarning(warningString: string): void; + draw3dText(location: btVector3, textString: string): void; + setDebugMode(debugMode: number): void; + getDebugMode(): number; + } + class DebugDrawer { + constructor(); + drawLine(from: btVector3, to: btVector3, color: btVector3): void; + drawContactPoint(pointOnB: btVector3, normalOnB: btVector3, distance: number, lifeTime: number, color: btVector3): void; + reportErrorWarning(warningString: string): void; + draw3dText(location: btVector3, textString: string): void; + setDebugMode(debugMode: number): void; + getDebugMode(): number; + } + class btVector3 { + constructor(); + constructor(x: number, y: number, z: number); + length(): number; + x(): number; + y(): number; + z(): number; + setX(x: number): void; + setY(y: number): void; + setZ(z: number): void; + setValue(x: number, y: number, z: number): void; + normalize(): void; + rotate(wAxis: btVector3, angle: number): btVector3; + dot(v: btVector3): number; + op_mul(x: number): btVector3; + op_add(v: btVector3): btVector3; + op_sub(v: btVector3): btVector3; + } + class btVector4 extends btVector3 { + constructor(); + constructor(x: number, y: number, z: number, w: number); + w(): number; + setValue(x: number, y: number, z: number): void; + setValue(x: number, y: number, z: number, w: number): void; + } + class btQuadWord { + x(): number; + y(): number; + z(): number; + w(): number; + setX(x: number): void; + setY(y: number): void; + setZ(z: number): void; + setW(w: number): void; + } + class btQuaternion extends btQuadWord { + constructor(x: number, y: number, z: number, w: number); + setValue(x: number, y: number, z: number, w: number): void; + setEulerZYX(z: number, y: number, x: number): void; + setRotation(axis: btVector3, angle: number): void; + normalize(): void; + length2(): number; + length(): number; + dot(q: btQuaternion): number; + normalized(): btQuaternion; + getAxis(): btVector3; + inverse(): btQuaternion; + getAngle(): number; + getAngleShortestPath(): number; + angle(q: btQuaternion): number; + angleShortestPath(q: btQuaternion): number; + op_add(q: btQuaternion): btQuaternion; + op_sub(q: btQuaternion): btQuaternion; + op_mul(s: number): btQuaternion; + op_mulq(q: btQuaternion): btQuaternion; + op_div(s: number): btQuaternion; + } + class btMatrix3x3 { + setEulerZYX(ex: number, ey: number, ez: number): void; + getRotation(q: btQuaternion): void; + getRow(y: number): btVector3; + } + class btTransform { + constructor(); + constructor(q: btQuaternion, v: btVector3); + setIdentity(): void; + setOrigin(origin: btVector3): void; + setRotation(rotation: btQuaternion): void; + getOrigin(): btVector3; + getRotation(): btQuaternion; + getBasis(): btMatrix3x3; + setFromOpenGLMatrix(m: ReadonlyArray): void; + inverse(): btTransform; + op_mul(t: btTransform): btTransform; + } + class btMotionState { + getWorldTransform(worldTrans: btTransform): void; + setWorldTransform(worldTrans: btTransform): void; + } + class btDefaultMotionState extends btMotionState { + constructor(startTrans?: btTransform, centerOfMassOffset?: btTransform); + get_m_graphicsWorldTrans(): btTransform; + set_m_graphicsWorldTrans(m_graphicsWorldTrans: btTransform): void; + } + class btCollisionObject { + setAnisotropicFriction(anisotropicFriction: btVector3, frictionMode: number): void; + getCollisionShape(): btCollisionShape; + setContactProcessingThreshold(contactProcessingThreshold: number): void; + setActivationState(newState: number): void; + forceActivationState(newState: number): void; + activate(forceActivation?: boolean): void; + isActive(): boolean; + isKinematicObject(): boolean; + isStaticObject(): boolean; + isStaticOrKinematicObject(): boolean; + getRestitution(): number; + getFriction(): number; + getRollingFriction(): number; + setRestitution(rest: number): void; + setFriction(frict: number): void; + setRollingFriction(frict: number): void; + getWorldTransform(): btTransform; + getCollisionFlags(): number; + setCollisionFlags(flags: number): void; + setWorldTransform(worldTrans: btTransform): void; + setCollisionShape(collisionShape: btCollisionShape): void; + setCcdMotionThreshold(ccdMotionThreshold: number): void; + setCcdSweptSphereRadius(radius: number): void; + getUserIndex(): number; + setUserIndex(index: number): void; + getUserPointer(): unknown; + setUserPointer(userPointer: unknown): void; + getBroadphaseHandle(): btBroadphaseProxy; + } + class btCollisionObjectWrapper { + getWorldTransform(): btTransform; + getCollisionObject(): btCollisionObject; + getCollisionShape(): btCollisionShape; + } + class RayResultCallback { + hasHit(): boolean; + get_m_collisionFilterGroup(): number; + set_m_collisionFilterGroup(m_collisionFilterGroup: number): void; + get_m_collisionFilterMask(): number; + set_m_collisionFilterMask(m_collisionFilterMask: number): void; + get_m_closestHitFraction(): number; + set_m_closestHitFraction(m_closestHitFraction: number): void; + get_m_collisionObject(): btCollisionObject; + set_m_collisionObject(m_collisionObject: btCollisionObject): void; + } + class ClosestRayResultCallback extends RayResultCallback { + constructor(from: btVector3, to: btVector3); + get_m_rayFromWorld(): btVector3; + set_m_rayFromWorld(m_rayFromWorld: btVector3): void; + get_m_rayToWorld(): btVector3; + set_m_rayToWorld(m_rayToWorld: btVector3): void; + get_m_hitNormalWorld(): btVector3; + set_m_hitNormalWorld(m_hitNormalWorld: btVector3): void; + get_m_hitPointWorld(): btVector3; + set_m_hitPointWorld(m_hitPointWorld: btVector3): void; + } + class btConstCollisionObjectArray { + size(): number; + at(n: number): btCollisionObject; + } + class btScalarArray { + size(): number; + at(n: number): number; + } + class AllHitsRayResultCallback extends RayResultCallback { + constructor(from: btVector3, to: btVector3); + get_m_collisionObjects(): btConstCollisionObjectArray; + set_m_collisionObjects(m_collisionObjects: btConstCollisionObjectArray): void; + get_m_rayFromWorld(): btVector3; + set_m_rayFromWorld(m_rayFromWorld: btVector3): void; + get_m_rayToWorld(): btVector3; + set_m_rayToWorld(m_rayToWorld: btVector3): void; + get_m_hitNormalWorld(): btVector3Array; + set_m_hitNormalWorld(m_hitNormalWorld: btVector3Array): void; + get_m_hitPointWorld(): btVector3Array; + set_m_hitPointWorld(m_hitPointWorld: btVector3Array): void; + get_m_hitFractions(): btScalarArray; + set_m_hitFractions(m_hitFractions: btScalarArray): void; + } + class btManifoldPoint { + getPositionWorldOnA(): btVector3; + getPositionWorldOnB(): btVector3; + getAppliedImpulse(): number; + getDistance(): number; + get_m_localPointA(): btVector3; + set_m_localPointA(m_localPointA: btVector3): void; + get_m_localPointB(): btVector3; + set_m_localPointB(m_localPointB: btVector3): void; + get_m_positionWorldOnB(): btVector3; + set_m_positionWorldOnB(m_positionWorldOnB: btVector3): void; + get_m_positionWorldOnA(): btVector3; + set_m_positionWorldOnA(m_positionWorldOnA: btVector3): void; + get_m_normalWorldOnB(): btVector3; + set_m_normalWorldOnB(m_normalWorldOnB: btVector3): void; + get_m_userPersistentData(): any; + set_m_userPersistentData(m_userPersistentData: any): void; + } + class ContactResultCallback { + addSingleResult(cp: btManifoldPoint, colObj0Wrap: btCollisionObjectWrapper, partId0: number, index0: number, colObj1Wrap: btCollisionObjectWrapper, partId1: number, index1: number): number; + } + class ConcreteContactResultCallback { + constructor(); + addSingleResult(cp: btManifoldPoint, colObj0Wrap: btCollisionObjectWrapper, partId0: number, index0: number, colObj1Wrap: btCollisionObjectWrapper, partId1: number, index1: number): number; + } + class LocalShapeInfo { + get_m_shapePart(): number; + set_m_shapePart(m_shapePart: number): void; + get_m_triangleIndex(): number; + set_m_triangleIndex(m_triangleIndex: number): void; + } + class LocalConvexResult { + constructor(hitCollisionObject: btCollisionObject, localShapeInfo: LocalShapeInfo, hitNormalLocal: btVector3, hitPointLocal: btVector3, hitFraction: number); + get_m_hitCollisionObject(): btCollisionObject; + set_m_hitCollisionObject(m_hitCollisionObject: btCollisionObject): void; + get_m_localShapeInfo(): LocalShapeInfo; + set_m_localShapeInfo(m_localShapeInfo: LocalShapeInfo): void; + get_m_hitNormalLocal(): btVector3; + set_m_hitNormalLocal(m_hitNormalLocal: btVector3): void; + get_m_hitPointLocal(): btVector3; + set_m_hitPointLocal(m_hitPointLocal: btVector3): void; + get_m_hitFraction(): number; + set_m_hitFraction(m_hitFraction: number): void; + } + class ConvexResultCallback { + hasHit(): boolean; + get_m_collisionFilterGroup(): number; + set_m_collisionFilterGroup(m_collisionFilterGroup: number): void; + get_m_collisionFilterMask(): number; + set_m_collisionFilterMask(m_collisionFilterMask: number): void; + get_m_closestHitFraction(): number; + set_m_closestHitFraction(m_closestHitFraction: number): void; + } + class ClosestConvexResultCallback extends ConvexResultCallback { + constructor(convexFromWorld: btVector3, convexToWorld: btVector3); + get_m_convexFromWorld(): btVector3; + set_m_convexFromWorld(m_convexFromWorld: btVector3): void; + get_m_convexToWorld(): btVector3; + set_m_convexToWorld(m_convexToWorld: btVector3): void; + get_m_hitNormalWorld(): btVector3; + set_m_hitNormalWorld(m_hitNormalWorld: btVector3): void; + get_m_hitPointWorld(): btVector3; + set_m_hitPointWorld(m_hitPointWorld: btVector3): void; + } + class btCollisionShape { + setLocalScaling(scaling: btVector3): void; + getLocalScaling(): btVector3; + calculateLocalInertia(mass: number, inertia: btVector3): void; + setMargin(margin: number): void; + getMargin(): number; + } + class btConvexShape extends btCollisionShape {} + class btConvexTriangleMeshShape extends btConvexShape { + constructor(meshInterface: btStridingMeshInterface, calcAabb?: boolean); + } + class btBoxShape extends btCollisionShape { + constructor(boxHalfExtents: btVector3); + setMargin(margin: number): void; + getMargin(): number; + } + class btCapsuleShape extends btCollisionShape { + constructor(radius: number, height: number); + setMargin(margin: number): void; + getMargin(): number; + getUpAxis(): number; + getRadius(): number; + getHalfHeight(): number; + } + class btCapsuleShapeX extends btCapsuleShape { + constructor(radius: number, height: number); + setMargin(margin: number): void; + getMargin(): number; + } + class btCapsuleShapeZ extends btCapsuleShape { + constructor(radius: number, height: number); + setMargin(margin: number): void; + getMargin(): number; + } + class btCylinderShape extends btCollisionShape { + constructor(halfExtents: btVector3); + setMargin(margin: number): void; + getMargin(): number; + } + class btCylinderShapeX extends btCylinderShape { + constructor(halfExtents: btVector3); + setMargin(margin: number): void; + getMargin(): number; + } + class btCylinderShapeZ extends btCylinderShape { + constructor(halfExtents: btVector3); + setMargin(margin: number): void; + getMargin(): number; + } + class btSphereShape extends btCollisionShape { + constructor(radius: number); + setMargin(margin: number): void; + getMargin(): number; + } + class btMultiSphereShape extends btCollisionShape { + constructor(positions: btVector3, radii: ReadonlyArray, numPoints: number); + } + class btConeShape extends btCollisionShape { + constructor(radius: number, height: number); + } + class btConeShapeX extends btConeShape { + constructor(radius: number, height: number); + } + class btConeShapeZ extends btConeShape { + constructor(radius: number, height: number); + } + class btIntArray { + size(): number; + at(n: number): number; + } + class btFace { + get_m_indices(): btIntArray; + set_m_indices(m_indices: btIntArray): void; + get_m_plane(): ReadonlyArray; + set_m_plane(m_plane: ReadonlyArray): void; + } + class btVector3Array { + size(): number; + at(n: number): btVector3; + } + class btFaceArray { + size(): number; + at(n: number): btFace; + } + class btConvexPolyhedron { + get_m_vertices(): btVector3Array; + set_m_vertices(m_vertices: btVector3Array): void; + get_m_faces(): btFaceArray; + set_m_faces(m_faces: btFaceArray): void; + } + class btConvexHullShape extends btCollisionShape { + constructor(points?: ReadonlyArray, numPoints?: number); + addPoint(point: btVector3, recalculateLocalAABB?: boolean): void; + setMargin(margin: number): void; + getMargin(): number; + getNumVertices(): number; + initializePolyhedralFeatures(shiftVerticesByMargin: number): boolean; + recalcLocalAabb(): void; + getConvexPolyhedron(): btConvexPolyhedron; + } + class btShapeHull { + constructor(shape: btConvexShape); + buildHull(margin: number): boolean; + numVertices(): number; + getVertexPointer(): btVector3; + } + class btCompoundShape extends btCollisionShape { + constructor(enableDynamicAabbTree?: boolean); + addChildShape(localTransform: btTransform, shape: btCollisionShape): void; + removeChildShape(shape: btCollisionShape): void; + removeChildShapeByIndex(childShapeindex: number): void; + getNumChildShapes(): number; + getChildShape(index: number): btCollisionShape; + updateChildTransform(childIndex: number, newChildTransform: btTransform, shouldRecalculateLocalAabb?: boolean): void; + setMargin(margin: number): void; + getMargin(): number; + } + class btStridingMeshInterface { + setScaling(scaling: btVector3): void; + } + class btIndexedMesh { + get_m_numTriangles(): number; + set_m_numTriangles(m_numTriangles: number): void; + } + class btIndexedMeshArray { + size(): number; + at(n: number): btIndexedMesh; + } + class btTriangleMesh extends btStridingMeshInterface { + constructor(use32bitIndices?: boolean, use4componentVertices?: boolean); + addTriangle(vertex0: btVector3, vertex1: btVector3, vertex2: btVector3, removeDuplicateVertices?: boolean): void; + findOrAddVertex(vertex: btVector3, removeDuplicateVertices: boolean): number; + addIndex(index: number): void; + getIndexedMeshArray(): btIndexedMeshArray; + } + type PHY_ScalarType = 'PHY_FLOAT' | 'PHY_DOUBLE' | 'PHY_INTEGER' | 'PHY_SHORT' | 'PHY_FIXEDPOINT88' | 'PHY_UCHAR'; + class btConcaveShape extends btCollisionShape {} + class btEmptyShape extends btConcaveShape { + constructor(); + } + class btStaticPlaneShape extends btConcaveShape { + constructor(planeNormal: btVector3, planeConstant: number); + } + class btTriangleMeshShape extends btConcaveShape {} + class btBvhTriangleMeshShape extends btTriangleMeshShape { + constructor(meshInterface: btStridingMeshInterface, useQuantizedAabbCompression: boolean, buildBvh?: boolean); + } + class btHeightfieldTerrainShape extends btConcaveShape { + constructor(heightStickWidth: number, heightStickLength: number, heightfieldData: unknown, heightScale: number, minHeight: number, maxHeight: number, upAxis: number, hdt: PHY_ScalarType, flipQuadEdges: boolean); + setMargin(margin: number): void; + getMargin(): number; + } + class btDefaultCollisionConstructionInfo { + constructor(); + } + class btDefaultCollisionConfiguration { + constructor(info?: btDefaultCollisionConstructionInfo); + } + class btPersistentManifold { + constructor(); + getBody0(): btCollisionObject; + getBody1(): btCollisionObject; + getNumContacts(): number; + getContactPoint(index: number): btManifoldPoint; + } + class btDispatcher { + getNumManifolds(): number; + getManifoldByIndexInternal(index: number): btPersistentManifold; + } + class btCollisionDispatcher extends btDispatcher { + constructor(conf: btDefaultCollisionConfiguration); + } + class btOverlappingPairCallback {} + class btOverlappingPairCache { + setInternalGhostPairCallback(ghostPairCallback: btOverlappingPairCallback): void; + getNumOverlappingPairs(): number; + } + class btAxisSweep3 { + constructor(worldAabbMin: btVector3, worldAabbMax: btVector3, maxHandles?: number, pairCache?: btOverlappingPairCache, disableRaycastAccelerator?: boolean); + } + class btBroadphaseInterface { + getOverlappingPairCache(): btOverlappingPairCache; + } + class btCollisionConfiguration {} + class btDbvtBroadphase extends btBroadphaseInterface { + constructor(); + } + class btBroadphaseProxy { + get_m_collisionFilterGroup(): number; + set_m_collisionFilterGroup(m_collisionFilterGroup: number): void; + get_m_collisionFilterMask(): number; + set_m_collisionFilterMask(m_collisionFilterMask: number): void; + } + class btRigidBodyConstructionInfo { + constructor(mass: number, motionState: btMotionState, collisionShape: btCollisionShape, localInertia?: btVector3); + get_m_linearDamping(): number; + set_m_linearDamping(m_linearDamping: number): void; + get_m_angularDamping(): number; + set_m_angularDamping(m_angularDamping: number): void; + get_m_friction(): number; + set_m_friction(m_friction: number): void; + get_m_rollingFriction(): number; + set_m_rollingFriction(m_rollingFriction: number): void; + get_m_restitution(): number; + set_m_restitution(m_restitution: number): void; + get_m_linearSleepingThreshold(): number; + set_m_linearSleepingThreshold(m_linearSleepingThreshold: number): void; + get_m_angularSleepingThreshold(): number; + set_m_angularSleepingThreshold(m_angularSleepingThreshold: number): void; + get_m_additionalDamping(): boolean; + set_m_additionalDamping(m_additionalDamping: boolean): void; + get_m_additionalDampingFactor(): number; + set_m_additionalDampingFactor(m_additionalDampingFactor: number): void; + get_m_additionalLinearDampingThresholdSqr(): number; + set_m_additionalLinearDampingThresholdSqr(m_additionalLinearDampingThresholdSqr: number): void; + get_m_additionalAngularDampingThresholdSqr(): number; + set_m_additionalAngularDampingThresholdSqr(m_additionalAngularDampingThresholdSqr: number): void; + get_m_additionalAngularDampingFactor(): number; + set_m_additionalAngularDampingFactor(m_additionalAngularDampingFactor: number): void; + } + class btRigidBody extends btCollisionObject { + constructor(constructionInfo: btRigidBodyConstructionInfo); + getCenterOfMassTransform(): btTransform; + setCenterOfMassTransform(xform: btTransform): void; + setSleepingThresholds(linear: number, angular: number): void; + getLinearDamping(): number; + getAngularDamping(): number; + setDamping(lin_damping: number, ang_damping: number): void; + setMassProps(mass: number, inertia: btVector3): void; + getLinearFactor(): btVector3; + setLinearFactor(linearFactor: btVector3): void; + applyTorque(torque: btVector3): void; + applyLocalTorque(torque: btVector3): void; + applyForce(force: btVector3, rel_pos: btVector3): void; + applyCentralForce(force: btVector3): void; + applyCentralLocalForce(force: btVector3): void; + applyTorqueImpulse(torque: btVector3): void; + applyImpulse(impulse: btVector3, rel_pos: btVector3): void; + applyCentralImpulse(impulse: btVector3): void; + updateInertiaTensor(): void; + getLinearVelocity(): btVector3; + getAngularVelocity(): btVector3; + setLinearVelocity(lin_vel: btVector3): void; + setAngularVelocity(ang_vel: btVector3): void; + getMotionState(): btMotionState; + setMotionState(motionState: btMotionState): void; + getAngularFactor(): btVector3; + setAngularFactor(angularFactor: btVector3): void; + upcast(colObj: btCollisionObject): btRigidBody; + getAabb(aabbMin: btVector3, aabbMax: btVector3): void; + applyGravity(): void; + getGravity(): btVector3; + setGravity(acceleration: btVector3): void; + getBroadphaseProxy(): btBroadphaseProxy; + clearForces(): void; + } + class btConstraintSetting { + constructor(); + get_m_tau(): number; + set_m_tau(m_tau: number): void; + get_m_damping(): number; + set_m_damping(m_damping: number): void; + get_m_impulseClamp(): number; + set_m_impulseClamp(m_impulseClamp: number): void; + } + class btTypedConstraint { + enableFeedback(needsFeedback: boolean): void; + getBreakingImpulseThreshold(): number; + setBreakingImpulseThreshold(threshold: number): void; + getParam(num: number, axis: number): number; + setParam(num: number, value: number, axis: number): void; + } + type btConstraintParams = 'BT_CONSTRAINT_ERP' | 'BT_CONSTRAINT_STOP_ERP' | 'BT_CONSTRAINT_CFM' | 'BT_CONSTRAINT_STOP_CFM'; + class btPoint2PointConstraint extends btTypedConstraint { + constructor(rbA: btRigidBody, rbB: btRigidBody, pivotInA: btVector3, pivotInB: btVector3); + constructor(rbA: btRigidBody, pivotInA: btVector3); + setPivotA(pivotA: btVector3): void; + setPivotB(pivotB: btVector3): void; + getPivotInA(): btVector3; + getPivotInB(): btVector3; + get_m_setting(): btConstraintSetting; + set_m_setting(m_setting: btConstraintSetting): void; + } + class btGeneric6DofConstraint extends btTypedConstraint { + constructor(rbA: btRigidBody, rbB: btRigidBody, frameInA: btTransform, frameInB: btTransform, useLinearFrameReferenceFrameA: boolean); + constructor(rbB: btRigidBody, frameInB: btTransform, useLinearFrameReferenceFrameB: boolean); + setLinearLowerLimit(linearLower: btVector3): void; + setLinearUpperLimit(linearUpper: btVector3): void; + setAngularLowerLimit(angularLower: btVector3): void; + setAngularUpperLimit(angularUpper: btVector3): void; + getFrameOffsetA(): btTransform; + } + class btGeneric6DofSpringConstraint extends btGeneric6DofConstraint { + constructor(rbA: btRigidBody, rbB: btRigidBody, frameInA: btTransform, frameInB: btTransform, useLinearFrameReferenceFrameA: boolean); + constructor(rbB: btRigidBody, frameInB: btTransform, useLinearFrameReferenceFrameB: boolean); + enableSpring(index: number, onOff: boolean): void; + setStiffness(index: number, stiffness: number): void; + setDamping(index: number, damping: number): void; + setEquilibriumPoint(index: number, val: number): void; + setEquilibriumPoint(index: number): void; + setEquilibriumPoint(): void; + } + class btSequentialImpulseConstraintSolver { + constructor(); + } + class btConeTwistConstraint extends btTypedConstraint { + constructor(rbA: btRigidBody, rbB: btRigidBody, rbAFrame: btTransform, rbBFrame: btTransform); + constructor(rbA: btRigidBody, rbAFrame: btTransform); + setLimit(limitIndex: number, limitValue: number): void; + setAngularOnly(angularOnly: boolean): void; + setDamping(damping: number): void; + enableMotor(b: boolean): void; + setMaxMotorImpulse(maxMotorImpulse: number): void; + setMaxMotorImpulseNormalized(maxMotorImpulse: number): void; + setMotorTarget(q: btQuaternion): void; + setMotorTargetInConstraintSpace(q: btQuaternion): void; + } + class btHingeConstraint extends btTypedConstraint { + constructor(rbA: btRigidBody, rbB: btRigidBody, pivotInA: btVector3, pivotInB: btVector3, axisInA: btVector3, axisInB: btVector3, useReferenceFrameA?: boolean); + constructor(rbA: btRigidBody, rbB: btRigidBody, rbAFrame: btTransform, rbBFrame: btTransform, useReferenceFrameA?: boolean); + constructor(rbA: btRigidBody, rbAFrame: btTransform, useReferenceFrameA?: boolean); + setLimit(low: number, high: number, softness: number, biasFactor: number, relaxationFactor?: number): void; + enableAngularMotor(enableMotor: boolean, targetVelocity: number, maxMotorImpulse: number): void; + setAngularOnly(angularOnly: boolean): void; + enableMotor(enableMotor: boolean): void; + setMaxMotorImpulse(maxMotorImpulse: number): void; + setMotorTarget(targetAngle: number, dt: number): void; + } + class btSliderConstraint extends btTypedConstraint { + constructor(rbA: btRigidBody, rbB: btRigidBody, frameInA: btTransform, frameInB: btTransform, useLinearReferenceFrameA: boolean); + constructor(rbB: btRigidBody, frameInB: btTransform, useLinearReferenceFrameA: boolean); + setLowerLinLimit(lowerLimit: number): void; + setUpperLinLimit(upperLimit: number): void; + setLowerAngLimit(lowerAngLimit: number): void; + setUpperAngLimit(upperAngLimit: number): void; + } + class btFixedConstraint extends btTypedConstraint { + constructor(rbA: btRigidBody, rbB: btRigidBody, frameInA: btTransform, frameInB: btTransform); + } + class btConstraintSolver {} + class btDispatcherInfo { + get_m_timeStep(): number; + set_m_timeStep(m_timeStep: number): void; + get_m_stepCount(): number; + set_m_stepCount(m_stepCount: number): void; + get_m_dispatchFunc(): number; + set_m_dispatchFunc(m_dispatchFunc: number): void; + get_m_timeOfImpact(): number; + set_m_timeOfImpact(m_timeOfImpact: number): void; + get_m_useContinuous(): boolean; + set_m_useContinuous(m_useContinuous: boolean): void; + get_m_enableSatConvex(): boolean; + set_m_enableSatConvex(m_enableSatConvex: boolean): void; + get_m_enableSPU(): boolean; + set_m_enableSPU(m_enableSPU: boolean): void; + get_m_useEpa(): boolean; + set_m_useEpa(m_useEpa: boolean): void; + get_m_allowedCcdPenetration(): number; + set_m_allowedCcdPenetration(m_allowedCcdPenetration: number): void; + get_m_useConvexConservativeDistanceUtil(): boolean; + set_m_useConvexConservativeDistanceUtil(m_useConvexConservativeDistanceUtil: boolean): void; + get_m_convexConservativeDistanceThreshold(): number; + set_m_convexConservativeDistanceThreshold(m_convexConservativeDistanceThreshold: number): void; + } + class btCollisionWorld { + getDispatcher(): btDispatcher; + rayTest(rayFromWorld: btVector3, rayToWorld: btVector3, resultCallback: RayResultCallback): void; + getPairCache(): btOverlappingPairCache; + getDispatchInfo(): btDispatcherInfo; + addCollisionObject(collisionObject: btCollisionObject, collisionFilterGroup?: number, collisionFilterMask?: number): void; + removeCollisionObject(collisionObject: btCollisionObject): void; + getBroadphase(): btBroadphaseInterface; + convexSweepTest(castShape: btConvexShape, from: btTransform, to: btTransform, resultCallback: ConvexResultCallback, allowedCcdPenetration: number): void; + contactPairTest(colObjA: btCollisionObject, colObjB: btCollisionObject, resultCallback: ContactResultCallback): void; + contactTest(colObj: btCollisionObject, resultCallback: ContactResultCallback): void; + updateSingleAabb(colObj: btCollisionObject): void; + setDebugDrawer(debugDrawer: btIDebugDraw): void; + getDebugDrawer(): btIDebugDraw; + debugDrawWorld(): void; + debugDrawObject(worldTransform: btTransform, shape: btCollisionShape, color: btVector3): void; + } + class btContactSolverInfo { + get_m_splitImpulse(): boolean; + set_m_splitImpulse(m_splitImpulse: boolean): void; + get_m_splitImpulsePenetrationThreshold(): number; + set_m_splitImpulsePenetrationThreshold(m_splitImpulsePenetrationThreshold: number): void; + get_m_numIterations(): number; + set_m_numIterations(m_numIterations: number): void; + } + type btInternalTickCallback = (world: btDynamicsWorld, timeStep: number) => void; + class btDynamicsWorld extends btCollisionWorld { + addAction(action: btActionInterface): void; + removeAction(action: btActionInterface): void; + getSolverInfo(): btContactSolverInfo; + setInternalTickCallback(cb: btInternalTickCallback, worldUserInfo?: unknown, isPreTick?: boolean): void; + } + class btDiscreteDynamicsWorld extends btDynamicsWorld { + constructor(dispatcher: btDispatcher, pairCache: btBroadphaseInterface, constraintSolver: btConstraintSolver, collisionConfiguration: btCollisionConfiguration); + setGravity(gravity: btVector3): void; + getGravity(): btVector3; + addRigidBody(body: btRigidBody): void; + addRigidBody(body: btRigidBody, group: number, mask: number): void; + removeRigidBody(body: btRigidBody): void; + addConstraint(constraint: btTypedConstraint, disableCollisionsBetweenLinkedBodies?: boolean): void; + removeConstraint(constraint: btTypedConstraint): void; + stepSimulation(timeStep: number, maxSubSteps?: number, fixedTimeStep?: number): number; + setContactAddedCallback(funcpointer: number): void; + setContactProcessedCallback(funcpointer: number): void; + setContactDestroyedCallback(funcpointer: number): void; + } + class btVehicleTuning { + constructor(); + get_m_suspensionStiffness(): number; + set_m_suspensionStiffness(m_suspensionStiffness: number): void; + get_m_suspensionCompression(): number; + set_m_suspensionCompression(m_suspensionCompression: number): void; + get_m_suspensionDamping(): number; + set_m_suspensionDamping(m_suspensionDamping: number): void; + get_m_maxSuspensionTravelCm(): number; + set_m_maxSuspensionTravelCm(m_maxSuspensionTravelCm: number): void; + get_m_frictionSlip(): number; + set_m_frictionSlip(m_frictionSlip: number): void; + get_m_maxSuspensionForce(): number; + set_m_maxSuspensionForce(m_maxSuspensionForce: number): void; + } + class btVehicleRaycasterResult { + get_m_hitPointInWorld(): btVector3; + set_m_hitPointInWorld(m_hitPointInWorld: btVector3): void; + get_m_hitNormalInWorld(): btVector3; + set_m_hitNormalInWorld(m_hitNormalInWorld: btVector3): void; + get_m_distFraction(): number; + set_m_distFraction(m_distFraction: number): void; + } + class btVehicleRaycaster { + castRay(from: btVector3, to: btVector3, result: btVehicleRaycasterResult): void; + } + class btDefaultVehicleRaycaster extends btVehicleRaycaster { + constructor(world: btDynamicsWorld); + } + class RaycastInfo { + get_m_contactNormalWS(): btVector3; + set_m_contactNormalWS(m_contactNormalWS: btVector3): void; + get_m_contactPointWS(): btVector3; + set_m_contactPointWS(m_contactPointWS: btVector3): void; + get_m_suspensionLength(): number; + set_m_suspensionLength(m_suspensionLength: number): void; + get_m_hardPointWS(): btVector3; + set_m_hardPointWS(m_hardPointWS: btVector3): void; + get_m_wheelDirectionWS(): btVector3; + set_m_wheelDirectionWS(m_wheelDirectionWS: btVector3): void; + get_m_wheelAxleWS(): btVector3; + set_m_wheelAxleWS(m_wheelAxleWS: btVector3): void; + get_m_isInContact(): boolean; + set_m_isInContact(m_isInContact: boolean): void; + get_m_groundObject(): any; + set_m_groundObject(m_groundObject: any): void; + } + class btWheelInfoConstructionInfo { + get_m_chassisConnectionCS(): btVector3; + set_m_chassisConnectionCS(m_chassisConnectionCS: btVector3): void; + get_m_wheelDirectionCS(): btVector3; + set_m_wheelDirectionCS(m_wheelDirectionCS: btVector3): void; + get_m_wheelAxleCS(): btVector3; + set_m_wheelAxleCS(m_wheelAxleCS: btVector3): void; + get_m_suspensionRestLength(): number; + set_m_suspensionRestLength(m_suspensionRestLength: number): void; + get_m_maxSuspensionTravelCm(): number; + set_m_maxSuspensionTravelCm(m_maxSuspensionTravelCm: number): void; + get_m_wheelRadius(): number; + set_m_wheelRadius(m_wheelRadius: number): void; + get_m_suspensionStiffness(): number; + set_m_suspensionStiffness(m_suspensionStiffness: number): void; + get_m_wheelsDampingCompression(): number; + set_m_wheelsDampingCompression(m_wheelsDampingCompression: number): void; + get_m_wheelsDampingRelaxation(): number; + set_m_wheelsDampingRelaxation(m_wheelsDampingRelaxation: number): void; + get_m_frictionSlip(): number; + set_m_frictionSlip(m_frictionSlip: number): void; + get_m_maxSuspensionForce(): number; + set_m_maxSuspensionForce(m_maxSuspensionForce: number): void; + get_m_bIsFrontWheel(): boolean; + set_m_bIsFrontWheel(m_bIsFrontWheel: boolean): void; + } + class btWheelInfo { + get_m_suspensionStiffness(): number; + set_m_suspensionStiffness(m_suspensionStiffness: number): void; + get_m_frictionSlip(): number; + set_m_frictionSlip(m_frictionSlip: number): void; + get_m_engineForce(): number; + set_m_engineForce(m_engineForce: number): void; + get_m_rollInfluence(): number; + set_m_rollInfluence(m_rollInfluence: number): void; + get_m_suspensionRestLength1(): number; + set_m_suspensionRestLength1(m_suspensionRestLength1: number): void; + get_m_wheelsRadius(): number; + set_m_wheelsRadius(m_wheelsRadius: number): void; + get_m_wheelsDampingCompression(): number; + set_m_wheelsDampingCompression(m_wheelsDampingCompression: number): void; + get_m_wheelsDampingRelaxation(): number; + set_m_wheelsDampingRelaxation(m_wheelsDampingRelaxation: number): void; + get_m_steering(): number; + set_m_steering(m_steering: number): void; + get_m_maxSuspensionForce(): number; + set_m_maxSuspensionForce(m_maxSuspensionForce: number): void; + get_m_maxSuspensionTravelCm(): number; + set_m_maxSuspensionTravelCm(m_maxSuspensionTravelCm: number): void; + get_m_wheelsSuspensionForce(): number; + set_m_wheelsSuspensionForce(m_wheelsSuspensionForce: number): void; + get_m_bIsFrontWheel(): boolean; + set_m_bIsFrontWheel(m_bIsFrontWheel: boolean): void; + get_m_raycastInfo(): RaycastInfo; + set_m_raycastInfo(m_raycastInfo: RaycastInfo): void; + get_m_chassisConnectionPointCS(): btVector3; + set_m_chassisConnectionPointCS(m_chassisConnectionPointCS: btVector3): void; + constructor(ci: btWheelInfoConstructionInfo); + getSuspensionRestLength(): number; + updateWheel(chassis: btRigidBody, raycastInfo: RaycastInfo): void; + get_m_worldTransform(): btTransform; + set_m_worldTransform(m_worldTransform: btTransform): void; + get_m_wheelDirectionCS(): btVector3; + set_m_wheelDirectionCS(m_wheelDirectionCS: btVector3): void; + get_m_wheelAxleCS(): btVector3; + set_m_wheelAxleCS(m_wheelAxleCS: btVector3): void; + get_m_rotation(): number; + set_m_rotation(m_rotation: number): void; + get_m_deltaRotation(): number; + set_m_deltaRotation(m_deltaRotation: number): void; + get_m_brake(): number; + set_m_brake(m_brake: number): void; + get_m_clippedInvContactDotSuspension(): number; + set_m_clippedInvContactDotSuspension(m_clippedInvContactDotSuspension: number): void; + get_m_suspensionRelativeVelocity(): number; + set_m_suspensionRelativeVelocity(m_suspensionRelativeVelocity: number): void; + get_m_skidInfo(): number; + set_m_skidInfo(m_skidInfo: number): void; + } + class btActionInterface { + updateAction(collisionWorld: btCollisionWorld, deltaTimeStep: number): void; + } + class btKinematicCharacterController extends btActionInterface { + constructor(ghostObject: btPairCachingGhostObject, convexShape: btConvexShape, stepHeight: number, upAxis?: number); + setUpAxis(axis: number): void; + setWalkDirection(walkDirection: btVector3): void; + setVelocityForTimeInterval(velocity: btVector3, timeInterval: number): void; + warp(origin: btVector3): void; + preStep(collisionWorld: btCollisionWorld): void; + playerStep(collisionWorld: btCollisionWorld, dt: number): void; + setFallSpeed(fallSpeed: number): void; + setJumpSpeed(jumpSpeed: number): void; + setMaxJumpHeight(maxJumpHeight: number): void; + canJump(): boolean; + jump(): void; + setGravity(gravity: number): void; + getGravity(): number; + setMaxSlope(slopeRadians: number): void; + getMaxSlope(): number; + getGhostObject(): btPairCachingGhostObject; + setUseGhostSweepTest(useGhostObjectSweepTest: boolean): void; + onGround(): boolean; + setUpInterpolate(value: boolean): void; + } + class btRaycastVehicle extends btActionInterface { + constructor(tuning: btVehicleTuning, chassis: btRigidBody, raycaster: btVehicleRaycaster); + applyEngineForce(force: number, wheel: number): void; + setSteeringValue(steering: number, wheel: number): void; + getWheelTransformWS(wheelIndex: number): btTransform; + updateWheelTransform(wheelIndex: number, interpolatedTransform: boolean): void; + addWheel(connectionPointCS0: btVector3, wheelDirectionCS0: btVector3, wheelAxleCS: btVector3, suspensionRestLength: number, wheelRadius: number, tuning: btVehicleTuning, isFrontWheel: boolean): btWheelInfo; + getNumWheels(): number; + getRigidBody(): btRigidBody; + getWheelInfo(index: number): btWheelInfo; + setBrake(brake: number, wheelIndex: number): void; + setCoordinateSystem(rightIndex: number, upIndex: number, forwardIndex: number): void; + getCurrentSpeedKmHour(): number; + getChassisWorldTransform(): btTransform; + rayCast(wheel: btWheelInfo): number; + updateVehicle(step: number): void; + resetSuspension(): void; + getSteeringValue(wheel: number): number; + updateWheelTransformsWS(wheel: btWheelInfo, interpolatedTransform?: boolean): void; + setPitchControl(pitch: number): void; + updateSuspension(deltaTime: number): void; + updateFriction(timeStep: number): void; + getRightAxis(): number; + getUpAxis(): number; + getForwardAxis(): number; + getForwardVector(): btVector3; + getUserConstraintType(): number; + setUserConstraintType(userConstraintType: number): void; + setUserConstraintId(uid: number): void; + getUserConstraintId(): number; + } + class btGhostObject extends btCollisionObject { + constructor(); + getNumOverlappingObjects(): number; + getOverlappingObject(index: number): btCollisionObject; + } + class btPairCachingGhostObject extends btGhostObject { + constructor(); + } + class btGhostPairCallback { + constructor(); + } + class btSoftBodyWorldInfo { + constructor(); + get_air_density(): number; + set_air_density(air_density: number): void; + get_water_density(): number; + set_water_density(water_density: number): void; + get_water_offset(): number; + set_water_offset(water_offset: number): void; + get_m_maxDisplacement(): number; + set_m_maxDisplacement(m_maxDisplacement: number): void; + get_water_normal(): btVector3; + set_water_normal(water_normal: btVector3): void; + get_m_broadphase(): btBroadphaseInterface; + set_m_broadphase(m_broadphase: btBroadphaseInterface): void; + get_m_dispatcher(): btDispatcher; + set_m_dispatcher(m_dispatcher: btDispatcher): void; + get_m_gravity(): btVector3; + set_m_gravity(m_gravity: btVector3): void; + } + class Face { + get_m_n(): ReadonlyArray; + set_m_n(m_n: ReadonlyArray): void; + get_m_normal(): btVector3; + set_m_normal(m_normal: btVector3): void; + get_m_ra(): number; + set_m_ra(m_ra: number): void; + } + class tFaceArray { + size(): number; + at(n: number): Face; + } + class Node { + get_m_x(): btVector3; + set_m_x(m_x: btVector3): void; + get_m_q(): btVector3; + set_m_q(m_q: btVector3): void; + get_m_v(): btVector3; + set_m_v(m_v: btVector3): void; + get_m_f(): btVector3; + set_m_f(m_f: btVector3): void; + get_m_n(): btVector3; + set_m_n(m_n: btVector3): void; + get_m_im(): number; + set_m_im(m_im: number): void; + get_m_area(): number; + set_m_area(m_area: number): void; + } + class tNodeArray { + size(): number; + at(n: number): Node; + } + class Material { + get_m_kLST(): number; + set_m_kLST(m_kLST: number): void; + get_m_kAST(): number; + set_m_kAST(m_kAST: number): void; + get_m_kVST(): number; + set_m_kVST(m_kVST: number): void; + get_m_flags(): number; + set_m_flags(m_flags: number): void; + } + class tMaterialArray { + size(): number; + at(n: number): Material; + } + class Anchor { + get_m_node(): Node; + set_m_node(m_node: Node): void; + get_m_local(): btVector3; + set_m_local(m_local: btVector3): void; + get_m_body(): btRigidBody; + set_m_body(m_body: btRigidBody): void; + get_m_influence(): number; + set_m_influence(m_influence: number): void; + get_m_c0(): btMatrix3x3; + set_m_c0(m_c0: btMatrix3x3): void; + get_m_c1(): btVector3; + set_m_c1(m_c1: btVector3): void; + get_m_c2(): number; + set_m_c2(m_c2: number): void; + } + class tAnchorArray { + size(): number; + at(n: number): Anchor; + clear(): void; + push_back(val: Anchor): void; + pop_back(): void; + } + class Config { + get_kVCF(): number; + set_kVCF(kVCF: number): void; + get_kDP(): number; + set_kDP(kDP: number): void; + get_kDG(): number; + set_kDG(kDG: number): void; + get_kLF(): number; + set_kLF(kLF: number): void; + get_kPR(): number; + set_kPR(kPR: number): void; + get_kVC(): number; + set_kVC(kVC: number): void; + get_kDF(): number; + set_kDF(kDF: number): void; + get_kMT(): number; + set_kMT(kMT: number): void; + get_kCHR(): number; + set_kCHR(kCHR: number): void; + get_kKHR(): number; + set_kKHR(kKHR: number): void; + get_kSHR(): number; + set_kSHR(kSHR: number): void; + get_kAHR(): number; + set_kAHR(kAHR: number): void; + get_kSRHR_CL(): number; + set_kSRHR_CL(kSRHR_CL: number): void; + get_kSKHR_CL(): number; + set_kSKHR_CL(kSKHR_CL: number): void; + get_kSSHR_CL(): number; + set_kSSHR_CL(kSSHR_CL: number): void; + get_kSR_SPLT_CL(): number; + set_kSR_SPLT_CL(kSR_SPLT_CL: number): void; + get_kSK_SPLT_CL(): number; + set_kSK_SPLT_CL(kSK_SPLT_CL: number): void; + get_kSS_SPLT_CL(): number; + set_kSS_SPLT_CL(kSS_SPLT_CL: number): void; + get_maxvolume(): number; + set_maxvolume(maxvolume: number): void; + get_timescale(): number; + set_timescale(timescale: number): void; + get_viterations(): number; + set_viterations(viterations: number): void; + get_piterations(): number; + set_piterations(piterations: number): void; + get_diterations(): number; + set_diterations(diterations: number): void; + get_citerations(): number; + set_citerations(citerations: number): void; + get_collisions(): number; + set_collisions(collisions: number): void; + } + class btSoftBody extends btCollisionObject { + constructor(worldInfo: btSoftBodyWorldInfo, node_count: number, x: btVector3, m: ReadonlyArray); + get_m_cfg(): Config; + set_m_cfg(m_cfg: Config): void; + get_m_nodes(): tNodeArray; + set_m_nodes(m_nodes: tNodeArray): void; + get_m_faces(): tFaceArray; + set_m_faces(m_faces: tFaceArray): void; + get_m_materials(): tMaterialArray; + set_m_materials(m_materials: tMaterialArray): void; + get_m_anchors(): tAnchorArray; + set_m_anchors(m_anchors: tAnchorArray): void; + checkLink(node0: number, node1: number): boolean; + checkFace(node0: number, node1: number, node2: number): boolean; + appendMaterial(): Material; + appendNode(x: btVector3, m: number): void; + appendLink(node0: number, node1: number, mat: Material, bcheckexist: boolean): void; + appendFace(node0: number, node1: number, node2: number, mat: Material): void; + appendTetra(node0: number, node1: number, node2: number, node3: number, mat: Material): void; + appendAnchor(node: number, body: btRigidBody, disableCollisionBetweenLinkedBodies: boolean, influence: number): void; + addForce(force: btVector3): void; + addForce(force: btVector3, node: number): void; + addAeroForceToNode(windVelocity: btVector3, nodeIndex: number): void; + getTotalMass(): number; + setTotalMass(mass: number, fromfaces: boolean): void; + setMass(node: number, mass: number): void; + transform(trs: btTransform): void; + translate(trs: btVector3): void; + rotate(rot: btQuaternion): void; + scale(scl: btVector3): void; + generateClusters(k: number, maxiterations?: number): number; + generateBendingConstraints(distance: number, mat: Material): number; + upcast(colObj: btCollisionObject): btSoftBody; + } + class btSoftBodyRigidBodyCollisionConfiguration extends btDefaultCollisionConfiguration { + constructor(info?: btDefaultCollisionConstructionInfo); + } + class btSoftBodySolver {} + class btDefaultSoftBodySolver extends btSoftBodySolver { + constructor(); + } + class btSoftBodyArray { + size(): number; + at(n: number): btSoftBody; + } + class btSoftRigidDynamicsWorld extends btDiscreteDynamicsWorld { + constructor(dispatcher: btDispatcher, pairCache: btBroadphaseInterface, constraintSolver: btConstraintSolver, collisionConfiguration: btCollisionConfiguration, softBodySolver: btSoftBodySolver); + addSoftBody(body: btSoftBody, collisionFilterGroup: number, collisionFilterMask: number): void; + removeSoftBody(body: btSoftBody): void; + removeCollisionObject(collisionObject: btCollisionObject): void; + getWorldInfo(): btSoftBodyWorldInfo; + getSoftBodyArray(): btSoftBodyArray; + } + class btSoftBodyHelpers { + constructor(); + CreateRope(worldInfo: btSoftBodyWorldInfo, from: btVector3, to: btVector3, res: number, fixeds: number): btSoftBody; + CreatePatch(worldInfo: btSoftBodyWorldInfo, corner00: btVector3, corner10: btVector3, corner01: btVector3, corner11: btVector3, resx: number, resy: number, fixeds: number, gendiags: boolean): btSoftBody; + CreatePatchUV(worldInfo: btSoftBodyWorldInfo, corner00: btVector3, corner10: btVector3, corner01: btVector3, corner11: btVector3, resx: number, resy: number, fixeds: number, gendiags: boolean, tex_coords: ReadonlyArray): btSoftBody; + CreateEllipsoid(worldInfo: btSoftBodyWorldInfo, center: btVector3, radius: btVector3, res: number): btSoftBody; + CreateFromTriMesh(worldInfo: btSoftBodyWorldInfo, vertices: ReadonlyArray, triangles: ReadonlyArray, ntriangles: number, randomizeConstraints: boolean): btSoftBody; + CreateFromConvexHull(worldInfo: btSoftBodyWorldInfo, vertices: btVector3, nvertices: number, randomizeConstraints: boolean): btSoftBody; + } +} diff --git a/packages/ammo/ammo.js b/packages/ammo/ammo.js new file mode 100644 index 00000000..1900cf91 --- /dev/null +++ b/packages/ammo/ammo.js @@ -0,0 +1,12327 @@ +// This is ammo.js, a port of Bullet Physics to JavaScript. zlib licensed. +var Ammo = (() => { + var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; + if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename; + return function (Ammo) { + Ammo = Ammo || {}; + + var b; + b || (b = typeof Ammo !== 'undefined' ? Ammo : {}); + var aa, ba; + b.ready = new Promise(function (a, c) { + aa = a; + ba = c; + }); + var ca = Object.assign({}, b), + da = 'object' == typeof window, + ea = 'function' == typeof importScripts, + fa = '', + ha, + ia, + ja, + fs, + ka, + la; + if ('object' == typeof process && 'object' == typeof process.versions && 'string' == typeof process.versions.node) + (fa = ea ? require('path').dirname(fa) + '/' : __dirname + '/'), + (la = () => { + ka || ((fs = require('fs')), (ka = require('path'))); + }), + (ha = function (a, c) { + la(); + a = ka.normalize(a); + return fs.readFileSync(a, c ? void 0 : 'utf8'); + }), + (ja = (a) => { + a = ha(a, !0); + a.buffer || (a = new Uint8Array(a)); + return a; + }), + (ia = (a, c, d) => { + la(); + a = ka.normalize(a); + fs.readFile(a, function (e, g) { + e ? d(e) : c(g.buffer); + }); + }), + 1 < process.argv.length && process.argv[1].replace(/\\/g, '/'), + process.argv.slice(2), + process.on('uncaughtException', function (a) { + throw a; + }), + process.on('unhandledRejection', function (a) { + throw a; + }), + (b.inspect = function () { + return '[Emscripten Module object]'; + }); + else if (da || ea) + ea ? (fa = self.location.href) : 'undefined' != typeof document && document.currentScript && (fa = document.currentScript.src), + _scriptDir && (fa = _scriptDir), + (fa = 0 !== fa.indexOf('blob:') ? fa.substr(0, fa.replace(/[?#].*/, '').lastIndexOf('/') + 1) : ''), + (ha = (a) => { + var c = new XMLHttpRequest(); + c.open('GET', a, !1); + c.send(null); + return c.responseText; + }), + ea && + (ja = (a) => { + var c = new XMLHttpRequest(); + c.open('GET', a, !1); + c.responseType = 'arraybuffer'; + c.send(null); + return new Uint8Array(c.response); + }), + (ia = (a, c, d) => { + var e = new XMLHttpRequest(); + e.open('GET', a, !0); + e.responseType = 'arraybuffer'; + e.onload = () => { + 200 == e.status || (0 == e.status && e.response) ? c(e.response) : d(); + }; + e.onerror = d; + e.send(null); + }); + b.print || console.log.bind(console); + var ma = b.printErr || console.warn.bind(console); + Object.assign(b, ca); + ca = null; + var na = [], + oa, + pa; + b.wasmBinary && (pa = b.wasmBinary); + var noExitRuntime = b.noExitRuntime || !0; + 'object' != typeof WebAssembly && qa('no native wasm support detected'); + var ra, + sa = !1, + ta = 'undefined' != typeof TextDecoder ? new TextDecoder('utf8') : void 0; + function ua(a, c) { + if (a) { + var d = va, + e = a + c; + for (c = a; d[c] && !(c >= e); ) ++c; + if (16 < c - a && d.subarray && ta) a = ta.decode(d.subarray(a, c)); + else { + for (e = ''; a < c; ) { + var g = d[a++]; + if (g & 128) { + var n = d[a++] & 63; + if (192 == (g & 224)) e += String.fromCharCode(((g & 31) << 6) | n); + else { + var D = d[a++] & 63; + g = 224 == (g & 240) ? ((g & 15) << 12) | (n << 6) | D : ((g & 7) << 18) | (n << 12) | (D << 6) | (d[a++] & 63); + 65536 > g ? (e += String.fromCharCode(g)) : ((g -= 65536), (e += String.fromCharCode(55296 | (g >> 10), 56320 | (g & 1023)))); + } + } else e += String.fromCharCode(g); + } + a = e; + } + } else a = ''; + return a; + } + var wa, + va, + xa, + ya, + za, + Aa, + Ba = [], + Ca = [], + Ea = [], + Fa = !1; + function Ga() { + var a = b.preRun.shift(); + Ba.unshift(a); + } + var Ha = 0, + Ia = null, + Ja = null; + b.preloadedImages = {}; + b.preloadedAudios = {}; + function qa(a) { + if (b.onAbort) b.onAbort(a); + a = 'Aborted(' + a + ')'; + ma(a); + sa = !0; + a = new WebAssembly.RuntimeError(a + '. Build with -s ASSERTIONS=1 for more info.'); + ba(a); + throw a; + } + function Ka() { + return La.startsWith('data:application/wasm;base64,'); + } + if (!Ka()) { + var Ma = La; + La = b.locateFile ? b.locateFile(Ma, fa) : fa + Ma; + } + function Na() { + var a = La; + try { + if (a == La && pa) return new Uint8Array(pa); + if (ja) return ja(a); + throw 'both async and sync fetching of the wasm failed'; + } catch (c) { + qa(c); + } + } + function Oa() { + if (!pa && (da || ea)) { + if ('function' == typeof fetch && !La.startsWith('file://')) + return fetch(La, { credentials: 'same-origin' }) + .then(function (a) { + if (!a.ok) throw "failed to load wasm binary file at '" + La + "'"; + return a.arrayBuffer(); + }) + .catch(function () { + return Na(); + }); + if (ia) + return new Promise(function (a, c) { + ia( + La, + function (d) { + a(new Uint8Array(d)); + }, + c, + ); + }); + } + return Promise.resolve().then(function () { + return Na(); + }); + } + var Pa = { + 27254: function (a, c, d, e) { + a = b.getCache(b.DebugDrawer)[a]; + if (!a.hasOwnProperty('drawLine')) throw 'a JSImplementation must implement all functions, you forgot DebugDrawer::drawLine.'; + a.drawLine(c, d, e); + }, + 27474: function (a, c, d, e, g, n) { + a = b.getCache(b.DebugDrawer)[a]; + if (!a.hasOwnProperty('drawContactPoint')) throw 'a JSImplementation must implement all functions, you forgot DebugDrawer::drawContactPoint.'; + a.drawContactPoint(c, d, e, g, n); + }, + 27724: function (a, c) { + a = b.getCache(b.DebugDrawer)[a]; + if (!a.hasOwnProperty('reportErrorWarning')) throw 'a JSImplementation must implement all functions, you forgot DebugDrawer::reportErrorWarning.'; + a.reportErrorWarning(c); + }, + 27968: function (a, c, d) { + a = b.getCache(b.DebugDrawer)[a]; + if (!a.hasOwnProperty('draw3dText')) throw 'a JSImplementation must implement all functions, you forgot DebugDrawer::draw3dText.'; + a.draw3dText(c, d); + }, + 28191: function (a, c) { + a = b.getCache(b.DebugDrawer)[a]; + if (!a.hasOwnProperty('setDebugMode')) throw 'a JSImplementation must implement all functions, you forgot DebugDrawer::setDebugMode.'; + a.setDebugMode(c); + }, + 28417: function (a) { + a = b.getCache(b.DebugDrawer)[a]; + if (!a.hasOwnProperty('getDebugMode')) throw 'a JSImplementation must implement all functions, you forgot DebugDrawer::getDebugMode.'; + return a.getDebugMode(); + }, + 28648: function (a, c, d, e, g, n, D, T) { + a = b.getCache(b.ConcreteContactResultCallback)[a]; + if (!a.hasOwnProperty('addSingleResult')) throw 'a JSImplementation must implement all functions, you forgot ConcreteContactResultCallback::addSingleResult.'; + return a.addSingleResult(c, d, e, g, n, D, T); + }, + }; + function Qa(a) { + for (; 0 < a.length; ) { + var c = a.shift(); + if ('function' == typeof c) c(b); + else { + var d = c.EH; + 'number' == typeof d ? (void 0 === c.AB ? Ra(d)() : Ra(d)(c.AB)) : d(void 0 === c.AB ? null : c.AB); + } + } + } + var Sa = []; + function Ra(a) { + var c = Sa[a]; + c || (a >= Sa.length && (Sa.length = a + 1), (Sa[a] = c = Aa.get(a))); + return c; + } + var Ta = []; + function Ua(a, c, d) { + Ta.length = 0; + var e; + for (d >>= 2; (e = va[c++]); ) (e = 105 > e) && d & 1 && d++, Ta.push(e ? za[d++ >> 1] : xa[d]), ++d; + return Pa[a].apply(null, Ta); + } + var Va = { + c: function () { + qa(''); + }, + f: function (a, c, d) { + return Ua(a, c, d); + }, + b: Ua, + e: function (a, c, d) { + va.copyWithin(a, c, c + d); + }, + d: function () { + qa('OOM'); + }, + a: function (a) { + var c = Date.now(); + xa[a >> 2] = (c / 1e3) | 0; + xa[(a + 4) >> 2] = ((c % 1e3) * 1e3) | 0; + return 0; + }, + }; + (function () { + function a(g) { + b.asm = g.exports; + ra = b.asm.g; + g = ra.buffer; + b.HEAP8 = wa = new Int8Array(g); + b.HEAP16 = new Int16Array(g); + b.HEAP32 = xa = new Int32Array(g); + b.HEAPU8 = va = new Uint8Array(g); + b.HEAPU16 = new Uint16Array(g); + b.HEAPU32 = new Uint32Array(g); + b.HEAPF32 = ya = new Float32Array(g); + b.HEAPF64 = za = new Float64Array(g); + Aa = b.asm.$A; + Ca.unshift(b.asm.h); + Ha--; + b.monitorRunDependencies && b.monitorRunDependencies(Ha); + 0 == Ha && (null !== Ia && (clearInterval(Ia), (Ia = null)), Ja && ((g = Ja), (Ja = null), g())); + } + function c(g) { + a(g.instance); + } + function d(g) { + return Oa() + .then(function (n) { + return WebAssembly.instantiate(n, e); + }) + .then(function (n) { + return n; + }) + .then(g, function (n) { + ma('failed to asynchronously prepare wasm: ' + n); + qa(n); + }); + } + var e = { a: Va }; + Ha++; + b.monitorRunDependencies && b.monitorRunDependencies(Ha); + if (b.instantiateWasm) + try { + return b.instantiateWasm(e, a); + } catch (g) { + return ma('Module.instantiateWasm callback failed with error: ' + g), !1; + } + (function () { + return pa || 'function' != typeof WebAssembly.instantiateStreaming || Ka() || La.startsWith('file://') || 'function' != typeof fetch + ? d(c) + : fetch(La, { credentials: 'same-origin' }).then(function (g) { + return WebAssembly.instantiateStreaming(g, e).then(c, function (n) { + ma('wasm streaming compile failed: ' + n); + ma('falling back to ArrayBuffer instantiation'); + return d(c); + }); + }); + })().catch(ba); + return {}; + })(); + b.___wasm_call_ctors = function () { + return (b.___wasm_call_ctors = b.asm.h).apply(null, arguments); + }; + var Wa = (b._emscripten_bind_btCollisionShape_setLocalScaling_1 = function () { + return (Wa = b._emscripten_bind_btCollisionShape_setLocalScaling_1 = b.asm.i).apply(null, arguments); + }), + Xa = (b._emscripten_bind_btCollisionShape_getLocalScaling_0 = function () { + return (Xa = b._emscripten_bind_btCollisionShape_getLocalScaling_0 = b.asm.j).apply(null, arguments); + }), + Ya = (b._emscripten_bind_btCollisionShape_calculateLocalInertia_2 = function () { + return (Ya = b._emscripten_bind_btCollisionShape_calculateLocalInertia_2 = b.asm.k).apply(null, arguments); + }), + Za = (b._emscripten_bind_btCollisionShape_setMargin_1 = function () { + return (Za = b._emscripten_bind_btCollisionShape_setMargin_1 = b.asm.l).apply(null, arguments); + }), + $a = (b._emscripten_bind_btCollisionShape_getMargin_0 = function () { + return ($a = b._emscripten_bind_btCollisionShape_getMargin_0 = b.asm.m).apply(null, arguments); + }), + ab = (b._emscripten_bind_btCollisionShape___destroy___0 = function () { + return (ab = b._emscripten_bind_btCollisionShape___destroy___0 = b.asm.n).apply(null, arguments); + }), + bb = (b._emscripten_bind_btCollisionWorld_getDispatcher_0 = function () { + return (bb = b._emscripten_bind_btCollisionWorld_getDispatcher_0 = b.asm.o).apply(null, arguments); + }), + cb = (b._emscripten_bind_btCollisionWorld_rayTest_3 = function () { + return (cb = b._emscripten_bind_btCollisionWorld_rayTest_3 = b.asm.p).apply(null, arguments); + }), + db = (b._emscripten_bind_btCollisionWorld_getPairCache_0 = function () { + return (db = b._emscripten_bind_btCollisionWorld_getPairCache_0 = b.asm.q).apply(null, arguments); + }), + eb = (b._emscripten_bind_btCollisionWorld_getDispatchInfo_0 = function () { + return (eb = b._emscripten_bind_btCollisionWorld_getDispatchInfo_0 = b.asm.r).apply(null, arguments); + }), + fb = (b._emscripten_bind_btCollisionWorld_addCollisionObject_1 = function () { + return (fb = b._emscripten_bind_btCollisionWorld_addCollisionObject_1 = b.asm.s).apply(null, arguments); + }), + gb = (b._emscripten_bind_btCollisionWorld_addCollisionObject_2 = function () { + return (gb = b._emscripten_bind_btCollisionWorld_addCollisionObject_2 = b.asm.t).apply(null, arguments); + }), + hb = (b._emscripten_bind_btCollisionWorld_addCollisionObject_3 = function () { + return (hb = b._emscripten_bind_btCollisionWorld_addCollisionObject_3 = b.asm.u).apply(null, arguments); + }), + ib = (b._emscripten_bind_btCollisionWorld_removeCollisionObject_1 = function () { + return (ib = b._emscripten_bind_btCollisionWorld_removeCollisionObject_1 = b.asm.v).apply(null, arguments); + }), + jb = (b._emscripten_bind_btCollisionWorld_getBroadphase_0 = function () { + return (jb = b._emscripten_bind_btCollisionWorld_getBroadphase_0 = b.asm.w).apply(null, arguments); + }), + kb = (b._emscripten_bind_btCollisionWorld_convexSweepTest_5 = function () { + return (kb = b._emscripten_bind_btCollisionWorld_convexSweepTest_5 = b.asm.x).apply(null, arguments); + }), + lb = (b._emscripten_bind_btCollisionWorld_contactPairTest_3 = function () { + return (lb = b._emscripten_bind_btCollisionWorld_contactPairTest_3 = b.asm.y).apply(null, arguments); + }), + mb = (b._emscripten_bind_btCollisionWorld_contactTest_2 = function () { + return (mb = b._emscripten_bind_btCollisionWorld_contactTest_2 = b.asm.z).apply(null, arguments); + }), + nb = (b._emscripten_bind_btCollisionWorld_updateSingleAabb_1 = function () { + return (nb = b._emscripten_bind_btCollisionWorld_updateSingleAabb_1 = b.asm.A).apply(null, arguments); + }), + ob = (b._emscripten_bind_btCollisionWorld_setDebugDrawer_1 = function () { + return (ob = b._emscripten_bind_btCollisionWorld_setDebugDrawer_1 = b.asm.B).apply(null, arguments); + }), + pb = (b._emscripten_bind_btCollisionWorld_getDebugDrawer_0 = function () { + return (pb = b._emscripten_bind_btCollisionWorld_getDebugDrawer_0 = b.asm.C).apply(null, arguments); + }), + qb = (b._emscripten_bind_btCollisionWorld_debugDrawWorld_0 = function () { + return (qb = b._emscripten_bind_btCollisionWorld_debugDrawWorld_0 = b.asm.D).apply(null, arguments); + }), + rb = (b._emscripten_bind_btCollisionWorld_debugDrawObject_3 = function () { + return (rb = b._emscripten_bind_btCollisionWorld_debugDrawObject_3 = b.asm.E).apply(null, arguments); + }), + sb = (b._emscripten_bind_btCollisionWorld___destroy___0 = function () { + return (sb = b._emscripten_bind_btCollisionWorld___destroy___0 = b.asm.F).apply(null, arguments); + }), + tb = (b._emscripten_bind_btCollisionObject_setAnisotropicFriction_2 = function () { + return (tb = b._emscripten_bind_btCollisionObject_setAnisotropicFriction_2 = b.asm.G).apply(null, arguments); + }), + ub = (b._emscripten_bind_btCollisionObject_getCollisionShape_0 = function () { + return (ub = b._emscripten_bind_btCollisionObject_getCollisionShape_0 = b.asm.H).apply(null, arguments); + }), + vb = (b._emscripten_bind_btCollisionObject_setContactProcessingThreshold_1 = function () { + return (vb = b._emscripten_bind_btCollisionObject_setContactProcessingThreshold_1 = b.asm.I).apply(null, arguments); + }), + wb = (b._emscripten_bind_btCollisionObject_setActivationState_1 = function () { + return (wb = b._emscripten_bind_btCollisionObject_setActivationState_1 = b.asm.J).apply(null, arguments); + }), + xb = (b._emscripten_bind_btCollisionObject_forceActivationState_1 = function () { + return (xb = b._emscripten_bind_btCollisionObject_forceActivationState_1 = b.asm.K).apply(null, arguments); + }), + yb = (b._emscripten_bind_btCollisionObject_activate_0 = function () { + return (yb = b._emscripten_bind_btCollisionObject_activate_0 = b.asm.L).apply(null, arguments); + }), + zb = (b._emscripten_bind_btCollisionObject_activate_1 = function () { + return (zb = b._emscripten_bind_btCollisionObject_activate_1 = b.asm.M).apply(null, arguments); + }), + Ab = (b._emscripten_bind_btCollisionObject_isActive_0 = function () { + return (Ab = b._emscripten_bind_btCollisionObject_isActive_0 = b.asm.N).apply(null, arguments); + }), + Bb = (b._emscripten_bind_btCollisionObject_isKinematicObject_0 = function () { + return (Bb = b._emscripten_bind_btCollisionObject_isKinematicObject_0 = b.asm.O).apply(null, arguments); + }), + Cb = (b._emscripten_bind_btCollisionObject_isStaticObject_0 = function () { + return (Cb = b._emscripten_bind_btCollisionObject_isStaticObject_0 = b.asm.P).apply(null, arguments); + }), + Db = (b._emscripten_bind_btCollisionObject_isStaticOrKinematicObject_0 = function () { + return (Db = b._emscripten_bind_btCollisionObject_isStaticOrKinematicObject_0 = b.asm.Q).apply(null, arguments); + }), + Eb = (b._emscripten_bind_btCollisionObject_getRestitution_0 = function () { + return (Eb = b._emscripten_bind_btCollisionObject_getRestitution_0 = b.asm.R).apply(null, arguments); + }), + Fb = (b._emscripten_bind_btCollisionObject_getFriction_0 = function () { + return (Fb = b._emscripten_bind_btCollisionObject_getFriction_0 = b.asm.S).apply(null, arguments); + }), + Gb = (b._emscripten_bind_btCollisionObject_getRollingFriction_0 = function () { + return (Gb = b._emscripten_bind_btCollisionObject_getRollingFriction_0 = b.asm.T).apply(null, arguments); + }), + Hb = (b._emscripten_bind_btCollisionObject_setRestitution_1 = function () { + return (Hb = b._emscripten_bind_btCollisionObject_setRestitution_1 = b.asm.U).apply(null, arguments); + }), + Ib = (b._emscripten_bind_btCollisionObject_setFriction_1 = function () { + return (Ib = b._emscripten_bind_btCollisionObject_setFriction_1 = b.asm.V).apply(null, arguments); + }), + Jb = (b._emscripten_bind_btCollisionObject_setRollingFriction_1 = function () { + return (Jb = b._emscripten_bind_btCollisionObject_setRollingFriction_1 = b.asm.W).apply(null, arguments); + }), + Kb = (b._emscripten_bind_btCollisionObject_getWorldTransform_0 = function () { + return (Kb = b._emscripten_bind_btCollisionObject_getWorldTransform_0 = b.asm.X).apply(null, arguments); + }), + Lb = (b._emscripten_bind_btCollisionObject_getCollisionFlags_0 = function () { + return (Lb = b._emscripten_bind_btCollisionObject_getCollisionFlags_0 = b.asm.Y).apply(null, arguments); + }), + Mb = (b._emscripten_bind_btCollisionObject_setCollisionFlags_1 = function () { + return (Mb = b._emscripten_bind_btCollisionObject_setCollisionFlags_1 = b.asm.Z).apply(null, arguments); + }), + Nb = (b._emscripten_bind_btCollisionObject_setWorldTransform_1 = function () { + return (Nb = b._emscripten_bind_btCollisionObject_setWorldTransform_1 = b.asm._).apply(null, arguments); + }), + Ob = (b._emscripten_bind_btCollisionObject_setCollisionShape_1 = function () { + return (Ob = b._emscripten_bind_btCollisionObject_setCollisionShape_1 = b.asm.$).apply(null, arguments); + }), + Pb = (b._emscripten_bind_btCollisionObject_setCcdMotionThreshold_1 = function () { + return (Pb = b._emscripten_bind_btCollisionObject_setCcdMotionThreshold_1 = b.asm.aa).apply(null, arguments); + }), + Qb = (b._emscripten_bind_btCollisionObject_setCcdSweptSphereRadius_1 = function () { + return (Qb = b._emscripten_bind_btCollisionObject_setCcdSweptSphereRadius_1 = b.asm.ba).apply(null, arguments); + }), + Rb = (b._emscripten_bind_btCollisionObject_getUserIndex_0 = function () { + return (Rb = b._emscripten_bind_btCollisionObject_getUserIndex_0 = b.asm.ca).apply(null, arguments); + }), + Sb = (b._emscripten_bind_btCollisionObject_setUserIndex_1 = function () { + return (Sb = b._emscripten_bind_btCollisionObject_setUserIndex_1 = b.asm.da).apply(null, arguments); + }), + Tb = (b._emscripten_bind_btCollisionObject_getUserPointer_0 = function () { + return (Tb = b._emscripten_bind_btCollisionObject_getUserPointer_0 = b.asm.ea).apply(null, arguments); + }), + Ub = (b._emscripten_bind_btCollisionObject_setUserPointer_1 = function () { + return (Ub = b._emscripten_bind_btCollisionObject_setUserPointer_1 = b.asm.fa).apply(null, arguments); + }), + Vb = (b._emscripten_bind_btCollisionObject_getBroadphaseHandle_0 = function () { + return (Vb = b._emscripten_bind_btCollisionObject_getBroadphaseHandle_0 = b.asm.ga).apply(null, arguments); + }), + Wb = (b._emscripten_bind_btCollisionObject___destroy___0 = function () { + return (Wb = b._emscripten_bind_btCollisionObject___destroy___0 = b.asm.ha).apply(null, arguments); + }), + Xb = (b._emscripten_bind_btConcaveShape_setLocalScaling_1 = function () { + return (Xb = b._emscripten_bind_btConcaveShape_setLocalScaling_1 = b.asm.ia).apply(null, arguments); + }), + Yb = (b._emscripten_bind_btConcaveShape_getLocalScaling_0 = function () { + return (Yb = b._emscripten_bind_btConcaveShape_getLocalScaling_0 = b.asm.ja).apply(null, arguments); + }), + Zb = (b._emscripten_bind_btConcaveShape_calculateLocalInertia_2 = function () { + return (Zb = b._emscripten_bind_btConcaveShape_calculateLocalInertia_2 = b.asm.ka).apply(null, arguments); + }), + $b = (b._emscripten_bind_btConcaveShape___destroy___0 = function () { + return ($b = b._emscripten_bind_btConcaveShape___destroy___0 = b.asm.la).apply(null, arguments); + }), + ac = (b._emscripten_bind_btCollisionAlgorithm___destroy___0 = function () { + return (ac = b._emscripten_bind_btCollisionAlgorithm___destroy___0 = b.asm.ma).apply(null, arguments); + }), + bc = (b._emscripten_bind_btTypedConstraint_enableFeedback_1 = function () { + return (bc = b._emscripten_bind_btTypedConstraint_enableFeedback_1 = b.asm.na).apply(null, arguments); + }), + cc = (b._emscripten_bind_btTypedConstraint_getBreakingImpulseThreshold_0 = function () { + return (cc = b._emscripten_bind_btTypedConstraint_getBreakingImpulseThreshold_0 = b.asm.oa).apply(null, arguments); + }), + ec = (b._emscripten_bind_btTypedConstraint_setBreakingImpulseThreshold_1 = function () { + return (ec = b._emscripten_bind_btTypedConstraint_setBreakingImpulseThreshold_1 = b.asm.pa).apply(null, arguments); + }), + fc = (b._emscripten_bind_btTypedConstraint_getParam_2 = function () { + return (fc = b._emscripten_bind_btTypedConstraint_getParam_2 = b.asm.qa).apply(null, arguments); + }), + gc = (b._emscripten_bind_btTypedConstraint_setParam_3 = function () { + return (gc = b._emscripten_bind_btTypedConstraint_setParam_3 = b.asm.ra).apply(null, arguments); + }), + hc = (b._emscripten_bind_btTypedConstraint___destroy___0 = function () { + return (hc = b._emscripten_bind_btTypedConstraint___destroy___0 = b.asm.sa).apply(null, arguments); + }), + ic = (b._emscripten_bind_btDynamicsWorld_addAction_1 = function () { + return (ic = b._emscripten_bind_btDynamicsWorld_addAction_1 = b.asm.ta).apply(null, arguments); + }), + jc = (b._emscripten_bind_btDynamicsWorld_removeAction_1 = function () { + return (jc = b._emscripten_bind_btDynamicsWorld_removeAction_1 = b.asm.ua).apply(null, arguments); + }), + kc = (b._emscripten_bind_btDynamicsWorld_getSolverInfo_0 = function () { + return (kc = b._emscripten_bind_btDynamicsWorld_getSolverInfo_0 = b.asm.va).apply(null, arguments); + }), + lc = (b._emscripten_bind_btDynamicsWorld_setInternalTickCallback_1 = function () { + return (lc = b._emscripten_bind_btDynamicsWorld_setInternalTickCallback_1 = b.asm.wa).apply(null, arguments); + }), + mc = (b._emscripten_bind_btDynamicsWorld_setInternalTickCallback_2 = function () { + return (mc = b._emscripten_bind_btDynamicsWorld_setInternalTickCallback_2 = b.asm.xa).apply(null, arguments); + }), + nc = (b._emscripten_bind_btDynamicsWorld_setInternalTickCallback_3 = function () { + return (nc = b._emscripten_bind_btDynamicsWorld_setInternalTickCallback_3 = b.asm.ya).apply(null, arguments); + }), + oc = (b._emscripten_bind_btDynamicsWorld_getDispatcher_0 = function () { + return (oc = b._emscripten_bind_btDynamicsWorld_getDispatcher_0 = b.asm.za).apply(null, arguments); + }), + pc = (b._emscripten_bind_btDynamicsWorld_rayTest_3 = function () { + return (pc = b._emscripten_bind_btDynamicsWorld_rayTest_3 = b.asm.Aa).apply(null, arguments); + }), + qc = (b._emscripten_bind_btDynamicsWorld_getPairCache_0 = function () { + return (qc = b._emscripten_bind_btDynamicsWorld_getPairCache_0 = b.asm.Ba).apply(null, arguments); + }), + rc = (b._emscripten_bind_btDynamicsWorld_getDispatchInfo_0 = function () { + return (rc = b._emscripten_bind_btDynamicsWorld_getDispatchInfo_0 = b.asm.Ca).apply(null, arguments); + }), + sc = (b._emscripten_bind_btDynamicsWorld_addCollisionObject_1 = function () { + return (sc = b._emscripten_bind_btDynamicsWorld_addCollisionObject_1 = b.asm.Da).apply(null, arguments); + }), + tc = (b._emscripten_bind_btDynamicsWorld_addCollisionObject_2 = function () { + return (tc = b._emscripten_bind_btDynamicsWorld_addCollisionObject_2 = b.asm.Ea).apply(null, arguments); + }), + uc = (b._emscripten_bind_btDynamicsWorld_addCollisionObject_3 = function () { + return (uc = b._emscripten_bind_btDynamicsWorld_addCollisionObject_3 = b.asm.Fa).apply(null, arguments); + }), + vc = (b._emscripten_bind_btDynamicsWorld_removeCollisionObject_1 = function () { + return (vc = b._emscripten_bind_btDynamicsWorld_removeCollisionObject_1 = b.asm.Ga).apply(null, arguments); + }), + wc = (b._emscripten_bind_btDynamicsWorld_getBroadphase_0 = function () { + return (wc = b._emscripten_bind_btDynamicsWorld_getBroadphase_0 = b.asm.Ha).apply(null, arguments); + }), + xc = (b._emscripten_bind_btDynamicsWorld_convexSweepTest_5 = function () { + return (xc = b._emscripten_bind_btDynamicsWorld_convexSweepTest_5 = b.asm.Ia).apply(null, arguments); + }), + yc = (b._emscripten_bind_btDynamicsWorld_contactPairTest_3 = function () { + return (yc = b._emscripten_bind_btDynamicsWorld_contactPairTest_3 = b.asm.Ja).apply(null, arguments); + }), + zc = (b._emscripten_bind_btDynamicsWorld_contactTest_2 = function () { + return (zc = b._emscripten_bind_btDynamicsWorld_contactTest_2 = b.asm.Ka).apply(null, arguments); + }), + Ac = (b._emscripten_bind_btDynamicsWorld_updateSingleAabb_1 = function () { + return (Ac = b._emscripten_bind_btDynamicsWorld_updateSingleAabb_1 = b.asm.La).apply(null, arguments); + }), + Bc = (b._emscripten_bind_btDynamicsWorld_setDebugDrawer_1 = function () { + return (Bc = b._emscripten_bind_btDynamicsWorld_setDebugDrawer_1 = b.asm.Ma).apply(null, arguments); + }), + Cc = (b._emscripten_bind_btDynamicsWorld_getDebugDrawer_0 = function () { + return (Cc = b._emscripten_bind_btDynamicsWorld_getDebugDrawer_0 = b.asm.Na).apply(null, arguments); + }), + Dc = (b._emscripten_bind_btDynamicsWorld_debugDrawWorld_0 = function () { + return (Dc = b._emscripten_bind_btDynamicsWorld_debugDrawWorld_0 = b.asm.Oa).apply(null, arguments); + }), + Ec = (b._emscripten_bind_btDynamicsWorld_debugDrawObject_3 = function () { + return (Ec = b._emscripten_bind_btDynamicsWorld_debugDrawObject_3 = b.asm.Pa).apply(null, arguments); + }), + Fc = (b._emscripten_bind_btDynamicsWorld___destroy___0 = function () { + return (Fc = b._emscripten_bind_btDynamicsWorld___destroy___0 = b.asm.Qa).apply(null, arguments); + }), + Gc = (b._emscripten_bind_btIDebugDraw_drawLine_3 = function () { + return (Gc = b._emscripten_bind_btIDebugDraw_drawLine_3 = b.asm.Ra).apply(null, arguments); + }), + Hc = (b._emscripten_bind_btIDebugDraw_drawContactPoint_5 = function () { + return (Hc = b._emscripten_bind_btIDebugDraw_drawContactPoint_5 = b.asm.Sa).apply(null, arguments); + }), + Ic = (b._emscripten_bind_btIDebugDraw_reportErrorWarning_1 = function () { + return (Ic = b._emscripten_bind_btIDebugDraw_reportErrorWarning_1 = b.asm.Ta).apply(null, arguments); + }), + Jc = (b._emscripten_bind_btIDebugDraw_draw3dText_2 = function () { + return (Jc = b._emscripten_bind_btIDebugDraw_draw3dText_2 = b.asm.Ua).apply(null, arguments); + }), + Kc = (b._emscripten_bind_btIDebugDraw_setDebugMode_1 = function () { + return (Kc = b._emscripten_bind_btIDebugDraw_setDebugMode_1 = b.asm.Va).apply(null, arguments); + }), + Lc = (b._emscripten_bind_btIDebugDraw_getDebugMode_0 = function () { + return (Lc = b._emscripten_bind_btIDebugDraw_getDebugMode_0 = b.asm.Wa).apply(null, arguments); + }), + Mc = (b._emscripten_bind_btIDebugDraw___destroy___0 = function () { + return (Mc = b._emscripten_bind_btIDebugDraw___destroy___0 = b.asm.Xa).apply(null, arguments); + }), + Nc = (b._emscripten_bind_btVector3_btVector3_0 = function () { + return (Nc = b._emscripten_bind_btVector3_btVector3_0 = b.asm.Ya).apply(null, arguments); + }), + Oc = (b._emscripten_bind_btVector3_btVector3_3 = function () { + return (Oc = b._emscripten_bind_btVector3_btVector3_3 = b.asm.Za).apply(null, arguments); + }), + Pc = (b._emscripten_bind_btVector3_length_0 = function () { + return (Pc = b._emscripten_bind_btVector3_length_0 = b.asm._a).apply(null, arguments); + }), + Qc = (b._emscripten_bind_btVector3_x_0 = function () { + return (Qc = b._emscripten_bind_btVector3_x_0 = b.asm.$a).apply(null, arguments); + }), + Rc = (b._emscripten_bind_btVector3_y_0 = function () { + return (Rc = b._emscripten_bind_btVector3_y_0 = b.asm.ab).apply(null, arguments); + }), + Sc = (b._emscripten_bind_btVector3_z_0 = function () { + return (Sc = b._emscripten_bind_btVector3_z_0 = b.asm.bb).apply(null, arguments); + }), + Tc = (b._emscripten_bind_btVector3_setX_1 = function () { + return (Tc = b._emscripten_bind_btVector3_setX_1 = b.asm.cb).apply(null, arguments); + }), + Uc = (b._emscripten_bind_btVector3_setY_1 = function () { + return (Uc = b._emscripten_bind_btVector3_setY_1 = b.asm.db).apply(null, arguments); + }), + Vc = (b._emscripten_bind_btVector3_setZ_1 = function () { + return (Vc = b._emscripten_bind_btVector3_setZ_1 = b.asm.eb).apply(null, arguments); + }), + Wc = (b._emscripten_bind_btVector3_setValue_3 = function () { + return (Wc = b._emscripten_bind_btVector3_setValue_3 = b.asm.fb).apply(null, arguments); + }), + Xc = (b._emscripten_bind_btVector3_normalize_0 = function () { + return (Xc = b._emscripten_bind_btVector3_normalize_0 = b.asm.gb).apply(null, arguments); + }), + Yc = (b._emscripten_bind_btVector3_rotate_2 = function () { + return (Yc = b._emscripten_bind_btVector3_rotate_2 = b.asm.hb).apply(null, arguments); + }), + Zc = (b._emscripten_bind_btVector3_dot_1 = function () { + return (Zc = b._emscripten_bind_btVector3_dot_1 = b.asm.ib).apply(null, arguments); + }), + $c = (b._emscripten_bind_btVector3_op_mul_1 = function () { + return ($c = b._emscripten_bind_btVector3_op_mul_1 = b.asm.jb).apply(null, arguments); + }), + ad = (b._emscripten_bind_btVector3_op_add_1 = function () { + return (ad = b._emscripten_bind_btVector3_op_add_1 = b.asm.kb).apply(null, arguments); + }), + bd = (b._emscripten_bind_btVector3_op_sub_1 = function () { + return (bd = b._emscripten_bind_btVector3_op_sub_1 = b.asm.lb).apply(null, arguments); + }), + cd = (b._emscripten_bind_btVector3___destroy___0 = function () { + return (cd = b._emscripten_bind_btVector3___destroy___0 = b.asm.mb).apply(null, arguments); + }), + dd = (b._emscripten_bind_btQuadWord_x_0 = function () { + return (dd = b._emscripten_bind_btQuadWord_x_0 = b.asm.nb).apply(null, arguments); + }), + ed = (b._emscripten_bind_btQuadWord_y_0 = function () { + return (ed = b._emscripten_bind_btQuadWord_y_0 = b.asm.ob).apply(null, arguments); + }), + fd = (b._emscripten_bind_btQuadWord_z_0 = function () { + return (fd = b._emscripten_bind_btQuadWord_z_0 = b.asm.pb).apply(null, arguments); + }), + gd = (b._emscripten_bind_btQuadWord_w_0 = function () { + return (gd = b._emscripten_bind_btQuadWord_w_0 = b.asm.qb).apply(null, arguments); + }), + hd = (b._emscripten_bind_btQuadWord_setX_1 = function () { + return (hd = b._emscripten_bind_btQuadWord_setX_1 = b.asm.rb).apply(null, arguments); + }), + jd = (b._emscripten_bind_btQuadWord_setY_1 = function () { + return (jd = b._emscripten_bind_btQuadWord_setY_1 = b.asm.sb).apply(null, arguments); + }), + kd = (b._emscripten_bind_btQuadWord_setZ_1 = function () { + return (kd = b._emscripten_bind_btQuadWord_setZ_1 = b.asm.tb).apply(null, arguments); + }), + ld = (b._emscripten_bind_btQuadWord_setW_1 = function () { + return (ld = b._emscripten_bind_btQuadWord_setW_1 = b.asm.ub).apply(null, arguments); + }), + md = (b._emscripten_bind_btQuadWord___destroy___0 = function () { + return (md = b._emscripten_bind_btQuadWord___destroy___0 = b.asm.vb).apply(null, arguments); + }), + nd = (b._emscripten_bind_btMotionState_getWorldTransform_1 = function () { + return (nd = b._emscripten_bind_btMotionState_getWorldTransform_1 = b.asm.wb).apply(null, arguments); + }), + od = (b._emscripten_bind_btMotionState_setWorldTransform_1 = function () { + return (od = b._emscripten_bind_btMotionState_setWorldTransform_1 = b.asm.xb).apply(null, arguments); + }), + pd = (b._emscripten_bind_btMotionState___destroy___0 = function () { + return (pd = b._emscripten_bind_btMotionState___destroy___0 = b.asm.yb).apply(null, arguments); + }), + qd = (b._emscripten_bind_RayResultCallback_hasHit_0 = function () { + return (qd = b._emscripten_bind_RayResultCallback_hasHit_0 = b.asm.zb).apply(null, arguments); + }), + rd = (b._emscripten_bind_RayResultCallback_get_m_collisionFilterGroup_0 = function () { + return (rd = b._emscripten_bind_RayResultCallback_get_m_collisionFilterGroup_0 = b.asm.Ab).apply(null, arguments); + }), + sd = (b._emscripten_bind_RayResultCallback_set_m_collisionFilterGroup_1 = function () { + return (sd = b._emscripten_bind_RayResultCallback_set_m_collisionFilterGroup_1 = b.asm.Bb).apply(null, arguments); + }), + td = (b._emscripten_bind_RayResultCallback_get_m_collisionFilterMask_0 = function () { + return (td = b._emscripten_bind_RayResultCallback_get_m_collisionFilterMask_0 = b.asm.Cb).apply(null, arguments); + }), + ud = (b._emscripten_bind_RayResultCallback_set_m_collisionFilterMask_1 = function () { + return (ud = b._emscripten_bind_RayResultCallback_set_m_collisionFilterMask_1 = b.asm.Db).apply(null, arguments); + }), + vd = (b._emscripten_bind_RayResultCallback_get_m_closestHitFraction_0 = function () { + return (vd = b._emscripten_bind_RayResultCallback_get_m_closestHitFraction_0 = b.asm.Eb).apply(null, arguments); + }), + wd = (b._emscripten_bind_RayResultCallback_set_m_closestHitFraction_1 = function () { + return (wd = b._emscripten_bind_RayResultCallback_set_m_closestHitFraction_1 = b.asm.Fb).apply(null, arguments); + }), + xd = (b._emscripten_bind_RayResultCallback_get_m_collisionObject_0 = function () { + return (xd = b._emscripten_bind_RayResultCallback_get_m_collisionObject_0 = b.asm.Gb).apply(null, arguments); + }), + yd = (b._emscripten_bind_RayResultCallback_set_m_collisionObject_1 = function () { + return (yd = b._emscripten_bind_RayResultCallback_set_m_collisionObject_1 = b.asm.Hb).apply(null, arguments); + }), + zd = (b._emscripten_bind_RayResultCallback_get_m_flags_0 = function () { + return (zd = b._emscripten_bind_RayResultCallback_get_m_flags_0 = b.asm.Ib).apply(null, arguments); + }), + Ad = (b._emscripten_bind_RayResultCallback_set_m_flags_1 = function () { + return (Ad = b._emscripten_bind_RayResultCallback_set_m_flags_1 = b.asm.Jb).apply(null, arguments); + }), + Bd = (b._emscripten_bind_RayResultCallback___destroy___0 = function () { + return (Bd = b._emscripten_bind_RayResultCallback___destroy___0 = b.asm.Kb).apply(null, arguments); + }), + Cd = (b._emscripten_bind_ContactResultCallback_addSingleResult_7 = function () { + return (Cd = b._emscripten_bind_ContactResultCallback_addSingleResult_7 = b.asm.Lb).apply(null, arguments); + }), + Dd = (b._emscripten_bind_ContactResultCallback___destroy___0 = function () { + return (Dd = b._emscripten_bind_ContactResultCallback___destroy___0 = b.asm.Mb).apply(null, arguments); + }), + Ed = (b._emscripten_bind_ConvexResultCallback_hasHit_0 = function () { + return (Ed = b._emscripten_bind_ConvexResultCallback_hasHit_0 = b.asm.Nb).apply(null, arguments); + }), + Fd = (b._emscripten_bind_ConvexResultCallback_get_m_collisionFilterGroup_0 = function () { + return (Fd = b._emscripten_bind_ConvexResultCallback_get_m_collisionFilterGroup_0 = b.asm.Ob).apply(null, arguments); + }), + Gd = (b._emscripten_bind_ConvexResultCallback_set_m_collisionFilterGroup_1 = function () { + return (Gd = b._emscripten_bind_ConvexResultCallback_set_m_collisionFilterGroup_1 = b.asm.Pb).apply(null, arguments); + }), + Hd = (b._emscripten_bind_ConvexResultCallback_get_m_collisionFilterMask_0 = function () { + return (Hd = b._emscripten_bind_ConvexResultCallback_get_m_collisionFilterMask_0 = b.asm.Qb).apply(null, arguments); + }), + Id = (b._emscripten_bind_ConvexResultCallback_set_m_collisionFilterMask_1 = function () { + return (Id = b._emscripten_bind_ConvexResultCallback_set_m_collisionFilterMask_1 = b.asm.Rb).apply(null, arguments); + }), + Jd = (b._emscripten_bind_ConvexResultCallback_get_m_closestHitFraction_0 = function () { + return (Jd = b._emscripten_bind_ConvexResultCallback_get_m_closestHitFraction_0 = b.asm.Sb).apply(null, arguments); + }), + Kd = (b._emscripten_bind_ConvexResultCallback_set_m_closestHitFraction_1 = function () { + return (Kd = b._emscripten_bind_ConvexResultCallback_set_m_closestHitFraction_1 = b.asm.Tb).apply(null, arguments); + }), + Ld = (b._emscripten_bind_ConvexResultCallback___destroy___0 = function () { + return (Ld = b._emscripten_bind_ConvexResultCallback___destroy___0 = b.asm.Ub).apply(null, arguments); + }), + Md = (b._emscripten_bind_btConvexShape_setLocalScaling_1 = function () { + return (Md = b._emscripten_bind_btConvexShape_setLocalScaling_1 = b.asm.Vb).apply(null, arguments); + }), + Nd = (b._emscripten_bind_btConvexShape_getLocalScaling_0 = function () { + return (Nd = b._emscripten_bind_btConvexShape_getLocalScaling_0 = b.asm.Wb).apply(null, arguments); + }), + Od = (b._emscripten_bind_btConvexShape_calculateLocalInertia_2 = function () { + return (Od = b._emscripten_bind_btConvexShape_calculateLocalInertia_2 = b.asm.Xb).apply(null, arguments); + }), + Pd = (b._emscripten_bind_btConvexShape_setMargin_1 = function () { + return (Pd = b._emscripten_bind_btConvexShape_setMargin_1 = b.asm.Yb).apply(null, arguments); + }), + Qd = (b._emscripten_bind_btConvexShape_getMargin_0 = function () { + return (Qd = b._emscripten_bind_btConvexShape_getMargin_0 = b.asm.Zb).apply(null, arguments); + }), + Rd = (b._emscripten_bind_btConvexShape___destroy___0 = function () { + return (Rd = b._emscripten_bind_btConvexShape___destroy___0 = b.asm._b).apply(null, arguments); + }), + Sd = (b._emscripten_bind_btCapsuleShape_btCapsuleShape_2 = function () { + return (Sd = b._emscripten_bind_btCapsuleShape_btCapsuleShape_2 = b.asm.$b).apply(null, arguments); + }), + Td = (b._emscripten_bind_btCapsuleShape_setMargin_1 = function () { + return (Td = b._emscripten_bind_btCapsuleShape_setMargin_1 = b.asm.ac).apply(null, arguments); + }), + Ud = (b._emscripten_bind_btCapsuleShape_getMargin_0 = function () { + return (Ud = b._emscripten_bind_btCapsuleShape_getMargin_0 = b.asm.bc).apply(null, arguments); + }), + Vd = (b._emscripten_bind_btCapsuleShape_getUpAxis_0 = function () { + return (Vd = b._emscripten_bind_btCapsuleShape_getUpAxis_0 = b.asm.cc).apply(null, arguments); + }), + Wd = (b._emscripten_bind_btCapsuleShape_getRadius_0 = function () { + return (Wd = b._emscripten_bind_btCapsuleShape_getRadius_0 = b.asm.dc).apply(null, arguments); + }), + Xd = (b._emscripten_bind_btCapsuleShape_getHalfHeight_0 = function () { + return (Xd = b._emscripten_bind_btCapsuleShape_getHalfHeight_0 = b.asm.ec).apply(null, arguments); + }), + Yd = (b._emscripten_bind_btCapsuleShape_setLocalScaling_1 = function () { + return (Yd = b._emscripten_bind_btCapsuleShape_setLocalScaling_1 = b.asm.fc).apply(null, arguments); + }), + Zd = (b._emscripten_bind_btCapsuleShape_getLocalScaling_0 = function () { + return (Zd = b._emscripten_bind_btCapsuleShape_getLocalScaling_0 = b.asm.gc).apply(null, arguments); + }), + $d = (b._emscripten_bind_btCapsuleShape_calculateLocalInertia_2 = function () { + return ($d = b._emscripten_bind_btCapsuleShape_calculateLocalInertia_2 = b.asm.hc).apply(null, arguments); + }), + ae = (b._emscripten_bind_btCapsuleShape___destroy___0 = function () { + return (ae = b._emscripten_bind_btCapsuleShape___destroy___0 = b.asm.ic).apply(null, arguments); + }), + be = (b._emscripten_bind_btCylinderShape_btCylinderShape_1 = function () { + return (be = b._emscripten_bind_btCylinderShape_btCylinderShape_1 = b.asm.jc).apply(null, arguments); + }), + ce = (b._emscripten_bind_btCylinderShape_setMargin_1 = function () { + return (ce = b._emscripten_bind_btCylinderShape_setMargin_1 = b.asm.kc).apply(null, arguments); + }), + de = (b._emscripten_bind_btCylinderShape_getMargin_0 = function () { + return (de = b._emscripten_bind_btCylinderShape_getMargin_0 = b.asm.lc).apply(null, arguments); + }), + ee = (b._emscripten_bind_btCylinderShape_setLocalScaling_1 = function () { + return (ee = b._emscripten_bind_btCylinderShape_setLocalScaling_1 = b.asm.mc).apply(null, arguments); + }), + fe = (b._emscripten_bind_btCylinderShape_getLocalScaling_0 = function () { + return (fe = b._emscripten_bind_btCylinderShape_getLocalScaling_0 = b.asm.nc).apply(null, arguments); + }), + ge = (b._emscripten_bind_btCylinderShape_calculateLocalInertia_2 = function () { + return (ge = b._emscripten_bind_btCylinderShape_calculateLocalInertia_2 = b.asm.oc).apply(null, arguments); + }), + he = (b._emscripten_bind_btCylinderShape___destroy___0 = function () { + return (he = b._emscripten_bind_btCylinderShape___destroy___0 = b.asm.pc).apply(null, arguments); + }), + ie = (b._emscripten_bind_btConeShape_btConeShape_2 = function () { + return (ie = b._emscripten_bind_btConeShape_btConeShape_2 = b.asm.qc).apply(null, arguments); + }), + je = (b._emscripten_bind_btConeShape_setLocalScaling_1 = function () { + return (je = b._emscripten_bind_btConeShape_setLocalScaling_1 = b.asm.rc).apply(null, arguments); + }), + ke = (b._emscripten_bind_btConeShape_getLocalScaling_0 = function () { + return (ke = b._emscripten_bind_btConeShape_getLocalScaling_0 = b.asm.sc).apply(null, arguments); + }), + le = (b._emscripten_bind_btConeShape_calculateLocalInertia_2 = function () { + return (le = b._emscripten_bind_btConeShape_calculateLocalInertia_2 = b.asm.tc).apply(null, arguments); + }), + me = (b._emscripten_bind_btConeShape___destroy___0 = function () { + return (me = b._emscripten_bind_btConeShape___destroy___0 = b.asm.uc).apply(null, arguments); + }), + ne = (b._emscripten_bind_btStridingMeshInterface_setScaling_1 = function () { + return (ne = b._emscripten_bind_btStridingMeshInterface_setScaling_1 = b.asm.vc).apply(null, arguments); + }), + oe = (b._emscripten_bind_btStridingMeshInterface___destroy___0 = function () { + return (oe = b._emscripten_bind_btStridingMeshInterface___destroy___0 = b.asm.wc).apply(null, arguments); + }), + pe = (b._emscripten_bind_btTriangleMeshShape_setLocalScaling_1 = function () { + return (pe = b._emscripten_bind_btTriangleMeshShape_setLocalScaling_1 = b.asm.xc).apply(null, arguments); + }), + qe = (b._emscripten_bind_btTriangleMeshShape_getLocalScaling_0 = function () { + return (qe = b._emscripten_bind_btTriangleMeshShape_getLocalScaling_0 = b.asm.yc).apply(null, arguments); + }), + re = (b._emscripten_bind_btTriangleMeshShape_calculateLocalInertia_2 = function () { + return (re = b._emscripten_bind_btTriangleMeshShape_calculateLocalInertia_2 = b.asm.zc).apply(null, arguments); + }), + se = (b._emscripten_bind_btTriangleMeshShape___destroy___0 = function () { + return (se = b._emscripten_bind_btTriangleMeshShape___destroy___0 = b.asm.Ac).apply(null, arguments); + }), + te = (b._emscripten_bind_btPrimitiveManagerBase_is_trimesh_0 = function () { + return (te = b._emscripten_bind_btPrimitiveManagerBase_is_trimesh_0 = b.asm.Bc).apply(null, arguments); + }), + ue = (b._emscripten_bind_btPrimitiveManagerBase_get_primitive_count_0 = function () { + return (ue = b._emscripten_bind_btPrimitiveManagerBase_get_primitive_count_0 = b.asm.Cc).apply(null, arguments); + }), + ve = (b._emscripten_bind_btPrimitiveManagerBase_get_primitive_box_2 = function () { + return (ve = b._emscripten_bind_btPrimitiveManagerBase_get_primitive_box_2 = b.asm.Dc).apply(null, arguments); + }), + we = (b._emscripten_bind_btPrimitiveManagerBase_get_primitive_triangle_2 = function () { + return (we = b._emscripten_bind_btPrimitiveManagerBase_get_primitive_triangle_2 = b.asm.Ec).apply(null, arguments); + }), + xe = (b._emscripten_bind_btPrimitiveManagerBase___destroy___0 = function () { + return (xe = b._emscripten_bind_btPrimitiveManagerBase___destroy___0 = b.asm.Fc).apply(null, arguments); + }), + ye = (b._emscripten_bind_btGImpactShapeInterface_updateBound_0 = function () { + return (ye = b._emscripten_bind_btGImpactShapeInterface_updateBound_0 = b.asm.Gc).apply(null, arguments); + }), + ze = (b._emscripten_bind_btGImpactShapeInterface_postUpdate_0 = function () { + return (ze = b._emscripten_bind_btGImpactShapeInterface_postUpdate_0 = b.asm.Hc).apply(null, arguments); + }), + Ae = (b._emscripten_bind_btGImpactShapeInterface_getShapeType_0 = function () { + return (Ae = b._emscripten_bind_btGImpactShapeInterface_getShapeType_0 = b.asm.Ic).apply(null, arguments); + }), + Be = (b._emscripten_bind_btGImpactShapeInterface_getName_0 = function () { + return (Be = b._emscripten_bind_btGImpactShapeInterface_getName_0 = b.asm.Jc).apply(null, arguments); + }), + Ce = (b._emscripten_bind_btGImpactShapeInterface_getGImpactShapeType_0 = function () { + return (Ce = b._emscripten_bind_btGImpactShapeInterface_getGImpactShapeType_0 = b.asm.Kc).apply(null, arguments); + }), + De = (b._emscripten_bind_btGImpactShapeInterface_getPrimitiveManager_0 = function () { + return (De = b._emscripten_bind_btGImpactShapeInterface_getPrimitiveManager_0 = b.asm.Lc).apply(null, arguments); + }), + Ee = (b._emscripten_bind_btGImpactShapeInterface_getNumChildShapes_0 = function () { + return (Ee = b._emscripten_bind_btGImpactShapeInterface_getNumChildShapes_0 = b.asm.Mc).apply(null, arguments); + }), + Fe = (b._emscripten_bind_btGImpactShapeInterface_childrenHasTransform_0 = function () { + return (Fe = b._emscripten_bind_btGImpactShapeInterface_childrenHasTransform_0 = b.asm.Nc).apply(null, arguments); + }), + Ge = (b._emscripten_bind_btGImpactShapeInterface_needsRetrieveTriangles_0 = function () { + return (Ge = b._emscripten_bind_btGImpactShapeInterface_needsRetrieveTriangles_0 = b.asm.Oc).apply(null, arguments); + }), + He = (b._emscripten_bind_btGImpactShapeInterface_needsRetrieveTetrahedrons_0 = function () { + return (He = b._emscripten_bind_btGImpactShapeInterface_needsRetrieveTetrahedrons_0 = b.asm.Pc).apply(null, arguments); + }), + Ie = (b._emscripten_bind_btGImpactShapeInterface_getBulletTriangle_2 = function () { + return (Ie = b._emscripten_bind_btGImpactShapeInterface_getBulletTriangle_2 = b.asm.Qc).apply(null, arguments); + }), + Je = (b._emscripten_bind_btGImpactShapeInterface_getBulletTetrahedron_2 = function () { + return (Je = b._emscripten_bind_btGImpactShapeInterface_getBulletTetrahedron_2 = b.asm.Rc).apply(null, arguments); + }), + Ke = (b._emscripten_bind_btGImpactShapeInterface_getChildShape_1 = function () { + return (Ke = b._emscripten_bind_btGImpactShapeInterface_getChildShape_1 = b.asm.Sc).apply(null, arguments); + }), + Le = (b._emscripten_bind_btGImpactShapeInterface_getChildTransform_1 = function () { + return (Le = b._emscripten_bind_btGImpactShapeInterface_getChildTransform_1 = b.asm.Tc).apply(null, arguments); + }), + Me = (b._emscripten_bind_btGImpactShapeInterface_setChildTransform_2 = function () { + return (Me = b._emscripten_bind_btGImpactShapeInterface_setChildTransform_2 = b.asm.Uc).apply(null, arguments); + }), + Ne = (b._emscripten_bind_btGImpactShapeInterface_setLocalScaling_1 = function () { + return (Ne = b._emscripten_bind_btGImpactShapeInterface_setLocalScaling_1 = b.asm.Vc).apply(null, arguments); + }), + Oe = (b._emscripten_bind_btGImpactShapeInterface_getLocalScaling_0 = function () { + return (Oe = b._emscripten_bind_btGImpactShapeInterface_getLocalScaling_0 = b.asm.Wc).apply(null, arguments); + }), + Pe = (b._emscripten_bind_btGImpactShapeInterface_calculateLocalInertia_2 = function () { + return (Pe = b._emscripten_bind_btGImpactShapeInterface_calculateLocalInertia_2 = b.asm.Xc).apply(null, arguments); + }), + Qe = (b._emscripten_bind_btGImpactShapeInterface___destroy___0 = function () { + return (Qe = b._emscripten_bind_btGImpactShapeInterface___destroy___0 = b.asm.Yc).apply(null, arguments); + }), + Re = (b._emscripten_bind_btActivatingCollisionAlgorithm___destroy___0 = function () { + return (Re = b._emscripten_bind_btActivatingCollisionAlgorithm___destroy___0 = b.asm.Zc).apply(null, arguments); + }), + Se = (b._emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_0 = function () { + return (Se = b._emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_0 = b.asm._c).apply(null, arguments); + }), + Te = (b._emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_1 = function () { + return (Te = b._emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_1 = b.asm.$c).apply(null, arguments); + }), + Ue = (b._emscripten_bind_btDefaultCollisionConfiguration___destroy___0 = function () { + return (Ue = b._emscripten_bind_btDefaultCollisionConfiguration___destroy___0 = b.asm.ad).apply(null, arguments); + }), + Ve = (b._emscripten_bind_btDispatcher_getNumManifolds_0 = function () { + return (Ve = b._emscripten_bind_btDispatcher_getNumManifolds_0 = b.asm.bd).apply(null, arguments); + }), + We = (b._emscripten_bind_btDispatcher_getManifoldByIndexInternal_1 = function () { + return (We = b._emscripten_bind_btDispatcher_getManifoldByIndexInternal_1 = b.asm.cd).apply(null, arguments); + }), + Xe = (b._emscripten_bind_btDispatcher___destroy___0 = function () { + return (Xe = b._emscripten_bind_btDispatcher___destroy___0 = b.asm.dd).apply(null, arguments); + }), + Ye = (b._emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_3 = function () { + return (Ye = b._emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_3 = b.asm.ed).apply(null, arguments); + }), + Ze = (b._emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_5 = function () { + return (Ze = b._emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_5 = b.asm.fd).apply(null, arguments); + }), + $e = (b._emscripten_bind_btGeneric6DofConstraint_setLinearLowerLimit_1 = function () { + return ($e = b._emscripten_bind_btGeneric6DofConstraint_setLinearLowerLimit_1 = b.asm.gd).apply(null, arguments); + }), + af = (b._emscripten_bind_btGeneric6DofConstraint_setLinearUpperLimit_1 = function () { + return (af = b._emscripten_bind_btGeneric6DofConstraint_setLinearUpperLimit_1 = b.asm.hd).apply(null, arguments); + }), + bf = (b._emscripten_bind_btGeneric6DofConstraint_setAngularLowerLimit_1 = function () { + return (bf = b._emscripten_bind_btGeneric6DofConstraint_setAngularLowerLimit_1 = b.asm.id).apply(null, arguments); + }), + cf = (b._emscripten_bind_btGeneric6DofConstraint_setAngularUpperLimit_1 = function () { + return (cf = b._emscripten_bind_btGeneric6DofConstraint_setAngularUpperLimit_1 = b.asm.jd).apply(null, arguments); + }), + df = (b._emscripten_bind_btGeneric6DofConstraint_getFrameOffsetA_0 = function () { + return (df = b._emscripten_bind_btGeneric6DofConstraint_getFrameOffsetA_0 = b.asm.kd).apply(null, arguments); + }), + ef = (b._emscripten_bind_btGeneric6DofConstraint_enableFeedback_1 = function () { + return (ef = b._emscripten_bind_btGeneric6DofConstraint_enableFeedback_1 = b.asm.ld).apply(null, arguments); + }), + ff = (b._emscripten_bind_btGeneric6DofConstraint_getBreakingImpulseThreshold_0 = function () { + return (ff = b._emscripten_bind_btGeneric6DofConstraint_getBreakingImpulseThreshold_0 = b.asm.md).apply(null, arguments); + }), + gf = (b._emscripten_bind_btGeneric6DofConstraint_setBreakingImpulseThreshold_1 = function () { + return (gf = b._emscripten_bind_btGeneric6DofConstraint_setBreakingImpulseThreshold_1 = b.asm.nd).apply(null, arguments); + }), + hf = (b._emscripten_bind_btGeneric6DofConstraint_getParam_2 = function () { + return (hf = b._emscripten_bind_btGeneric6DofConstraint_getParam_2 = b.asm.od).apply(null, arguments); + }), + jf = (b._emscripten_bind_btGeneric6DofConstraint_setParam_3 = function () { + return (jf = b._emscripten_bind_btGeneric6DofConstraint_setParam_3 = b.asm.pd).apply(null, arguments); + }), + kf = (b._emscripten_bind_btGeneric6DofConstraint___destroy___0 = function () { + return (kf = b._emscripten_bind_btGeneric6DofConstraint___destroy___0 = b.asm.qd).apply(null, arguments); + }), + lf = (b._emscripten_bind_btDiscreteDynamicsWorld_btDiscreteDynamicsWorld_4 = function () { + return (lf = b._emscripten_bind_btDiscreteDynamicsWorld_btDiscreteDynamicsWorld_4 = b.asm.rd).apply(null, arguments); + }), + mf = (b._emscripten_bind_btDiscreteDynamicsWorld_setGravity_1 = function () { + return (mf = b._emscripten_bind_btDiscreteDynamicsWorld_setGravity_1 = b.asm.sd).apply(null, arguments); + }), + nf = (b._emscripten_bind_btDiscreteDynamicsWorld_getGravity_0 = function () { + return (nf = b._emscripten_bind_btDiscreteDynamicsWorld_getGravity_0 = b.asm.td).apply(null, arguments); + }), + of = (b._emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_1 = function () { + return (of = b._emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_1 = b.asm.ud).apply(null, arguments); + }), + pf = (b._emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_3 = function () { + return (pf = b._emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_3 = b.asm.vd).apply(null, arguments); + }), + qf = (b._emscripten_bind_btDiscreteDynamicsWorld_removeRigidBody_1 = function () { + return (qf = b._emscripten_bind_btDiscreteDynamicsWorld_removeRigidBody_1 = b.asm.wd).apply(null, arguments); + }), + rf = (b._emscripten_bind_btDiscreteDynamicsWorld_addConstraint_1 = function () { + return (rf = b._emscripten_bind_btDiscreteDynamicsWorld_addConstraint_1 = b.asm.xd).apply(null, arguments); + }), + sf = (b._emscripten_bind_btDiscreteDynamicsWorld_addConstraint_2 = function () { + return (sf = b._emscripten_bind_btDiscreteDynamicsWorld_addConstraint_2 = b.asm.yd).apply(null, arguments); + }), + tf = (b._emscripten_bind_btDiscreteDynamicsWorld_removeConstraint_1 = function () { + return (tf = b._emscripten_bind_btDiscreteDynamicsWorld_removeConstraint_1 = b.asm.zd).apply(null, arguments); + }), + uf = (b._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_1 = function () { + return (uf = b._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_1 = b.asm.Ad).apply(null, arguments); + }), + vf = (b._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_2 = function () { + return (vf = b._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_2 = b.asm.Bd).apply(null, arguments); + }), + wf = (b._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_3 = function () { + return (wf = b._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_3 = b.asm.Cd).apply(null, arguments); + }), + xf = (b._emscripten_bind_btDiscreteDynamicsWorld_setContactAddedCallback_1 = function () { + return (xf = b._emscripten_bind_btDiscreteDynamicsWorld_setContactAddedCallback_1 = b.asm.Dd).apply(null, arguments); + }), + yf = (b._emscripten_bind_btDiscreteDynamicsWorld_setContactProcessedCallback_1 = function () { + return (yf = b._emscripten_bind_btDiscreteDynamicsWorld_setContactProcessedCallback_1 = b.asm.Ed).apply(null, arguments); + }), + zf = (b._emscripten_bind_btDiscreteDynamicsWorld_setContactDestroyedCallback_1 = function () { + return (zf = b._emscripten_bind_btDiscreteDynamicsWorld_setContactDestroyedCallback_1 = b.asm.Fd).apply(null, arguments); + }), + Af = (b._emscripten_bind_btDiscreteDynamicsWorld_getDispatcher_0 = function () { + return (Af = b._emscripten_bind_btDiscreteDynamicsWorld_getDispatcher_0 = b.asm.Gd).apply(null, arguments); + }), + Bf = (b._emscripten_bind_btDiscreteDynamicsWorld_rayTest_3 = function () { + return (Bf = b._emscripten_bind_btDiscreteDynamicsWorld_rayTest_3 = b.asm.Hd).apply(null, arguments); + }), + Cf = (b._emscripten_bind_btDiscreteDynamicsWorld_getPairCache_0 = function () { + return (Cf = b._emscripten_bind_btDiscreteDynamicsWorld_getPairCache_0 = b.asm.Id).apply(null, arguments); + }), + Df = (b._emscripten_bind_btDiscreteDynamicsWorld_getDispatchInfo_0 = function () { + return (Df = b._emscripten_bind_btDiscreteDynamicsWorld_getDispatchInfo_0 = b.asm.Jd).apply(null, arguments); + }), + Ef = (b._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_1 = function () { + return (Ef = b._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_1 = b.asm.Kd).apply(null, arguments); + }), + Ff = (b._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_2 = function () { + return (Ff = b._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_2 = b.asm.Ld).apply(null, arguments); + }), + Gf = (b._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_3 = function () { + return (Gf = b._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_3 = b.asm.Md).apply(null, arguments); + }), + Hf = (b._emscripten_bind_btDiscreteDynamicsWorld_removeCollisionObject_1 = function () { + return (Hf = b._emscripten_bind_btDiscreteDynamicsWorld_removeCollisionObject_1 = b.asm.Nd).apply(null, arguments); + }), + If = (b._emscripten_bind_btDiscreteDynamicsWorld_getBroadphase_0 = function () { + return (If = b._emscripten_bind_btDiscreteDynamicsWorld_getBroadphase_0 = b.asm.Od).apply(null, arguments); + }), + Jf = (b._emscripten_bind_btDiscreteDynamicsWorld_convexSweepTest_5 = function () { + return (Jf = b._emscripten_bind_btDiscreteDynamicsWorld_convexSweepTest_5 = b.asm.Pd).apply(null, arguments); + }), + Kf = (b._emscripten_bind_btDiscreteDynamicsWorld_contactPairTest_3 = function () { + return (Kf = b._emscripten_bind_btDiscreteDynamicsWorld_contactPairTest_3 = b.asm.Qd).apply(null, arguments); + }), + Lf = (b._emscripten_bind_btDiscreteDynamicsWorld_contactTest_2 = function () { + return (Lf = b._emscripten_bind_btDiscreteDynamicsWorld_contactTest_2 = b.asm.Rd).apply(null, arguments); + }), + Mf = (b._emscripten_bind_btDiscreteDynamicsWorld_updateSingleAabb_1 = function () { + return (Mf = b._emscripten_bind_btDiscreteDynamicsWorld_updateSingleAabb_1 = b.asm.Sd).apply(null, arguments); + }), + Nf = (b._emscripten_bind_btDiscreteDynamicsWorld_setDebugDrawer_1 = function () { + return (Nf = b._emscripten_bind_btDiscreteDynamicsWorld_setDebugDrawer_1 = b.asm.Td).apply(null, arguments); + }), + Of = (b._emscripten_bind_btDiscreteDynamicsWorld_getDebugDrawer_0 = function () { + return (Of = b._emscripten_bind_btDiscreteDynamicsWorld_getDebugDrawer_0 = b.asm.Ud).apply(null, arguments); + }), + Pf = (b._emscripten_bind_btDiscreteDynamicsWorld_debugDrawWorld_0 = function () { + return (Pf = b._emscripten_bind_btDiscreteDynamicsWorld_debugDrawWorld_0 = b.asm.Vd).apply(null, arguments); + }), + Qf = (b._emscripten_bind_btDiscreteDynamicsWorld_debugDrawObject_3 = function () { + return (Qf = b._emscripten_bind_btDiscreteDynamicsWorld_debugDrawObject_3 = b.asm.Wd).apply(null, arguments); + }), + Rf = (b._emscripten_bind_btDiscreteDynamicsWorld_addAction_1 = function () { + return (Rf = b._emscripten_bind_btDiscreteDynamicsWorld_addAction_1 = b.asm.Xd).apply(null, arguments); + }), + Sf = (b._emscripten_bind_btDiscreteDynamicsWorld_removeAction_1 = function () { + return (Sf = b._emscripten_bind_btDiscreteDynamicsWorld_removeAction_1 = b.asm.Yd).apply(null, arguments); + }), + Tf = (b._emscripten_bind_btDiscreteDynamicsWorld_getSolverInfo_0 = function () { + return (Tf = b._emscripten_bind_btDiscreteDynamicsWorld_getSolverInfo_0 = b.asm.Zd).apply(null, arguments); + }), + Uf = (b._emscripten_bind_btDiscreteDynamicsWorld_setInternalTickCallback_1 = function () { + return (Uf = b._emscripten_bind_btDiscreteDynamicsWorld_setInternalTickCallback_1 = b.asm._d).apply(null, arguments); + }), + Vf = (b._emscripten_bind_btDiscreteDynamicsWorld_setInternalTickCallback_2 = function () { + return (Vf = b._emscripten_bind_btDiscreteDynamicsWorld_setInternalTickCallback_2 = b.asm.$d).apply(null, arguments); + }), + Wf = (b._emscripten_bind_btDiscreteDynamicsWorld_setInternalTickCallback_3 = function () { + return (Wf = b._emscripten_bind_btDiscreteDynamicsWorld_setInternalTickCallback_3 = b.asm.ae).apply(null, arguments); + }), + Xf = (b._emscripten_bind_btDiscreteDynamicsWorld___destroy___0 = function () { + return (Xf = b._emscripten_bind_btDiscreteDynamicsWorld___destroy___0 = b.asm.be).apply(null, arguments); + }), + Yf = (b._emscripten_bind_btVehicleRaycaster_castRay_3 = function () { + return (Yf = b._emscripten_bind_btVehicleRaycaster_castRay_3 = b.asm.ce).apply(null, arguments); + }), + Zf = (b._emscripten_bind_btVehicleRaycaster___destroy___0 = function () { + return (Zf = b._emscripten_bind_btVehicleRaycaster___destroy___0 = b.asm.de).apply(null, arguments); + }), + $f = (b._emscripten_bind_btActionInterface_updateAction_2 = function () { + return ($f = b._emscripten_bind_btActionInterface_updateAction_2 = b.asm.ee).apply(null, arguments); + }), + ag = (b._emscripten_bind_btActionInterface___destroy___0 = function () { + return (ag = b._emscripten_bind_btActionInterface___destroy___0 = b.asm.fe).apply(null, arguments); + }), + bg = (b._emscripten_bind_btGhostObject_btGhostObject_0 = function () { + return (bg = b._emscripten_bind_btGhostObject_btGhostObject_0 = b.asm.ge).apply(null, arguments); + }), + cg = (b._emscripten_bind_btGhostObject_getNumOverlappingObjects_0 = function () { + return (cg = b._emscripten_bind_btGhostObject_getNumOverlappingObjects_0 = b.asm.he).apply(null, arguments); + }), + dg = (b._emscripten_bind_btGhostObject_getOverlappingObject_1 = function () { + return (dg = b._emscripten_bind_btGhostObject_getOverlappingObject_1 = b.asm.ie).apply(null, arguments); + }), + eg = (b._emscripten_bind_btGhostObject_setAnisotropicFriction_2 = function () { + return (eg = b._emscripten_bind_btGhostObject_setAnisotropicFriction_2 = b.asm.je).apply(null, arguments); + }), + fg = (b._emscripten_bind_btGhostObject_getCollisionShape_0 = function () { + return (fg = b._emscripten_bind_btGhostObject_getCollisionShape_0 = b.asm.ke).apply(null, arguments); + }), + gg = (b._emscripten_bind_btGhostObject_setContactProcessingThreshold_1 = function () { + return (gg = b._emscripten_bind_btGhostObject_setContactProcessingThreshold_1 = b.asm.le).apply(null, arguments); + }), + hg = (b._emscripten_bind_btGhostObject_setActivationState_1 = function () { + return (hg = b._emscripten_bind_btGhostObject_setActivationState_1 = b.asm.me).apply(null, arguments); + }), + ig = (b._emscripten_bind_btGhostObject_forceActivationState_1 = function () { + return (ig = b._emscripten_bind_btGhostObject_forceActivationState_1 = b.asm.ne).apply(null, arguments); + }), + jg = (b._emscripten_bind_btGhostObject_activate_0 = function () { + return (jg = b._emscripten_bind_btGhostObject_activate_0 = b.asm.oe).apply(null, arguments); + }), + kg = (b._emscripten_bind_btGhostObject_activate_1 = function () { + return (kg = b._emscripten_bind_btGhostObject_activate_1 = b.asm.pe).apply(null, arguments); + }), + lg = (b._emscripten_bind_btGhostObject_isActive_0 = function () { + return (lg = b._emscripten_bind_btGhostObject_isActive_0 = b.asm.qe).apply(null, arguments); + }), + mg = (b._emscripten_bind_btGhostObject_isKinematicObject_0 = function () { + return (mg = b._emscripten_bind_btGhostObject_isKinematicObject_0 = b.asm.re).apply(null, arguments); + }), + ng = (b._emscripten_bind_btGhostObject_isStaticObject_0 = function () { + return (ng = b._emscripten_bind_btGhostObject_isStaticObject_0 = b.asm.se).apply(null, arguments); + }), + og = (b._emscripten_bind_btGhostObject_isStaticOrKinematicObject_0 = function () { + return (og = b._emscripten_bind_btGhostObject_isStaticOrKinematicObject_0 = b.asm.te).apply(null, arguments); + }), + pg = (b._emscripten_bind_btGhostObject_getRestitution_0 = function () { + return (pg = b._emscripten_bind_btGhostObject_getRestitution_0 = b.asm.ue).apply(null, arguments); + }), + qg = (b._emscripten_bind_btGhostObject_getFriction_0 = function () { + return (qg = b._emscripten_bind_btGhostObject_getFriction_0 = b.asm.ve).apply(null, arguments); + }), + rg = (b._emscripten_bind_btGhostObject_getRollingFriction_0 = function () { + return (rg = b._emscripten_bind_btGhostObject_getRollingFriction_0 = b.asm.we).apply(null, arguments); + }), + sg = (b._emscripten_bind_btGhostObject_setRestitution_1 = function () { + return (sg = b._emscripten_bind_btGhostObject_setRestitution_1 = b.asm.xe).apply(null, arguments); + }), + tg = (b._emscripten_bind_btGhostObject_setFriction_1 = function () { + return (tg = b._emscripten_bind_btGhostObject_setFriction_1 = b.asm.ye).apply(null, arguments); + }), + ug = (b._emscripten_bind_btGhostObject_setRollingFriction_1 = function () { + return (ug = b._emscripten_bind_btGhostObject_setRollingFriction_1 = b.asm.ze).apply(null, arguments); + }), + vg = (b._emscripten_bind_btGhostObject_getWorldTransform_0 = function () { + return (vg = b._emscripten_bind_btGhostObject_getWorldTransform_0 = b.asm.Ae).apply(null, arguments); + }), + wg = (b._emscripten_bind_btGhostObject_getCollisionFlags_0 = function () { + return (wg = b._emscripten_bind_btGhostObject_getCollisionFlags_0 = b.asm.Be).apply(null, arguments); + }), + xg = (b._emscripten_bind_btGhostObject_setCollisionFlags_1 = function () { + return (xg = b._emscripten_bind_btGhostObject_setCollisionFlags_1 = b.asm.Ce).apply(null, arguments); + }), + yg = (b._emscripten_bind_btGhostObject_setWorldTransform_1 = function () { + return (yg = b._emscripten_bind_btGhostObject_setWorldTransform_1 = b.asm.De).apply(null, arguments); + }), + zg = (b._emscripten_bind_btGhostObject_setCollisionShape_1 = function () { + return (zg = b._emscripten_bind_btGhostObject_setCollisionShape_1 = b.asm.Ee).apply(null, arguments); + }), + Ag = (b._emscripten_bind_btGhostObject_setCcdMotionThreshold_1 = function () { + return (Ag = b._emscripten_bind_btGhostObject_setCcdMotionThreshold_1 = b.asm.Fe).apply(null, arguments); + }), + Bg = (b._emscripten_bind_btGhostObject_setCcdSweptSphereRadius_1 = function () { + return (Bg = b._emscripten_bind_btGhostObject_setCcdSweptSphereRadius_1 = b.asm.Ge).apply(null, arguments); + }), + Cg = (b._emscripten_bind_btGhostObject_getUserIndex_0 = function () { + return (Cg = b._emscripten_bind_btGhostObject_getUserIndex_0 = b.asm.He).apply(null, arguments); + }), + Dg = (b._emscripten_bind_btGhostObject_setUserIndex_1 = function () { + return (Dg = b._emscripten_bind_btGhostObject_setUserIndex_1 = b.asm.Ie).apply(null, arguments); + }), + Eg = (b._emscripten_bind_btGhostObject_getUserPointer_0 = function () { + return (Eg = b._emscripten_bind_btGhostObject_getUserPointer_0 = b.asm.Je).apply(null, arguments); + }), + Fg = (b._emscripten_bind_btGhostObject_setUserPointer_1 = function () { + return (Fg = b._emscripten_bind_btGhostObject_setUserPointer_1 = b.asm.Ke).apply(null, arguments); + }), + Gg = (b._emscripten_bind_btGhostObject_getBroadphaseHandle_0 = function () { + return (Gg = b._emscripten_bind_btGhostObject_getBroadphaseHandle_0 = b.asm.Le).apply(null, arguments); + }), + Hg = (b._emscripten_bind_btGhostObject___destroy___0 = function () { + return (Hg = b._emscripten_bind_btGhostObject___destroy___0 = b.asm.Me).apply(null, arguments); + }), + Ig = (b._emscripten_bind_btSoftBodySolver___destroy___0 = function () { + return (Ig = b._emscripten_bind_btSoftBodySolver___destroy___0 = b.asm.Ne).apply(null, arguments); + }), + Jg = (b._emscripten_bind_VoidPtr___destroy___0 = function () { + return (Jg = b._emscripten_bind_VoidPtr___destroy___0 = b.asm.Oe).apply(null, arguments); + }), + Kg = (b._emscripten_bind_DebugDrawer_DebugDrawer_0 = function () { + return (Kg = b._emscripten_bind_DebugDrawer_DebugDrawer_0 = b.asm.Pe).apply(null, arguments); + }), + Lg = (b._emscripten_bind_DebugDrawer_drawLine_3 = function () { + return (Lg = b._emscripten_bind_DebugDrawer_drawLine_3 = b.asm.Qe).apply(null, arguments); + }), + Mg = (b._emscripten_bind_DebugDrawer_drawContactPoint_5 = function () { + return (Mg = b._emscripten_bind_DebugDrawer_drawContactPoint_5 = b.asm.Re).apply(null, arguments); + }), + Ng = (b._emscripten_bind_DebugDrawer_reportErrorWarning_1 = function () { + return (Ng = b._emscripten_bind_DebugDrawer_reportErrorWarning_1 = b.asm.Se).apply(null, arguments); + }), + Og = (b._emscripten_bind_DebugDrawer_draw3dText_2 = function () { + return (Og = b._emscripten_bind_DebugDrawer_draw3dText_2 = b.asm.Te).apply(null, arguments); + }), + Pg = (b._emscripten_bind_DebugDrawer_setDebugMode_1 = function () { + return (Pg = b._emscripten_bind_DebugDrawer_setDebugMode_1 = b.asm.Ue).apply(null, arguments); + }), + Qg = (b._emscripten_bind_DebugDrawer_getDebugMode_0 = function () { + return (Qg = b._emscripten_bind_DebugDrawer_getDebugMode_0 = b.asm.Ve).apply(null, arguments); + }), + Rg = (b._emscripten_bind_DebugDrawer___destroy___0 = function () { + return (Rg = b._emscripten_bind_DebugDrawer___destroy___0 = b.asm.We).apply(null, arguments); + }), + Sg = (b._emscripten_bind_btVector4_btVector4_0 = function () { + return (Sg = b._emscripten_bind_btVector4_btVector4_0 = b.asm.Xe).apply(null, arguments); + }), + Tg = (b._emscripten_bind_btVector4_btVector4_4 = function () { + return (Tg = b._emscripten_bind_btVector4_btVector4_4 = b.asm.Ye).apply(null, arguments); + }), + Ug = (b._emscripten_bind_btVector4_w_0 = function () { + return (Ug = b._emscripten_bind_btVector4_w_0 = b.asm.Ze).apply(null, arguments); + }), + Vg = (b._emscripten_bind_btVector4_setValue_4 = function () { + return (Vg = b._emscripten_bind_btVector4_setValue_4 = b.asm._e).apply(null, arguments); + }), + Wg = (b._emscripten_bind_btVector4_length_0 = function () { + return (Wg = b._emscripten_bind_btVector4_length_0 = b.asm.$e).apply(null, arguments); + }), + Xg = (b._emscripten_bind_btVector4_x_0 = function () { + return (Xg = b._emscripten_bind_btVector4_x_0 = b.asm.af).apply(null, arguments); + }), + Yg = (b._emscripten_bind_btVector4_y_0 = function () { + return (Yg = b._emscripten_bind_btVector4_y_0 = b.asm.bf).apply(null, arguments); + }), + Zg = (b._emscripten_bind_btVector4_z_0 = function () { + return (Zg = b._emscripten_bind_btVector4_z_0 = b.asm.cf).apply(null, arguments); + }), + $g = (b._emscripten_bind_btVector4_setX_1 = function () { + return ($g = b._emscripten_bind_btVector4_setX_1 = b.asm.df).apply(null, arguments); + }), + ah = (b._emscripten_bind_btVector4_setY_1 = function () { + return (ah = b._emscripten_bind_btVector4_setY_1 = b.asm.ef).apply(null, arguments); + }), + bh = (b._emscripten_bind_btVector4_setZ_1 = function () { + return (bh = b._emscripten_bind_btVector4_setZ_1 = b.asm.ff).apply(null, arguments); + }), + ch = (b._emscripten_bind_btVector4_normalize_0 = function () { + return (ch = b._emscripten_bind_btVector4_normalize_0 = b.asm.gf).apply(null, arguments); + }), + dh = (b._emscripten_bind_btVector4_rotate_2 = function () { + return (dh = b._emscripten_bind_btVector4_rotate_2 = b.asm.hf).apply(null, arguments); + }), + eh = (b._emscripten_bind_btVector4_dot_1 = function () { + return (eh = b._emscripten_bind_btVector4_dot_1 = b.asm.jf).apply(null, arguments); + }), + fh = (b._emscripten_bind_btVector4_op_mul_1 = function () { + return (fh = b._emscripten_bind_btVector4_op_mul_1 = b.asm.kf).apply(null, arguments); + }), + gh = (b._emscripten_bind_btVector4_op_add_1 = function () { + return (gh = b._emscripten_bind_btVector4_op_add_1 = b.asm.lf).apply(null, arguments); + }), + hh = (b._emscripten_bind_btVector4_op_sub_1 = function () { + return (hh = b._emscripten_bind_btVector4_op_sub_1 = b.asm.mf).apply(null, arguments); + }), + ih = (b._emscripten_bind_btVector4___destroy___0 = function () { + return (ih = b._emscripten_bind_btVector4___destroy___0 = b.asm.nf).apply(null, arguments); + }), + jh = (b._emscripten_bind_btQuaternion_btQuaternion_4 = function () { + return (jh = b._emscripten_bind_btQuaternion_btQuaternion_4 = b.asm.of).apply(null, arguments); + }), + kh = (b._emscripten_bind_btQuaternion_setValue_4 = function () { + return (kh = b._emscripten_bind_btQuaternion_setValue_4 = b.asm.pf).apply(null, arguments); + }), + lh = (b._emscripten_bind_btQuaternion_setEulerZYX_3 = function () { + return (lh = b._emscripten_bind_btQuaternion_setEulerZYX_3 = b.asm.qf).apply(null, arguments); + }), + mh = (b._emscripten_bind_btQuaternion_setRotation_2 = function () { + return (mh = b._emscripten_bind_btQuaternion_setRotation_2 = b.asm.rf).apply(null, arguments); + }), + nh = (b._emscripten_bind_btQuaternion_normalize_0 = function () { + return (nh = b._emscripten_bind_btQuaternion_normalize_0 = b.asm.sf).apply(null, arguments); + }), + oh = (b._emscripten_bind_btQuaternion_length2_0 = function () { + return (oh = b._emscripten_bind_btQuaternion_length2_0 = b.asm.tf).apply(null, arguments); + }), + ph = (b._emscripten_bind_btQuaternion_length_0 = function () { + return (ph = b._emscripten_bind_btQuaternion_length_0 = b.asm.uf).apply(null, arguments); + }), + qh = (b._emscripten_bind_btQuaternion_dot_1 = function () { + return (qh = b._emscripten_bind_btQuaternion_dot_1 = b.asm.vf).apply(null, arguments); + }), + rh = (b._emscripten_bind_btQuaternion_normalized_0 = function () { + return (rh = b._emscripten_bind_btQuaternion_normalized_0 = b.asm.wf).apply(null, arguments); + }), + sh = (b._emscripten_bind_btQuaternion_getAxis_0 = function () { + return (sh = b._emscripten_bind_btQuaternion_getAxis_0 = b.asm.xf).apply(null, arguments); + }), + th = (b._emscripten_bind_btQuaternion_inverse_0 = function () { + return (th = b._emscripten_bind_btQuaternion_inverse_0 = b.asm.yf).apply(null, arguments); + }), + uh = (b._emscripten_bind_btQuaternion_getAngle_0 = function () { + return (uh = b._emscripten_bind_btQuaternion_getAngle_0 = b.asm.zf).apply(null, arguments); + }), + vh = (b._emscripten_bind_btQuaternion_getAngleShortestPath_0 = function () { + return (vh = b._emscripten_bind_btQuaternion_getAngleShortestPath_0 = b.asm.Af).apply(null, arguments); + }), + wh = (b._emscripten_bind_btQuaternion_angle_1 = function () { + return (wh = b._emscripten_bind_btQuaternion_angle_1 = b.asm.Bf).apply(null, arguments); + }), + xh = (b._emscripten_bind_btQuaternion_angleShortestPath_1 = function () { + return (xh = b._emscripten_bind_btQuaternion_angleShortestPath_1 = b.asm.Cf).apply(null, arguments); + }), + yh = (b._emscripten_bind_btQuaternion_op_add_1 = function () { + return (yh = b._emscripten_bind_btQuaternion_op_add_1 = b.asm.Df).apply(null, arguments); + }), + zh = (b._emscripten_bind_btQuaternion_op_sub_1 = function () { + return (zh = b._emscripten_bind_btQuaternion_op_sub_1 = b.asm.Ef).apply(null, arguments); + }), + Ah = (b._emscripten_bind_btQuaternion_op_mul_1 = function () { + return (Ah = b._emscripten_bind_btQuaternion_op_mul_1 = b.asm.Ff).apply(null, arguments); + }), + Bh = (b._emscripten_bind_btQuaternion_op_mulq_1 = function () { + return (Bh = b._emscripten_bind_btQuaternion_op_mulq_1 = b.asm.Gf).apply(null, arguments); + }), + Ch = (b._emscripten_bind_btQuaternion_op_div_1 = function () { + return (Ch = b._emscripten_bind_btQuaternion_op_div_1 = b.asm.Hf).apply(null, arguments); + }), + Dh = (b._emscripten_bind_btQuaternion_x_0 = function () { + return (Dh = b._emscripten_bind_btQuaternion_x_0 = b.asm.If).apply(null, arguments); + }), + Eh = (b._emscripten_bind_btQuaternion_y_0 = function () { + return (Eh = b._emscripten_bind_btQuaternion_y_0 = b.asm.Jf).apply(null, arguments); + }), + Fh = (b._emscripten_bind_btQuaternion_z_0 = function () { + return (Fh = b._emscripten_bind_btQuaternion_z_0 = b.asm.Kf).apply(null, arguments); + }), + Gh = (b._emscripten_bind_btQuaternion_w_0 = function () { + return (Gh = b._emscripten_bind_btQuaternion_w_0 = b.asm.Lf).apply(null, arguments); + }), + Hh = (b._emscripten_bind_btQuaternion_setX_1 = function () { + return (Hh = b._emscripten_bind_btQuaternion_setX_1 = b.asm.Mf).apply(null, arguments); + }), + Ih = (b._emscripten_bind_btQuaternion_setY_1 = function () { + return (Ih = b._emscripten_bind_btQuaternion_setY_1 = b.asm.Nf).apply(null, arguments); + }), + Jh = (b._emscripten_bind_btQuaternion_setZ_1 = function () { + return (Jh = b._emscripten_bind_btQuaternion_setZ_1 = b.asm.Of).apply(null, arguments); + }), + Kh = (b._emscripten_bind_btQuaternion_setW_1 = function () { + return (Kh = b._emscripten_bind_btQuaternion_setW_1 = b.asm.Pf).apply(null, arguments); + }), + Lh = (b._emscripten_bind_btQuaternion___destroy___0 = function () { + return (Lh = b._emscripten_bind_btQuaternion___destroy___0 = b.asm.Qf).apply(null, arguments); + }), + Mh = (b._emscripten_bind_btMatrix3x3_setEulerZYX_3 = function () { + return (Mh = b._emscripten_bind_btMatrix3x3_setEulerZYX_3 = b.asm.Rf).apply(null, arguments); + }), + Nh = (b._emscripten_bind_btMatrix3x3_getRotation_1 = function () { + return (Nh = b._emscripten_bind_btMatrix3x3_getRotation_1 = b.asm.Sf).apply(null, arguments); + }), + Oh = (b._emscripten_bind_btMatrix3x3_getRow_1 = function () { + return (Oh = b._emscripten_bind_btMatrix3x3_getRow_1 = b.asm.Tf).apply(null, arguments); + }), + Ph = (b._emscripten_bind_btMatrix3x3___destroy___0 = function () { + return (Ph = b._emscripten_bind_btMatrix3x3___destroy___0 = b.asm.Uf).apply(null, arguments); + }), + Qh = (b._emscripten_bind_btTransform_btTransform_0 = function () { + return (Qh = b._emscripten_bind_btTransform_btTransform_0 = b.asm.Vf).apply(null, arguments); + }), + Rh = (b._emscripten_bind_btTransform_btTransform_2 = function () { + return (Rh = b._emscripten_bind_btTransform_btTransform_2 = b.asm.Wf).apply(null, arguments); + }), + Sh = (b._emscripten_bind_btTransform_setIdentity_0 = function () { + return (Sh = b._emscripten_bind_btTransform_setIdentity_0 = b.asm.Xf).apply(null, arguments); + }), + Th = (b._emscripten_bind_btTransform_setOrigin_1 = function () { + return (Th = b._emscripten_bind_btTransform_setOrigin_1 = b.asm.Yf).apply(null, arguments); + }), + Uh = (b._emscripten_bind_btTransform_setRotation_1 = function () { + return (Uh = b._emscripten_bind_btTransform_setRotation_1 = b.asm.Zf).apply(null, arguments); + }), + Vh = (b._emscripten_bind_btTransform_getOrigin_0 = function () { + return (Vh = b._emscripten_bind_btTransform_getOrigin_0 = b.asm._f).apply(null, arguments); + }), + Wh = (b._emscripten_bind_btTransform_getRotation_0 = function () { + return (Wh = b._emscripten_bind_btTransform_getRotation_0 = b.asm.$f).apply(null, arguments); + }), + Xh = (b._emscripten_bind_btTransform_getBasis_0 = function () { + return (Xh = b._emscripten_bind_btTransform_getBasis_0 = b.asm.ag).apply(null, arguments); + }), + Yh = (b._emscripten_bind_btTransform_setFromOpenGLMatrix_1 = function () { + return (Yh = b._emscripten_bind_btTransform_setFromOpenGLMatrix_1 = b.asm.bg).apply(null, arguments); + }), + Zh = (b._emscripten_bind_btTransform_inverse_0 = function () { + return (Zh = b._emscripten_bind_btTransform_inverse_0 = b.asm.cg).apply(null, arguments); + }), + $h = (b._emscripten_bind_btTransform_op_mul_1 = function () { + return ($h = b._emscripten_bind_btTransform_op_mul_1 = b.asm.dg).apply(null, arguments); + }), + ai = (b._emscripten_bind_btTransform___destroy___0 = function () { + return (ai = b._emscripten_bind_btTransform___destroy___0 = b.asm.eg).apply(null, arguments); + }), + bi = (b._emscripten_bind_btDefaultMotionState_btDefaultMotionState_0 = function () { + return (bi = b._emscripten_bind_btDefaultMotionState_btDefaultMotionState_0 = b.asm.fg).apply(null, arguments); + }), + ci = (b._emscripten_bind_btDefaultMotionState_btDefaultMotionState_1 = function () { + return (ci = b._emscripten_bind_btDefaultMotionState_btDefaultMotionState_1 = b.asm.gg).apply(null, arguments); + }), + di = (b._emscripten_bind_btDefaultMotionState_btDefaultMotionState_2 = function () { + return (di = b._emscripten_bind_btDefaultMotionState_btDefaultMotionState_2 = b.asm.hg).apply(null, arguments); + }), + ei = (b._emscripten_bind_btDefaultMotionState_getWorldTransform_1 = function () { + return (ei = b._emscripten_bind_btDefaultMotionState_getWorldTransform_1 = b.asm.ig).apply(null, arguments); + }), + fi = (b._emscripten_bind_btDefaultMotionState_setWorldTransform_1 = function () { + return (fi = b._emscripten_bind_btDefaultMotionState_setWorldTransform_1 = b.asm.jg).apply(null, arguments); + }), + gi = (b._emscripten_bind_btDefaultMotionState_get_m_graphicsWorldTrans_0 = function () { + return (gi = b._emscripten_bind_btDefaultMotionState_get_m_graphicsWorldTrans_0 = b.asm.kg).apply(null, arguments); + }), + hi = (b._emscripten_bind_btDefaultMotionState_set_m_graphicsWorldTrans_1 = function () { + return (hi = b._emscripten_bind_btDefaultMotionState_set_m_graphicsWorldTrans_1 = b.asm.lg).apply(null, arguments); + }), + ii = (b._emscripten_bind_btDefaultMotionState___destroy___0 = function () { + return (ii = b._emscripten_bind_btDefaultMotionState___destroy___0 = b.asm.mg).apply(null, arguments); + }), + ji = (b._emscripten_bind_btCollisionObjectWrapper_getWorldTransform_0 = function () { + return (ji = b._emscripten_bind_btCollisionObjectWrapper_getWorldTransform_0 = b.asm.ng).apply(null, arguments); + }), + ki = (b._emscripten_bind_btCollisionObjectWrapper_getCollisionObject_0 = function () { + return (ki = b._emscripten_bind_btCollisionObjectWrapper_getCollisionObject_0 = b.asm.og).apply(null, arguments); + }), + li = (b._emscripten_bind_btCollisionObjectWrapper_getCollisionShape_0 = function () { + return (li = b._emscripten_bind_btCollisionObjectWrapper_getCollisionShape_0 = b.asm.pg).apply(null, arguments); + }), + mi = (b._emscripten_bind_ClosestRayResultCallback_ClosestRayResultCallback_2 = function () { + return (mi = b._emscripten_bind_ClosestRayResultCallback_ClosestRayResultCallback_2 = b.asm.qg).apply(null, arguments); + }), + ni = (b._emscripten_bind_ClosestRayResultCallback_hasHit_0 = function () { + return (ni = b._emscripten_bind_ClosestRayResultCallback_hasHit_0 = b.asm.rg).apply(null, arguments); + }), + oi = (b._emscripten_bind_ClosestRayResultCallback_get_m_rayFromWorld_0 = function () { + return (oi = b._emscripten_bind_ClosestRayResultCallback_get_m_rayFromWorld_0 = b.asm.sg).apply(null, arguments); + }), + pi = (b._emscripten_bind_ClosestRayResultCallback_set_m_rayFromWorld_1 = function () { + return (pi = b._emscripten_bind_ClosestRayResultCallback_set_m_rayFromWorld_1 = b.asm.tg).apply(null, arguments); + }), + qi = (b._emscripten_bind_ClosestRayResultCallback_get_m_rayToWorld_0 = function () { + return (qi = b._emscripten_bind_ClosestRayResultCallback_get_m_rayToWorld_0 = b.asm.ug).apply(null, arguments); + }), + ri = (b._emscripten_bind_ClosestRayResultCallback_set_m_rayToWorld_1 = function () { + return (ri = b._emscripten_bind_ClosestRayResultCallback_set_m_rayToWorld_1 = b.asm.vg).apply(null, arguments); + }), + si = (b._emscripten_bind_ClosestRayResultCallback_get_m_hitNormalWorld_0 = function () { + return (si = b._emscripten_bind_ClosestRayResultCallback_get_m_hitNormalWorld_0 = b.asm.wg).apply(null, arguments); + }), + ti = (b._emscripten_bind_ClosestRayResultCallback_set_m_hitNormalWorld_1 = function () { + return (ti = b._emscripten_bind_ClosestRayResultCallback_set_m_hitNormalWorld_1 = b.asm.xg).apply(null, arguments); + }), + ui = (b._emscripten_bind_ClosestRayResultCallback_get_m_hitPointWorld_0 = function () { + return (ui = b._emscripten_bind_ClosestRayResultCallback_get_m_hitPointWorld_0 = b.asm.yg).apply(null, arguments); + }), + vi = (b._emscripten_bind_ClosestRayResultCallback_set_m_hitPointWorld_1 = function () { + return (vi = b._emscripten_bind_ClosestRayResultCallback_set_m_hitPointWorld_1 = b.asm.zg).apply(null, arguments); + }), + wi = (b._emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterGroup_0 = function () { + return (wi = b._emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterGroup_0 = b.asm.Ag).apply(null, arguments); + }), + xi = (b._emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterGroup_1 = function () { + return (xi = b._emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterGroup_1 = b.asm.Bg).apply(null, arguments); + }), + yi = (b._emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterMask_0 = function () { + return (yi = b._emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterMask_0 = b.asm.Cg).apply(null, arguments); + }), + zi = (b._emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterMask_1 = function () { + return (zi = b._emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterMask_1 = b.asm.Dg).apply(null, arguments); + }), + Ai = (b._emscripten_bind_ClosestRayResultCallback_get_m_closestHitFraction_0 = function () { + return (Ai = b._emscripten_bind_ClosestRayResultCallback_get_m_closestHitFraction_0 = b.asm.Eg).apply(null, arguments); + }), + Bi = (b._emscripten_bind_ClosestRayResultCallback_set_m_closestHitFraction_1 = function () { + return (Bi = b._emscripten_bind_ClosestRayResultCallback_set_m_closestHitFraction_1 = b.asm.Fg).apply(null, arguments); + }), + Ci = (b._emscripten_bind_ClosestRayResultCallback_get_m_collisionObject_0 = function () { + return (Ci = b._emscripten_bind_ClosestRayResultCallback_get_m_collisionObject_0 = b.asm.Gg).apply(null, arguments); + }), + Di = (b._emscripten_bind_ClosestRayResultCallback_set_m_collisionObject_1 = function () { + return (Di = b._emscripten_bind_ClosestRayResultCallback_set_m_collisionObject_1 = b.asm.Hg).apply(null, arguments); + }), + Ei = (b._emscripten_bind_ClosestRayResultCallback_get_m_flags_0 = function () { + return (Ei = b._emscripten_bind_ClosestRayResultCallback_get_m_flags_0 = b.asm.Ig).apply(null, arguments); + }), + Fi = (b._emscripten_bind_ClosestRayResultCallback_set_m_flags_1 = function () { + return (Fi = b._emscripten_bind_ClosestRayResultCallback_set_m_flags_1 = b.asm.Jg).apply(null, arguments); + }), + Gi = (b._emscripten_bind_ClosestRayResultCallback___destroy___0 = function () { + return (Gi = b._emscripten_bind_ClosestRayResultCallback___destroy___0 = b.asm.Kg).apply(null, arguments); + }), + Hi = (b._emscripten_bind_btConstCollisionObjectArray_size_0 = function () { + return (Hi = b._emscripten_bind_btConstCollisionObjectArray_size_0 = b.asm.Lg).apply(null, arguments); + }), + Ii = (b._emscripten_bind_btConstCollisionObjectArray_at_1 = function () { + return (Ii = b._emscripten_bind_btConstCollisionObjectArray_at_1 = b.asm.Mg).apply(null, arguments); + }), + Ji = (b._emscripten_bind_btConstCollisionObjectArray___destroy___0 = function () { + return (Ji = b._emscripten_bind_btConstCollisionObjectArray___destroy___0 = b.asm.Ng).apply(null, arguments); + }), + Ki = (b._emscripten_bind_btScalarArray_size_0 = function () { + return (Ki = b._emscripten_bind_btScalarArray_size_0 = b.asm.Og).apply(null, arguments); + }), + Li = (b._emscripten_bind_btScalarArray_at_1 = function () { + return (Li = b._emscripten_bind_btScalarArray_at_1 = b.asm.Pg).apply(null, arguments); + }), + Mi = (b._emscripten_bind_btScalarArray___destroy___0 = function () { + return (Mi = b._emscripten_bind_btScalarArray___destroy___0 = b.asm.Qg).apply(null, arguments); + }), + Ni = (b._emscripten_bind_AllHitsRayResultCallback_AllHitsRayResultCallback_2 = function () { + return (Ni = b._emscripten_bind_AllHitsRayResultCallback_AllHitsRayResultCallback_2 = b.asm.Rg).apply(null, arguments); + }), + Oi = (b._emscripten_bind_AllHitsRayResultCallback_hasHit_0 = function () { + return (Oi = b._emscripten_bind_AllHitsRayResultCallback_hasHit_0 = b.asm.Sg).apply(null, arguments); + }), + Pi = (b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionObjects_0 = function () { + return (Pi = b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionObjects_0 = b.asm.Tg).apply(null, arguments); + }), + Qi = (b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionObjects_1 = function () { + return (Qi = b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionObjects_1 = b.asm.Ug).apply(null, arguments); + }), + Ri = (b._emscripten_bind_AllHitsRayResultCallback_get_m_rayFromWorld_0 = function () { + return (Ri = b._emscripten_bind_AllHitsRayResultCallback_get_m_rayFromWorld_0 = b.asm.Vg).apply(null, arguments); + }), + Si = (b._emscripten_bind_AllHitsRayResultCallback_set_m_rayFromWorld_1 = function () { + return (Si = b._emscripten_bind_AllHitsRayResultCallback_set_m_rayFromWorld_1 = b.asm.Wg).apply(null, arguments); + }), + Ti = (b._emscripten_bind_AllHitsRayResultCallback_get_m_rayToWorld_0 = function () { + return (Ti = b._emscripten_bind_AllHitsRayResultCallback_get_m_rayToWorld_0 = b.asm.Xg).apply(null, arguments); + }), + Ui = (b._emscripten_bind_AllHitsRayResultCallback_set_m_rayToWorld_1 = function () { + return (Ui = b._emscripten_bind_AllHitsRayResultCallback_set_m_rayToWorld_1 = b.asm.Yg).apply(null, arguments); + }), + Vi = (b._emscripten_bind_AllHitsRayResultCallback_get_m_hitNormalWorld_0 = function () { + return (Vi = b._emscripten_bind_AllHitsRayResultCallback_get_m_hitNormalWorld_0 = b.asm.Zg).apply(null, arguments); + }), + Wi = (b._emscripten_bind_AllHitsRayResultCallback_set_m_hitNormalWorld_1 = function () { + return (Wi = b._emscripten_bind_AllHitsRayResultCallback_set_m_hitNormalWorld_1 = b.asm._g).apply(null, arguments); + }), + Xi = (b._emscripten_bind_AllHitsRayResultCallback_get_m_hitPointWorld_0 = function () { + return (Xi = b._emscripten_bind_AllHitsRayResultCallback_get_m_hitPointWorld_0 = b.asm.$g).apply(null, arguments); + }), + Yi = (b._emscripten_bind_AllHitsRayResultCallback_set_m_hitPointWorld_1 = function () { + return (Yi = b._emscripten_bind_AllHitsRayResultCallback_set_m_hitPointWorld_1 = b.asm.ah).apply(null, arguments); + }), + Zi = (b._emscripten_bind_AllHitsRayResultCallback_get_m_hitFractions_0 = function () { + return (Zi = b._emscripten_bind_AllHitsRayResultCallback_get_m_hitFractions_0 = b.asm.bh).apply(null, arguments); + }), + $i = (b._emscripten_bind_AllHitsRayResultCallback_set_m_hitFractions_1 = function () { + return ($i = b._emscripten_bind_AllHitsRayResultCallback_set_m_hitFractions_1 = b.asm.ch).apply(null, arguments); + }), + aj = (b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionFilterGroup_0 = function () { + return (aj = b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionFilterGroup_0 = b.asm.dh).apply(null, arguments); + }), + bj = (b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionFilterGroup_1 = function () { + return (bj = b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionFilterGroup_1 = b.asm.eh).apply(null, arguments); + }), + cj = (b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionFilterMask_0 = function () { + return (cj = b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionFilterMask_0 = b.asm.fh).apply(null, arguments); + }), + dj = (b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionFilterMask_1 = function () { + return (dj = b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionFilterMask_1 = b.asm.gh).apply(null, arguments); + }), + ej = (b._emscripten_bind_AllHitsRayResultCallback_get_m_closestHitFraction_0 = function () { + return (ej = b._emscripten_bind_AllHitsRayResultCallback_get_m_closestHitFraction_0 = b.asm.hh).apply(null, arguments); + }), + fj = (b._emscripten_bind_AllHitsRayResultCallback_set_m_closestHitFraction_1 = function () { + return (fj = b._emscripten_bind_AllHitsRayResultCallback_set_m_closestHitFraction_1 = b.asm.ih).apply(null, arguments); + }), + gj = (b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionObject_0 = function () { + return (gj = b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionObject_0 = b.asm.jh).apply(null, arguments); + }), + hj = (b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionObject_1 = function () { + return (hj = b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionObject_1 = b.asm.kh).apply(null, arguments); + }), + ij = (b._emscripten_bind_AllHitsRayResultCallback_get_m_flags_0 = function () { + return (ij = b._emscripten_bind_AllHitsRayResultCallback_get_m_flags_0 = b.asm.lh).apply(null, arguments); + }), + jj = (b._emscripten_bind_AllHitsRayResultCallback_set_m_flags_1 = function () { + return (jj = b._emscripten_bind_AllHitsRayResultCallback_set_m_flags_1 = b.asm.mh).apply(null, arguments); + }), + kj = (b._emscripten_bind_AllHitsRayResultCallback___destroy___0 = function () { + return (kj = b._emscripten_bind_AllHitsRayResultCallback___destroy___0 = b.asm.nh).apply(null, arguments); + }), + lj = (b._emscripten_bind_btManifoldPoint_getPositionWorldOnA_0 = function () { + return (lj = b._emscripten_bind_btManifoldPoint_getPositionWorldOnA_0 = b.asm.oh).apply(null, arguments); + }), + mj = (b._emscripten_bind_btManifoldPoint_getPositionWorldOnB_0 = function () { + return (mj = b._emscripten_bind_btManifoldPoint_getPositionWorldOnB_0 = b.asm.ph).apply(null, arguments); + }), + nj = (b._emscripten_bind_btManifoldPoint_getAppliedImpulse_0 = function () { + return (nj = b._emscripten_bind_btManifoldPoint_getAppliedImpulse_0 = b.asm.qh).apply(null, arguments); + }), + oj = (b._emscripten_bind_btManifoldPoint_getDistance_0 = function () { + return (oj = b._emscripten_bind_btManifoldPoint_getDistance_0 = b.asm.rh).apply(null, arguments); + }), + pj = (b._emscripten_bind_btManifoldPoint_get_m_localPointA_0 = function () { + return (pj = b._emscripten_bind_btManifoldPoint_get_m_localPointA_0 = b.asm.sh).apply(null, arguments); + }), + qj = (b._emscripten_bind_btManifoldPoint_set_m_localPointA_1 = function () { + return (qj = b._emscripten_bind_btManifoldPoint_set_m_localPointA_1 = b.asm.th).apply(null, arguments); + }), + rj = (b._emscripten_bind_btManifoldPoint_get_m_localPointB_0 = function () { + return (rj = b._emscripten_bind_btManifoldPoint_get_m_localPointB_0 = b.asm.uh).apply(null, arguments); + }), + sj = (b._emscripten_bind_btManifoldPoint_set_m_localPointB_1 = function () { + return (sj = b._emscripten_bind_btManifoldPoint_set_m_localPointB_1 = b.asm.vh).apply(null, arguments); + }), + tj = (b._emscripten_bind_btManifoldPoint_get_m_positionWorldOnB_0 = function () { + return (tj = b._emscripten_bind_btManifoldPoint_get_m_positionWorldOnB_0 = b.asm.wh).apply(null, arguments); + }), + uj = (b._emscripten_bind_btManifoldPoint_set_m_positionWorldOnB_1 = function () { + return (uj = b._emscripten_bind_btManifoldPoint_set_m_positionWorldOnB_1 = b.asm.xh).apply(null, arguments); + }), + vj = (b._emscripten_bind_btManifoldPoint_get_m_positionWorldOnA_0 = function () { + return (vj = b._emscripten_bind_btManifoldPoint_get_m_positionWorldOnA_0 = b.asm.yh).apply(null, arguments); + }), + wj = (b._emscripten_bind_btManifoldPoint_set_m_positionWorldOnA_1 = function () { + return (wj = b._emscripten_bind_btManifoldPoint_set_m_positionWorldOnA_1 = b.asm.zh).apply(null, arguments); + }), + xj = (b._emscripten_bind_btManifoldPoint_get_m_normalWorldOnB_0 = function () { + return (xj = b._emscripten_bind_btManifoldPoint_get_m_normalWorldOnB_0 = b.asm.Ah).apply(null, arguments); + }), + yj = (b._emscripten_bind_btManifoldPoint_set_m_normalWorldOnB_1 = function () { + return (yj = b._emscripten_bind_btManifoldPoint_set_m_normalWorldOnB_1 = b.asm.Bh).apply(null, arguments); + }), + zj = (b._emscripten_bind_btManifoldPoint_get_m_userPersistentData_0 = function () { + return (zj = b._emscripten_bind_btManifoldPoint_get_m_userPersistentData_0 = b.asm.Ch).apply(null, arguments); + }), + Aj = (b._emscripten_bind_btManifoldPoint_set_m_userPersistentData_1 = function () { + return (Aj = b._emscripten_bind_btManifoldPoint_set_m_userPersistentData_1 = b.asm.Dh).apply(null, arguments); + }), + Bj = (b._emscripten_bind_btManifoldPoint___destroy___0 = function () { + return (Bj = b._emscripten_bind_btManifoldPoint___destroy___0 = b.asm.Eh).apply(null, arguments); + }), + Cj = (b._emscripten_bind_ConcreteContactResultCallback_ConcreteContactResultCallback_0 = function () { + return (Cj = b._emscripten_bind_ConcreteContactResultCallback_ConcreteContactResultCallback_0 = b.asm.Fh).apply(null, arguments); + }), + Dj = (b._emscripten_bind_ConcreteContactResultCallback_addSingleResult_7 = function () { + return (Dj = b._emscripten_bind_ConcreteContactResultCallback_addSingleResult_7 = b.asm.Gh).apply(null, arguments); + }), + Ej = (b._emscripten_bind_ConcreteContactResultCallback___destroy___0 = function () { + return (Ej = b._emscripten_bind_ConcreteContactResultCallback___destroy___0 = b.asm.Hh).apply(null, arguments); + }), + Fj = (b._emscripten_bind_LocalShapeInfo_get_m_shapePart_0 = function () { + return (Fj = b._emscripten_bind_LocalShapeInfo_get_m_shapePart_0 = b.asm.Ih).apply(null, arguments); + }), + Gj = (b._emscripten_bind_LocalShapeInfo_set_m_shapePart_1 = function () { + return (Gj = b._emscripten_bind_LocalShapeInfo_set_m_shapePart_1 = b.asm.Jh).apply(null, arguments); + }), + Hj = (b._emscripten_bind_LocalShapeInfo_get_m_triangleIndex_0 = function () { + return (Hj = b._emscripten_bind_LocalShapeInfo_get_m_triangleIndex_0 = b.asm.Kh).apply(null, arguments); + }), + Ij = (b._emscripten_bind_LocalShapeInfo_set_m_triangleIndex_1 = function () { + return (Ij = b._emscripten_bind_LocalShapeInfo_set_m_triangleIndex_1 = b.asm.Lh).apply(null, arguments); + }), + Jj = (b._emscripten_bind_LocalShapeInfo___destroy___0 = function () { + return (Jj = b._emscripten_bind_LocalShapeInfo___destroy___0 = b.asm.Mh).apply(null, arguments); + }), + Kj = (b._emscripten_bind_LocalConvexResult_LocalConvexResult_5 = function () { + return (Kj = b._emscripten_bind_LocalConvexResult_LocalConvexResult_5 = b.asm.Nh).apply(null, arguments); + }), + Lj = (b._emscripten_bind_LocalConvexResult_get_m_hitCollisionObject_0 = function () { + return (Lj = b._emscripten_bind_LocalConvexResult_get_m_hitCollisionObject_0 = b.asm.Oh).apply(null, arguments); + }), + Mj = (b._emscripten_bind_LocalConvexResult_set_m_hitCollisionObject_1 = function () { + return (Mj = b._emscripten_bind_LocalConvexResult_set_m_hitCollisionObject_1 = b.asm.Ph).apply(null, arguments); + }), + Nj = (b._emscripten_bind_LocalConvexResult_get_m_localShapeInfo_0 = function () { + return (Nj = b._emscripten_bind_LocalConvexResult_get_m_localShapeInfo_0 = b.asm.Qh).apply(null, arguments); + }), + Oj = (b._emscripten_bind_LocalConvexResult_set_m_localShapeInfo_1 = function () { + return (Oj = b._emscripten_bind_LocalConvexResult_set_m_localShapeInfo_1 = b.asm.Rh).apply(null, arguments); + }), + Pj = (b._emscripten_bind_LocalConvexResult_get_m_hitNormalLocal_0 = function () { + return (Pj = b._emscripten_bind_LocalConvexResult_get_m_hitNormalLocal_0 = b.asm.Sh).apply(null, arguments); + }), + Qj = (b._emscripten_bind_LocalConvexResult_set_m_hitNormalLocal_1 = function () { + return (Qj = b._emscripten_bind_LocalConvexResult_set_m_hitNormalLocal_1 = b.asm.Th).apply(null, arguments); + }), + Rj = (b._emscripten_bind_LocalConvexResult_get_m_hitPointLocal_0 = function () { + return (Rj = b._emscripten_bind_LocalConvexResult_get_m_hitPointLocal_0 = b.asm.Uh).apply(null, arguments); + }), + Sj = (b._emscripten_bind_LocalConvexResult_set_m_hitPointLocal_1 = function () { + return (Sj = b._emscripten_bind_LocalConvexResult_set_m_hitPointLocal_1 = b.asm.Vh).apply(null, arguments); + }), + Tj = (b._emscripten_bind_LocalConvexResult_get_m_hitFraction_0 = function () { + return (Tj = b._emscripten_bind_LocalConvexResult_get_m_hitFraction_0 = b.asm.Wh).apply(null, arguments); + }), + Uj = (b._emscripten_bind_LocalConvexResult_set_m_hitFraction_1 = function () { + return (Uj = b._emscripten_bind_LocalConvexResult_set_m_hitFraction_1 = b.asm.Xh).apply(null, arguments); + }), + Vj = (b._emscripten_bind_LocalConvexResult___destroy___0 = function () { + return (Vj = b._emscripten_bind_LocalConvexResult___destroy___0 = b.asm.Yh).apply(null, arguments); + }), + Wj = (b._emscripten_bind_ClosestConvexResultCallback_ClosestConvexResultCallback_2 = function () { + return (Wj = b._emscripten_bind_ClosestConvexResultCallback_ClosestConvexResultCallback_2 = b.asm.Zh).apply(null, arguments); + }), + Xj = (b._emscripten_bind_ClosestConvexResultCallback_hasHit_0 = function () { + return (Xj = b._emscripten_bind_ClosestConvexResultCallback_hasHit_0 = b.asm._h).apply(null, arguments); + }), + Yj = (b._emscripten_bind_ClosestConvexResultCallback_get_m_hitCollisionObject_0 = function () { + return (Yj = b._emscripten_bind_ClosestConvexResultCallback_get_m_hitCollisionObject_0 = b.asm.$h).apply(null, arguments); + }), + Zj = (b._emscripten_bind_ClosestConvexResultCallback_set_m_hitCollisionObject_1 = function () { + return (Zj = b._emscripten_bind_ClosestConvexResultCallback_set_m_hitCollisionObject_1 = b.asm.ai).apply(null, arguments); + }), + ak = (b._emscripten_bind_ClosestConvexResultCallback_get_m_convexFromWorld_0 = function () { + return (ak = b._emscripten_bind_ClosestConvexResultCallback_get_m_convexFromWorld_0 = b.asm.bi).apply(null, arguments); + }), + bk = (b._emscripten_bind_ClosestConvexResultCallback_set_m_convexFromWorld_1 = function () { + return (bk = b._emscripten_bind_ClosestConvexResultCallback_set_m_convexFromWorld_1 = b.asm.ci).apply(null, arguments); + }), + ck = (b._emscripten_bind_ClosestConvexResultCallback_get_m_convexToWorld_0 = function () { + return (ck = b._emscripten_bind_ClosestConvexResultCallback_get_m_convexToWorld_0 = b.asm.di).apply(null, arguments); + }), + dk = (b._emscripten_bind_ClosestConvexResultCallback_set_m_convexToWorld_1 = function () { + return (dk = b._emscripten_bind_ClosestConvexResultCallback_set_m_convexToWorld_1 = b.asm.ei).apply(null, arguments); + }), + ek = (b._emscripten_bind_ClosestConvexResultCallback_get_m_hitNormalWorld_0 = function () { + return (ek = b._emscripten_bind_ClosestConvexResultCallback_get_m_hitNormalWorld_0 = b.asm.fi).apply(null, arguments); + }), + fk = (b._emscripten_bind_ClosestConvexResultCallback_set_m_hitNormalWorld_1 = function () { + return (fk = b._emscripten_bind_ClosestConvexResultCallback_set_m_hitNormalWorld_1 = b.asm.gi).apply(null, arguments); + }), + gk = (b._emscripten_bind_ClosestConvexResultCallback_get_m_hitPointWorld_0 = function () { + return (gk = b._emscripten_bind_ClosestConvexResultCallback_get_m_hitPointWorld_0 = b.asm.hi).apply(null, arguments); + }), + hk = (b._emscripten_bind_ClosestConvexResultCallback_set_m_hitPointWorld_1 = function () { + return (hk = b._emscripten_bind_ClosestConvexResultCallback_set_m_hitPointWorld_1 = b.asm.ii).apply(null, arguments); + }), + ik = (b._emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterGroup_0 = function () { + return (ik = b._emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterGroup_0 = b.asm.ji).apply(null, arguments); + }), + jk = (b._emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterGroup_1 = function () { + return (jk = b._emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterGroup_1 = b.asm.ki).apply(null, arguments); + }), + kk = (b._emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterMask_0 = function () { + return (kk = b._emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterMask_0 = b.asm.li).apply(null, arguments); + }), + lk = (b._emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterMask_1 = function () { + return (lk = b._emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterMask_1 = b.asm.mi).apply(null, arguments); + }), + mk = (b._emscripten_bind_ClosestConvexResultCallback_get_m_closestHitFraction_0 = function () { + return (mk = b._emscripten_bind_ClosestConvexResultCallback_get_m_closestHitFraction_0 = b.asm.ni).apply(null, arguments); + }), + nk = (b._emscripten_bind_ClosestConvexResultCallback_set_m_closestHitFraction_1 = function () { + return (nk = b._emscripten_bind_ClosestConvexResultCallback_set_m_closestHitFraction_1 = b.asm.oi).apply(null, arguments); + }), + ok = (b._emscripten_bind_ClosestConvexResultCallback___destroy___0 = function () { + return (ok = b._emscripten_bind_ClosestConvexResultCallback___destroy___0 = b.asm.pi).apply(null, arguments); + }), + pk = (b._emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_1 = function () { + return (pk = b._emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_1 = b.asm.qi).apply(null, arguments); + }), + qk = (b._emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_2 = function () { + return (qk = b._emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_2 = b.asm.ri).apply(null, arguments); + }), + rk = (b._emscripten_bind_btConvexTriangleMeshShape_setLocalScaling_1 = function () { + return (rk = b._emscripten_bind_btConvexTriangleMeshShape_setLocalScaling_1 = b.asm.si).apply(null, arguments); + }), + sk = (b._emscripten_bind_btConvexTriangleMeshShape_getLocalScaling_0 = function () { + return (sk = b._emscripten_bind_btConvexTriangleMeshShape_getLocalScaling_0 = b.asm.ti).apply(null, arguments); + }), + tk = (b._emscripten_bind_btConvexTriangleMeshShape_calculateLocalInertia_2 = function () { + return (tk = b._emscripten_bind_btConvexTriangleMeshShape_calculateLocalInertia_2 = b.asm.ui).apply(null, arguments); + }), + uk = (b._emscripten_bind_btConvexTriangleMeshShape_setMargin_1 = function () { + return (uk = b._emscripten_bind_btConvexTriangleMeshShape_setMargin_1 = b.asm.vi).apply(null, arguments); + }), + vk = (b._emscripten_bind_btConvexTriangleMeshShape_getMargin_0 = function () { + return (vk = b._emscripten_bind_btConvexTriangleMeshShape_getMargin_0 = b.asm.wi).apply(null, arguments); + }), + wk = (b._emscripten_bind_btConvexTriangleMeshShape___destroy___0 = function () { + return (wk = b._emscripten_bind_btConvexTriangleMeshShape___destroy___0 = b.asm.xi).apply(null, arguments); + }), + xk = (b._emscripten_bind_btBoxShape_btBoxShape_1 = function () { + return (xk = b._emscripten_bind_btBoxShape_btBoxShape_1 = b.asm.yi).apply(null, arguments); + }), + yk = (b._emscripten_bind_btBoxShape_setMargin_1 = function () { + return (yk = b._emscripten_bind_btBoxShape_setMargin_1 = b.asm.zi).apply(null, arguments); + }), + zk = (b._emscripten_bind_btBoxShape_getMargin_0 = function () { + return (zk = b._emscripten_bind_btBoxShape_getMargin_0 = b.asm.Ai).apply(null, arguments); + }), + Ak = (b._emscripten_bind_btBoxShape_setLocalScaling_1 = function () { + return (Ak = b._emscripten_bind_btBoxShape_setLocalScaling_1 = b.asm.Bi).apply(null, arguments); + }), + Bk = (b._emscripten_bind_btBoxShape_getLocalScaling_0 = function () { + return (Bk = b._emscripten_bind_btBoxShape_getLocalScaling_0 = b.asm.Ci).apply(null, arguments); + }), + Ck = (b._emscripten_bind_btBoxShape_calculateLocalInertia_2 = function () { + return (Ck = b._emscripten_bind_btBoxShape_calculateLocalInertia_2 = b.asm.Di).apply(null, arguments); + }), + Dk = (b._emscripten_bind_btBoxShape___destroy___0 = function () { + return (Dk = b._emscripten_bind_btBoxShape___destroy___0 = b.asm.Ei).apply(null, arguments); + }), + Ek = (b._emscripten_bind_btCapsuleShapeX_btCapsuleShapeX_2 = function () { + return (Ek = b._emscripten_bind_btCapsuleShapeX_btCapsuleShapeX_2 = b.asm.Fi).apply(null, arguments); + }), + Fk = (b._emscripten_bind_btCapsuleShapeX_setMargin_1 = function () { + return (Fk = b._emscripten_bind_btCapsuleShapeX_setMargin_1 = b.asm.Gi).apply(null, arguments); + }), + Gk = (b._emscripten_bind_btCapsuleShapeX_getMargin_0 = function () { + return (Gk = b._emscripten_bind_btCapsuleShapeX_getMargin_0 = b.asm.Hi).apply(null, arguments); + }), + Hk = (b._emscripten_bind_btCapsuleShapeX_getUpAxis_0 = function () { + return (Hk = b._emscripten_bind_btCapsuleShapeX_getUpAxis_0 = b.asm.Ii).apply(null, arguments); + }), + Ik = (b._emscripten_bind_btCapsuleShapeX_getRadius_0 = function () { + return (Ik = b._emscripten_bind_btCapsuleShapeX_getRadius_0 = b.asm.Ji).apply(null, arguments); + }), + Jk = (b._emscripten_bind_btCapsuleShapeX_getHalfHeight_0 = function () { + return (Jk = b._emscripten_bind_btCapsuleShapeX_getHalfHeight_0 = b.asm.Ki).apply(null, arguments); + }), + Kk = (b._emscripten_bind_btCapsuleShapeX_setLocalScaling_1 = function () { + return (Kk = b._emscripten_bind_btCapsuleShapeX_setLocalScaling_1 = b.asm.Li).apply(null, arguments); + }), + Lk = (b._emscripten_bind_btCapsuleShapeX_getLocalScaling_0 = function () { + return (Lk = b._emscripten_bind_btCapsuleShapeX_getLocalScaling_0 = b.asm.Mi).apply(null, arguments); + }), + Mk = (b._emscripten_bind_btCapsuleShapeX_calculateLocalInertia_2 = function () { + return (Mk = b._emscripten_bind_btCapsuleShapeX_calculateLocalInertia_2 = b.asm.Ni).apply(null, arguments); + }), + Nk = (b._emscripten_bind_btCapsuleShapeX___destroy___0 = function () { + return (Nk = b._emscripten_bind_btCapsuleShapeX___destroy___0 = b.asm.Oi).apply(null, arguments); + }), + Ok = (b._emscripten_bind_btCapsuleShapeZ_btCapsuleShapeZ_2 = function () { + return (Ok = b._emscripten_bind_btCapsuleShapeZ_btCapsuleShapeZ_2 = b.asm.Pi).apply(null, arguments); + }), + Pk = (b._emscripten_bind_btCapsuleShapeZ_setMargin_1 = function () { + return (Pk = b._emscripten_bind_btCapsuleShapeZ_setMargin_1 = b.asm.Qi).apply(null, arguments); + }), + Qk = (b._emscripten_bind_btCapsuleShapeZ_getMargin_0 = function () { + return (Qk = b._emscripten_bind_btCapsuleShapeZ_getMargin_0 = b.asm.Ri).apply(null, arguments); + }), + Rk = (b._emscripten_bind_btCapsuleShapeZ_getUpAxis_0 = function () { + return (Rk = b._emscripten_bind_btCapsuleShapeZ_getUpAxis_0 = b.asm.Si).apply(null, arguments); + }), + Sk = (b._emscripten_bind_btCapsuleShapeZ_getRadius_0 = function () { + return (Sk = b._emscripten_bind_btCapsuleShapeZ_getRadius_0 = b.asm.Ti).apply(null, arguments); + }), + Tk = (b._emscripten_bind_btCapsuleShapeZ_getHalfHeight_0 = function () { + return (Tk = b._emscripten_bind_btCapsuleShapeZ_getHalfHeight_0 = b.asm.Ui).apply(null, arguments); + }), + Uk = (b._emscripten_bind_btCapsuleShapeZ_setLocalScaling_1 = function () { + return (Uk = b._emscripten_bind_btCapsuleShapeZ_setLocalScaling_1 = b.asm.Vi).apply(null, arguments); + }), + Vk = (b._emscripten_bind_btCapsuleShapeZ_getLocalScaling_0 = function () { + return (Vk = b._emscripten_bind_btCapsuleShapeZ_getLocalScaling_0 = b.asm.Wi).apply(null, arguments); + }), + Wk = (b._emscripten_bind_btCapsuleShapeZ_calculateLocalInertia_2 = function () { + return (Wk = b._emscripten_bind_btCapsuleShapeZ_calculateLocalInertia_2 = b.asm.Xi).apply(null, arguments); + }), + Xk = (b._emscripten_bind_btCapsuleShapeZ___destroy___0 = function () { + return (Xk = b._emscripten_bind_btCapsuleShapeZ___destroy___0 = b.asm.Yi).apply(null, arguments); + }), + Yk = (b._emscripten_bind_btCylinderShapeX_btCylinderShapeX_1 = function () { + return (Yk = b._emscripten_bind_btCylinderShapeX_btCylinderShapeX_1 = b.asm.Zi).apply(null, arguments); + }), + Zk = (b._emscripten_bind_btCylinderShapeX_setMargin_1 = function () { + return (Zk = b._emscripten_bind_btCylinderShapeX_setMargin_1 = b.asm._i).apply(null, arguments); + }), + $k = (b._emscripten_bind_btCylinderShapeX_getMargin_0 = function () { + return ($k = b._emscripten_bind_btCylinderShapeX_getMargin_0 = b.asm.$i).apply(null, arguments); + }), + al = (b._emscripten_bind_btCylinderShapeX_setLocalScaling_1 = function () { + return (al = b._emscripten_bind_btCylinderShapeX_setLocalScaling_1 = b.asm.aj).apply(null, arguments); + }), + bl = (b._emscripten_bind_btCylinderShapeX_getLocalScaling_0 = function () { + return (bl = b._emscripten_bind_btCylinderShapeX_getLocalScaling_0 = b.asm.bj).apply(null, arguments); + }), + cl = (b._emscripten_bind_btCylinderShapeX_calculateLocalInertia_2 = function () { + return (cl = b._emscripten_bind_btCylinderShapeX_calculateLocalInertia_2 = b.asm.cj).apply(null, arguments); + }), + dl = (b._emscripten_bind_btCylinderShapeX___destroy___0 = function () { + return (dl = b._emscripten_bind_btCylinderShapeX___destroy___0 = b.asm.dj).apply(null, arguments); + }), + el = (b._emscripten_bind_btCylinderShapeZ_btCylinderShapeZ_1 = function () { + return (el = b._emscripten_bind_btCylinderShapeZ_btCylinderShapeZ_1 = b.asm.ej).apply(null, arguments); + }), + fl = (b._emscripten_bind_btCylinderShapeZ_setMargin_1 = function () { + return (fl = b._emscripten_bind_btCylinderShapeZ_setMargin_1 = b.asm.fj).apply(null, arguments); + }), + gl = (b._emscripten_bind_btCylinderShapeZ_getMargin_0 = function () { + return (gl = b._emscripten_bind_btCylinderShapeZ_getMargin_0 = b.asm.gj).apply(null, arguments); + }), + hl = (b._emscripten_bind_btCylinderShapeZ_setLocalScaling_1 = function () { + return (hl = b._emscripten_bind_btCylinderShapeZ_setLocalScaling_1 = b.asm.hj).apply(null, arguments); + }), + il = (b._emscripten_bind_btCylinderShapeZ_getLocalScaling_0 = function () { + return (il = b._emscripten_bind_btCylinderShapeZ_getLocalScaling_0 = b.asm.ij).apply(null, arguments); + }), + jl = (b._emscripten_bind_btCylinderShapeZ_calculateLocalInertia_2 = function () { + return (jl = b._emscripten_bind_btCylinderShapeZ_calculateLocalInertia_2 = b.asm.jj).apply(null, arguments); + }), + kl = (b._emscripten_bind_btCylinderShapeZ___destroy___0 = function () { + return (kl = b._emscripten_bind_btCylinderShapeZ___destroy___0 = b.asm.kj).apply(null, arguments); + }), + ll = (b._emscripten_bind_btSphereShape_btSphereShape_1 = function () { + return (ll = b._emscripten_bind_btSphereShape_btSphereShape_1 = b.asm.lj).apply(null, arguments); + }), + ml = (b._emscripten_bind_btSphereShape_setMargin_1 = function () { + return (ml = b._emscripten_bind_btSphereShape_setMargin_1 = b.asm.mj).apply(null, arguments); + }), + nl = (b._emscripten_bind_btSphereShape_getMargin_0 = function () { + return (nl = b._emscripten_bind_btSphereShape_getMargin_0 = b.asm.nj).apply(null, arguments); + }), + ol = (b._emscripten_bind_btSphereShape_setLocalScaling_1 = function () { + return (ol = b._emscripten_bind_btSphereShape_setLocalScaling_1 = b.asm.oj).apply(null, arguments); + }), + pl = (b._emscripten_bind_btSphereShape_getLocalScaling_0 = function () { + return (pl = b._emscripten_bind_btSphereShape_getLocalScaling_0 = b.asm.pj).apply(null, arguments); + }), + ql = (b._emscripten_bind_btSphereShape_calculateLocalInertia_2 = function () { + return (ql = b._emscripten_bind_btSphereShape_calculateLocalInertia_2 = b.asm.qj).apply(null, arguments); + }), + rl = (b._emscripten_bind_btSphereShape___destroy___0 = function () { + return (rl = b._emscripten_bind_btSphereShape___destroy___0 = b.asm.rj).apply(null, arguments); + }), + sl = (b._emscripten_bind_btMultiSphereShape_btMultiSphereShape_3 = function () { + return (sl = b._emscripten_bind_btMultiSphereShape_btMultiSphereShape_3 = b.asm.sj).apply(null, arguments); + }), + tl = (b._emscripten_bind_btMultiSphereShape_setLocalScaling_1 = function () { + return (tl = b._emscripten_bind_btMultiSphereShape_setLocalScaling_1 = b.asm.tj).apply(null, arguments); + }), + ul = (b._emscripten_bind_btMultiSphereShape_getLocalScaling_0 = function () { + return (ul = b._emscripten_bind_btMultiSphereShape_getLocalScaling_0 = b.asm.uj).apply(null, arguments); + }), + vl = (b._emscripten_bind_btMultiSphereShape_calculateLocalInertia_2 = function () { + return (vl = b._emscripten_bind_btMultiSphereShape_calculateLocalInertia_2 = b.asm.vj).apply(null, arguments); + }), + wl = (b._emscripten_bind_btMultiSphereShape___destroy___0 = function () { + return (wl = b._emscripten_bind_btMultiSphereShape___destroy___0 = b.asm.wj).apply(null, arguments); + }), + xl = (b._emscripten_bind_btConeShapeX_btConeShapeX_2 = function () { + return (xl = b._emscripten_bind_btConeShapeX_btConeShapeX_2 = b.asm.xj).apply(null, arguments); + }), + yl = (b._emscripten_bind_btConeShapeX_setLocalScaling_1 = function () { + return (yl = b._emscripten_bind_btConeShapeX_setLocalScaling_1 = b.asm.yj).apply(null, arguments); + }), + zl = (b._emscripten_bind_btConeShapeX_getLocalScaling_0 = function () { + return (zl = b._emscripten_bind_btConeShapeX_getLocalScaling_0 = b.asm.zj).apply(null, arguments); + }), + Al = (b._emscripten_bind_btConeShapeX_calculateLocalInertia_2 = function () { + return (Al = b._emscripten_bind_btConeShapeX_calculateLocalInertia_2 = b.asm.Aj).apply(null, arguments); + }), + Bl = (b._emscripten_bind_btConeShapeX___destroy___0 = function () { + return (Bl = b._emscripten_bind_btConeShapeX___destroy___0 = b.asm.Bj).apply(null, arguments); + }), + Cl = (b._emscripten_bind_btConeShapeZ_btConeShapeZ_2 = function () { + return (Cl = b._emscripten_bind_btConeShapeZ_btConeShapeZ_2 = b.asm.Cj).apply(null, arguments); + }), + Dl = (b._emscripten_bind_btConeShapeZ_setLocalScaling_1 = function () { + return (Dl = b._emscripten_bind_btConeShapeZ_setLocalScaling_1 = b.asm.Dj).apply(null, arguments); + }), + El = (b._emscripten_bind_btConeShapeZ_getLocalScaling_0 = function () { + return (El = b._emscripten_bind_btConeShapeZ_getLocalScaling_0 = b.asm.Ej).apply(null, arguments); + }), + Fl = (b._emscripten_bind_btConeShapeZ_calculateLocalInertia_2 = function () { + return (Fl = b._emscripten_bind_btConeShapeZ_calculateLocalInertia_2 = b.asm.Fj).apply(null, arguments); + }), + Gl = (b._emscripten_bind_btConeShapeZ___destroy___0 = function () { + return (Gl = b._emscripten_bind_btConeShapeZ___destroy___0 = b.asm.Gj).apply(null, arguments); + }), + Hl = (b._emscripten_bind_btIntArray_size_0 = function () { + return (Hl = b._emscripten_bind_btIntArray_size_0 = b.asm.Hj).apply(null, arguments); + }), + Il = (b._emscripten_bind_btIntArray_at_1 = function () { + return (Il = b._emscripten_bind_btIntArray_at_1 = b.asm.Ij).apply(null, arguments); + }), + Jl = (b._emscripten_bind_btIntArray___destroy___0 = function () { + return (Jl = b._emscripten_bind_btIntArray___destroy___0 = b.asm.Jj).apply(null, arguments); + }), + Kl = (b._emscripten_bind_btFace_get_m_indices_0 = function () { + return (Kl = b._emscripten_bind_btFace_get_m_indices_0 = b.asm.Kj).apply(null, arguments); + }), + Ll = (b._emscripten_bind_btFace_set_m_indices_1 = function () { + return (Ll = b._emscripten_bind_btFace_set_m_indices_1 = b.asm.Lj).apply(null, arguments); + }), + Ml = (b._emscripten_bind_btFace_get_m_plane_1 = function () { + return (Ml = b._emscripten_bind_btFace_get_m_plane_1 = b.asm.Mj).apply(null, arguments); + }), + Nl = (b._emscripten_bind_btFace_set_m_plane_2 = function () { + return (Nl = b._emscripten_bind_btFace_set_m_plane_2 = b.asm.Nj).apply(null, arguments); + }), + Ol = (b._emscripten_bind_btFace___destroy___0 = function () { + return (Ol = b._emscripten_bind_btFace___destroy___0 = b.asm.Oj).apply(null, arguments); + }), + Pl = (b._emscripten_bind_btVector3Array_size_0 = function () { + return (Pl = b._emscripten_bind_btVector3Array_size_0 = b.asm.Pj).apply(null, arguments); + }), + Ql = (b._emscripten_bind_btVector3Array_at_1 = function () { + return (Ql = b._emscripten_bind_btVector3Array_at_1 = b.asm.Qj).apply(null, arguments); + }), + Rl = (b._emscripten_bind_btVector3Array___destroy___0 = function () { + return (Rl = b._emscripten_bind_btVector3Array___destroy___0 = b.asm.Rj).apply(null, arguments); + }), + Sl = (b._emscripten_bind_btFaceArray_size_0 = function () { + return (Sl = b._emscripten_bind_btFaceArray_size_0 = b.asm.Sj).apply(null, arguments); + }), + Tl = (b._emscripten_bind_btFaceArray_at_1 = function () { + return (Tl = b._emscripten_bind_btFaceArray_at_1 = b.asm.Tj).apply(null, arguments); + }), + Ul = (b._emscripten_bind_btFaceArray___destroy___0 = function () { + return (Ul = b._emscripten_bind_btFaceArray___destroy___0 = b.asm.Uj).apply(null, arguments); + }), + Vl = (b._emscripten_bind_btConvexPolyhedron_get_m_vertices_0 = function () { + return (Vl = b._emscripten_bind_btConvexPolyhedron_get_m_vertices_0 = b.asm.Vj).apply(null, arguments); + }), + Wl = (b._emscripten_bind_btConvexPolyhedron_set_m_vertices_1 = function () { + return (Wl = b._emscripten_bind_btConvexPolyhedron_set_m_vertices_1 = b.asm.Wj).apply(null, arguments); + }), + Xl = (b._emscripten_bind_btConvexPolyhedron_get_m_faces_0 = function () { + return (Xl = b._emscripten_bind_btConvexPolyhedron_get_m_faces_0 = b.asm.Xj).apply(null, arguments); + }), + Yl = (b._emscripten_bind_btConvexPolyhedron_set_m_faces_1 = function () { + return (Yl = b._emscripten_bind_btConvexPolyhedron_set_m_faces_1 = b.asm.Yj).apply(null, arguments); + }), + Zl = (b._emscripten_bind_btConvexPolyhedron___destroy___0 = function () { + return (Zl = b._emscripten_bind_btConvexPolyhedron___destroy___0 = b.asm.Zj).apply(null, arguments); + }), + $l = (b._emscripten_bind_btConvexHullShape_btConvexHullShape_0 = function () { + return ($l = b._emscripten_bind_btConvexHullShape_btConvexHullShape_0 = b.asm._j).apply(null, arguments); + }), + am = (b._emscripten_bind_btConvexHullShape_btConvexHullShape_1 = function () { + return (am = b._emscripten_bind_btConvexHullShape_btConvexHullShape_1 = b.asm.$j).apply(null, arguments); + }), + bm = (b._emscripten_bind_btConvexHullShape_btConvexHullShape_2 = function () { + return (bm = b._emscripten_bind_btConvexHullShape_btConvexHullShape_2 = b.asm.ak).apply(null, arguments); + }), + cm = (b._emscripten_bind_btConvexHullShape_addPoint_1 = function () { + return (cm = b._emscripten_bind_btConvexHullShape_addPoint_1 = b.asm.bk).apply(null, arguments); + }), + dm = (b._emscripten_bind_btConvexHullShape_addPoint_2 = function () { + return (dm = b._emscripten_bind_btConvexHullShape_addPoint_2 = b.asm.ck).apply(null, arguments); + }), + em = (b._emscripten_bind_btConvexHullShape_setMargin_1 = function () { + return (em = b._emscripten_bind_btConvexHullShape_setMargin_1 = b.asm.dk).apply(null, arguments); + }), + fm = (b._emscripten_bind_btConvexHullShape_getMargin_0 = function () { + return (fm = b._emscripten_bind_btConvexHullShape_getMargin_0 = b.asm.ek).apply(null, arguments); + }), + gm = (b._emscripten_bind_btConvexHullShape_getNumVertices_0 = function () { + return (gm = b._emscripten_bind_btConvexHullShape_getNumVertices_0 = b.asm.fk).apply(null, arguments); + }), + hm = (b._emscripten_bind_btConvexHullShape_initializePolyhedralFeatures_1 = function () { + return (hm = b._emscripten_bind_btConvexHullShape_initializePolyhedralFeatures_1 = b.asm.gk).apply(null, arguments); + }), + im = (b._emscripten_bind_btConvexHullShape_recalcLocalAabb_0 = function () { + return (im = b._emscripten_bind_btConvexHullShape_recalcLocalAabb_0 = b.asm.hk).apply(null, arguments); + }), + jm = (b._emscripten_bind_btConvexHullShape_getConvexPolyhedron_0 = function () { + return (jm = b._emscripten_bind_btConvexHullShape_getConvexPolyhedron_0 = b.asm.ik).apply(null, arguments); + }), + km = (b._emscripten_bind_btConvexHullShape_setLocalScaling_1 = function () { + return (km = b._emscripten_bind_btConvexHullShape_setLocalScaling_1 = b.asm.jk).apply(null, arguments); + }), + lm = (b._emscripten_bind_btConvexHullShape_getLocalScaling_0 = function () { + return (lm = b._emscripten_bind_btConvexHullShape_getLocalScaling_0 = b.asm.kk).apply(null, arguments); + }), + mm = (b._emscripten_bind_btConvexHullShape_calculateLocalInertia_2 = function () { + return (mm = b._emscripten_bind_btConvexHullShape_calculateLocalInertia_2 = b.asm.lk).apply(null, arguments); + }), + nm = (b._emscripten_bind_btConvexHullShape___destroy___0 = function () { + return (nm = b._emscripten_bind_btConvexHullShape___destroy___0 = b.asm.mk).apply(null, arguments); + }), + om = (b._emscripten_bind_btShapeHull_btShapeHull_1 = function () { + return (om = b._emscripten_bind_btShapeHull_btShapeHull_1 = b.asm.nk).apply(null, arguments); + }), + pm = (b._emscripten_bind_btShapeHull_buildHull_1 = function () { + return (pm = b._emscripten_bind_btShapeHull_buildHull_1 = b.asm.ok).apply(null, arguments); + }), + qm = (b._emscripten_bind_btShapeHull_numVertices_0 = function () { + return (qm = b._emscripten_bind_btShapeHull_numVertices_0 = b.asm.pk).apply(null, arguments); + }), + rm = (b._emscripten_bind_btShapeHull_getVertexPointer_0 = function () { + return (rm = b._emscripten_bind_btShapeHull_getVertexPointer_0 = b.asm.qk).apply(null, arguments); + }), + sm = (b._emscripten_bind_btShapeHull___destroy___0 = function () { + return (sm = b._emscripten_bind_btShapeHull___destroy___0 = b.asm.rk).apply(null, arguments); + }), + tm = (b._emscripten_bind_btCompoundShape_btCompoundShape_0 = function () { + return (tm = b._emscripten_bind_btCompoundShape_btCompoundShape_0 = b.asm.sk).apply(null, arguments); + }), + um = (b._emscripten_bind_btCompoundShape_btCompoundShape_1 = function () { + return (um = b._emscripten_bind_btCompoundShape_btCompoundShape_1 = b.asm.tk).apply(null, arguments); + }), + wm = (b._emscripten_bind_btCompoundShape_addChildShape_2 = function () { + return (wm = b._emscripten_bind_btCompoundShape_addChildShape_2 = b.asm.uk).apply(null, arguments); + }), + xm = (b._emscripten_bind_btCompoundShape_removeChildShape_1 = function () { + return (xm = b._emscripten_bind_btCompoundShape_removeChildShape_1 = b.asm.vk).apply(null, arguments); + }), + ym = (b._emscripten_bind_btCompoundShape_removeChildShapeByIndex_1 = function () { + return (ym = b._emscripten_bind_btCompoundShape_removeChildShapeByIndex_1 = b.asm.wk).apply(null, arguments); + }), + zm = (b._emscripten_bind_btCompoundShape_getNumChildShapes_0 = function () { + return (zm = b._emscripten_bind_btCompoundShape_getNumChildShapes_0 = b.asm.xk).apply(null, arguments); + }), + Am = (b._emscripten_bind_btCompoundShape_getChildShape_1 = function () { + return (Am = b._emscripten_bind_btCompoundShape_getChildShape_1 = b.asm.yk).apply(null, arguments); + }), + Bm = (b._emscripten_bind_btCompoundShape_updateChildTransform_2 = function () { + return (Bm = b._emscripten_bind_btCompoundShape_updateChildTransform_2 = b.asm.zk).apply(null, arguments); + }), + Cm = (b._emscripten_bind_btCompoundShape_updateChildTransform_3 = function () { + return (Cm = b._emscripten_bind_btCompoundShape_updateChildTransform_3 = b.asm.Ak).apply(null, arguments); + }), + Dm = (b._emscripten_bind_btCompoundShape_setMargin_1 = function () { + return (Dm = b._emscripten_bind_btCompoundShape_setMargin_1 = b.asm.Bk).apply(null, arguments); + }), + Em = (b._emscripten_bind_btCompoundShape_getMargin_0 = function () { + return (Em = b._emscripten_bind_btCompoundShape_getMargin_0 = b.asm.Ck).apply(null, arguments); + }), + Fm = (b._emscripten_bind_btCompoundShape_setLocalScaling_1 = function () { + return (Fm = b._emscripten_bind_btCompoundShape_setLocalScaling_1 = b.asm.Dk).apply(null, arguments); + }), + Gm = (b._emscripten_bind_btCompoundShape_getLocalScaling_0 = function () { + return (Gm = b._emscripten_bind_btCompoundShape_getLocalScaling_0 = b.asm.Ek).apply(null, arguments); + }), + Hm = (b._emscripten_bind_btCompoundShape_calculateLocalInertia_2 = function () { + return (Hm = b._emscripten_bind_btCompoundShape_calculateLocalInertia_2 = b.asm.Fk).apply(null, arguments); + }), + Im = (b._emscripten_bind_btCompoundShape___destroy___0 = function () { + return (Im = b._emscripten_bind_btCompoundShape___destroy___0 = b.asm.Gk).apply(null, arguments); + }), + Jm = (b._emscripten_bind_btIndexedMesh_get_m_numTriangles_0 = function () { + return (Jm = b._emscripten_bind_btIndexedMesh_get_m_numTriangles_0 = b.asm.Hk).apply(null, arguments); + }), + Km = (b._emscripten_bind_btIndexedMesh_set_m_numTriangles_1 = function () { + return (Km = b._emscripten_bind_btIndexedMesh_set_m_numTriangles_1 = b.asm.Ik).apply(null, arguments); + }), + Lm = (b._emscripten_bind_btIndexedMesh___destroy___0 = function () { + return (Lm = b._emscripten_bind_btIndexedMesh___destroy___0 = b.asm.Jk).apply(null, arguments); + }), + Mm = (b._emscripten_bind_btIndexedMeshArray_size_0 = function () { + return (Mm = b._emscripten_bind_btIndexedMeshArray_size_0 = b.asm.Kk).apply(null, arguments); + }), + Nm = (b._emscripten_bind_btIndexedMeshArray_at_1 = function () { + return (Nm = b._emscripten_bind_btIndexedMeshArray_at_1 = b.asm.Lk).apply(null, arguments); + }), + Om = (b._emscripten_bind_btIndexedMeshArray___destroy___0 = function () { + return (Om = b._emscripten_bind_btIndexedMeshArray___destroy___0 = b.asm.Mk).apply(null, arguments); + }), + Pm = (b._emscripten_bind_btTriangleMesh_btTriangleMesh_0 = function () { + return (Pm = b._emscripten_bind_btTriangleMesh_btTriangleMesh_0 = b.asm.Nk).apply(null, arguments); + }), + Qm = (b._emscripten_bind_btTriangleMesh_btTriangleMesh_1 = function () { + return (Qm = b._emscripten_bind_btTriangleMesh_btTriangleMesh_1 = b.asm.Ok).apply(null, arguments); + }), + Rm = (b._emscripten_bind_btTriangleMesh_btTriangleMesh_2 = function () { + return (Rm = b._emscripten_bind_btTriangleMesh_btTriangleMesh_2 = b.asm.Pk).apply(null, arguments); + }), + Sm = (b._emscripten_bind_btTriangleMesh_addTriangle_3 = function () { + return (Sm = b._emscripten_bind_btTriangleMesh_addTriangle_3 = b.asm.Qk).apply(null, arguments); + }), + Tm = (b._emscripten_bind_btTriangleMesh_addTriangle_4 = function () { + return (Tm = b._emscripten_bind_btTriangleMesh_addTriangle_4 = b.asm.Rk).apply(null, arguments); + }), + Um = (b._emscripten_bind_btTriangleMesh_findOrAddVertex_2 = function () { + return (Um = b._emscripten_bind_btTriangleMesh_findOrAddVertex_2 = b.asm.Sk).apply(null, arguments); + }), + Vm = (b._emscripten_bind_btTriangleMesh_addIndex_1 = function () { + return (Vm = b._emscripten_bind_btTriangleMesh_addIndex_1 = b.asm.Tk).apply(null, arguments); + }), + Wm = (b._emscripten_bind_btTriangleMesh_getIndexedMeshArray_0 = function () { + return (Wm = b._emscripten_bind_btTriangleMesh_getIndexedMeshArray_0 = b.asm.Uk).apply(null, arguments); + }), + Xm = (b._emscripten_bind_btTriangleMesh_setScaling_1 = function () { + return (Xm = b._emscripten_bind_btTriangleMesh_setScaling_1 = b.asm.Vk).apply(null, arguments); + }), + Ym = (b._emscripten_bind_btTriangleMesh___destroy___0 = function () { + return (Ym = b._emscripten_bind_btTriangleMesh___destroy___0 = b.asm.Wk).apply(null, arguments); + }), + Zm = (b._emscripten_bind_btEmptyShape_btEmptyShape_0 = function () { + return (Zm = b._emscripten_bind_btEmptyShape_btEmptyShape_0 = b.asm.Xk).apply(null, arguments); + }), + $m = (b._emscripten_bind_btEmptyShape_setLocalScaling_1 = function () { + return ($m = b._emscripten_bind_btEmptyShape_setLocalScaling_1 = b.asm.Yk).apply(null, arguments); + }), + an = (b._emscripten_bind_btEmptyShape_getLocalScaling_0 = function () { + return (an = b._emscripten_bind_btEmptyShape_getLocalScaling_0 = b.asm.Zk).apply(null, arguments); + }), + bn = (b._emscripten_bind_btEmptyShape_calculateLocalInertia_2 = function () { + return (bn = b._emscripten_bind_btEmptyShape_calculateLocalInertia_2 = b.asm._k).apply(null, arguments); + }), + cn = (b._emscripten_bind_btEmptyShape___destroy___0 = function () { + return (cn = b._emscripten_bind_btEmptyShape___destroy___0 = b.asm.$k).apply(null, arguments); + }), + dn = (b._emscripten_bind_btStaticPlaneShape_btStaticPlaneShape_2 = function () { + return (dn = b._emscripten_bind_btStaticPlaneShape_btStaticPlaneShape_2 = b.asm.al).apply(null, arguments); + }), + en = (b._emscripten_bind_btStaticPlaneShape_setLocalScaling_1 = function () { + return (en = b._emscripten_bind_btStaticPlaneShape_setLocalScaling_1 = b.asm.bl).apply(null, arguments); + }), + fn = (b._emscripten_bind_btStaticPlaneShape_getLocalScaling_0 = function () { + return (fn = b._emscripten_bind_btStaticPlaneShape_getLocalScaling_0 = b.asm.cl).apply(null, arguments); + }), + gn = (b._emscripten_bind_btStaticPlaneShape_calculateLocalInertia_2 = function () { + return (gn = b._emscripten_bind_btStaticPlaneShape_calculateLocalInertia_2 = b.asm.dl).apply(null, arguments); + }), + hn = (b._emscripten_bind_btStaticPlaneShape___destroy___0 = function () { + return (hn = b._emscripten_bind_btStaticPlaneShape___destroy___0 = b.asm.el).apply(null, arguments); + }), + jn = (b._emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_2 = function () { + return (jn = b._emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_2 = b.asm.fl).apply(null, arguments); + }), + kn = (b._emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_3 = function () { + return (kn = b._emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_3 = b.asm.gl).apply(null, arguments); + }), + ln = (b._emscripten_bind_btBvhTriangleMeshShape_setLocalScaling_1 = function () { + return (ln = b._emscripten_bind_btBvhTriangleMeshShape_setLocalScaling_1 = b.asm.hl).apply(null, arguments); + }), + mn = (b._emscripten_bind_btBvhTriangleMeshShape_getLocalScaling_0 = function () { + return (mn = b._emscripten_bind_btBvhTriangleMeshShape_getLocalScaling_0 = b.asm.il).apply(null, arguments); + }), + nn = (b._emscripten_bind_btBvhTriangleMeshShape_calculateLocalInertia_2 = function () { + return (nn = b._emscripten_bind_btBvhTriangleMeshShape_calculateLocalInertia_2 = b.asm.jl).apply(null, arguments); + }), + on = (b._emscripten_bind_btBvhTriangleMeshShape___destroy___0 = function () { + return (on = b._emscripten_bind_btBvhTriangleMeshShape___destroy___0 = b.asm.kl).apply(null, arguments); + }), + pn = (b._emscripten_bind_btHeightfieldTerrainShape_btHeightfieldTerrainShape_9 = function () { + return (pn = b._emscripten_bind_btHeightfieldTerrainShape_btHeightfieldTerrainShape_9 = b.asm.ll).apply(null, arguments); + }), + qn = (b._emscripten_bind_btHeightfieldTerrainShape_setMargin_1 = function () { + return (qn = b._emscripten_bind_btHeightfieldTerrainShape_setMargin_1 = b.asm.ml).apply(null, arguments); + }), + rn = (b._emscripten_bind_btHeightfieldTerrainShape_getMargin_0 = function () { + return (rn = b._emscripten_bind_btHeightfieldTerrainShape_getMargin_0 = b.asm.nl).apply(null, arguments); + }), + sn = (b._emscripten_bind_btHeightfieldTerrainShape_setLocalScaling_1 = function () { + return (sn = b._emscripten_bind_btHeightfieldTerrainShape_setLocalScaling_1 = b.asm.ol).apply(null, arguments); + }), + tn = (b._emscripten_bind_btHeightfieldTerrainShape_getLocalScaling_0 = function () { + return (tn = b._emscripten_bind_btHeightfieldTerrainShape_getLocalScaling_0 = b.asm.pl).apply(null, arguments); + }), + un = (b._emscripten_bind_btHeightfieldTerrainShape_calculateLocalInertia_2 = function () { + return (un = b._emscripten_bind_btHeightfieldTerrainShape_calculateLocalInertia_2 = b.asm.ql).apply(null, arguments); + }), + vn = (b._emscripten_bind_btHeightfieldTerrainShape___destroy___0 = function () { + return (vn = b._emscripten_bind_btHeightfieldTerrainShape___destroy___0 = b.asm.rl).apply(null, arguments); + }), + wn = (b._emscripten_bind_btAABB_btAABB_4 = function () { + return (wn = b._emscripten_bind_btAABB_btAABB_4 = b.asm.sl).apply(null, arguments); + }), + xn = (b._emscripten_bind_btAABB_invalidate_0 = function () { + return (xn = b._emscripten_bind_btAABB_invalidate_0 = b.asm.tl).apply(null, arguments); + }), + yn = (b._emscripten_bind_btAABB_increment_margin_1 = function () { + return (yn = b._emscripten_bind_btAABB_increment_margin_1 = b.asm.ul).apply(null, arguments); + }), + zn = (b._emscripten_bind_btAABB_copy_with_margin_2 = function () { + return (zn = b._emscripten_bind_btAABB_copy_with_margin_2 = b.asm.vl).apply(null, arguments); + }), + An = (b._emscripten_bind_btAABB___destroy___0 = function () { + return (An = b._emscripten_bind_btAABB___destroy___0 = b.asm.wl).apply(null, arguments); + }), + Bn = (b._emscripten_bind_btPrimitiveTriangle_btPrimitiveTriangle_0 = function () { + return (Bn = b._emscripten_bind_btPrimitiveTriangle_btPrimitiveTriangle_0 = b.asm.xl).apply(null, arguments); + }), + Cn = (b._emscripten_bind_btPrimitiveTriangle___destroy___0 = function () { + return (Cn = b._emscripten_bind_btPrimitiveTriangle___destroy___0 = b.asm.yl).apply(null, arguments); + }), + Dn = (b._emscripten_bind_btTriangleShapeEx_btTriangleShapeEx_3 = function () { + return (Dn = b._emscripten_bind_btTriangleShapeEx_btTriangleShapeEx_3 = b.asm.zl).apply(null, arguments); + }), + En = (b._emscripten_bind_btTriangleShapeEx_getAabb_3 = function () { + return (En = b._emscripten_bind_btTriangleShapeEx_getAabb_3 = b.asm.Al).apply(null, arguments); + }), + Fn = (b._emscripten_bind_btTriangleShapeEx_applyTransform_1 = function () { + return (Fn = b._emscripten_bind_btTriangleShapeEx_applyTransform_1 = b.asm.Bl).apply(null, arguments); + }), + Gn = (b._emscripten_bind_btTriangleShapeEx_buildTriPlane_1 = function () { + return (Gn = b._emscripten_bind_btTriangleShapeEx_buildTriPlane_1 = b.asm.Cl).apply(null, arguments); + }), + Hn = (b._emscripten_bind_btTriangleShapeEx___destroy___0 = function () { + return (Hn = b._emscripten_bind_btTriangleShapeEx___destroy___0 = b.asm.Dl).apply(null, arguments); + }), + In = (b._emscripten_bind_btTetrahedronShapeEx_btTetrahedronShapeEx_0 = function () { + return (In = b._emscripten_bind_btTetrahedronShapeEx_btTetrahedronShapeEx_0 = b.asm.El).apply(null, arguments); + }), + Jn = (b._emscripten_bind_btTetrahedronShapeEx_setVertices_4 = function () { + return (Jn = b._emscripten_bind_btTetrahedronShapeEx_setVertices_4 = b.asm.Fl).apply(null, arguments); + }), + Kn = (b._emscripten_bind_btTetrahedronShapeEx___destroy___0 = function () { + return (Kn = b._emscripten_bind_btTetrahedronShapeEx___destroy___0 = b.asm.Gl).apply(null, arguments); + }), + Ln = (b._emscripten_bind_CompoundPrimitiveManager_get_primitive_count_0 = function () { + return (Ln = b._emscripten_bind_CompoundPrimitiveManager_get_primitive_count_0 = b.asm.Hl).apply(null, arguments); + }), + Mn = (b._emscripten_bind_CompoundPrimitiveManager_get_primitive_box_2 = function () { + return (Mn = b._emscripten_bind_CompoundPrimitiveManager_get_primitive_box_2 = b.asm.Il).apply(null, arguments); + }), + Nn = (b._emscripten_bind_CompoundPrimitiveManager_get_primitive_triangle_2 = function () { + return (Nn = b._emscripten_bind_CompoundPrimitiveManager_get_primitive_triangle_2 = b.asm.Jl).apply(null, arguments); + }), + On = (b._emscripten_bind_CompoundPrimitiveManager_is_trimesh_0 = function () { + return (On = b._emscripten_bind_CompoundPrimitiveManager_is_trimesh_0 = b.asm.Kl).apply(null, arguments); + }), + Pn = (b._emscripten_bind_CompoundPrimitiveManager_get_m_compoundShape_0 = function () { + return (Pn = b._emscripten_bind_CompoundPrimitiveManager_get_m_compoundShape_0 = b.asm.Ll).apply(null, arguments); + }), + Qn = (b._emscripten_bind_CompoundPrimitiveManager_set_m_compoundShape_1 = function () { + return (Qn = b._emscripten_bind_CompoundPrimitiveManager_set_m_compoundShape_1 = b.asm.Ml).apply(null, arguments); + }), + Rn = (b._emscripten_bind_CompoundPrimitiveManager___destroy___0 = function () { + return (Rn = b._emscripten_bind_CompoundPrimitiveManager___destroy___0 = b.asm.Nl).apply(null, arguments); + }), + Sn = (b._emscripten_bind_btGImpactCompoundShape_btGImpactCompoundShape_0 = function () { + return (Sn = b._emscripten_bind_btGImpactCompoundShape_btGImpactCompoundShape_0 = b.asm.Ol).apply(null, arguments); + }), + Tn = (b._emscripten_bind_btGImpactCompoundShape_btGImpactCompoundShape_1 = function () { + return (Tn = b._emscripten_bind_btGImpactCompoundShape_btGImpactCompoundShape_1 = b.asm.Pl).apply(null, arguments); + }), + Un = (b._emscripten_bind_btGImpactCompoundShape_childrenHasTransform_0 = function () { + return (Un = b._emscripten_bind_btGImpactCompoundShape_childrenHasTransform_0 = b.asm.Ql).apply(null, arguments); + }), + Vn = (b._emscripten_bind_btGImpactCompoundShape_getPrimitiveManager_0 = function () { + return (Vn = b._emscripten_bind_btGImpactCompoundShape_getPrimitiveManager_0 = b.asm.Rl).apply(null, arguments); + }), + Wn = (b._emscripten_bind_btGImpactCompoundShape_getCompoundPrimitiveManager_0 = function () { + return (Wn = b._emscripten_bind_btGImpactCompoundShape_getCompoundPrimitiveManager_0 = b.asm.Sl).apply(null, arguments); + }), + Xn = (b._emscripten_bind_btGImpactCompoundShape_getNumChildShapes_0 = function () { + return (Xn = b._emscripten_bind_btGImpactCompoundShape_getNumChildShapes_0 = b.asm.Tl).apply(null, arguments); + }), + Yn = (b._emscripten_bind_btGImpactCompoundShape_addChildShape_2 = function () { + return (Yn = b._emscripten_bind_btGImpactCompoundShape_addChildShape_2 = b.asm.Ul).apply(null, arguments); + }), + Zn = (b._emscripten_bind_btGImpactCompoundShape_getChildShape_1 = function () { + return (Zn = b._emscripten_bind_btGImpactCompoundShape_getChildShape_1 = b.asm.Vl).apply(null, arguments); + }), + $n = (b._emscripten_bind_btGImpactCompoundShape_getChildAabb_4 = function () { + return ($n = b._emscripten_bind_btGImpactCompoundShape_getChildAabb_4 = b.asm.Wl).apply(null, arguments); + }), + ao = (b._emscripten_bind_btGImpactCompoundShape_getChildTransform_1 = function () { + return (ao = b._emscripten_bind_btGImpactCompoundShape_getChildTransform_1 = b.asm.Xl).apply(null, arguments); + }), + bo = (b._emscripten_bind_btGImpactCompoundShape_setChildTransform_2 = function () { + return (bo = b._emscripten_bind_btGImpactCompoundShape_setChildTransform_2 = b.asm.Yl).apply(null, arguments); + }), + co = (b._emscripten_bind_btGImpactCompoundShape_calculateLocalInertia_2 = function () { + return (co = b._emscripten_bind_btGImpactCompoundShape_calculateLocalInertia_2 = b.asm.Zl).apply(null, arguments); + }), + eo = (b._emscripten_bind_btGImpactCompoundShape_getName_0 = function () { + return (eo = b._emscripten_bind_btGImpactCompoundShape_getName_0 = b.asm._l).apply(null, arguments); + }), + fo = (b._emscripten_bind_btGImpactCompoundShape_getGImpactShapeType_0 = function () { + return (fo = b._emscripten_bind_btGImpactCompoundShape_getGImpactShapeType_0 = b.asm.$l).apply(null, arguments); + }), + go = (b._emscripten_bind_btGImpactCompoundShape_setLocalScaling_1 = function () { + return (go = b._emscripten_bind_btGImpactCompoundShape_setLocalScaling_1 = b.asm.am).apply(null, arguments); + }), + ho = (b._emscripten_bind_btGImpactCompoundShape_getLocalScaling_0 = function () { + return (ho = b._emscripten_bind_btGImpactCompoundShape_getLocalScaling_0 = b.asm.bm).apply(null, arguments); + }), + io = (b._emscripten_bind_btGImpactCompoundShape_updateBound_0 = function () { + return (io = b._emscripten_bind_btGImpactCompoundShape_updateBound_0 = b.asm.cm).apply(null, arguments); + }), + jo = (b._emscripten_bind_btGImpactCompoundShape_postUpdate_0 = function () { + return (jo = b._emscripten_bind_btGImpactCompoundShape_postUpdate_0 = b.asm.dm).apply(null, arguments); + }), + ko = (b._emscripten_bind_btGImpactCompoundShape_getShapeType_0 = function () { + return (ko = b._emscripten_bind_btGImpactCompoundShape_getShapeType_0 = b.asm.em).apply(null, arguments); + }), + lo = (b._emscripten_bind_btGImpactCompoundShape_needsRetrieveTriangles_0 = function () { + return (lo = b._emscripten_bind_btGImpactCompoundShape_needsRetrieveTriangles_0 = b.asm.fm).apply(null, arguments); + }), + mo = (b._emscripten_bind_btGImpactCompoundShape_needsRetrieveTetrahedrons_0 = function () { + return (mo = b._emscripten_bind_btGImpactCompoundShape_needsRetrieveTetrahedrons_0 = b.asm.gm).apply(null, arguments); + }), + no = (b._emscripten_bind_btGImpactCompoundShape_getBulletTriangle_2 = function () { + return (no = b._emscripten_bind_btGImpactCompoundShape_getBulletTriangle_2 = b.asm.hm).apply(null, arguments); + }), + oo = (b._emscripten_bind_btGImpactCompoundShape_getBulletTetrahedron_2 = function () { + return (oo = b._emscripten_bind_btGImpactCompoundShape_getBulletTetrahedron_2 = b.asm.im).apply(null, arguments); + }), + po = (b._emscripten_bind_btGImpactCompoundShape___destroy___0 = function () { + return (po = b._emscripten_bind_btGImpactCompoundShape___destroy___0 = b.asm.jm).apply(null, arguments); + }), + qo = (b._emscripten_bind_TrimeshPrimitiveManager_TrimeshPrimitiveManager_0 = function () { + return (qo = b._emscripten_bind_TrimeshPrimitiveManager_TrimeshPrimitiveManager_0 = b.asm.km).apply(null, arguments); + }), + ro = (b._emscripten_bind_TrimeshPrimitiveManager_TrimeshPrimitiveManager_1 = function () { + return (ro = b._emscripten_bind_TrimeshPrimitiveManager_TrimeshPrimitiveManager_1 = b.asm.lm).apply(null, arguments); + }), + so = (b._emscripten_bind_TrimeshPrimitiveManager_lock_0 = function () { + return (so = b._emscripten_bind_TrimeshPrimitiveManager_lock_0 = b.asm.mm).apply(null, arguments); + }), + to = (b._emscripten_bind_TrimeshPrimitiveManager_unlock_0 = function () { + return (to = b._emscripten_bind_TrimeshPrimitiveManager_unlock_0 = b.asm.nm).apply(null, arguments); + }), + uo = (b._emscripten_bind_TrimeshPrimitiveManager_is_trimesh_0 = function () { + return (uo = b._emscripten_bind_TrimeshPrimitiveManager_is_trimesh_0 = b.asm.om).apply(null, arguments); + }), + vo = (b._emscripten_bind_TrimeshPrimitiveManager_get_vertex_count_0 = function () { + return (vo = b._emscripten_bind_TrimeshPrimitiveManager_get_vertex_count_0 = b.asm.pm).apply(null, arguments); + }), + wo = (b._emscripten_bind_TrimeshPrimitiveManager_get_indices_4 = function () { + return (wo = b._emscripten_bind_TrimeshPrimitiveManager_get_indices_4 = b.asm.qm).apply(null, arguments); + }), + xo = (b._emscripten_bind_TrimeshPrimitiveManager_get_vertex_2 = function () { + return (xo = b._emscripten_bind_TrimeshPrimitiveManager_get_vertex_2 = b.asm.rm).apply(null, arguments); + }), + yo = (b._emscripten_bind_TrimeshPrimitiveManager_get_bullet_triangle_2 = function () { + return (yo = b._emscripten_bind_TrimeshPrimitiveManager_get_bullet_triangle_2 = b.asm.sm).apply(null, arguments); + }), + zo = (b._emscripten_bind_TrimeshPrimitiveManager_get_m_margin_0 = function () { + return (zo = b._emscripten_bind_TrimeshPrimitiveManager_get_m_margin_0 = b.asm.tm).apply(null, arguments); + }), + Ao = (b._emscripten_bind_TrimeshPrimitiveManager_set_m_margin_1 = function () { + return (Ao = b._emscripten_bind_TrimeshPrimitiveManager_set_m_margin_1 = b.asm.um).apply(null, arguments); + }), + Bo = (b._emscripten_bind_TrimeshPrimitiveManager_get_m_meshInterface_0 = function () { + return (Bo = b._emscripten_bind_TrimeshPrimitiveManager_get_m_meshInterface_0 = b.asm.vm).apply(null, arguments); + }), + Co = (b._emscripten_bind_TrimeshPrimitiveManager_set_m_meshInterface_1 = function () { + return (Co = b._emscripten_bind_TrimeshPrimitiveManager_set_m_meshInterface_1 = b.asm.wm).apply(null, arguments); + }), + Do = (b._emscripten_bind_TrimeshPrimitiveManager_get_m_part_0 = function () { + return (Do = b._emscripten_bind_TrimeshPrimitiveManager_get_m_part_0 = b.asm.xm).apply(null, arguments); + }), + Eo = (b._emscripten_bind_TrimeshPrimitiveManager_set_m_part_1 = function () { + return (Eo = b._emscripten_bind_TrimeshPrimitiveManager_set_m_part_1 = b.asm.ym).apply(null, arguments); + }), + Fo = (b._emscripten_bind_TrimeshPrimitiveManager_get_m_lock_count_0 = function () { + return (Fo = b._emscripten_bind_TrimeshPrimitiveManager_get_m_lock_count_0 = b.asm.zm).apply(null, arguments); + }), + Go = (b._emscripten_bind_TrimeshPrimitiveManager_set_m_lock_count_1 = function () { + return (Go = b._emscripten_bind_TrimeshPrimitiveManager_set_m_lock_count_1 = b.asm.Am).apply(null, arguments); + }), + Ho = (b._emscripten_bind_TrimeshPrimitiveManager_get_numverts_0 = function () { + return (Ho = b._emscripten_bind_TrimeshPrimitiveManager_get_numverts_0 = b.asm.Bm).apply(null, arguments); + }), + Io = (b._emscripten_bind_TrimeshPrimitiveManager_set_numverts_1 = function () { + return (Io = b._emscripten_bind_TrimeshPrimitiveManager_set_numverts_1 = b.asm.Cm).apply(null, arguments); + }), + Jo = (b._emscripten_bind_TrimeshPrimitiveManager_get_type_0 = function () { + return (Jo = b._emscripten_bind_TrimeshPrimitiveManager_get_type_0 = b.asm.Dm).apply(null, arguments); + }), + Ko = (b._emscripten_bind_TrimeshPrimitiveManager_set_type_1 = function () { + return (Ko = b._emscripten_bind_TrimeshPrimitiveManager_set_type_1 = b.asm.Em).apply(null, arguments); + }), + Lo = (b._emscripten_bind_TrimeshPrimitiveManager_get_stride_0 = function () { + return (Lo = b._emscripten_bind_TrimeshPrimitiveManager_get_stride_0 = b.asm.Fm).apply(null, arguments); + }), + Mo = (b._emscripten_bind_TrimeshPrimitiveManager_set_stride_1 = function () { + return (Mo = b._emscripten_bind_TrimeshPrimitiveManager_set_stride_1 = b.asm.Gm).apply(null, arguments); + }), + No = (b._emscripten_bind_TrimeshPrimitiveManager_get_indexstride_0 = function () { + return (No = b._emscripten_bind_TrimeshPrimitiveManager_get_indexstride_0 = b.asm.Hm).apply(null, arguments); + }), + Oo = (b._emscripten_bind_TrimeshPrimitiveManager_set_indexstride_1 = function () { + return (Oo = b._emscripten_bind_TrimeshPrimitiveManager_set_indexstride_1 = b.asm.Im).apply(null, arguments); + }), + Po = (b._emscripten_bind_TrimeshPrimitiveManager_get_numfaces_0 = function () { + return (Po = b._emscripten_bind_TrimeshPrimitiveManager_get_numfaces_0 = b.asm.Jm).apply(null, arguments); + }), + Qo = (b._emscripten_bind_TrimeshPrimitiveManager_set_numfaces_1 = function () { + return (Qo = b._emscripten_bind_TrimeshPrimitiveManager_set_numfaces_1 = b.asm.Km).apply(null, arguments); + }), + Ro = (b._emscripten_bind_TrimeshPrimitiveManager_get_indicestype_0 = function () { + return (Ro = b._emscripten_bind_TrimeshPrimitiveManager_get_indicestype_0 = b.asm.Lm).apply(null, arguments); + }), + So = (b._emscripten_bind_TrimeshPrimitiveManager_set_indicestype_1 = function () { + return (So = b._emscripten_bind_TrimeshPrimitiveManager_set_indicestype_1 = b.asm.Mm).apply(null, arguments); + }), + To = (b._emscripten_bind_TrimeshPrimitiveManager___destroy___0 = function () { + return (To = b._emscripten_bind_TrimeshPrimitiveManager___destroy___0 = b.asm.Nm).apply(null, arguments); + }), + Uo = (b._emscripten_bind_btGImpactMeshShapePart_btGImpactMeshShapePart_2 = function () { + return (Uo = b._emscripten_bind_btGImpactMeshShapePart_btGImpactMeshShapePart_2 = b.asm.Om).apply(null, arguments); + }), + Vo = (b._emscripten_bind_btGImpactMeshShapePart_getTrimeshPrimitiveManager_0 = function () { + return (Vo = b._emscripten_bind_btGImpactMeshShapePart_getTrimeshPrimitiveManager_0 = b.asm.Pm).apply(null, arguments); + }), + Wo = (b._emscripten_bind_btGImpactMeshShapePart_getVertexCount_0 = function () { + return (Wo = b._emscripten_bind_btGImpactMeshShapePart_getVertexCount_0 = b.asm.Qm).apply(null, arguments); + }), + Xo = (b._emscripten_bind_btGImpactMeshShapePart_getVertex_2 = function () { + return (Xo = b._emscripten_bind_btGImpactMeshShapePart_getVertex_2 = b.asm.Rm).apply(null, arguments); + }), + Yo = (b._emscripten_bind_btGImpactMeshShapePart_getPart_0 = function () { + return (Yo = b._emscripten_bind_btGImpactMeshShapePart_getPart_0 = b.asm.Sm).apply(null, arguments); + }), + Zo = (b._emscripten_bind_btGImpactMeshShapePart_setLocalScaling_1 = function () { + return (Zo = b._emscripten_bind_btGImpactMeshShapePart_setLocalScaling_1 = b.asm.Tm).apply(null, arguments); + }), + $o = (b._emscripten_bind_btGImpactMeshShapePart_getLocalScaling_0 = function () { + return ($o = b._emscripten_bind_btGImpactMeshShapePart_getLocalScaling_0 = b.asm.Um).apply(null, arguments); + }), + ap = (b._emscripten_bind_btGImpactMeshShapePart_updateBound_0 = function () { + return (ap = b._emscripten_bind_btGImpactMeshShapePart_updateBound_0 = b.asm.Vm).apply(null, arguments); + }), + bp = (b._emscripten_bind_btGImpactMeshShapePart_postUpdate_0 = function () { + return (bp = b._emscripten_bind_btGImpactMeshShapePart_postUpdate_0 = b.asm.Wm).apply(null, arguments); + }), + cp = (b._emscripten_bind_btGImpactMeshShapePart_getShapeType_0 = function () { + return (cp = b._emscripten_bind_btGImpactMeshShapePart_getShapeType_0 = b.asm.Xm).apply(null, arguments); + }), + dp = (b._emscripten_bind_btGImpactMeshShapePart_needsRetrieveTriangles_0 = function () { + return (dp = b._emscripten_bind_btGImpactMeshShapePart_needsRetrieveTriangles_0 = b.asm.Ym).apply(null, arguments); + }), + ep = (b._emscripten_bind_btGImpactMeshShapePart_needsRetrieveTetrahedrons_0 = function () { + return (ep = b._emscripten_bind_btGImpactMeshShapePart_needsRetrieveTetrahedrons_0 = b.asm.Zm).apply(null, arguments); + }), + fp = (b._emscripten_bind_btGImpactMeshShapePart_getBulletTriangle_2 = function () { + return (fp = b._emscripten_bind_btGImpactMeshShapePart_getBulletTriangle_2 = b.asm._m).apply(null, arguments); + }), + gp = (b._emscripten_bind_btGImpactMeshShapePart_getBulletTetrahedron_2 = function () { + return (gp = b._emscripten_bind_btGImpactMeshShapePart_getBulletTetrahedron_2 = b.asm.$m).apply(null, arguments); + }), + hp = (b._emscripten_bind_btGImpactMeshShapePart___destroy___0 = function () { + return (hp = b._emscripten_bind_btGImpactMeshShapePart___destroy___0 = b.asm.an).apply(null, arguments); + }), + ip = (b._emscripten_bind_btGImpactMeshShape_btGImpactMeshShape_1 = function () { + return (ip = b._emscripten_bind_btGImpactMeshShape_btGImpactMeshShape_1 = b.asm.bn).apply(null, arguments); + }), + jp = (b._emscripten_bind_btGImpactMeshShape_getMeshInterface_0 = function () { + return (jp = b._emscripten_bind_btGImpactMeshShape_getMeshInterface_0 = b.asm.cn).apply(null, arguments); + }), + kp = (b._emscripten_bind_btGImpactMeshShape_getMeshPartCount_0 = function () { + return (kp = b._emscripten_bind_btGImpactMeshShape_getMeshPartCount_0 = b.asm.dn).apply(null, arguments); + }), + lp = (b._emscripten_bind_btGImpactMeshShape_getMeshPart_1 = function () { + return (lp = b._emscripten_bind_btGImpactMeshShape_getMeshPart_1 = b.asm.en).apply(null, arguments); + }), + mp = (b._emscripten_bind_btGImpactMeshShape_calculateSerializeBufferSize_0 = function () { + return (mp = b._emscripten_bind_btGImpactMeshShape_calculateSerializeBufferSize_0 = b.asm.fn).apply(null, arguments); + }), + np = (b._emscripten_bind_btGImpactMeshShape_setLocalScaling_1 = function () { + return (np = b._emscripten_bind_btGImpactMeshShape_setLocalScaling_1 = b.asm.gn).apply(null, arguments); + }), + op = (b._emscripten_bind_btGImpactMeshShape_getLocalScaling_0 = function () { + return (op = b._emscripten_bind_btGImpactMeshShape_getLocalScaling_0 = b.asm.hn).apply(null, arguments); + }), + pp = (b._emscripten_bind_btGImpactMeshShape_updateBound_0 = function () { + return (pp = b._emscripten_bind_btGImpactMeshShape_updateBound_0 = b.asm.jn).apply(null, arguments); + }), + qp = (b._emscripten_bind_btGImpactMeshShape_postUpdate_0 = function () { + return (qp = b._emscripten_bind_btGImpactMeshShape_postUpdate_0 = b.asm.kn).apply(null, arguments); + }), + rp = (b._emscripten_bind_btGImpactMeshShape_getShapeType_0 = function () { + return (rp = b._emscripten_bind_btGImpactMeshShape_getShapeType_0 = b.asm.ln).apply(null, arguments); + }), + sp = (b._emscripten_bind_btGImpactMeshShape_needsRetrieveTriangles_0 = function () { + return (sp = b._emscripten_bind_btGImpactMeshShape_needsRetrieveTriangles_0 = b.asm.mn).apply(null, arguments); + }), + tp = (b._emscripten_bind_btGImpactMeshShape_needsRetrieveTetrahedrons_0 = function () { + return (tp = b._emscripten_bind_btGImpactMeshShape_needsRetrieveTetrahedrons_0 = b.asm.nn).apply(null, arguments); + }), + up = (b._emscripten_bind_btGImpactMeshShape_getBulletTriangle_2 = function () { + return (up = b._emscripten_bind_btGImpactMeshShape_getBulletTriangle_2 = b.asm.on).apply(null, arguments); + }), + vp = (b._emscripten_bind_btGImpactMeshShape_getBulletTetrahedron_2 = function () { + return (vp = b._emscripten_bind_btGImpactMeshShape_getBulletTetrahedron_2 = b.asm.pn).apply(null, arguments); + }), + wp = (b._emscripten_bind_btGImpactMeshShape___destroy___0 = function () { + return (wp = b._emscripten_bind_btGImpactMeshShape___destroy___0 = b.asm.qn).apply(null, arguments); + }), + xp = (b._emscripten_bind_btCollisionAlgorithmConstructionInfo_btCollisionAlgorithmConstructionInfo_0 = function () { + return (xp = b._emscripten_bind_btCollisionAlgorithmConstructionInfo_btCollisionAlgorithmConstructionInfo_0 = b.asm.rn).apply(null, arguments); + }), + yp = (b._emscripten_bind_btCollisionAlgorithmConstructionInfo_btCollisionAlgorithmConstructionInfo_2 = function () { + return (yp = b._emscripten_bind_btCollisionAlgorithmConstructionInfo_btCollisionAlgorithmConstructionInfo_2 = b.asm.sn).apply(null, arguments); + }), + zp = (b._emscripten_bind_btCollisionAlgorithmConstructionInfo_get_m_dispatcher1_0 = function () { + return (zp = b._emscripten_bind_btCollisionAlgorithmConstructionInfo_get_m_dispatcher1_0 = b.asm.tn).apply(null, arguments); + }), + Ap = (b._emscripten_bind_btCollisionAlgorithmConstructionInfo_set_m_dispatcher1_1 = function () { + return (Ap = b._emscripten_bind_btCollisionAlgorithmConstructionInfo_set_m_dispatcher1_1 = b.asm.un).apply(null, arguments); + }), + Bp = (b._emscripten_bind_btCollisionAlgorithmConstructionInfo_get_m_manifold_0 = function () { + return (Bp = b._emscripten_bind_btCollisionAlgorithmConstructionInfo_get_m_manifold_0 = b.asm.vn).apply(null, arguments); + }), + Cp = (b._emscripten_bind_btCollisionAlgorithmConstructionInfo_set_m_manifold_1 = function () { + return (Cp = b._emscripten_bind_btCollisionAlgorithmConstructionInfo_set_m_manifold_1 = b.asm.wn).apply(null, arguments); + }), + Dp = (b._emscripten_bind_btCollisionAlgorithmConstructionInfo___destroy___0 = function () { + return (Dp = b._emscripten_bind_btCollisionAlgorithmConstructionInfo___destroy___0 = b.asm.xn).apply(null, arguments); + }), + Ep = (b._emscripten_bind_btGImpactCollisionAlgorithm_btGImpactCollisionAlgorithm_3 = function () { + return (Ep = b._emscripten_bind_btGImpactCollisionAlgorithm_btGImpactCollisionAlgorithm_3 = b.asm.yn).apply(null, arguments); + }), + Fp = (b._emscripten_bind_btGImpactCollisionAlgorithm_registerAlgorithm_1 = function () { + return (Fp = b._emscripten_bind_btGImpactCollisionAlgorithm_registerAlgorithm_1 = b.asm.zn).apply(null, arguments); + }), + Gp = (b._emscripten_bind_btGImpactCollisionAlgorithm___destroy___0 = function () { + return (Gp = b._emscripten_bind_btGImpactCollisionAlgorithm___destroy___0 = b.asm.An).apply(null, arguments); + }), + Hp = (b._emscripten_bind_btDefaultCollisionConstructionInfo_btDefaultCollisionConstructionInfo_0 = function () { + return (Hp = b._emscripten_bind_btDefaultCollisionConstructionInfo_btDefaultCollisionConstructionInfo_0 = b.asm.Bn).apply(null, arguments); + }), + Ip = (b._emscripten_bind_btDefaultCollisionConstructionInfo___destroy___0 = function () { + return (Ip = b._emscripten_bind_btDefaultCollisionConstructionInfo___destroy___0 = b.asm.Cn).apply(null, arguments); + }), + Jp = (b._emscripten_bind_btPersistentManifold_btPersistentManifold_0 = function () { + return (Jp = b._emscripten_bind_btPersistentManifold_btPersistentManifold_0 = b.asm.Dn).apply(null, arguments); + }), + Kp = (b._emscripten_bind_btPersistentManifold_getBody0_0 = function () { + return (Kp = b._emscripten_bind_btPersistentManifold_getBody0_0 = b.asm.En).apply(null, arguments); + }), + Lp = (b._emscripten_bind_btPersistentManifold_getBody1_0 = function () { + return (Lp = b._emscripten_bind_btPersistentManifold_getBody1_0 = b.asm.Fn).apply(null, arguments); + }), + Mp = (b._emscripten_bind_btPersistentManifold_getNumContacts_0 = function () { + return (Mp = b._emscripten_bind_btPersistentManifold_getNumContacts_0 = b.asm.Gn).apply(null, arguments); + }), + Np = (b._emscripten_bind_btPersistentManifold_getContactPoint_1 = function () { + return (Np = b._emscripten_bind_btPersistentManifold_getContactPoint_1 = b.asm.Hn).apply(null, arguments); + }), + Op = (b._emscripten_bind_btPersistentManifold___destroy___0 = function () { + return (Op = b._emscripten_bind_btPersistentManifold___destroy___0 = b.asm.In).apply(null, arguments); + }), + Pp = (b._emscripten_bind_btCollisionDispatcher_btCollisionDispatcher_1 = function () { + return (Pp = b._emscripten_bind_btCollisionDispatcher_btCollisionDispatcher_1 = b.asm.Jn).apply(null, arguments); + }), + Qp = (b._emscripten_bind_btCollisionDispatcher_getNumManifolds_0 = function () { + return (Qp = b._emscripten_bind_btCollisionDispatcher_getNumManifolds_0 = b.asm.Kn).apply(null, arguments); + }), + Rp = (b._emscripten_bind_btCollisionDispatcher_getManifoldByIndexInternal_1 = function () { + return (Rp = b._emscripten_bind_btCollisionDispatcher_getManifoldByIndexInternal_1 = b.asm.Ln).apply(null, arguments); + }), + Sp = (b._emscripten_bind_btCollisionDispatcher___destroy___0 = function () { + return (Sp = b._emscripten_bind_btCollisionDispatcher___destroy___0 = b.asm.Mn).apply(null, arguments); + }), + Tp = (b._emscripten_bind_btOverlappingPairCallback___destroy___0 = function () { + return (Tp = b._emscripten_bind_btOverlappingPairCallback___destroy___0 = b.asm.Nn).apply(null, arguments); + }), + Up = (b._emscripten_bind_btOverlappingPairCache_setInternalGhostPairCallback_1 = function () { + return (Up = b._emscripten_bind_btOverlappingPairCache_setInternalGhostPairCallback_1 = b.asm.On).apply(null, arguments); + }), + Vp = (b._emscripten_bind_btOverlappingPairCache_getNumOverlappingPairs_0 = function () { + return (Vp = b._emscripten_bind_btOverlappingPairCache_getNumOverlappingPairs_0 = b.asm.Pn).apply(null, arguments); + }), + Wp = (b._emscripten_bind_btOverlappingPairCache___destroy___0 = function () { + return (Wp = b._emscripten_bind_btOverlappingPairCache___destroy___0 = b.asm.Qn).apply(null, arguments); + }), + Xp = (b._emscripten_bind_btAxisSweep3_btAxisSweep3_2 = function () { + return (Xp = b._emscripten_bind_btAxisSweep3_btAxisSweep3_2 = b.asm.Rn).apply(null, arguments); + }), + Yp = (b._emscripten_bind_btAxisSweep3_btAxisSweep3_3 = function () { + return (Yp = b._emscripten_bind_btAxisSweep3_btAxisSweep3_3 = b.asm.Sn).apply(null, arguments); + }), + Zp = (b._emscripten_bind_btAxisSweep3_btAxisSweep3_4 = function () { + return (Zp = b._emscripten_bind_btAxisSweep3_btAxisSweep3_4 = b.asm.Tn).apply(null, arguments); + }), + $p = (b._emscripten_bind_btAxisSweep3_btAxisSweep3_5 = function () { + return ($p = b._emscripten_bind_btAxisSweep3_btAxisSweep3_5 = b.asm.Un).apply(null, arguments); + }), + aq = (b._emscripten_bind_btAxisSweep3___destroy___0 = function () { + return (aq = b._emscripten_bind_btAxisSweep3___destroy___0 = b.asm.Vn).apply(null, arguments); + }), + bq = (b._emscripten_bind_btBroadphaseInterface_getOverlappingPairCache_0 = function () { + return (bq = b._emscripten_bind_btBroadphaseInterface_getOverlappingPairCache_0 = b.asm.Wn).apply(null, arguments); + }), + cq = (b._emscripten_bind_btBroadphaseInterface___destroy___0 = function () { + return (cq = b._emscripten_bind_btBroadphaseInterface___destroy___0 = b.asm.Xn).apply(null, arguments); + }), + dq = (b._emscripten_bind_btCollisionConfiguration___destroy___0 = function () { + return (dq = b._emscripten_bind_btCollisionConfiguration___destroy___0 = b.asm.Yn).apply(null, arguments); + }), + eq = (b._emscripten_bind_btDbvtBroadphase_btDbvtBroadphase_0 = function () { + return (eq = b._emscripten_bind_btDbvtBroadphase_btDbvtBroadphase_0 = b.asm.Zn).apply(null, arguments); + }), + fq = (b._emscripten_bind_btDbvtBroadphase___destroy___0 = function () { + return (fq = b._emscripten_bind_btDbvtBroadphase___destroy___0 = b.asm._n).apply(null, arguments); + }), + gq = (b._emscripten_bind_btBroadphaseProxy_get_m_collisionFilterGroup_0 = function () { + return (gq = b._emscripten_bind_btBroadphaseProxy_get_m_collisionFilterGroup_0 = b.asm.$n).apply(null, arguments); + }), + hq = (b._emscripten_bind_btBroadphaseProxy_set_m_collisionFilterGroup_1 = function () { + return (hq = b._emscripten_bind_btBroadphaseProxy_set_m_collisionFilterGroup_1 = b.asm.ao).apply(null, arguments); + }), + iq = (b._emscripten_bind_btBroadphaseProxy_get_m_collisionFilterMask_0 = function () { + return (iq = b._emscripten_bind_btBroadphaseProxy_get_m_collisionFilterMask_0 = b.asm.bo).apply(null, arguments); + }), + jq = (b._emscripten_bind_btBroadphaseProxy_set_m_collisionFilterMask_1 = function () { + return (jq = b._emscripten_bind_btBroadphaseProxy_set_m_collisionFilterMask_1 = b.asm.co).apply(null, arguments); + }), + kq = (b._emscripten_bind_btBroadphaseProxy___destroy___0 = function () { + return (kq = b._emscripten_bind_btBroadphaseProxy___destroy___0 = b.asm.eo).apply(null, arguments); + }), + lq = (b._emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_3 = function () { + return (lq = b._emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_3 = b.asm.fo).apply(null, arguments); + }), + mq = (b._emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_4 = function () { + return (mq = b._emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_4 = b.asm.go).apply(null, arguments); + }), + nq = (b._emscripten_bind_btRigidBodyConstructionInfo_get_m_linearDamping_0 = function () { + return (nq = b._emscripten_bind_btRigidBodyConstructionInfo_get_m_linearDamping_0 = b.asm.ho).apply(null, arguments); + }), + oq = (b._emscripten_bind_btRigidBodyConstructionInfo_set_m_linearDamping_1 = function () { + return (oq = b._emscripten_bind_btRigidBodyConstructionInfo_set_m_linearDamping_1 = b.asm.io).apply(null, arguments); + }), + pq = (b._emscripten_bind_btRigidBodyConstructionInfo_get_m_angularDamping_0 = function () { + return (pq = b._emscripten_bind_btRigidBodyConstructionInfo_get_m_angularDamping_0 = b.asm.jo).apply(null, arguments); + }), + qq = (b._emscripten_bind_btRigidBodyConstructionInfo_set_m_angularDamping_1 = function () { + return (qq = b._emscripten_bind_btRigidBodyConstructionInfo_set_m_angularDamping_1 = b.asm.ko).apply(null, arguments); + }), + rq = (b._emscripten_bind_btRigidBodyConstructionInfo_get_m_friction_0 = function () { + return (rq = b._emscripten_bind_btRigidBodyConstructionInfo_get_m_friction_0 = b.asm.lo).apply(null, arguments); + }), + sq = (b._emscripten_bind_btRigidBodyConstructionInfo_set_m_friction_1 = function () { + return (sq = b._emscripten_bind_btRigidBodyConstructionInfo_set_m_friction_1 = b.asm.mo).apply(null, arguments); + }), + tq = (b._emscripten_bind_btRigidBodyConstructionInfo_get_m_rollingFriction_0 = function () { + return (tq = b._emscripten_bind_btRigidBodyConstructionInfo_get_m_rollingFriction_0 = b.asm.no).apply(null, arguments); + }), + uq = (b._emscripten_bind_btRigidBodyConstructionInfo_set_m_rollingFriction_1 = function () { + return (uq = b._emscripten_bind_btRigidBodyConstructionInfo_set_m_rollingFriction_1 = b.asm.oo).apply(null, arguments); + }), + vq = (b._emscripten_bind_btRigidBodyConstructionInfo_get_m_restitution_0 = function () { + return (vq = b._emscripten_bind_btRigidBodyConstructionInfo_get_m_restitution_0 = b.asm.po).apply(null, arguments); + }), + wq = (b._emscripten_bind_btRigidBodyConstructionInfo_set_m_restitution_1 = function () { + return (wq = b._emscripten_bind_btRigidBodyConstructionInfo_set_m_restitution_1 = b.asm.qo).apply(null, arguments); + }), + xq = (b._emscripten_bind_btRigidBodyConstructionInfo_get_m_linearSleepingThreshold_0 = function () { + return (xq = b._emscripten_bind_btRigidBodyConstructionInfo_get_m_linearSleepingThreshold_0 = b.asm.ro).apply(null, arguments); + }), + yq = (b._emscripten_bind_btRigidBodyConstructionInfo_set_m_linearSleepingThreshold_1 = function () { + return (yq = b._emscripten_bind_btRigidBodyConstructionInfo_set_m_linearSleepingThreshold_1 = b.asm.so).apply(null, arguments); + }), + zq = (b._emscripten_bind_btRigidBodyConstructionInfo_get_m_angularSleepingThreshold_0 = function () { + return (zq = b._emscripten_bind_btRigidBodyConstructionInfo_get_m_angularSleepingThreshold_0 = b.asm.to).apply(null, arguments); + }), + Aq = (b._emscripten_bind_btRigidBodyConstructionInfo_set_m_angularSleepingThreshold_1 = function () { + return (Aq = b._emscripten_bind_btRigidBodyConstructionInfo_set_m_angularSleepingThreshold_1 = b.asm.uo).apply(null, arguments); + }), + Bq = (b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDamping_0 = function () { + return (Bq = b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDamping_0 = b.asm.vo).apply(null, arguments); + }), + Cq = (b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDamping_1 = function () { + return (Cq = b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDamping_1 = b.asm.wo).apply(null, arguments); + }), + Dq = (b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDampingFactor_0 = function () { + return (Dq = b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDampingFactor_0 = b.asm.xo).apply(null, arguments); + }), + Eq = (b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDampingFactor_1 = function () { + return (Eq = b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDampingFactor_1 = b.asm.yo).apply(null, arguments); + }), + Fq = (b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalLinearDampingThresholdSqr_0 = function () { + return (Fq = b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalLinearDampingThresholdSqr_0 = b.asm.zo).apply(null, arguments); + }), + Gq = (b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalLinearDampingThresholdSqr_1 = function () { + return (Gq = b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalLinearDampingThresholdSqr_1 = b.asm.Ao).apply(null, arguments); + }), + Hq = (b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingThresholdSqr_0 = function () { + return (Hq = b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingThresholdSqr_0 = b.asm.Bo).apply(null, arguments); + }), + Iq = (b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingThresholdSqr_1 = function () { + return (Iq = b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingThresholdSqr_1 = b.asm.Co).apply(null, arguments); + }), + Jq = (b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingFactor_0 = function () { + return (Jq = b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingFactor_0 = b.asm.Do).apply(null, arguments); + }), + Kq = (b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingFactor_1 = function () { + return (Kq = b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingFactor_1 = b.asm.Eo).apply(null, arguments); + }), + Lq = (b._emscripten_bind_btRigidBodyConstructionInfo___destroy___0 = function () { + return (Lq = b._emscripten_bind_btRigidBodyConstructionInfo___destroy___0 = b.asm.Fo).apply(null, arguments); + }), + Mq = (b._emscripten_bind_btRigidBody_btRigidBody_1 = function () { + return (Mq = b._emscripten_bind_btRigidBody_btRigidBody_1 = b.asm.Go).apply(null, arguments); + }), + Nq = (b._emscripten_bind_btRigidBody_getCenterOfMassTransform_0 = function () { + return (Nq = b._emscripten_bind_btRigidBody_getCenterOfMassTransform_0 = b.asm.Ho).apply(null, arguments); + }), + Oq = (b._emscripten_bind_btRigidBody_setCenterOfMassTransform_1 = function () { + return (Oq = b._emscripten_bind_btRigidBody_setCenterOfMassTransform_1 = b.asm.Io).apply(null, arguments); + }), + Pq = (b._emscripten_bind_btRigidBody_setSleepingThresholds_2 = function () { + return (Pq = b._emscripten_bind_btRigidBody_setSleepingThresholds_2 = b.asm.Jo).apply(null, arguments); + }), + Qq = (b._emscripten_bind_btRigidBody_getLinearDamping_0 = function () { + return (Qq = b._emscripten_bind_btRigidBody_getLinearDamping_0 = b.asm.Ko).apply(null, arguments); + }), + Rq = (b._emscripten_bind_btRigidBody_getAngularDamping_0 = function () { + return (Rq = b._emscripten_bind_btRigidBody_getAngularDamping_0 = b.asm.Lo).apply(null, arguments); + }), + Sq = (b._emscripten_bind_btRigidBody_setDamping_2 = function () { + return (Sq = b._emscripten_bind_btRigidBody_setDamping_2 = b.asm.Mo).apply(null, arguments); + }), + Tq = (b._emscripten_bind_btRigidBody_setMassProps_2 = function () { + return (Tq = b._emscripten_bind_btRigidBody_setMassProps_2 = b.asm.No).apply(null, arguments); + }), + Uq = (b._emscripten_bind_btRigidBody_getLinearFactor_0 = function () { + return (Uq = b._emscripten_bind_btRigidBody_getLinearFactor_0 = b.asm.Oo).apply(null, arguments); + }), + Vq = (b._emscripten_bind_btRigidBody_setLinearFactor_1 = function () { + return (Vq = b._emscripten_bind_btRigidBody_setLinearFactor_1 = b.asm.Po).apply(null, arguments); + }), + Wq = (b._emscripten_bind_btRigidBody_applyTorque_1 = function () { + return (Wq = b._emscripten_bind_btRigidBody_applyTorque_1 = b.asm.Qo).apply(null, arguments); + }), + Xq = (b._emscripten_bind_btRigidBody_applyLocalTorque_1 = function () { + return (Xq = b._emscripten_bind_btRigidBody_applyLocalTorque_1 = b.asm.Ro).apply(null, arguments); + }), + Yq = (b._emscripten_bind_btRigidBody_applyForce_2 = function () { + return (Yq = b._emscripten_bind_btRigidBody_applyForce_2 = b.asm.So).apply(null, arguments); + }), + Zq = (b._emscripten_bind_btRigidBody_applyCentralForce_1 = function () { + return (Zq = b._emscripten_bind_btRigidBody_applyCentralForce_1 = b.asm.To).apply(null, arguments); + }), + $q = (b._emscripten_bind_btRigidBody_applyCentralLocalForce_1 = function () { + return ($q = b._emscripten_bind_btRigidBody_applyCentralLocalForce_1 = b.asm.Uo).apply(null, arguments); + }), + ar = (b._emscripten_bind_btRigidBody_applyTorqueImpulse_1 = function () { + return (ar = b._emscripten_bind_btRigidBody_applyTorqueImpulse_1 = b.asm.Vo).apply(null, arguments); + }), + br = (b._emscripten_bind_btRigidBody_applyImpulse_2 = function () { + return (br = b._emscripten_bind_btRigidBody_applyImpulse_2 = b.asm.Wo).apply(null, arguments); + }), + cr = (b._emscripten_bind_btRigidBody_applyCentralImpulse_1 = function () { + return (cr = b._emscripten_bind_btRigidBody_applyCentralImpulse_1 = b.asm.Xo).apply(null, arguments); + }), + dr = (b._emscripten_bind_btRigidBody_updateInertiaTensor_0 = function () { + return (dr = b._emscripten_bind_btRigidBody_updateInertiaTensor_0 = b.asm.Yo).apply(null, arguments); + }), + er = (b._emscripten_bind_btRigidBody_getLinearVelocity_0 = function () { + return (er = b._emscripten_bind_btRigidBody_getLinearVelocity_0 = b.asm.Zo).apply(null, arguments); + }), + fr = (b._emscripten_bind_btRigidBody_getAngularVelocity_0 = function () { + return (fr = b._emscripten_bind_btRigidBody_getAngularVelocity_0 = b.asm._o).apply(null, arguments); + }), + gr = (b._emscripten_bind_btRigidBody_setLinearVelocity_1 = function () { + return (gr = b._emscripten_bind_btRigidBody_setLinearVelocity_1 = b.asm.$o).apply(null, arguments); + }), + hr = (b._emscripten_bind_btRigidBody_setAngularVelocity_1 = function () { + return (hr = b._emscripten_bind_btRigidBody_setAngularVelocity_1 = b.asm.ap).apply(null, arguments); + }), + ir = (b._emscripten_bind_btRigidBody_getMotionState_0 = function () { + return (ir = b._emscripten_bind_btRigidBody_getMotionState_0 = b.asm.bp).apply(null, arguments); + }), + jr = (b._emscripten_bind_btRigidBody_setMotionState_1 = function () { + return (jr = b._emscripten_bind_btRigidBody_setMotionState_1 = b.asm.cp).apply(null, arguments); + }), + kr = (b._emscripten_bind_btRigidBody_getAngularFactor_0 = function () { + return (kr = b._emscripten_bind_btRigidBody_getAngularFactor_0 = b.asm.dp).apply(null, arguments); + }), + lr = (b._emscripten_bind_btRigidBody_setAngularFactor_1 = function () { + return (lr = b._emscripten_bind_btRigidBody_setAngularFactor_1 = b.asm.ep).apply(null, arguments); + }), + mr = (b._emscripten_bind_btRigidBody_upcast_1 = function () { + return (mr = b._emscripten_bind_btRigidBody_upcast_1 = b.asm.fp).apply(null, arguments); + }), + nr = (b._emscripten_bind_btRigidBody_getAabb_2 = function () { + return (nr = b._emscripten_bind_btRigidBody_getAabb_2 = b.asm.gp).apply(null, arguments); + }), + or = (b._emscripten_bind_btRigidBody_applyGravity_0 = function () { + return (or = b._emscripten_bind_btRigidBody_applyGravity_0 = b.asm.hp).apply(null, arguments); + }), + pr = (b._emscripten_bind_btRigidBody_getGravity_0 = function () { + return (pr = b._emscripten_bind_btRigidBody_getGravity_0 = b.asm.ip).apply(null, arguments); + }), + qr = (b._emscripten_bind_btRigidBody_setGravity_1 = function () { + return (qr = b._emscripten_bind_btRigidBody_setGravity_1 = b.asm.jp).apply(null, arguments); + }), + rr = (b._emscripten_bind_btRigidBody_getBroadphaseProxy_0 = function () { + return (rr = b._emscripten_bind_btRigidBody_getBroadphaseProxy_0 = b.asm.kp).apply(null, arguments); + }), + sr = (b._emscripten_bind_btRigidBody_clearForces_0 = function () { + return (sr = b._emscripten_bind_btRigidBody_clearForces_0 = b.asm.lp).apply(null, arguments); + }), + tr = (b._emscripten_bind_btRigidBody_setAnisotropicFriction_2 = function () { + return (tr = b._emscripten_bind_btRigidBody_setAnisotropicFriction_2 = b.asm.mp).apply(null, arguments); + }), + ur = (b._emscripten_bind_btRigidBody_getCollisionShape_0 = function () { + return (ur = b._emscripten_bind_btRigidBody_getCollisionShape_0 = b.asm.np).apply(null, arguments); + }), + vr = (b._emscripten_bind_btRigidBody_setContactProcessingThreshold_1 = function () { + return (vr = b._emscripten_bind_btRigidBody_setContactProcessingThreshold_1 = b.asm.op).apply(null, arguments); + }), + wr = (b._emscripten_bind_btRigidBody_setActivationState_1 = function () { + return (wr = b._emscripten_bind_btRigidBody_setActivationState_1 = b.asm.pp).apply(null, arguments); + }), + xr = (b._emscripten_bind_btRigidBody_forceActivationState_1 = function () { + return (xr = b._emscripten_bind_btRigidBody_forceActivationState_1 = b.asm.qp).apply(null, arguments); + }), + yr = (b._emscripten_bind_btRigidBody_activate_0 = function () { + return (yr = b._emscripten_bind_btRigidBody_activate_0 = b.asm.rp).apply(null, arguments); + }), + zr = (b._emscripten_bind_btRigidBody_activate_1 = function () { + return (zr = b._emscripten_bind_btRigidBody_activate_1 = b.asm.sp).apply(null, arguments); + }), + Ar = (b._emscripten_bind_btRigidBody_isActive_0 = function () { + return (Ar = b._emscripten_bind_btRigidBody_isActive_0 = b.asm.tp).apply(null, arguments); + }), + Br = (b._emscripten_bind_btRigidBody_isKinematicObject_0 = function () { + return (Br = b._emscripten_bind_btRigidBody_isKinematicObject_0 = b.asm.up).apply(null, arguments); + }), + Cr = (b._emscripten_bind_btRigidBody_isStaticObject_0 = function () { + return (Cr = b._emscripten_bind_btRigidBody_isStaticObject_0 = b.asm.vp).apply(null, arguments); + }), + Dr = (b._emscripten_bind_btRigidBody_isStaticOrKinematicObject_0 = function () { + return (Dr = b._emscripten_bind_btRigidBody_isStaticOrKinematicObject_0 = b.asm.wp).apply(null, arguments); + }), + Er = (b._emscripten_bind_btRigidBody_getRestitution_0 = function () { + return (Er = b._emscripten_bind_btRigidBody_getRestitution_0 = b.asm.xp).apply(null, arguments); + }), + Fr = (b._emscripten_bind_btRigidBody_getFriction_0 = function () { + return (Fr = b._emscripten_bind_btRigidBody_getFriction_0 = b.asm.yp).apply(null, arguments); + }), + Gr = (b._emscripten_bind_btRigidBody_getRollingFriction_0 = function () { + return (Gr = b._emscripten_bind_btRigidBody_getRollingFriction_0 = b.asm.zp).apply(null, arguments); + }), + Hr = (b._emscripten_bind_btRigidBody_setRestitution_1 = function () { + return (Hr = b._emscripten_bind_btRigidBody_setRestitution_1 = b.asm.Ap).apply(null, arguments); + }), + Ir = (b._emscripten_bind_btRigidBody_setFriction_1 = function () { + return (Ir = b._emscripten_bind_btRigidBody_setFriction_1 = b.asm.Bp).apply(null, arguments); + }), + Jr = (b._emscripten_bind_btRigidBody_setRollingFriction_1 = function () { + return (Jr = b._emscripten_bind_btRigidBody_setRollingFriction_1 = b.asm.Cp).apply(null, arguments); + }), + Kr = (b._emscripten_bind_btRigidBody_getWorldTransform_0 = function () { + return (Kr = b._emscripten_bind_btRigidBody_getWorldTransform_0 = b.asm.Dp).apply(null, arguments); + }), + Lr = (b._emscripten_bind_btRigidBody_getCollisionFlags_0 = function () { + return (Lr = b._emscripten_bind_btRigidBody_getCollisionFlags_0 = b.asm.Ep).apply(null, arguments); + }), + Mr = (b._emscripten_bind_btRigidBody_setCollisionFlags_1 = function () { + return (Mr = b._emscripten_bind_btRigidBody_setCollisionFlags_1 = b.asm.Fp).apply(null, arguments); + }), + Nr = (b._emscripten_bind_btRigidBody_setWorldTransform_1 = function () { + return (Nr = b._emscripten_bind_btRigidBody_setWorldTransform_1 = b.asm.Gp).apply(null, arguments); + }), + Or = (b._emscripten_bind_btRigidBody_setCollisionShape_1 = function () { + return (Or = b._emscripten_bind_btRigidBody_setCollisionShape_1 = b.asm.Hp).apply(null, arguments); + }), + Pr = (b._emscripten_bind_btRigidBody_setCcdMotionThreshold_1 = function () { + return (Pr = b._emscripten_bind_btRigidBody_setCcdMotionThreshold_1 = b.asm.Ip).apply(null, arguments); + }), + Qr = (b._emscripten_bind_btRigidBody_setCcdSweptSphereRadius_1 = function () { + return (Qr = b._emscripten_bind_btRigidBody_setCcdSweptSphereRadius_1 = b.asm.Jp).apply(null, arguments); + }), + Rr = (b._emscripten_bind_btRigidBody_getUserIndex_0 = function () { + return (Rr = b._emscripten_bind_btRigidBody_getUserIndex_0 = b.asm.Kp).apply(null, arguments); + }), + Sr = (b._emscripten_bind_btRigidBody_setUserIndex_1 = function () { + return (Sr = b._emscripten_bind_btRigidBody_setUserIndex_1 = b.asm.Lp).apply(null, arguments); + }), + Tr = (b._emscripten_bind_btRigidBody_getUserPointer_0 = function () { + return (Tr = b._emscripten_bind_btRigidBody_getUserPointer_0 = b.asm.Mp).apply(null, arguments); + }), + Ur = (b._emscripten_bind_btRigidBody_setUserPointer_1 = function () { + return (Ur = b._emscripten_bind_btRigidBody_setUserPointer_1 = b.asm.Np).apply(null, arguments); + }), + Vr = (b._emscripten_bind_btRigidBody_getBroadphaseHandle_0 = function () { + return (Vr = b._emscripten_bind_btRigidBody_getBroadphaseHandle_0 = b.asm.Op).apply(null, arguments); + }), + Wr = (b._emscripten_bind_btRigidBody___destroy___0 = function () { + return (Wr = b._emscripten_bind_btRigidBody___destroy___0 = b.asm.Pp).apply(null, arguments); + }), + Xr = (b._emscripten_bind_btConstraintSetting_btConstraintSetting_0 = function () { + return (Xr = b._emscripten_bind_btConstraintSetting_btConstraintSetting_0 = b.asm.Qp).apply(null, arguments); + }), + Yr = (b._emscripten_bind_btConstraintSetting_get_m_tau_0 = function () { + return (Yr = b._emscripten_bind_btConstraintSetting_get_m_tau_0 = b.asm.Rp).apply(null, arguments); + }), + Zr = (b._emscripten_bind_btConstraintSetting_set_m_tau_1 = function () { + return (Zr = b._emscripten_bind_btConstraintSetting_set_m_tau_1 = b.asm.Sp).apply(null, arguments); + }), + $r = (b._emscripten_bind_btConstraintSetting_get_m_damping_0 = function () { + return ($r = b._emscripten_bind_btConstraintSetting_get_m_damping_0 = b.asm.Tp).apply(null, arguments); + }), + as = (b._emscripten_bind_btConstraintSetting_set_m_damping_1 = function () { + return (as = b._emscripten_bind_btConstraintSetting_set_m_damping_1 = b.asm.Up).apply(null, arguments); + }), + bs = (b._emscripten_bind_btConstraintSetting_get_m_impulseClamp_0 = function () { + return (bs = b._emscripten_bind_btConstraintSetting_get_m_impulseClamp_0 = b.asm.Vp).apply(null, arguments); + }), + cs = (b._emscripten_bind_btConstraintSetting_set_m_impulseClamp_1 = function () { + return (cs = b._emscripten_bind_btConstraintSetting_set_m_impulseClamp_1 = b.asm.Wp).apply(null, arguments); + }), + ds = (b._emscripten_bind_btConstraintSetting___destroy___0 = function () { + return (ds = b._emscripten_bind_btConstraintSetting___destroy___0 = b.asm.Xp).apply(null, arguments); + }), + es = (b._emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_2 = function () { + return (es = b._emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_2 = b.asm.Yp).apply(null, arguments); + }), + gs = (b._emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_4 = function () { + return (gs = b._emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_4 = b.asm.Zp).apply(null, arguments); + }), + hs = (b._emscripten_bind_btPoint2PointConstraint_setPivotA_1 = function () { + return (hs = b._emscripten_bind_btPoint2PointConstraint_setPivotA_1 = b.asm._p).apply(null, arguments); + }), + is = (b._emscripten_bind_btPoint2PointConstraint_setPivotB_1 = function () { + return (is = b._emscripten_bind_btPoint2PointConstraint_setPivotB_1 = b.asm.$p).apply(null, arguments); + }), + js = (b._emscripten_bind_btPoint2PointConstraint_getPivotInA_0 = function () { + return (js = b._emscripten_bind_btPoint2PointConstraint_getPivotInA_0 = b.asm.aq).apply(null, arguments); + }), + ks = (b._emscripten_bind_btPoint2PointConstraint_getPivotInB_0 = function () { + return (ks = b._emscripten_bind_btPoint2PointConstraint_getPivotInB_0 = b.asm.bq).apply(null, arguments); + }), + ls = (b._emscripten_bind_btPoint2PointConstraint_enableFeedback_1 = function () { + return (ls = b._emscripten_bind_btPoint2PointConstraint_enableFeedback_1 = b.asm.cq).apply(null, arguments); + }), + ms = (b._emscripten_bind_btPoint2PointConstraint_getBreakingImpulseThreshold_0 = function () { + return (ms = b._emscripten_bind_btPoint2PointConstraint_getBreakingImpulseThreshold_0 = b.asm.dq).apply(null, arguments); + }), + ns = (b._emscripten_bind_btPoint2PointConstraint_setBreakingImpulseThreshold_1 = function () { + return (ns = b._emscripten_bind_btPoint2PointConstraint_setBreakingImpulseThreshold_1 = b.asm.eq).apply(null, arguments); + }), + ps = (b._emscripten_bind_btPoint2PointConstraint_getParam_2 = function () { + return (ps = b._emscripten_bind_btPoint2PointConstraint_getParam_2 = b.asm.fq).apply(null, arguments); + }), + qs = (b._emscripten_bind_btPoint2PointConstraint_setParam_3 = function () { + return (qs = b._emscripten_bind_btPoint2PointConstraint_setParam_3 = b.asm.gq).apply(null, arguments); + }), + rs = (b._emscripten_bind_btPoint2PointConstraint_get_m_setting_0 = function () { + return (rs = b._emscripten_bind_btPoint2PointConstraint_get_m_setting_0 = b.asm.hq).apply(null, arguments); + }), + ss = (b._emscripten_bind_btPoint2PointConstraint_set_m_setting_1 = function () { + return (ss = b._emscripten_bind_btPoint2PointConstraint_set_m_setting_1 = b.asm.iq).apply(null, arguments); + }), + ts = (b._emscripten_bind_btPoint2PointConstraint___destroy___0 = function () { + return (ts = b._emscripten_bind_btPoint2PointConstraint___destroy___0 = b.asm.jq).apply(null, arguments); + }), + us = (b._emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_3 = function () { + return (us = b._emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_3 = b.asm.kq).apply(null, arguments); + }), + vs = (b._emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_5 = function () { + return (vs = b._emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_5 = b.asm.lq).apply(null, arguments); + }), + xs = (b._emscripten_bind_btGeneric6DofSpringConstraint_enableSpring_2 = function () { + return (xs = b._emscripten_bind_btGeneric6DofSpringConstraint_enableSpring_2 = b.asm.mq).apply(null, arguments); + }), + ys = (b._emscripten_bind_btGeneric6DofSpringConstraint_setStiffness_2 = function () { + return (ys = b._emscripten_bind_btGeneric6DofSpringConstraint_setStiffness_2 = b.asm.nq).apply(null, arguments); + }), + zs = (b._emscripten_bind_btGeneric6DofSpringConstraint_setDamping_2 = function () { + return (zs = b._emscripten_bind_btGeneric6DofSpringConstraint_setDamping_2 = b.asm.oq).apply(null, arguments); + }), + As = (b._emscripten_bind_btGeneric6DofSpringConstraint_setEquilibriumPoint_0 = function () { + return (As = b._emscripten_bind_btGeneric6DofSpringConstraint_setEquilibriumPoint_0 = b.asm.pq).apply(null, arguments); + }), + Bs = (b._emscripten_bind_btGeneric6DofSpringConstraint_setEquilibriumPoint_1 = function () { + return (Bs = b._emscripten_bind_btGeneric6DofSpringConstraint_setEquilibriumPoint_1 = b.asm.qq).apply(null, arguments); + }), + Cs = (b._emscripten_bind_btGeneric6DofSpringConstraint_setEquilibriumPoint_2 = function () { + return (Cs = b._emscripten_bind_btGeneric6DofSpringConstraint_setEquilibriumPoint_2 = b.asm.rq).apply(null, arguments); + }), + Ds = (b._emscripten_bind_btGeneric6DofSpringConstraint_setLinearLowerLimit_1 = function () { + return (Ds = b._emscripten_bind_btGeneric6DofSpringConstraint_setLinearLowerLimit_1 = b.asm.sq).apply(null, arguments); + }), + Es = (b._emscripten_bind_btGeneric6DofSpringConstraint_setLinearUpperLimit_1 = function () { + return (Es = b._emscripten_bind_btGeneric6DofSpringConstraint_setLinearUpperLimit_1 = b.asm.tq).apply(null, arguments); + }), + Fs = (b._emscripten_bind_btGeneric6DofSpringConstraint_setAngularLowerLimit_1 = function () { + return (Fs = b._emscripten_bind_btGeneric6DofSpringConstraint_setAngularLowerLimit_1 = b.asm.uq).apply(null, arguments); + }), + Gs = (b._emscripten_bind_btGeneric6DofSpringConstraint_setAngularUpperLimit_1 = function () { + return (Gs = b._emscripten_bind_btGeneric6DofSpringConstraint_setAngularUpperLimit_1 = b.asm.vq).apply(null, arguments); + }), + Hs = (b._emscripten_bind_btGeneric6DofSpringConstraint_getFrameOffsetA_0 = function () { + return (Hs = b._emscripten_bind_btGeneric6DofSpringConstraint_getFrameOffsetA_0 = b.asm.wq).apply(null, arguments); + }), + Is = (b._emscripten_bind_btGeneric6DofSpringConstraint_enableFeedback_1 = function () { + return (Is = b._emscripten_bind_btGeneric6DofSpringConstraint_enableFeedback_1 = b.asm.xq).apply(null, arguments); + }), + Js = (b._emscripten_bind_btGeneric6DofSpringConstraint_getBreakingImpulseThreshold_0 = function () { + return (Js = b._emscripten_bind_btGeneric6DofSpringConstraint_getBreakingImpulseThreshold_0 = b.asm.yq).apply(null, arguments); + }), + Ks = (b._emscripten_bind_btGeneric6DofSpringConstraint_setBreakingImpulseThreshold_1 = function () { + return (Ks = b._emscripten_bind_btGeneric6DofSpringConstraint_setBreakingImpulseThreshold_1 = b.asm.zq).apply(null, arguments); + }), + Ls = (b._emscripten_bind_btGeneric6DofSpringConstraint_getParam_2 = function () { + return (Ls = b._emscripten_bind_btGeneric6DofSpringConstraint_getParam_2 = b.asm.Aq).apply(null, arguments); + }), + Ms = (b._emscripten_bind_btGeneric6DofSpringConstraint_setParam_3 = function () { + return (Ms = b._emscripten_bind_btGeneric6DofSpringConstraint_setParam_3 = b.asm.Bq).apply(null, arguments); + }), + Ns = (b._emscripten_bind_btGeneric6DofSpringConstraint___destroy___0 = function () { + return (Ns = b._emscripten_bind_btGeneric6DofSpringConstraint___destroy___0 = b.asm.Cq).apply(null, arguments); + }), + Os = (b._emscripten_bind_btSequentialImpulseConstraintSolver_btSequentialImpulseConstraintSolver_0 = function () { + return (Os = b._emscripten_bind_btSequentialImpulseConstraintSolver_btSequentialImpulseConstraintSolver_0 = b.asm.Dq).apply(null, arguments); + }), + Ps = (b._emscripten_bind_btSequentialImpulseConstraintSolver___destroy___0 = function () { + return (Ps = b._emscripten_bind_btSequentialImpulseConstraintSolver___destroy___0 = b.asm.Eq).apply(null, arguments); + }), + Qs = (b._emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_2 = function () { + return (Qs = b._emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_2 = b.asm.Fq).apply(null, arguments); + }), + Rs = (b._emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_4 = function () { + return (Rs = b._emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_4 = b.asm.Gq).apply(null, arguments); + }), + Ss = (b._emscripten_bind_btConeTwistConstraint_setLimit_2 = function () { + return (Ss = b._emscripten_bind_btConeTwistConstraint_setLimit_2 = b.asm.Hq).apply(null, arguments); + }), + Ts = (b._emscripten_bind_btConeTwistConstraint_setAngularOnly_1 = function () { + return (Ts = b._emscripten_bind_btConeTwistConstraint_setAngularOnly_1 = b.asm.Iq).apply(null, arguments); + }), + Us = (b._emscripten_bind_btConeTwistConstraint_setDamping_1 = function () { + return (Us = b._emscripten_bind_btConeTwistConstraint_setDamping_1 = b.asm.Jq).apply(null, arguments); + }), + Vs = (b._emscripten_bind_btConeTwistConstraint_enableMotor_1 = function () { + return (Vs = b._emscripten_bind_btConeTwistConstraint_enableMotor_1 = b.asm.Kq).apply(null, arguments); + }), + Ws = (b._emscripten_bind_btConeTwistConstraint_setMaxMotorImpulse_1 = function () { + return (Ws = b._emscripten_bind_btConeTwistConstraint_setMaxMotorImpulse_1 = b.asm.Lq).apply(null, arguments); + }), + Xs = (b._emscripten_bind_btConeTwistConstraint_setMaxMotorImpulseNormalized_1 = function () { + return (Xs = b._emscripten_bind_btConeTwistConstraint_setMaxMotorImpulseNormalized_1 = b.asm.Mq).apply(null, arguments); + }), + Ys = (b._emscripten_bind_btConeTwistConstraint_setMotorTarget_1 = function () { + return (Ys = b._emscripten_bind_btConeTwistConstraint_setMotorTarget_1 = b.asm.Nq).apply(null, arguments); + }), + Zs = (b._emscripten_bind_btConeTwistConstraint_setMotorTargetInConstraintSpace_1 = function () { + return (Zs = b._emscripten_bind_btConeTwistConstraint_setMotorTargetInConstraintSpace_1 = b.asm.Oq).apply(null, arguments); + }), + $s = (b._emscripten_bind_btConeTwistConstraint_enableFeedback_1 = function () { + return ($s = b._emscripten_bind_btConeTwistConstraint_enableFeedback_1 = b.asm.Pq).apply(null, arguments); + }), + at = (b._emscripten_bind_btConeTwistConstraint_getBreakingImpulseThreshold_0 = function () { + return (at = b._emscripten_bind_btConeTwistConstraint_getBreakingImpulseThreshold_0 = b.asm.Qq).apply(null, arguments); + }), + bt = (b._emscripten_bind_btConeTwistConstraint_setBreakingImpulseThreshold_1 = function () { + return (bt = b._emscripten_bind_btConeTwistConstraint_setBreakingImpulseThreshold_1 = b.asm.Rq).apply(null, arguments); + }), + ct = (b._emscripten_bind_btConeTwistConstraint_getParam_2 = function () { + return (ct = b._emscripten_bind_btConeTwistConstraint_getParam_2 = b.asm.Sq).apply(null, arguments); + }), + dt = (b._emscripten_bind_btConeTwistConstraint_setParam_3 = function () { + return (dt = b._emscripten_bind_btConeTwistConstraint_setParam_3 = b.asm.Tq).apply(null, arguments); + }), + et = (b._emscripten_bind_btConeTwistConstraint___destroy___0 = function () { + return (et = b._emscripten_bind_btConeTwistConstraint___destroy___0 = b.asm.Uq).apply(null, arguments); + }), + ft = (b._emscripten_bind_btHingeConstraint_btHingeConstraint_2 = function () { + return (ft = b._emscripten_bind_btHingeConstraint_btHingeConstraint_2 = b.asm.Vq).apply(null, arguments); + }), + gt = (b._emscripten_bind_btHingeConstraint_btHingeConstraint_3 = function () { + return (gt = b._emscripten_bind_btHingeConstraint_btHingeConstraint_3 = b.asm.Wq).apply(null, arguments); + }), + ht = (b._emscripten_bind_btHingeConstraint_btHingeConstraint_4 = function () { + return (ht = b._emscripten_bind_btHingeConstraint_btHingeConstraint_4 = b.asm.Xq).apply(null, arguments); + }), + it = (b._emscripten_bind_btHingeConstraint_btHingeConstraint_5 = function () { + return (it = b._emscripten_bind_btHingeConstraint_btHingeConstraint_5 = b.asm.Yq).apply(null, arguments); + }), + jt = (b._emscripten_bind_btHingeConstraint_btHingeConstraint_6 = function () { + return (jt = b._emscripten_bind_btHingeConstraint_btHingeConstraint_6 = b.asm.Zq).apply(null, arguments); + }), + kt = (b._emscripten_bind_btHingeConstraint_btHingeConstraint_7 = function () { + return (kt = b._emscripten_bind_btHingeConstraint_btHingeConstraint_7 = b.asm._q).apply(null, arguments); + }), + lt = (b._emscripten_bind_btHingeConstraint_setLimit_4 = function () { + return (lt = b._emscripten_bind_btHingeConstraint_setLimit_4 = b.asm.$q).apply(null, arguments); + }), + mt = (b._emscripten_bind_btHingeConstraint_setLimit_5 = function () { + return (mt = b._emscripten_bind_btHingeConstraint_setLimit_5 = b.asm.ar).apply(null, arguments); + }), + nt = (b._emscripten_bind_btHingeConstraint_enableAngularMotor_3 = function () { + return (nt = b._emscripten_bind_btHingeConstraint_enableAngularMotor_3 = b.asm.br).apply(null, arguments); + }), + ot = (b._emscripten_bind_btHingeConstraint_setAngularOnly_1 = function () { + return (ot = b._emscripten_bind_btHingeConstraint_setAngularOnly_1 = b.asm.cr).apply(null, arguments); + }), + pt = (b._emscripten_bind_btHingeConstraint_enableMotor_1 = function () { + return (pt = b._emscripten_bind_btHingeConstraint_enableMotor_1 = b.asm.dr).apply(null, arguments); + }), + qt = (b._emscripten_bind_btHingeConstraint_setMaxMotorImpulse_1 = function () { + return (qt = b._emscripten_bind_btHingeConstraint_setMaxMotorImpulse_1 = b.asm.er).apply(null, arguments); + }), + rt = (b._emscripten_bind_btHingeConstraint_setMotorTarget_2 = function () { + return (rt = b._emscripten_bind_btHingeConstraint_setMotorTarget_2 = b.asm.fr).apply(null, arguments); + }), + st = (b._emscripten_bind_btHingeConstraint_enableFeedback_1 = function () { + return (st = b._emscripten_bind_btHingeConstraint_enableFeedback_1 = b.asm.gr).apply(null, arguments); + }), + tt = (b._emscripten_bind_btHingeConstraint_getBreakingImpulseThreshold_0 = function () { + return (tt = b._emscripten_bind_btHingeConstraint_getBreakingImpulseThreshold_0 = b.asm.hr).apply(null, arguments); + }), + ut = (b._emscripten_bind_btHingeConstraint_setBreakingImpulseThreshold_1 = function () { + return (ut = b._emscripten_bind_btHingeConstraint_setBreakingImpulseThreshold_1 = b.asm.ir).apply(null, arguments); + }), + vt = (b._emscripten_bind_btHingeConstraint_getParam_2 = function () { + return (vt = b._emscripten_bind_btHingeConstraint_getParam_2 = b.asm.jr).apply(null, arguments); + }), + wt = (b._emscripten_bind_btHingeConstraint_setParam_3 = function () { + return (wt = b._emscripten_bind_btHingeConstraint_setParam_3 = b.asm.kr).apply(null, arguments); + }), + xt = (b._emscripten_bind_btHingeConstraint___destroy___0 = function () { + return (xt = b._emscripten_bind_btHingeConstraint___destroy___0 = b.asm.lr).apply(null, arguments); + }), + yt = (b._emscripten_bind_btSliderConstraint_btSliderConstraint_3 = function () { + return (yt = b._emscripten_bind_btSliderConstraint_btSliderConstraint_3 = b.asm.mr).apply(null, arguments); + }), + zt = (b._emscripten_bind_btSliderConstraint_btSliderConstraint_5 = function () { + return (zt = b._emscripten_bind_btSliderConstraint_btSliderConstraint_5 = b.asm.nr).apply(null, arguments); + }), + At = (b._emscripten_bind_btSliderConstraint_setLowerLinLimit_1 = function () { + return (At = b._emscripten_bind_btSliderConstraint_setLowerLinLimit_1 = b.asm.or).apply(null, arguments); + }), + Bt = (b._emscripten_bind_btSliderConstraint_setUpperLinLimit_1 = function () { + return (Bt = b._emscripten_bind_btSliderConstraint_setUpperLinLimit_1 = b.asm.pr).apply(null, arguments); + }), + Ct = (b._emscripten_bind_btSliderConstraint_setLowerAngLimit_1 = function () { + return (Ct = b._emscripten_bind_btSliderConstraint_setLowerAngLimit_1 = b.asm.qr).apply(null, arguments); + }), + Dt = (b._emscripten_bind_btSliderConstraint_setUpperAngLimit_1 = function () { + return (Dt = b._emscripten_bind_btSliderConstraint_setUpperAngLimit_1 = b.asm.rr).apply(null, arguments); + }), + Et = (b._emscripten_bind_btSliderConstraint_setPoweredLinMotor_1 = function () { + return (Et = b._emscripten_bind_btSliderConstraint_setPoweredLinMotor_1 = b.asm.sr).apply(null, arguments); + }), + Ft = (b._emscripten_bind_btSliderConstraint_setMaxLinMotorForce_1 = function () { + return (Ft = b._emscripten_bind_btSliderConstraint_setMaxLinMotorForce_1 = b.asm.tr).apply(null, arguments); + }), + Gt = (b._emscripten_bind_btSliderConstraint_setTargetLinMotorVelocity_1 = function () { + return (Gt = b._emscripten_bind_btSliderConstraint_setTargetLinMotorVelocity_1 = b.asm.ur).apply(null, arguments); + }), + Ht = (b._emscripten_bind_btSliderConstraint_enableFeedback_1 = function () { + return (Ht = b._emscripten_bind_btSliderConstraint_enableFeedback_1 = b.asm.vr).apply(null, arguments); + }), + It = (b._emscripten_bind_btSliderConstraint_getBreakingImpulseThreshold_0 = function () { + return (It = b._emscripten_bind_btSliderConstraint_getBreakingImpulseThreshold_0 = b.asm.wr).apply(null, arguments); + }), + Jt = (b._emscripten_bind_btSliderConstraint_setBreakingImpulseThreshold_1 = function () { + return (Jt = b._emscripten_bind_btSliderConstraint_setBreakingImpulseThreshold_1 = b.asm.xr).apply(null, arguments); + }), + Kt = (b._emscripten_bind_btSliderConstraint_getParam_2 = function () { + return (Kt = b._emscripten_bind_btSliderConstraint_getParam_2 = b.asm.yr).apply(null, arguments); + }), + Lt = (b._emscripten_bind_btSliderConstraint_setParam_3 = function () { + return (Lt = b._emscripten_bind_btSliderConstraint_setParam_3 = b.asm.zr).apply(null, arguments); + }), + Mt = (b._emscripten_bind_btSliderConstraint___destroy___0 = function () { + return (Mt = b._emscripten_bind_btSliderConstraint___destroy___0 = b.asm.Ar).apply(null, arguments); + }), + Nt = (b._emscripten_bind_btFixedConstraint_btFixedConstraint_4 = function () { + return (Nt = b._emscripten_bind_btFixedConstraint_btFixedConstraint_4 = b.asm.Br).apply(null, arguments); + }), + Ot = (b._emscripten_bind_btFixedConstraint_enableFeedback_1 = function () { + return (Ot = b._emscripten_bind_btFixedConstraint_enableFeedback_1 = b.asm.Cr).apply(null, arguments); + }), + Pt = (b._emscripten_bind_btFixedConstraint_getBreakingImpulseThreshold_0 = function () { + return (Pt = b._emscripten_bind_btFixedConstraint_getBreakingImpulseThreshold_0 = b.asm.Dr).apply(null, arguments); + }), + Qt = (b._emscripten_bind_btFixedConstraint_setBreakingImpulseThreshold_1 = function () { + return (Qt = b._emscripten_bind_btFixedConstraint_setBreakingImpulseThreshold_1 = b.asm.Er).apply(null, arguments); + }), + Rt = (b._emscripten_bind_btFixedConstraint_getParam_2 = function () { + return (Rt = b._emscripten_bind_btFixedConstraint_getParam_2 = b.asm.Fr).apply(null, arguments); + }), + St = (b._emscripten_bind_btFixedConstraint_setParam_3 = function () { + return (St = b._emscripten_bind_btFixedConstraint_setParam_3 = b.asm.Gr).apply(null, arguments); + }), + Tt = (b._emscripten_bind_btFixedConstraint___destroy___0 = function () { + return (Tt = b._emscripten_bind_btFixedConstraint___destroy___0 = b.asm.Hr).apply(null, arguments); + }), + Ut = (b._emscripten_bind_btConstraintSolver___destroy___0 = function () { + return (Ut = b._emscripten_bind_btConstraintSolver___destroy___0 = b.asm.Ir).apply(null, arguments); + }), + Vt = (b._emscripten_bind_btDispatcherInfo_get_m_timeStep_0 = function () { + return (Vt = b._emscripten_bind_btDispatcherInfo_get_m_timeStep_0 = b.asm.Jr).apply(null, arguments); + }), + Wt = (b._emscripten_bind_btDispatcherInfo_set_m_timeStep_1 = function () { + return (Wt = b._emscripten_bind_btDispatcherInfo_set_m_timeStep_1 = b.asm.Kr).apply(null, arguments); + }), + Xt = (b._emscripten_bind_btDispatcherInfo_get_m_stepCount_0 = function () { + return (Xt = b._emscripten_bind_btDispatcherInfo_get_m_stepCount_0 = b.asm.Lr).apply(null, arguments); + }), + Yt = (b._emscripten_bind_btDispatcherInfo_set_m_stepCount_1 = function () { + return (Yt = b._emscripten_bind_btDispatcherInfo_set_m_stepCount_1 = b.asm.Mr).apply(null, arguments); + }), + Zt = (b._emscripten_bind_btDispatcherInfo_get_m_dispatchFunc_0 = function () { + return (Zt = b._emscripten_bind_btDispatcherInfo_get_m_dispatchFunc_0 = b.asm.Nr).apply(null, arguments); + }), + $t = (b._emscripten_bind_btDispatcherInfo_set_m_dispatchFunc_1 = function () { + return ($t = b._emscripten_bind_btDispatcherInfo_set_m_dispatchFunc_1 = b.asm.Or).apply(null, arguments); + }), + au = (b._emscripten_bind_btDispatcherInfo_get_m_timeOfImpact_0 = function () { + return (au = b._emscripten_bind_btDispatcherInfo_get_m_timeOfImpact_0 = b.asm.Pr).apply(null, arguments); + }), + bu = (b._emscripten_bind_btDispatcherInfo_set_m_timeOfImpact_1 = function () { + return (bu = b._emscripten_bind_btDispatcherInfo_set_m_timeOfImpact_1 = b.asm.Qr).apply(null, arguments); + }), + cu = (b._emscripten_bind_btDispatcherInfo_get_m_useContinuous_0 = function () { + return (cu = b._emscripten_bind_btDispatcherInfo_get_m_useContinuous_0 = b.asm.Rr).apply(null, arguments); + }), + du = (b._emscripten_bind_btDispatcherInfo_set_m_useContinuous_1 = function () { + return (du = b._emscripten_bind_btDispatcherInfo_set_m_useContinuous_1 = b.asm.Sr).apply(null, arguments); + }), + eu = (b._emscripten_bind_btDispatcherInfo_get_m_enableSatConvex_0 = function () { + return (eu = b._emscripten_bind_btDispatcherInfo_get_m_enableSatConvex_0 = b.asm.Tr).apply(null, arguments); + }), + fu = (b._emscripten_bind_btDispatcherInfo_set_m_enableSatConvex_1 = function () { + return (fu = b._emscripten_bind_btDispatcherInfo_set_m_enableSatConvex_1 = b.asm.Ur).apply(null, arguments); + }), + gu = (b._emscripten_bind_btDispatcherInfo_get_m_enableSPU_0 = function () { + return (gu = b._emscripten_bind_btDispatcherInfo_get_m_enableSPU_0 = b.asm.Vr).apply(null, arguments); + }), + hu = (b._emscripten_bind_btDispatcherInfo_set_m_enableSPU_1 = function () { + return (hu = b._emscripten_bind_btDispatcherInfo_set_m_enableSPU_1 = b.asm.Wr).apply(null, arguments); + }), + iu = (b._emscripten_bind_btDispatcherInfo_get_m_useEpa_0 = function () { + return (iu = b._emscripten_bind_btDispatcherInfo_get_m_useEpa_0 = b.asm.Xr).apply(null, arguments); + }), + ju = (b._emscripten_bind_btDispatcherInfo_set_m_useEpa_1 = function () { + return (ju = b._emscripten_bind_btDispatcherInfo_set_m_useEpa_1 = b.asm.Yr).apply(null, arguments); + }), + ku = (b._emscripten_bind_btDispatcherInfo_get_m_allowedCcdPenetration_0 = function () { + return (ku = b._emscripten_bind_btDispatcherInfo_get_m_allowedCcdPenetration_0 = b.asm.Zr).apply(null, arguments); + }), + lu = (b._emscripten_bind_btDispatcherInfo_set_m_allowedCcdPenetration_1 = function () { + return (lu = b._emscripten_bind_btDispatcherInfo_set_m_allowedCcdPenetration_1 = b.asm._r).apply(null, arguments); + }), + mu = (b._emscripten_bind_btDispatcherInfo_get_m_useConvexConservativeDistanceUtil_0 = function () { + return (mu = b._emscripten_bind_btDispatcherInfo_get_m_useConvexConservativeDistanceUtil_0 = b.asm.$r).apply(null, arguments); + }), + nu = (b._emscripten_bind_btDispatcherInfo_set_m_useConvexConservativeDistanceUtil_1 = function () { + return (nu = b._emscripten_bind_btDispatcherInfo_set_m_useConvexConservativeDistanceUtil_1 = b.asm.as).apply(null, arguments); + }), + ou = (b._emscripten_bind_btDispatcherInfo_get_m_convexConservativeDistanceThreshold_0 = function () { + return (ou = b._emscripten_bind_btDispatcherInfo_get_m_convexConservativeDistanceThreshold_0 = b.asm.bs).apply(null, arguments); + }), + pu = (b._emscripten_bind_btDispatcherInfo_set_m_convexConservativeDistanceThreshold_1 = function () { + return (pu = b._emscripten_bind_btDispatcherInfo_set_m_convexConservativeDistanceThreshold_1 = b.asm.cs).apply(null, arguments); + }), + qu = (b._emscripten_bind_btDispatcherInfo___destroy___0 = function () { + return (qu = b._emscripten_bind_btDispatcherInfo___destroy___0 = b.asm.ds).apply(null, arguments); + }), + ru = (b._emscripten_bind_btContactSolverInfo_get_m_splitImpulse_0 = function () { + return (ru = b._emscripten_bind_btContactSolverInfo_get_m_splitImpulse_0 = b.asm.es).apply(null, arguments); + }), + su = (b._emscripten_bind_btContactSolverInfo_set_m_splitImpulse_1 = function () { + return (su = b._emscripten_bind_btContactSolverInfo_set_m_splitImpulse_1 = b.asm.fs).apply(null, arguments); + }), + tu = (b._emscripten_bind_btContactSolverInfo_get_m_splitImpulsePenetrationThreshold_0 = function () { + return (tu = b._emscripten_bind_btContactSolverInfo_get_m_splitImpulsePenetrationThreshold_0 = b.asm.gs).apply(null, arguments); + }), + uu = (b._emscripten_bind_btContactSolverInfo_set_m_splitImpulsePenetrationThreshold_1 = function () { + return (uu = b._emscripten_bind_btContactSolverInfo_set_m_splitImpulsePenetrationThreshold_1 = b.asm.hs).apply(null, arguments); + }), + vu = (b._emscripten_bind_btContactSolverInfo_get_m_numIterations_0 = function () { + return (vu = b._emscripten_bind_btContactSolverInfo_get_m_numIterations_0 = b.asm.is).apply(null, arguments); + }), + wu = (b._emscripten_bind_btContactSolverInfo_set_m_numIterations_1 = function () { + return (wu = b._emscripten_bind_btContactSolverInfo_set_m_numIterations_1 = b.asm.js).apply(null, arguments); + }), + xu = (b._emscripten_bind_btContactSolverInfo___destroy___0 = function () { + return (xu = b._emscripten_bind_btContactSolverInfo___destroy___0 = b.asm.ks).apply(null, arguments); + }), + yu = (b._emscripten_bind_btVehicleTuning_btVehicleTuning_0 = function () { + return (yu = b._emscripten_bind_btVehicleTuning_btVehicleTuning_0 = b.asm.ls).apply(null, arguments); + }), + zu = (b._emscripten_bind_btVehicleTuning_get_m_suspensionStiffness_0 = function () { + return (zu = b._emscripten_bind_btVehicleTuning_get_m_suspensionStiffness_0 = b.asm.ms).apply(null, arguments); + }), + Au = (b._emscripten_bind_btVehicleTuning_set_m_suspensionStiffness_1 = function () { + return (Au = b._emscripten_bind_btVehicleTuning_set_m_suspensionStiffness_1 = b.asm.ns).apply(null, arguments); + }), + Bu = (b._emscripten_bind_btVehicleTuning_get_m_suspensionCompression_0 = function () { + return (Bu = b._emscripten_bind_btVehicleTuning_get_m_suspensionCompression_0 = b.asm.os).apply(null, arguments); + }), + Cu = (b._emscripten_bind_btVehicleTuning_set_m_suspensionCompression_1 = function () { + return (Cu = b._emscripten_bind_btVehicleTuning_set_m_suspensionCompression_1 = b.asm.ps).apply(null, arguments); + }), + Du = (b._emscripten_bind_btVehicleTuning_get_m_suspensionDamping_0 = function () { + return (Du = b._emscripten_bind_btVehicleTuning_get_m_suspensionDamping_0 = b.asm.qs).apply(null, arguments); + }), + Eu = (b._emscripten_bind_btVehicleTuning_set_m_suspensionDamping_1 = function () { + return (Eu = b._emscripten_bind_btVehicleTuning_set_m_suspensionDamping_1 = b.asm.rs).apply(null, arguments); + }), + Fu = (b._emscripten_bind_btVehicleTuning_get_m_maxSuspensionTravelCm_0 = function () { + return (Fu = b._emscripten_bind_btVehicleTuning_get_m_maxSuspensionTravelCm_0 = b.asm.ss).apply(null, arguments); + }), + Gu = (b._emscripten_bind_btVehicleTuning_set_m_maxSuspensionTravelCm_1 = function () { + return (Gu = b._emscripten_bind_btVehicleTuning_set_m_maxSuspensionTravelCm_1 = b.asm.ts).apply(null, arguments); + }), + Hu = (b._emscripten_bind_btVehicleTuning_get_m_frictionSlip_0 = function () { + return (Hu = b._emscripten_bind_btVehicleTuning_get_m_frictionSlip_0 = b.asm.us).apply(null, arguments); + }), + Iu = (b._emscripten_bind_btVehicleTuning_set_m_frictionSlip_1 = function () { + return (Iu = b._emscripten_bind_btVehicleTuning_set_m_frictionSlip_1 = b.asm.vs).apply(null, arguments); + }), + Ju = (b._emscripten_bind_btVehicleTuning_get_m_maxSuspensionForce_0 = function () { + return (Ju = b._emscripten_bind_btVehicleTuning_get_m_maxSuspensionForce_0 = b.asm.ws).apply(null, arguments); + }), + Ku = (b._emscripten_bind_btVehicleTuning_set_m_maxSuspensionForce_1 = function () { + return (Ku = b._emscripten_bind_btVehicleTuning_set_m_maxSuspensionForce_1 = b.asm.xs).apply(null, arguments); + }), + Lu = (b._emscripten_bind_btVehicleRaycasterResult_get_m_hitPointInWorld_0 = function () { + return (Lu = b._emscripten_bind_btVehicleRaycasterResult_get_m_hitPointInWorld_0 = b.asm.ys).apply(null, arguments); + }), + Mu = (b._emscripten_bind_btVehicleRaycasterResult_set_m_hitPointInWorld_1 = function () { + return (Mu = b._emscripten_bind_btVehicleRaycasterResult_set_m_hitPointInWorld_1 = b.asm.zs).apply(null, arguments); + }), + Nu = (b._emscripten_bind_btVehicleRaycasterResult_get_m_hitNormalInWorld_0 = function () { + return (Nu = b._emscripten_bind_btVehicleRaycasterResult_get_m_hitNormalInWorld_0 = b.asm.As).apply(null, arguments); + }), + Ou = (b._emscripten_bind_btVehicleRaycasterResult_set_m_hitNormalInWorld_1 = function () { + return (Ou = b._emscripten_bind_btVehicleRaycasterResult_set_m_hitNormalInWorld_1 = b.asm.Bs).apply(null, arguments); + }), + Pu = (b._emscripten_bind_btVehicleRaycasterResult_get_m_distFraction_0 = function () { + return (Pu = b._emscripten_bind_btVehicleRaycasterResult_get_m_distFraction_0 = b.asm.Cs).apply(null, arguments); + }), + Qu = (b._emscripten_bind_btVehicleRaycasterResult_set_m_distFraction_1 = function () { + return (Qu = b._emscripten_bind_btVehicleRaycasterResult_set_m_distFraction_1 = b.asm.Ds).apply(null, arguments); + }), + Ru = (b._emscripten_bind_btVehicleRaycasterResult___destroy___0 = function () { + return (Ru = b._emscripten_bind_btVehicleRaycasterResult___destroy___0 = b.asm.Es).apply(null, arguments); + }), + Su = (b._emscripten_bind_btDefaultVehicleRaycaster_btDefaultVehicleRaycaster_1 = function () { + return (Su = b._emscripten_bind_btDefaultVehicleRaycaster_btDefaultVehicleRaycaster_1 = b.asm.Fs).apply(null, arguments); + }), + Tu = (b._emscripten_bind_btDefaultVehicleRaycaster_castRay_3 = function () { + return (Tu = b._emscripten_bind_btDefaultVehicleRaycaster_castRay_3 = b.asm.Gs).apply(null, arguments); + }), + Uu = (b._emscripten_bind_btDefaultVehicleRaycaster___destroy___0 = function () { + return (Uu = b._emscripten_bind_btDefaultVehicleRaycaster___destroy___0 = b.asm.Hs).apply(null, arguments); + }), + Vu = (b._emscripten_bind_RaycastInfo_get_m_contactNormalWS_0 = function () { + return (Vu = b._emscripten_bind_RaycastInfo_get_m_contactNormalWS_0 = b.asm.Is).apply(null, arguments); + }), + Wu = (b._emscripten_bind_RaycastInfo_set_m_contactNormalWS_1 = function () { + return (Wu = b._emscripten_bind_RaycastInfo_set_m_contactNormalWS_1 = b.asm.Js).apply(null, arguments); + }), + Xu = (b._emscripten_bind_RaycastInfo_get_m_contactPointWS_0 = function () { + return (Xu = b._emscripten_bind_RaycastInfo_get_m_contactPointWS_0 = b.asm.Ks).apply(null, arguments); + }), + Yu = (b._emscripten_bind_RaycastInfo_set_m_contactPointWS_1 = function () { + return (Yu = b._emscripten_bind_RaycastInfo_set_m_contactPointWS_1 = b.asm.Ls).apply(null, arguments); + }), + Zu = (b._emscripten_bind_RaycastInfo_get_m_suspensionLength_0 = function () { + return (Zu = b._emscripten_bind_RaycastInfo_get_m_suspensionLength_0 = b.asm.Ms).apply(null, arguments); + }), + $u = (b._emscripten_bind_RaycastInfo_set_m_suspensionLength_1 = function () { + return ($u = b._emscripten_bind_RaycastInfo_set_m_suspensionLength_1 = b.asm.Ns).apply(null, arguments); + }), + av = (b._emscripten_bind_RaycastInfo_get_m_hardPointWS_0 = function () { + return (av = b._emscripten_bind_RaycastInfo_get_m_hardPointWS_0 = b.asm.Os).apply(null, arguments); + }), + bv = (b._emscripten_bind_RaycastInfo_set_m_hardPointWS_1 = function () { + return (bv = b._emscripten_bind_RaycastInfo_set_m_hardPointWS_1 = b.asm.Ps).apply(null, arguments); + }), + cv = (b._emscripten_bind_RaycastInfo_get_m_wheelDirectionWS_0 = function () { + return (cv = b._emscripten_bind_RaycastInfo_get_m_wheelDirectionWS_0 = b.asm.Qs).apply(null, arguments); + }), + dv = (b._emscripten_bind_RaycastInfo_set_m_wheelDirectionWS_1 = function () { + return (dv = b._emscripten_bind_RaycastInfo_set_m_wheelDirectionWS_1 = b.asm.Rs).apply(null, arguments); + }), + ev = (b._emscripten_bind_RaycastInfo_get_m_wheelAxleWS_0 = function () { + return (ev = b._emscripten_bind_RaycastInfo_get_m_wheelAxleWS_0 = b.asm.Ss).apply(null, arguments); + }), + fv = (b._emscripten_bind_RaycastInfo_set_m_wheelAxleWS_1 = function () { + return (fv = b._emscripten_bind_RaycastInfo_set_m_wheelAxleWS_1 = b.asm.Ts).apply(null, arguments); + }), + gv = (b._emscripten_bind_RaycastInfo_get_m_isInContact_0 = function () { + return (gv = b._emscripten_bind_RaycastInfo_get_m_isInContact_0 = b.asm.Us).apply(null, arguments); + }), + hv = (b._emscripten_bind_RaycastInfo_set_m_isInContact_1 = function () { + return (hv = b._emscripten_bind_RaycastInfo_set_m_isInContact_1 = b.asm.Vs).apply(null, arguments); + }), + iv = (b._emscripten_bind_RaycastInfo_get_m_groundObject_0 = function () { + return (iv = b._emscripten_bind_RaycastInfo_get_m_groundObject_0 = b.asm.Ws).apply(null, arguments); + }), + jv = (b._emscripten_bind_RaycastInfo_set_m_groundObject_1 = function () { + return (jv = b._emscripten_bind_RaycastInfo_set_m_groundObject_1 = b.asm.Xs).apply(null, arguments); + }), + kv = (b._emscripten_bind_RaycastInfo___destroy___0 = function () { + return (kv = b._emscripten_bind_RaycastInfo___destroy___0 = b.asm.Ys).apply(null, arguments); + }), + lv = (b._emscripten_bind_btWheelInfoConstructionInfo_get_m_chassisConnectionCS_0 = function () { + return (lv = b._emscripten_bind_btWheelInfoConstructionInfo_get_m_chassisConnectionCS_0 = b.asm.Zs).apply(null, arguments); + }), + mv = (b._emscripten_bind_btWheelInfoConstructionInfo_set_m_chassisConnectionCS_1 = function () { + return (mv = b._emscripten_bind_btWheelInfoConstructionInfo_set_m_chassisConnectionCS_1 = b.asm._s).apply(null, arguments); + }), + nv = (b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelDirectionCS_0 = function () { + return (nv = b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelDirectionCS_0 = b.asm.$s).apply(null, arguments); + }), + ov = (b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelDirectionCS_1 = function () { + return (ov = b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelDirectionCS_1 = b.asm.at).apply(null, arguments); + }), + pv = (b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelAxleCS_0 = function () { + return (pv = b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelAxleCS_0 = b.asm.bt).apply(null, arguments); + }), + qv = (b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelAxleCS_1 = function () { + return (qv = b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelAxleCS_1 = b.asm.ct).apply(null, arguments); + }), + rv = (b._emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionRestLength_0 = function () { + return (rv = b._emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionRestLength_0 = b.asm.dt).apply(null, arguments); + }), + sv = (b._emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionRestLength_1 = function () { + return (sv = b._emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionRestLength_1 = b.asm.et).apply(null, arguments); + }), + tv = (b._emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionTravelCm_0 = function () { + return (tv = b._emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionTravelCm_0 = b.asm.ft).apply(null, arguments); + }), + uv = (b._emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionTravelCm_1 = function () { + return (uv = b._emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionTravelCm_1 = b.asm.gt).apply(null, arguments); + }), + vv = (b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelRadius_0 = function () { + return (vv = b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelRadius_0 = b.asm.ht).apply(null, arguments); + }), + wv = (b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelRadius_1 = function () { + return (wv = b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelRadius_1 = b.asm.it).apply(null, arguments); + }), + xv = (b._emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionStiffness_0 = function () { + return (xv = b._emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionStiffness_0 = b.asm.jt).apply(null, arguments); + }), + yv = (b._emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionStiffness_1 = function () { + return (yv = b._emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionStiffness_1 = b.asm.kt).apply(null, arguments); + }), + zv = (b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingCompression_0 = function () { + return (zv = b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingCompression_0 = b.asm.lt).apply(null, arguments); + }), + Av = (b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingCompression_1 = function () { + return (Av = b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingCompression_1 = b.asm.mt).apply(null, arguments); + }), + Bv = (b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingRelaxation_0 = function () { + return (Bv = b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingRelaxation_0 = b.asm.nt).apply(null, arguments); + }), + Cv = (b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingRelaxation_1 = function () { + return (Cv = b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingRelaxation_1 = b.asm.ot).apply(null, arguments); + }), + Dv = (b._emscripten_bind_btWheelInfoConstructionInfo_get_m_frictionSlip_0 = function () { + return (Dv = b._emscripten_bind_btWheelInfoConstructionInfo_get_m_frictionSlip_0 = b.asm.pt).apply(null, arguments); + }), + Ev = (b._emscripten_bind_btWheelInfoConstructionInfo_set_m_frictionSlip_1 = function () { + return (Ev = b._emscripten_bind_btWheelInfoConstructionInfo_set_m_frictionSlip_1 = b.asm.qt).apply(null, arguments); + }), + Fv = (b._emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionForce_0 = function () { + return (Fv = b._emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionForce_0 = b.asm.rt).apply(null, arguments); + }), + Gv = (b._emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionForce_1 = function () { + return (Gv = b._emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionForce_1 = b.asm.st).apply(null, arguments); + }), + Hv = (b._emscripten_bind_btWheelInfoConstructionInfo_get_m_bIsFrontWheel_0 = function () { + return (Hv = b._emscripten_bind_btWheelInfoConstructionInfo_get_m_bIsFrontWheel_0 = b.asm.tt).apply(null, arguments); + }), + Iv = (b._emscripten_bind_btWheelInfoConstructionInfo_set_m_bIsFrontWheel_1 = function () { + return (Iv = b._emscripten_bind_btWheelInfoConstructionInfo_set_m_bIsFrontWheel_1 = b.asm.ut).apply(null, arguments); + }), + Jv = (b._emscripten_bind_btWheelInfoConstructionInfo___destroy___0 = function () { + return (Jv = b._emscripten_bind_btWheelInfoConstructionInfo___destroy___0 = b.asm.vt).apply(null, arguments); + }), + Kv = (b._emscripten_bind_btWheelInfo_btWheelInfo_1 = function () { + return (Kv = b._emscripten_bind_btWheelInfo_btWheelInfo_1 = b.asm.wt).apply(null, arguments); + }), + Lv = (b._emscripten_bind_btWheelInfo_getSuspensionRestLength_0 = function () { + return (Lv = b._emscripten_bind_btWheelInfo_getSuspensionRestLength_0 = b.asm.xt).apply(null, arguments); + }), + Mv = (b._emscripten_bind_btWheelInfo_updateWheel_2 = function () { + return (Mv = b._emscripten_bind_btWheelInfo_updateWheel_2 = b.asm.yt).apply(null, arguments); + }), + Nv = (b._emscripten_bind_btWheelInfo_get_m_suspensionStiffness_0 = function () { + return (Nv = b._emscripten_bind_btWheelInfo_get_m_suspensionStiffness_0 = b.asm.zt).apply(null, arguments); + }), + Ov = (b._emscripten_bind_btWheelInfo_set_m_suspensionStiffness_1 = function () { + return (Ov = b._emscripten_bind_btWheelInfo_set_m_suspensionStiffness_1 = b.asm.At).apply(null, arguments); + }), + Pv = (b._emscripten_bind_btWheelInfo_get_m_frictionSlip_0 = function () { + return (Pv = b._emscripten_bind_btWheelInfo_get_m_frictionSlip_0 = b.asm.Bt).apply(null, arguments); + }), + Qv = (b._emscripten_bind_btWheelInfo_set_m_frictionSlip_1 = function () { + return (Qv = b._emscripten_bind_btWheelInfo_set_m_frictionSlip_1 = b.asm.Ct).apply(null, arguments); + }), + Rv = (b._emscripten_bind_btWheelInfo_get_m_engineForce_0 = function () { + return (Rv = b._emscripten_bind_btWheelInfo_get_m_engineForce_0 = b.asm.Dt).apply(null, arguments); + }), + Sv = (b._emscripten_bind_btWheelInfo_set_m_engineForce_1 = function () { + return (Sv = b._emscripten_bind_btWheelInfo_set_m_engineForce_1 = b.asm.Et).apply(null, arguments); + }), + Tv = (b._emscripten_bind_btWheelInfo_get_m_rollInfluence_0 = function () { + return (Tv = b._emscripten_bind_btWheelInfo_get_m_rollInfluence_0 = b.asm.Ft).apply(null, arguments); + }), + Uv = (b._emscripten_bind_btWheelInfo_set_m_rollInfluence_1 = function () { + return (Uv = b._emscripten_bind_btWheelInfo_set_m_rollInfluence_1 = b.asm.Gt).apply(null, arguments); + }), + Vv = (b._emscripten_bind_btWheelInfo_get_m_suspensionRestLength1_0 = function () { + return (Vv = b._emscripten_bind_btWheelInfo_get_m_suspensionRestLength1_0 = b.asm.Ht).apply(null, arguments); + }), + Wv = (b._emscripten_bind_btWheelInfo_set_m_suspensionRestLength1_1 = function () { + return (Wv = b._emscripten_bind_btWheelInfo_set_m_suspensionRestLength1_1 = b.asm.It).apply(null, arguments); + }), + Xv = (b._emscripten_bind_btWheelInfo_get_m_wheelsRadius_0 = function () { + return (Xv = b._emscripten_bind_btWheelInfo_get_m_wheelsRadius_0 = b.asm.Jt).apply(null, arguments); + }), + Yv = (b._emscripten_bind_btWheelInfo_set_m_wheelsRadius_1 = function () { + return (Yv = b._emscripten_bind_btWheelInfo_set_m_wheelsRadius_1 = b.asm.Kt).apply(null, arguments); + }), + Zv = (b._emscripten_bind_btWheelInfo_get_m_wheelsDampingCompression_0 = function () { + return (Zv = b._emscripten_bind_btWheelInfo_get_m_wheelsDampingCompression_0 = b.asm.Lt).apply(null, arguments); + }), + $v = (b._emscripten_bind_btWheelInfo_set_m_wheelsDampingCompression_1 = function () { + return ($v = b._emscripten_bind_btWheelInfo_set_m_wheelsDampingCompression_1 = b.asm.Mt).apply(null, arguments); + }), + aw = (b._emscripten_bind_btWheelInfo_get_m_wheelsDampingRelaxation_0 = function () { + return (aw = b._emscripten_bind_btWheelInfo_get_m_wheelsDampingRelaxation_0 = b.asm.Nt).apply(null, arguments); + }), + bw = (b._emscripten_bind_btWheelInfo_set_m_wheelsDampingRelaxation_1 = function () { + return (bw = b._emscripten_bind_btWheelInfo_set_m_wheelsDampingRelaxation_1 = b.asm.Ot).apply(null, arguments); + }), + cw = (b._emscripten_bind_btWheelInfo_get_m_steering_0 = function () { + return (cw = b._emscripten_bind_btWheelInfo_get_m_steering_0 = b.asm.Pt).apply(null, arguments); + }), + dw = (b._emscripten_bind_btWheelInfo_set_m_steering_1 = function () { + return (dw = b._emscripten_bind_btWheelInfo_set_m_steering_1 = b.asm.Qt).apply(null, arguments); + }), + ew = (b._emscripten_bind_btWheelInfo_get_m_maxSuspensionForce_0 = function () { + return (ew = b._emscripten_bind_btWheelInfo_get_m_maxSuspensionForce_0 = b.asm.Rt).apply(null, arguments); + }), + fw = (b._emscripten_bind_btWheelInfo_set_m_maxSuspensionForce_1 = function () { + return (fw = b._emscripten_bind_btWheelInfo_set_m_maxSuspensionForce_1 = b.asm.St).apply(null, arguments); + }), + gw = (b._emscripten_bind_btWheelInfo_get_m_maxSuspensionTravelCm_0 = function () { + return (gw = b._emscripten_bind_btWheelInfo_get_m_maxSuspensionTravelCm_0 = b.asm.Tt).apply(null, arguments); + }), + hw = (b._emscripten_bind_btWheelInfo_set_m_maxSuspensionTravelCm_1 = function () { + return (hw = b._emscripten_bind_btWheelInfo_set_m_maxSuspensionTravelCm_1 = b.asm.Ut).apply(null, arguments); + }), + iw = (b._emscripten_bind_btWheelInfo_get_m_wheelsSuspensionForce_0 = function () { + return (iw = b._emscripten_bind_btWheelInfo_get_m_wheelsSuspensionForce_0 = b.asm.Vt).apply(null, arguments); + }), + jw = (b._emscripten_bind_btWheelInfo_set_m_wheelsSuspensionForce_1 = function () { + return (jw = b._emscripten_bind_btWheelInfo_set_m_wheelsSuspensionForce_1 = b.asm.Wt).apply(null, arguments); + }), + kw = (b._emscripten_bind_btWheelInfo_get_m_bIsFrontWheel_0 = function () { + return (kw = b._emscripten_bind_btWheelInfo_get_m_bIsFrontWheel_0 = b.asm.Xt).apply(null, arguments); + }), + lw = (b._emscripten_bind_btWheelInfo_set_m_bIsFrontWheel_1 = function () { + return (lw = b._emscripten_bind_btWheelInfo_set_m_bIsFrontWheel_1 = b.asm.Yt).apply(null, arguments); + }), + mw = (b._emscripten_bind_btWheelInfo_get_m_raycastInfo_0 = function () { + return (mw = b._emscripten_bind_btWheelInfo_get_m_raycastInfo_0 = b.asm.Zt).apply(null, arguments); + }), + nw = (b._emscripten_bind_btWheelInfo_set_m_raycastInfo_1 = function () { + return (nw = b._emscripten_bind_btWheelInfo_set_m_raycastInfo_1 = b.asm._t).apply(null, arguments); + }), + ow = (b._emscripten_bind_btWheelInfo_get_m_chassisConnectionPointCS_0 = function () { + return (ow = b._emscripten_bind_btWheelInfo_get_m_chassisConnectionPointCS_0 = b.asm.$t).apply(null, arguments); + }), + pw = (b._emscripten_bind_btWheelInfo_set_m_chassisConnectionPointCS_1 = function () { + return (pw = b._emscripten_bind_btWheelInfo_set_m_chassisConnectionPointCS_1 = b.asm.au).apply(null, arguments); + }), + qw = (b._emscripten_bind_btWheelInfo_get_m_worldTransform_0 = function () { + return (qw = b._emscripten_bind_btWheelInfo_get_m_worldTransform_0 = b.asm.bu).apply(null, arguments); + }), + rw = (b._emscripten_bind_btWheelInfo_set_m_worldTransform_1 = function () { + return (rw = b._emscripten_bind_btWheelInfo_set_m_worldTransform_1 = b.asm.cu).apply(null, arguments); + }), + sw = (b._emscripten_bind_btWheelInfo_get_m_wheelDirectionCS_0 = function () { + return (sw = b._emscripten_bind_btWheelInfo_get_m_wheelDirectionCS_0 = b.asm.du).apply(null, arguments); + }), + tw = (b._emscripten_bind_btWheelInfo_set_m_wheelDirectionCS_1 = function () { + return (tw = b._emscripten_bind_btWheelInfo_set_m_wheelDirectionCS_1 = b.asm.eu).apply(null, arguments); + }), + uw = (b._emscripten_bind_btWheelInfo_get_m_wheelAxleCS_0 = function () { + return (uw = b._emscripten_bind_btWheelInfo_get_m_wheelAxleCS_0 = b.asm.fu).apply(null, arguments); + }), + vw = (b._emscripten_bind_btWheelInfo_set_m_wheelAxleCS_1 = function () { + return (vw = b._emscripten_bind_btWheelInfo_set_m_wheelAxleCS_1 = b.asm.gu).apply(null, arguments); + }), + ww = (b._emscripten_bind_btWheelInfo_get_m_rotation_0 = function () { + return (ww = b._emscripten_bind_btWheelInfo_get_m_rotation_0 = b.asm.hu).apply(null, arguments); + }), + xw = (b._emscripten_bind_btWheelInfo_set_m_rotation_1 = function () { + return (xw = b._emscripten_bind_btWheelInfo_set_m_rotation_1 = b.asm.iu).apply(null, arguments); + }), + yw = (b._emscripten_bind_btWheelInfo_get_m_deltaRotation_0 = function () { + return (yw = b._emscripten_bind_btWheelInfo_get_m_deltaRotation_0 = b.asm.ju).apply(null, arguments); + }), + zw = (b._emscripten_bind_btWheelInfo_set_m_deltaRotation_1 = function () { + return (zw = b._emscripten_bind_btWheelInfo_set_m_deltaRotation_1 = b.asm.ku).apply(null, arguments); + }), + Aw = (b._emscripten_bind_btWheelInfo_get_m_brake_0 = function () { + return (Aw = b._emscripten_bind_btWheelInfo_get_m_brake_0 = b.asm.lu).apply(null, arguments); + }), + Bw = (b._emscripten_bind_btWheelInfo_set_m_brake_1 = function () { + return (Bw = b._emscripten_bind_btWheelInfo_set_m_brake_1 = b.asm.mu).apply(null, arguments); + }), + Cw = (b._emscripten_bind_btWheelInfo_get_m_clippedInvContactDotSuspension_0 = function () { + return (Cw = b._emscripten_bind_btWheelInfo_get_m_clippedInvContactDotSuspension_0 = b.asm.nu).apply(null, arguments); + }), + Dw = (b._emscripten_bind_btWheelInfo_set_m_clippedInvContactDotSuspension_1 = function () { + return (Dw = b._emscripten_bind_btWheelInfo_set_m_clippedInvContactDotSuspension_1 = b.asm.ou).apply(null, arguments); + }), + Ew = (b._emscripten_bind_btWheelInfo_get_m_suspensionRelativeVelocity_0 = function () { + return (Ew = b._emscripten_bind_btWheelInfo_get_m_suspensionRelativeVelocity_0 = b.asm.pu).apply(null, arguments); + }), + Fw = (b._emscripten_bind_btWheelInfo_set_m_suspensionRelativeVelocity_1 = function () { + return (Fw = b._emscripten_bind_btWheelInfo_set_m_suspensionRelativeVelocity_1 = b.asm.qu).apply(null, arguments); + }), + Gw = (b._emscripten_bind_btWheelInfo_get_m_skidInfo_0 = function () { + return (Gw = b._emscripten_bind_btWheelInfo_get_m_skidInfo_0 = b.asm.ru).apply(null, arguments); + }), + Hw = (b._emscripten_bind_btWheelInfo_set_m_skidInfo_1 = function () { + return (Hw = b._emscripten_bind_btWheelInfo_set_m_skidInfo_1 = b.asm.su).apply(null, arguments); + }), + Iw = (b._emscripten_bind_btWheelInfo___destroy___0 = function () { + return (Iw = b._emscripten_bind_btWheelInfo___destroy___0 = b.asm.tu).apply(null, arguments); + }), + Jw = (b._emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_3 = function () { + return (Jw = b._emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_3 = b.asm.uu).apply(null, arguments); + }), + Kw = (b._emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_4 = function () { + return (Kw = b._emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_4 = b.asm.vu).apply(null, arguments); + }), + Lw = (b._emscripten_bind_btKinematicCharacterController_setUpAxis_1 = function () { + return (Lw = b._emscripten_bind_btKinematicCharacterController_setUpAxis_1 = b.asm.wu).apply(null, arguments); + }), + Mw = (b._emscripten_bind_btKinematicCharacterController_setWalkDirection_1 = function () { + return (Mw = b._emscripten_bind_btKinematicCharacterController_setWalkDirection_1 = b.asm.xu).apply(null, arguments); + }), + Nw = (b._emscripten_bind_btKinematicCharacterController_setVelocityForTimeInterval_2 = function () { + return (Nw = b._emscripten_bind_btKinematicCharacterController_setVelocityForTimeInterval_2 = b.asm.yu).apply(null, arguments); + }), + Ow = (b._emscripten_bind_btKinematicCharacterController_warp_1 = function () { + return (Ow = b._emscripten_bind_btKinematicCharacterController_warp_1 = b.asm.zu).apply(null, arguments); + }), + Pw = (b._emscripten_bind_btKinematicCharacterController_preStep_1 = function () { + return (Pw = b._emscripten_bind_btKinematicCharacterController_preStep_1 = b.asm.Au).apply(null, arguments); + }), + Qw = (b._emscripten_bind_btKinematicCharacterController_playerStep_2 = function () { + return (Qw = b._emscripten_bind_btKinematicCharacterController_playerStep_2 = b.asm.Bu).apply(null, arguments); + }), + Rw = (b._emscripten_bind_btKinematicCharacterController_setFallSpeed_1 = function () { + return (Rw = b._emscripten_bind_btKinematicCharacterController_setFallSpeed_1 = b.asm.Cu).apply(null, arguments); + }), + Sw = (b._emscripten_bind_btKinematicCharacterController_setJumpSpeed_1 = function () { + return (Sw = b._emscripten_bind_btKinematicCharacterController_setJumpSpeed_1 = b.asm.Du).apply(null, arguments); + }), + Tw = (b._emscripten_bind_btKinematicCharacterController_setMaxJumpHeight_1 = function () { + return (Tw = b._emscripten_bind_btKinematicCharacterController_setMaxJumpHeight_1 = b.asm.Eu).apply(null, arguments); + }), + Uw = (b._emscripten_bind_btKinematicCharacterController_canJump_0 = function () { + return (Uw = b._emscripten_bind_btKinematicCharacterController_canJump_0 = b.asm.Fu).apply(null, arguments); + }), + Vw = (b._emscripten_bind_btKinematicCharacterController_jump_0 = function () { + return (Vw = b._emscripten_bind_btKinematicCharacterController_jump_0 = b.asm.Gu).apply(null, arguments); + }), + Ww = (b._emscripten_bind_btKinematicCharacterController_setGravity_1 = function () { + return (Ww = b._emscripten_bind_btKinematicCharacterController_setGravity_1 = b.asm.Hu).apply(null, arguments); + }), + Xw = (b._emscripten_bind_btKinematicCharacterController_getGravity_0 = function () { + return (Xw = b._emscripten_bind_btKinematicCharacterController_getGravity_0 = b.asm.Iu).apply(null, arguments); + }), + Yw = (b._emscripten_bind_btKinematicCharacterController_setMaxSlope_1 = function () { + return (Yw = b._emscripten_bind_btKinematicCharacterController_setMaxSlope_1 = b.asm.Ju).apply(null, arguments); + }), + Zw = (b._emscripten_bind_btKinematicCharacterController_getMaxSlope_0 = function () { + return (Zw = b._emscripten_bind_btKinematicCharacterController_getMaxSlope_0 = b.asm.Ku).apply(null, arguments); + }), + $w = (b._emscripten_bind_btKinematicCharacterController_getGhostObject_0 = function () { + return ($w = b._emscripten_bind_btKinematicCharacterController_getGhostObject_0 = b.asm.Lu).apply(null, arguments); + }), + ax = (b._emscripten_bind_btKinematicCharacterController_setUseGhostSweepTest_1 = function () { + return (ax = b._emscripten_bind_btKinematicCharacterController_setUseGhostSweepTest_1 = b.asm.Mu).apply(null, arguments); + }), + bx = (b._emscripten_bind_btKinematicCharacterController_onGround_0 = function () { + return (bx = b._emscripten_bind_btKinematicCharacterController_onGround_0 = b.asm.Nu).apply(null, arguments); + }), + cx = (b._emscripten_bind_btKinematicCharacterController_setUpInterpolate_1 = function () { + return (cx = b._emscripten_bind_btKinematicCharacterController_setUpInterpolate_1 = b.asm.Ou).apply(null, arguments); + }), + dx = (b._emscripten_bind_btKinematicCharacterController_updateAction_2 = function () { + return (dx = b._emscripten_bind_btKinematicCharacterController_updateAction_2 = b.asm.Pu).apply(null, arguments); + }), + ex = (b._emscripten_bind_btKinematicCharacterController___destroy___0 = function () { + return (ex = b._emscripten_bind_btKinematicCharacterController___destroy___0 = b.asm.Qu).apply(null, arguments); + }), + fx = (b._emscripten_bind_btRaycastVehicle_btRaycastVehicle_3 = function () { + return (fx = b._emscripten_bind_btRaycastVehicle_btRaycastVehicle_3 = b.asm.Ru).apply(null, arguments); + }), + gx = (b._emscripten_bind_btRaycastVehicle_applyEngineForce_2 = function () { + return (gx = b._emscripten_bind_btRaycastVehicle_applyEngineForce_2 = b.asm.Su).apply(null, arguments); + }), + hx = (b._emscripten_bind_btRaycastVehicle_setSteeringValue_2 = function () { + return (hx = b._emscripten_bind_btRaycastVehicle_setSteeringValue_2 = b.asm.Tu).apply(null, arguments); + }), + ix = (b._emscripten_bind_btRaycastVehicle_getWheelTransformWS_1 = function () { + return (ix = b._emscripten_bind_btRaycastVehicle_getWheelTransformWS_1 = b.asm.Uu).apply(null, arguments); + }), + jx = (b._emscripten_bind_btRaycastVehicle_updateWheelTransform_2 = function () { + return (jx = b._emscripten_bind_btRaycastVehicle_updateWheelTransform_2 = b.asm.Vu).apply(null, arguments); + }), + kx = (b._emscripten_bind_btRaycastVehicle_addWheel_7 = function () { + return (kx = b._emscripten_bind_btRaycastVehicle_addWheel_7 = b.asm.Wu).apply(null, arguments); + }), + lx = (b._emscripten_bind_btRaycastVehicle_getNumWheels_0 = function () { + return (lx = b._emscripten_bind_btRaycastVehicle_getNumWheels_0 = b.asm.Xu).apply(null, arguments); + }), + mx = (b._emscripten_bind_btRaycastVehicle_getRigidBody_0 = function () { + return (mx = b._emscripten_bind_btRaycastVehicle_getRigidBody_0 = b.asm.Yu).apply(null, arguments); + }), + nx = (b._emscripten_bind_btRaycastVehicle_getWheelInfo_1 = function () { + return (nx = b._emscripten_bind_btRaycastVehicle_getWheelInfo_1 = b.asm.Zu).apply(null, arguments); + }), + ox = (b._emscripten_bind_btRaycastVehicle_setBrake_2 = function () { + return (ox = b._emscripten_bind_btRaycastVehicle_setBrake_2 = b.asm._u).apply(null, arguments); + }), + px = (b._emscripten_bind_btRaycastVehicle_setCoordinateSystem_3 = function () { + return (px = b._emscripten_bind_btRaycastVehicle_setCoordinateSystem_3 = b.asm.$u).apply(null, arguments); + }), + qx = (b._emscripten_bind_btRaycastVehicle_getCurrentSpeedKmHour_0 = function () { + return (qx = b._emscripten_bind_btRaycastVehicle_getCurrentSpeedKmHour_0 = b.asm.av).apply(null, arguments); + }), + rx = (b._emscripten_bind_btRaycastVehicle_getChassisWorldTransform_0 = function () { + return (rx = b._emscripten_bind_btRaycastVehicle_getChassisWorldTransform_0 = b.asm.bv).apply(null, arguments); + }), + sx = (b._emscripten_bind_btRaycastVehicle_rayCast_1 = function () { + return (sx = b._emscripten_bind_btRaycastVehicle_rayCast_1 = b.asm.cv).apply(null, arguments); + }), + tx = (b._emscripten_bind_btRaycastVehicle_updateVehicle_1 = function () { + return (tx = b._emscripten_bind_btRaycastVehicle_updateVehicle_1 = b.asm.dv).apply(null, arguments); + }), + ux = (b._emscripten_bind_btRaycastVehicle_resetSuspension_0 = function () { + return (ux = b._emscripten_bind_btRaycastVehicle_resetSuspension_0 = b.asm.ev).apply(null, arguments); + }), + vx = (b._emscripten_bind_btRaycastVehicle_getSteeringValue_1 = function () { + return (vx = b._emscripten_bind_btRaycastVehicle_getSteeringValue_1 = b.asm.fv).apply(null, arguments); + }), + wx = (b._emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_1 = function () { + return (wx = b._emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_1 = b.asm.gv).apply(null, arguments); + }), + xx = (b._emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_2 = function () { + return (xx = b._emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_2 = b.asm.hv).apply(null, arguments); + }), + yx = (b._emscripten_bind_btRaycastVehicle_setPitchControl_1 = function () { + return (yx = b._emscripten_bind_btRaycastVehicle_setPitchControl_1 = b.asm.iv).apply(null, arguments); + }), + zx = (b._emscripten_bind_btRaycastVehicle_updateSuspension_1 = function () { + return (zx = b._emscripten_bind_btRaycastVehicle_updateSuspension_1 = b.asm.jv).apply(null, arguments); + }), + Ax = (b._emscripten_bind_btRaycastVehicle_updateFriction_1 = function () { + return (Ax = b._emscripten_bind_btRaycastVehicle_updateFriction_1 = b.asm.kv).apply(null, arguments); + }), + Bx = (b._emscripten_bind_btRaycastVehicle_getRightAxis_0 = function () { + return (Bx = b._emscripten_bind_btRaycastVehicle_getRightAxis_0 = b.asm.lv).apply(null, arguments); + }), + Cx = (b._emscripten_bind_btRaycastVehicle_getUpAxis_0 = function () { + return (Cx = b._emscripten_bind_btRaycastVehicle_getUpAxis_0 = b.asm.mv).apply(null, arguments); + }), + Dx = (b._emscripten_bind_btRaycastVehicle_getForwardAxis_0 = function () { + return (Dx = b._emscripten_bind_btRaycastVehicle_getForwardAxis_0 = b.asm.nv).apply(null, arguments); + }), + Ex = (b._emscripten_bind_btRaycastVehicle_getForwardVector_0 = function () { + return (Ex = b._emscripten_bind_btRaycastVehicle_getForwardVector_0 = b.asm.ov).apply(null, arguments); + }), + Fx = (b._emscripten_bind_btRaycastVehicle_getUserConstraintType_0 = function () { + return (Fx = b._emscripten_bind_btRaycastVehicle_getUserConstraintType_0 = b.asm.pv).apply(null, arguments); + }), + Gx = (b._emscripten_bind_btRaycastVehicle_setUserConstraintType_1 = function () { + return (Gx = b._emscripten_bind_btRaycastVehicle_setUserConstraintType_1 = b.asm.qv).apply(null, arguments); + }), + Hx = (b._emscripten_bind_btRaycastVehicle_setUserConstraintId_1 = function () { + return (Hx = b._emscripten_bind_btRaycastVehicle_setUserConstraintId_1 = b.asm.rv).apply(null, arguments); + }), + Ix = (b._emscripten_bind_btRaycastVehicle_getUserConstraintId_0 = function () { + return (Ix = b._emscripten_bind_btRaycastVehicle_getUserConstraintId_0 = b.asm.sv).apply(null, arguments); + }), + Jx = (b._emscripten_bind_btRaycastVehicle_updateAction_2 = function () { + return (Jx = b._emscripten_bind_btRaycastVehicle_updateAction_2 = b.asm.tv).apply(null, arguments); + }), + Kx = (b._emscripten_bind_btRaycastVehicle___destroy___0 = function () { + return (Kx = b._emscripten_bind_btRaycastVehicle___destroy___0 = b.asm.uv).apply(null, arguments); + }), + Lx = (b._emscripten_bind_btPairCachingGhostObject_btPairCachingGhostObject_0 = function () { + return (Lx = b._emscripten_bind_btPairCachingGhostObject_btPairCachingGhostObject_0 = b.asm.vv).apply(null, arguments); + }), + Mx = (b._emscripten_bind_btPairCachingGhostObject_setAnisotropicFriction_2 = function () { + return (Mx = b._emscripten_bind_btPairCachingGhostObject_setAnisotropicFriction_2 = b.asm.wv).apply(null, arguments); + }), + Nx = (b._emscripten_bind_btPairCachingGhostObject_getCollisionShape_0 = function () { + return (Nx = b._emscripten_bind_btPairCachingGhostObject_getCollisionShape_0 = b.asm.xv).apply(null, arguments); + }), + Ox = (b._emscripten_bind_btPairCachingGhostObject_setContactProcessingThreshold_1 = function () { + return (Ox = b._emscripten_bind_btPairCachingGhostObject_setContactProcessingThreshold_1 = b.asm.yv).apply(null, arguments); + }), + Px = (b._emscripten_bind_btPairCachingGhostObject_setActivationState_1 = function () { + return (Px = b._emscripten_bind_btPairCachingGhostObject_setActivationState_1 = b.asm.zv).apply(null, arguments); + }), + Qx = (b._emscripten_bind_btPairCachingGhostObject_forceActivationState_1 = function () { + return (Qx = b._emscripten_bind_btPairCachingGhostObject_forceActivationState_1 = b.asm.Av).apply(null, arguments); + }), + Rx = (b._emscripten_bind_btPairCachingGhostObject_activate_0 = function () { + return (Rx = b._emscripten_bind_btPairCachingGhostObject_activate_0 = b.asm.Bv).apply(null, arguments); + }), + Sx = (b._emscripten_bind_btPairCachingGhostObject_activate_1 = function () { + return (Sx = b._emscripten_bind_btPairCachingGhostObject_activate_1 = b.asm.Cv).apply(null, arguments); + }), + Tx = (b._emscripten_bind_btPairCachingGhostObject_isActive_0 = function () { + return (Tx = b._emscripten_bind_btPairCachingGhostObject_isActive_0 = b.asm.Dv).apply(null, arguments); + }), + Ux = (b._emscripten_bind_btPairCachingGhostObject_isKinematicObject_0 = function () { + return (Ux = b._emscripten_bind_btPairCachingGhostObject_isKinematicObject_0 = b.asm.Ev).apply(null, arguments); + }), + Vx = (b._emscripten_bind_btPairCachingGhostObject_isStaticObject_0 = function () { + return (Vx = b._emscripten_bind_btPairCachingGhostObject_isStaticObject_0 = b.asm.Fv).apply(null, arguments); + }), + Wx = (b._emscripten_bind_btPairCachingGhostObject_isStaticOrKinematicObject_0 = function () { + return (Wx = b._emscripten_bind_btPairCachingGhostObject_isStaticOrKinematicObject_0 = b.asm.Gv).apply(null, arguments); + }), + Xx = (b._emscripten_bind_btPairCachingGhostObject_getRestitution_0 = function () { + return (Xx = b._emscripten_bind_btPairCachingGhostObject_getRestitution_0 = b.asm.Hv).apply(null, arguments); + }), + Yx = (b._emscripten_bind_btPairCachingGhostObject_getFriction_0 = function () { + return (Yx = b._emscripten_bind_btPairCachingGhostObject_getFriction_0 = b.asm.Iv).apply(null, arguments); + }), + Zx = (b._emscripten_bind_btPairCachingGhostObject_getRollingFriction_0 = function () { + return (Zx = b._emscripten_bind_btPairCachingGhostObject_getRollingFriction_0 = b.asm.Jv).apply(null, arguments); + }), + $x = (b._emscripten_bind_btPairCachingGhostObject_setRestitution_1 = function () { + return ($x = b._emscripten_bind_btPairCachingGhostObject_setRestitution_1 = b.asm.Kv).apply(null, arguments); + }), + ay = (b._emscripten_bind_btPairCachingGhostObject_setFriction_1 = function () { + return (ay = b._emscripten_bind_btPairCachingGhostObject_setFriction_1 = b.asm.Lv).apply(null, arguments); + }), + by = (b._emscripten_bind_btPairCachingGhostObject_setRollingFriction_1 = function () { + return (by = b._emscripten_bind_btPairCachingGhostObject_setRollingFriction_1 = b.asm.Mv).apply(null, arguments); + }), + cy = (b._emscripten_bind_btPairCachingGhostObject_getWorldTransform_0 = function () { + return (cy = b._emscripten_bind_btPairCachingGhostObject_getWorldTransform_0 = b.asm.Nv).apply(null, arguments); + }), + dy = (b._emscripten_bind_btPairCachingGhostObject_getCollisionFlags_0 = function () { + return (dy = b._emscripten_bind_btPairCachingGhostObject_getCollisionFlags_0 = b.asm.Ov).apply(null, arguments); + }), + ey = (b._emscripten_bind_btPairCachingGhostObject_setCollisionFlags_1 = function () { + return (ey = b._emscripten_bind_btPairCachingGhostObject_setCollisionFlags_1 = b.asm.Pv).apply(null, arguments); + }), + fy = (b._emscripten_bind_btPairCachingGhostObject_setWorldTransform_1 = function () { + return (fy = b._emscripten_bind_btPairCachingGhostObject_setWorldTransform_1 = b.asm.Qv).apply(null, arguments); + }), + gy = (b._emscripten_bind_btPairCachingGhostObject_setCollisionShape_1 = function () { + return (gy = b._emscripten_bind_btPairCachingGhostObject_setCollisionShape_1 = b.asm.Rv).apply(null, arguments); + }), + hy = (b._emscripten_bind_btPairCachingGhostObject_setCcdMotionThreshold_1 = function () { + return (hy = b._emscripten_bind_btPairCachingGhostObject_setCcdMotionThreshold_1 = b.asm.Sv).apply(null, arguments); + }), + iy = (b._emscripten_bind_btPairCachingGhostObject_setCcdSweptSphereRadius_1 = function () { + return (iy = b._emscripten_bind_btPairCachingGhostObject_setCcdSweptSphereRadius_1 = b.asm.Tv).apply(null, arguments); + }), + jy = (b._emscripten_bind_btPairCachingGhostObject_getUserIndex_0 = function () { + return (jy = b._emscripten_bind_btPairCachingGhostObject_getUserIndex_0 = b.asm.Uv).apply(null, arguments); + }), + ky = (b._emscripten_bind_btPairCachingGhostObject_setUserIndex_1 = function () { + return (ky = b._emscripten_bind_btPairCachingGhostObject_setUserIndex_1 = b.asm.Vv).apply(null, arguments); + }), + ly = (b._emscripten_bind_btPairCachingGhostObject_getUserPointer_0 = function () { + return (ly = b._emscripten_bind_btPairCachingGhostObject_getUserPointer_0 = b.asm.Wv).apply(null, arguments); + }), + my = (b._emscripten_bind_btPairCachingGhostObject_setUserPointer_1 = function () { + return (my = b._emscripten_bind_btPairCachingGhostObject_setUserPointer_1 = b.asm.Xv).apply(null, arguments); + }), + ny = (b._emscripten_bind_btPairCachingGhostObject_getBroadphaseHandle_0 = function () { + return (ny = b._emscripten_bind_btPairCachingGhostObject_getBroadphaseHandle_0 = b.asm.Yv).apply(null, arguments); + }), + oy = (b._emscripten_bind_btPairCachingGhostObject_getNumOverlappingObjects_0 = function () { + return (oy = b._emscripten_bind_btPairCachingGhostObject_getNumOverlappingObjects_0 = b.asm.Zv).apply(null, arguments); + }), + py = (b._emscripten_bind_btPairCachingGhostObject_getOverlappingObject_1 = function () { + return (py = b._emscripten_bind_btPairCachingGhostObject_getOverlappingObject_1 = b.asm._v).apply(null, arguments); + }), + qy = (b._emscripten_bind_btPairCachingGhostObject___destroy___0 = function () { + return (qy = b._emscripten_bind_btPairCachingGhostObject___destroy___0 = b.asm.$v).apply(null, arguments); + }), + ry = (b._emscripten_bind_btGhostPairCallback_btGhostPairCallback_0 = function () { + return (ry = b._emscripten_bind_btGhostPairCallback_btGhostPairCallback_0 = b.asm.aw).apply(null, arguments); + }), + sy = (b._emscripten_bind_btGhostPairCallback___destroy___0 = function () { + return (sy = b._emscripten_bind_btGhostPairCallback___destroy___0 = b.asm.bw).apply(null, arguments); + }), + ty = (b._emscripten_bind_btSoftBodyWorldInfo_btSoftBodyWorldInfo_0 = function () { + return (ty = b._emscripten_bind_btSoftBodyWorldInfo_btSoftBodyWorldInfo_0 = b.asm.cw).apply(null, arguments); + }), + uy = (b._emscripten_bind_btSoftBodyWorldInfo_get_air_density_0 = function () { + return (uy = b._emscripten_bind_btSoftBodyWorldInfo_get_air_density_0 = b.asm.dw).apply(null, arguments); + }), + vy = (b._emscripten_bind_btSoftBodyWorldInfo_set_air_density_1 = function () { + return (vy = b._emscripten_bind_btSoftBodyWorldInfo_set_air_density_1 = b.asm.ew).apply(null, arguments); + }), + wy = (b._emscripten_bind_btSoftBodyWorldInfo_get_water_density_0 = function () { + return (wy = b._emscripten_bind_btSoftBodyWorldInfo_get_water_density_0 = b.asm.fw).apply(null, arguments); + }), + xy = (b._emscripten_bind_btSoftBodyWorldInfo_set_water_density_1 = function () { + return (xy = b._emscripten_bind_btSoftBodyWorldInfo_set_water_density_1 = b.asm.gw).apply(null, arguments); + }), + yy = (b._emscripten_bind_btSoftBodyWorldInfo_get_water_offset_0 = function () { + return (yy = b._emscripten_bind_btSoftBodyWorldInfo_get_water_offset_0 = b.asm.hw).apply(null, arguments); + }), + zy = (b._emscripten_bind_btSoftBodyWorldInfo_set_water_offset_1 = function () { + return (zy = b._emscripten_bind_btSoftBodyWorldInfo_set_water_offset_1 = b.asm.iw).apply(null, arguments); + }), + Ay = (b._emscripten_bind_btSoftBodyWorldInfo_get_m_maxDisplacement_0 = function () { + return (Ay = b._emscripten_bind_btSoftBodyWorldInfo_get_m_maxDisplacement_0 = b.asm.jw).apply(null, arguments); + }), + By = (b._emscripten_bind_btSoftBodyWorldInfo_set_m_maxDisplacement_1 = function () { + return (By = b._emscripten_bind_btSoftBodyWorldInfo_set_m_maxDisplacement_1 = b.asm.kw).apply(null, arguments); + }), + Cy = (b._emscripten_bind_btSoftBodyWorldInfo_get_water_normal_0 = function () { + return (Cy = b._emscripten_bind_btSoftBodyWorldInfo_get_water_normal_0 = b.asm.lw).apply(null, arguments); + }), + Dy = (b._emscripten_bind_btSoftBodyWorldInfo_set_water_normal_1 = function () { + return (Dy = b._emscripten_bind_btSoftBodyWorldInfo_set_water_normal_1 = b.asm.mw).apply(null, arguments); + }), + Ey = (b._emscripten_bind_btSoftBodyWorldInfo_get_m_broadphase_0 = function () { + return (Ey = b._emscripten_bind_btSoftBodyWorldInfo_get_m_broadphase_0 = b.asm.nw).apply(null, arguments); + }), + Fy = (b._emscripten_bind_btSoftBodyWorldInfo_set_m_broadphase_1 = function () { + return (Fy = b._emscripten_bind_btSoftBodyWorldInfo_set_m_broadphase_1 = b.asm.ow).apply(null, arguments); + }), + Gy = (b._emscripten_bind_btSoftBodyWorldInfo_get_m_dispatcher_0 = function () { + return (Gy = b._emscripten_bind_btSoftBodyWorldInfo_get_m_dispatcher_0 = b.asm.pw).apply(null, arguments); + }), + Hy = (b._emscripten_bind_btSoftBodyWorldInfo_set_m_dispatcher_1 = function () { + return (Hy = b._emscripten_bind_btSoftBodyWorldInfo_set_m_dispatcher_1 = b.asm.qw).apply(null, arguments); + }), + Iy = (b._emscripten_bind_btSoftBodyWorldInfo_get_m_gravity_0 = function () { + return (Iy = b._emscripten_bind_btSoftBodyWorldInfo_get_m_gravity_0 = b.asm.rw).apply(null, arguments); + }), + Jy = (b._emscripten_bind_btSoftBodyWorldInfo_set_m_gravity_1 = function () { + return (Jy = b._emscripten_bind_btSoftBodyWorldInfo_set_m_gravity_1 = b.asm.sw).apply(null, arguments); + }), + Ky = (b._emscripten_bind_btSoftBodyWorldInfo___destroy___0 = function () { + return (Ky = b._emscripten_bind_btSoftBodyWorldInfo___destroy___0 = b.asm.tw).apply(null, arguments); + }), + Ly = (b._emscripten_bind_Face_get_m_n_1 = function () { + return (Ly = b._emscripten_bind_Face_get_m_n_1 = b.asm.uw).apply(null, arguments); + }), + My = (b._emscripten_bind_Face_set_m_n_2 = function () { + return (My = b._emscripten_bind_Face_set_m_n_2 = b.asm.vw).apply(null, arguments); + }), + Ny = (b._emscripten_bind_Face_get_m_normal_0 = function () { + return (Ny = b._emscripten_bind_Face_get_m_normal_0 = b.asm.ww).apply(null, arguments); + }), + Oy = (b._emscripten_bind_Face_set_m_normal_1 = function () { + return (Oy = b._emscripten_bind_Face_set_m_normal_1 = b.asm.xw).apply(null, arguments); + }), + Py = (b._emscripten_bind_Face_get_m_ra_0 = function () { + return (Py = b._emscripten_bind_Face_get_m_ra_0 = b.asm.yw).apply(null, arguments); + }), + Qy = (b._emscripten_bind_Face_set_m_ra_1 = function () { + return (Qy = b._emscripten_bind_Face_set_m_ra_1 = b.asm.zw).apply(null, arguments); + }), + Ry = (b._emscripten_bind_Face___destroy___0 = function () { + return (Ry = b._emscripten_bind_Face___destroy___0 = b.asm.Aw).apply(null, arguments); + }), + Sy = (b._emscripten_bind_tFaceArray_size_0 = function () { + return (Sy = b._emscripten_bind_tFaceArray_size_0 = b.asm.Bw).apply(null, arguments); + }), + Ty = (b._emscripten_bind_tFaceArray_at_1 = function () { + return (Ty = b._emscripten_bind_tFaceArray_at_1 = b.asm.Cw).apply(null, arguments); + }), + Uy = (b._emscripten_bind_tFaceArray___destroy___0 = function () { + return (Uy = b._emscripten_bind_tFaceArray___destroy___0 = b.asm.Dw).apply(null, arguments); + }), + Vy = (b._emscripten_bind_Node_get_m_x_0 = function () { + return (Vy = b._emscripten_bind_Node_get_m_x_0 = b.asm.Ew).apply(null, arguments); + }), + Wy = (b._emscripten_bind_Node_set_m_x_1 = function () { + return (Wy = b._emscripten_bind_Node_set_m_x_1 = b.asm.Fw).apply(null, arguments); + }), + Xy = (b._emscripten_bind_Node_get_m_q_0 = function () { + return (Xy = b._emscripten_bind_Node_get_m_q_0 = b.asm.Gw).apply(null, arguments); + }), + Yy = (b._emscripten_bind_Node_set_m_q_1 = function () { + return (Yy = b._emscripten_bind_Node_set_m_q_1 = b.asm.Hw).apply(null, arguments); + }), + Zy = (b._emscripten_bind_Node_get_m_v_0 = function () { + return (Zy = b._emscripten_bind_Node_get_m_v_0 = b.asm.Iw).apply(null, arguments); + }), + $y = (b._emscripten_bind_Node_set_m_v_1 = function () { + return ($y = b._emscripten_bind_Node_set_m_v_1 = b.asm.Jw).apply(null, arguments); + }), + az = (b._emscripten_bind_Node_get_m_f_0 = function () { + return (az = b._emscripten_bind_Node_get_m_f_0 = b.asm.Kw).apply(null, arguments); + }), + bz = (b._emscripten_bind_Node_set_m_f_1 = function () { + return (bz = b._emscripten_bind_Node_set_m_f_1 = b.asm.Lw).apply(null, arguments); + }), + cz = (b._emscripten_bind_Node_get_m_n_0 = function () { + return (cz = b._emscripten_bind_Node_get_m_n_0 = b.asm.Mw).apply(null, arguments); + }), + dz = (b._emscripten_bind_Node_set_m_n_1 = function () { + return (dz = b._emscripten_bind_Node_set_m_n_1 = b.asm.Nw).apply(null, arguments); + }), + ez = (b._emscripten_bind_Node_get_m_im_0 = function () { + return (ez = b._emscripten_bind_Node_get_m_im_0 = b.asm.Ow).apply(null, arguments); + }), + fz = (b._emscripten_bind_Node_set_m_im_1 = function () { + return (fz = b._emscripten_bind_Node_set_m_im_1 = b.asm.Pw).apply(null, arguments); + }), + gz = (b._emscripten_bind_Node_get_m_area_0 = function () { + return (gz = b._emscripten_bind_Node_get_m_area_0 = b.asm.Qw).apply(null, arguments); + }), + hz = (b._emscripten_bind_Node_set_m_area_1 = function () { + return (hz = b._emscripten_bind_Node_set_m_area_1 = b.asm.Rw).apply(null, arguments); + }), + iz = (b._emscripten_bind_Node___destroy___0 = function () { + return (iz = b._emscripten_bind_Node___destroy___0 = b.asm.Sw).apply(null, arguments); + }), + jz = (b._emscripten_bind_tNodeArray_size_0 = function () { + return (jz = b._emscripten_bind_tNodeArray_size_0 = b.asm.Tw).apply(null, arguments); + }), + kz = (b._emscripten_bind_tNodeArray_at_1 = function () { + return (kz = b._emscripten_bind_tNodeArray_at_1 = b.asm.Uw).apply(null, arguments); + }), + lz = (b._emscripten_bind_tNodeArray___destroy___0 = function () { + return (lz = b._emscripten_bind_tNodeArray___destroy___0 = b.asm.Vw).apply(null, arguments); + }), + mz = (b._emscripten_bind_Material_get_m_kLST_0 = function () { + return (mz = b._emscripten_bind_Material_get_m_kLST_0 = b.asm.Ww).apply(null, arguments); + }), + nz = (b._emscripten_bind_Material_set_m_kLST_1 = function () { + return (nz = b._emscripten_bind_Material_set_m_kLST_1 = b.asm.Xw).apply(null, arguments); + }), + oz = (b._emscripten_bind_Material_get_m_kAST_0 = function () { + return (oz = b._emscripten_bind_Material_get_m_kAST_0 = b.asm.Yw).apply(null, arguments); + }), + pz = (b._emscripten_bind_Material_set_m_kAST_1 = function () { + return (pz = b._emscripten_bind_Material_set_m_kAST_1 = b.asm.Zw).apply(null, arguments); + }), + qz = (b._emscripten_bind_Material_get_m_kVST_0 = function () { + return (qz = b._emscripten_bind_Material_get_m_kVST_0 = b.asm._w).apply(null, arguments); + }), + rz = (b._emscripten_bind_Material_set_m_kVST_1 = function () { + return (rz = b._emscripten_bind_Material_set_m_kVST_1 = b.asm.$w).apply(null, arguments); + }), + sz = (b._emscripten_bind_Material_get_m_flags_0 = function () { + return (sz = b._emscripten_bind_Material_get_m_flags_0 = b.asm.ax).apply(null, arguments); + }), + tz = (b._emscripten_bind_Material_set_m_flags_1 = function () { + return (tz = b._emscripten_bind_Material_set_m_flags_1 = b.asm.bx).apply(null, arguments); + }), + uz = (b._emscripten_bind_Material___destroy___0 = function () { + return (uz = b._emscripten_bind_Material___destroy___0 = b.asm.cx).apply(null, arguments); + }), + vz = (b._emscripten_bind_tMaterialArray_size_0 = function () { + return (vz = b._emscripten_bind_tMaterialArray_size_0 = b.asm.dx).apply(null, arguments); + }), + wz = (b._emscripten_bind_tMaterialArray_at_1 = function () { + return (wz = b._emscripten_bind_tMaterialArray_at_1 = b.asm.ex).apply(null, arguments); + }), + xz = (b._emscripten_bind_tMaterialArray___destroy___0 = function () { + return (xz = b._emscripten_bind_tMaterialArray___destroy___0 = b.asm.fx).apply(null, arguments); + }), + yz = (b._emscripten_bind_Anchor_get_m_node_0 = function () { + return (yz = b._emscripten_bind_Anchor_get_m_node_0 = b.asm.gx).apply(null, arguments); + }), + zz = (b._emscripten_bind_Anchor_set_m_node_1 = function () { + return (zz = b._emscripten_bind_Anchor_set_m_node_1 = b.asm.hx).apply(null, arguments); + }), + Az = (b._emscripten_bind_Anchor_get_m_local_0 = function () { + return (Az = b._emscripten_bind_Anchor_get_m_local_0 = b.asm.ix).apply(null, arguments); + }), + Bz = (b._emscripten_bind_Anchor_set_m_local_1 = function () { + return (Bz = b._emscripten_bind_Anchor_set_m_local_1 = b.asm.jx).apply(null, arguments); + }), + Cz = (b._emscripten_bind_Anchor_get_m_body_0 = function () { + return (Cz = b._emscripten_bind_Anchor_get_m_body_0 = b.asm.kx).apply(null, arguments); + }), + Dz = (b._emscripten_bind_Anchor_set_m_body_1 = function () { + return (Dz = b._emscripten_bind_Anchor_set_m_body_1 = b.asm.lx).apply(null, arguments); + }), + Ez = (b._emscripten_bind_Anchor_get_m_influence_0 = function () { + return (Ez = b._emscripten_bind_Anchor_get_m_influence_0 = b.asm.mx).apply(null, arguments); + }), + Fz = (b._emscripten_bind_Anchor_set_m_influence_1 = function () { + return (Fz = b._emscripten_bind_Anchor_set_m_influence_1 = b.asm.nx).apply(null, arguments); + }), + Gz = (b._emscripten_bind_Anchor_get_m_c0_0 = function () { + return (Gz = b._emscripten_bind_Anchor_get_m_c0_0 = b.asm.ox).apply(null, arguments); + }), + Hz = (b._emscripten_bind_Anchor_set_m_c0_1 = function () { + return (Hz = b._emscripten_bind_Anchor_set_m_c0_1 = b.asm.px).apply(null, arguments); + }), + Iz = (b._emscripten_bind_Anchor_get_m_c1_0 = function () { + return (Iz = b._emscripten_bind_Anchor_get_m_c1_0 = b.asm.qx).apply(null, arguments); + }), + Jz = (b._emscripten_bind_Anchor_set_m_c1_1 = function () { + return (Jz = b._emscripten_bind_Anchor_set_m_c1_1 = b.asm.rx).apply(null, arguments); + }), + Kz = (b._emscripten_bind_Anchor_get_m_c2_0 = function () { + return (Kz = b._emscripten_bind_Anchor_get_m_c2_0 = b.asm.sx).apply(null, arguments); + }), + Lz = (b._emscripten_bind_Anchor_set_m_c2_1 = function () { + return (Lz = b._emscripten_bind_Anchor_set_m_c2_1 = b.asm.tx).apply(null, arguments); + }), + Mz = (b._emscripten_bind_Anchor___destroy___0 = function () { + return (Mz = b._emscripten_bind_Anchor___destroy___0 = b.asm.ux).apply(null, arguments); + }), + Nz = (b._emscripten_bind_tAnchorArray_size_0 = function () { + return (Nz = b._emscripten_bind_tAnchorArray_size_0 = b.asm.vx).apply(null, arguments); + }), + Oz = (b._emscripten_bind_tAnchorArray_at_1 = function () { + return (Oz = b._emscripten_bind_tAnchorArray_at_1 = b.asm.wx).apply(null, arguments); + }), + Pz = (b._emscripten_bind_tAnchorArray_clear_0 = function () { + return (Pz = b._emscripten_bind_tAnchorArray_clear_0 = b.asm.xx).apply(null, arguments); + }), + Qz = (b._emscripten_bind_tAnchorArray_push_back_1 = function () { + return (Qz = b._emscripten_bind_tAnchorArray_push_back_1 = b.asm.yx).apply(null, arguments); + }), + Rz = (b._emscripten_bind_tAnchorArray_pop_back_0 = function () { + return (Rz = b._emscripten_bind_tAnchorArray_pop_back_0 = b.asm.zx).apply(null, arguments); + }), + Sz = (b._emscripten_bind_tAnchorArray___destroy___0 = function () { + return (Sz = b._emscripten_bind_tAnchorArray___destroy___0 = b.asm.Ax).apply(null, arguments); + }), + Tz = (b._emscripten_bind_Config_get_kVCF_0 = function () { + return (Tz = b._emscripten_bind_Config_get_kVCF_0 = b.asm.Bx).apply(null, arguments); + }), + Uz = (b._emscripten_bind_Config_set_kVCF_1 = function () { + return (Uz = b._emscripten_bind_Config_set_kVCF_1 = b.asm.Cx).apply(null, arguments); + }), + Vz = (b._emscripten_bind_Config_get_kDP_0 = function () { + return (Vz = b._emscripten_bind_Config_get_kDP_0 = b.asm.Dx).apply(null, arguments); + }), + Wz = (b._emscripten_bind_Config_set_kDP_1 = function () { + return (Wz = b._emscripten_bind_Config_set_kDP_1 = b.asm.Ex).apply(null, arguments); + }), + Xz = (b._emscripten_bind_Config_get_kDG_0 = function () { + return (Xz = b._emscripten_bind_Config_get_kDG_0 = b.asm.Fx).apply(null, arguments); + }), + Yz = (b._emscripten_bind_Config_set_kDG_1 = function () { + return (Yz = b._emscripten_bind_Config_set_kDG_1 = b.asm.Gx).apply(null, arguments); + }), + Zz = (b._emscripten_bind_Config_get_kLF_0 = function () { + return (Zz = b._emscripten_bind_Config_get_kLF_0 = b.asm.Hx).apply(null, arguments); + }), + $z = (b._emscripten_bind_Config_set_kLF_1 = function () { + return ($z = b._emscripten_bind_Config_set_kLF_1 = b.asm.Ix).apply(null, arguments); + }), + aA = (b._emscripten_bind_Config_get_kPR_0 = function () { + return (aA = b._emscripten_bind_Config_get_kPR_0 = b.asm.Jx).apply(null, arguments); + }), + bA = (b._emscripten_bind_Config_set_kPR_1 = function () { + return (bA = b._emscripten_bind_Config_set_kPR_1 = b.asm.Kx).apply(null, arguments); + }), + cA = (b._emscripten_bind_Config_get_kVC_0 = function () { + return (cA = b._emscripten_bind_Config_get_kVC_0 = b.asm.Lx).apply(null, arguments); + }), + dA = (b._emscripten_bind_Config_set_kVC_1 = function () { + return (dA = b._emscripten_bind_Config_set_kVC_1 = b.asm.Mx).apply(null, arguments); + }), + eA = (b._emscripten_bind_Config_get_kDF_0 = function () { + return (eA = b._emscripten_bind_Config_get_kDF_0 = b.asm.Nx).apply(null, arguments); + }), + fA = (b._emscripten_bind_Config_set_kDF_1 = function () { + return (fA = b._emscripten_bind_Config_set_kDF_1 = b.asm.Ox).apply(null, arguments); + }), + gA = (b._emscripten_bind_Config_get_kMT_0 = function () { + return (gA = b._emscripten_bind_Config_get_kMT_0 = b.asm.Px).apply(null, arguments); + }), + hA = (b._emscripten_bind_Config_set_kMT_1 = function () { + return (hA = b._emscripten_bind_Config_set_kMT_1 = b.asm.Qx).apply(null, arguments); + }), + iA = (b._emscripten_bind_Config_get_kCHR_0 = function () { + return (iA = b._emscripten_bind_Config_get_kCHR_0 = b.asm.Rx).apply(null, arguments); + }), + jA = (b._emscripten_bind_Config_set_kCHR_1 = function () { + return (jA = b._emscripten_bind_Config_set_kCHR_1 = b.asm.Sx).apply(null, arguments); + }), + kA = (b._emscripten_bind_Config_get_kKHR_0 = function () { + return (kA = b._emscripten_bind_Config_get_kKHR_0 = b.asm.Tx).apply(null, arguments); + }), + lA = (b._emscripten_bind_Config_set_kKHR_1 = function () { + return (lA = b._emscripten_bind_Config_set_kKHR_1 = b.asm.Ux).apply(null, arguments); + }), + mA = (b._emscripten_bind_Config_get_kSHR_0 = function () { + return (mA = b._emscripten_bind_Config_get_kSHR_0 = b.asm.Vx).apply(null, arguments); + }), + nA = (b._emscripten_bind_Config_set_kSHR_1 = function () { + return (nA = b._emscripten_bind_Config_set_kSHR_1 = b.asm.Wx).apply(null, arguments); + }), + oA = (b._emscripten_bind_Config_get_kAHR_0 = function () { + return (oA = b._emscripten_bind_Config_get_kAHR_0 = b.asm.Xx).apply(null, arguments); + }), + pA = (b._emscripten_bind_Config_set_kAHR_1 = function () { + return (pA = b._emscripten_bind_Config_set_kAHR_1 = b.asm.Yx).apply(null, arguments); + }), + qA = (b._emscripten_bind_Config_get_kSRHR_CL_0 = function () { + return (qA = b._emscripten_bind_Config_get_kSRHR_CL_0 = b.asm.Zx).apply(null, arguments); + }), + rA = (b._emscripten_bind_Config_set_kSRHR_CL_1 = function () { + return (rA = b._emscripten_bind_Config_set_kSRHR_CL_1 = b.asm._x).apply(null, arguments); + }), + sA = (b._emscripten_bind_Config_get_kSKHR_CL_0 = function () { + return (sA = b._emscripten_bind_Config_get_kSKHR_CL_0 = b.asm.$x).apply(null, arguments); + }), + tA = (b._emscripten_bind_Config_set_kSKHR_CL_1 = function () { + return (tA = b._emscripten_bind_Config_set_kSKHR_CL_1 = b.asm.ay).apply(null, arguments); + }), + uA = (b._emscripten_bind_Config_get_kSSHR_CL_0 = function () { + return (uA = b._emscripten_bind_Config_get_kSSHR_CL_0 = b.asm.by).apply(null, arguments); + }), + vA = (b._emscripten_bind_Config_set_kSSHR_CL_1 = function () { + return (vA = b._emscripten_bind_Config_set_kSSHR_CL_1 = b.asm.cy).apply(null, arguments); + }), + wA = (b._emscripten_bind_Config_get_kSR_SPLT_CL_0 = function () { + return (wA = b._emscripten_bind_Config_get_kSR_SPLT_CL_0 = b.asm.dy).apply(null, arguments); + }), + xA = (b._emscripten_bind_Config_set_kSR_SPLT_CL_1 = function () { + return (xA = b._emscripten_bind_Config_set_kSR_SPLT_CL_1 = b.asm.ey).apply(null, arguments); + }), + yA = (b._emscripten_bind_Config_get_kSK_SPLT_CL_0 = function () { + return (yA = b._emscripten_bind_Config_get_kSK_SPLT_CL_0 = b.asm.fy).apply(null, arguments); + }), + zA = (b._emscripten_bind_Config_set_kSK_SPLT_CL_1 = function () { + return (zA = b._emscripten_bind_Config_set_kSK_SPLT_CL_1 = b.asm.gy).apply(null, arguments); + }), + AA = (b._emscripten_bind_Config_get_kSS_SPLT_CL_0 = function () { + return (AA = b._emscripten_bind_Config_get_kSS_SPLT_CL_0 = b.asm.hy).apply(null, arguments); + }), + BA = (b._emscripten_bind_Config_set_kSS_SPLT_CL_1 = function () { + return (BA = b._emscripten_bind_Config_set_kSS_SPLT_CL_1 = b.asm.iy).apply(null, arguments); + }), + CA = (b._emscripten_bind_Config_get_maxvolume_0 = function () { + return (CA = b._emscripten_bind_Config_get_maxvolume_0 = b.asm.jy).apply(null, arguments); + }), + DA = (b._emscripten_bind_Config_set_maxvolume_1 = function () { + return (DA = b._emscripten_bind_Config_set_maxvolume_1 = b.asm.ky).apply(null, arguments); + }), + EA = (b._emscripten_bind_Config_get_timescale_0 = function () { + return (EA = b._emscripten_bind_Config_get_timescale_0 = b.asm.ly).apply(null, arguments); + }), + FA = (b._emscripten_bind_Config_set_timescale_1 = function () { + return (FA = b._emscripten_bind_Config_set_timescale_1 = b.asm.my).apply(null, arguments); + }), + GA = (b._emscripten_bind_Config_get_viterations_0 = function () { + return (GA = b._emscripten_bind_Config_get_viterations_0 = b.asm.ny).apply(null, arguments); + }), + HA = (b._emscripten_bind_Config_set_viterations_1 = function () { + return (HA = b._emscripten_bind_Config_set_viterations_1 = b.asm.oy).apply(null, arguments); + }), + IA = (b._emscripten_bind_Config_get_piterations_0 = function () { + return (IA = b._emscripten_bind_Config_get_piterations_0 = b.asm.py).apply(null, arguments); + }), + JA = (b._emscripten_bind_Config_set_piterations_1 = function () { + return (JA = b._emscripten_bind_Config_set_piterations_1 = b.asm.qy).apply(null, arguments); + }), + KA = (b._emscripten_bind_Config_get_diterations_0 = function () { + return (KA = b._emscripten_bind_Config_get_diterations_0 = b.asm.ry).apply(null, arguments); + }), + LA = (b._emscripten_bind_Config_set_diterations_1 = function () { + return (LA = b._emscripten_bind_Config_set_diterations_1 = b.asm.sy).apply(null, arguments); + }), + MA = (b._emscripten_bind_Config_get_citerations_0 = function () { + return (MA = b._emscripten_bind_Config_get_citerations_0 = b.asm.ty).apply(null, arguments); + }), + NA = (b._emscripten_bind_Config_set_citerations_1 = function () { + return (NA = b._emscripten_bind_Config_set_citerations_1 = b.asm.uy).apply(null, arguments); + }), + OA = (b._emscripten_bind_Config_get_collisions_0 = function () { + return (OA = b._emscripten_bind_Config_get_collisions_0 = b.asm.vy).apply(null, arguments); + }), + PA = (b._emscripten_bind_Config_set_collisions_1 = function () { + return (PA = b._emscripten_bind_Config_set_collisions_1 = b.asm.wy).apply(null, arguments); + }), + QA = (b._emscripten_bind_Config___destroy___0 = function () { + return (QA = b._emscripten_bind_Config___destroy___0 = b.asm.xy).apply(null, arguments); + }), + RA = (b._emscripten_bind_btSoftBody_btSoftBody_4 = function () { + return (RA = b._emscripten_bind_btSoftBody_btSoftBody_4 = b.asm.yy).apply(null, arguments); + }), + SA = (b._emscripten_bind_btSoftBody_checkLink_2 = function () { + return (SA = b._emscripten_bind_btSoftBody_checkLink_2 = b.asm.zy).apply(null, arguments); + }), + TA = (b._emscripten_bind_btSoftBody_checkFace_3 = function () { + return (TA = b._emscripten_bind_btSoftBody_checkFace_3 = b.asm.Ay).apply(null, arguments); + }), + UA = (b._emscripten_bind_btSoftBody_appendMaterial_0 = function () { + return (UA = b._emscripten_bind_btSoftBody_appendMaterial_0 = b.asm.By).apply(null, arguments); + }), + VA = (b._emscripten_bind_btSoftBody_appendNode_2 = function () { + return (VA = b._emscripten_bind_btSoftBody_appendNode_2 = b.asm.Cy).apply(null, arguments); + }), + WA = (b._emscripten_bind_btSoftBody_appendLink_4 = function () { + return (WA = b._emscripten_bind_btSoftBody_appendLink_4 = b.asm.Dy).apply(null, arguments); + }), + XA = (b._emscripten_bind_btSoftBody_appendFace_4 = function () { + return (XA = b._emscripten_bind_btSoftBody_appendFace_4 = b.asm.Ey).apply(null, arguments); + }), + YA = (b._emscripten_bind_btSoftBody_appendTetra_5 = function () { + return (YA = b._emscripten_bind_btSoftBody_appendTetra_5 = b.asm.Fy).apply(null, arguments); + }), + ZA = (b._emscripten_bind_btSoftBody_appendAnchor_4 = function () { + return (ZA = b._emscripten_bind_btSoftBody_appendAnchor_4 = b.asm.Gy).apply(null, arguments); + }), + $A = (b._emscripten_bind_btSoftBody_addForce_1 = function () { + return ($A = b._emscripten_bind_btSoftBody_addForce_1 = b.asm.Hy).apply(null, arguments); + }), + aB = (b._emscripten_bind_btSoftBody_addForce_2 = function () { + return (aB = b._emscripten_bind_btSoftBody_addForce_2 = b.asm.Iy).apply(null, arguments); + }), + bB = (b._emscripten_bind_btSoftBody_addAeroForceToNode_2 = function () { + return (bB = b._emscripten_bind_btSoftBody_addAeroForceToNode_2 = b.asm.Jy).apply(null, arguments); + }), + cB = (b._emscripten_bind_btSoftBody_getTotalMass_0 = function () { + return (cB = b._emscripten_bind_btSoftBody_getTotalMass_0 = b.asm.Ky).apply(null, arguments); + }), + dB = (b._emscripten_bind_btSoftBody_setTotalMass_2 = function () { + return (dB = b._emscripten_bind_btSoftBody_setTotalMass_2 = b.asm.Ly).apply(null, arguments); + }), + eB = (b._emscripten_bind_btSoftBody_setMass_2 = function () { + return (eB = b._emscripten_bind_btSoftBody_setMass_2 = b.asm.My).apply(null, arguments); + }), + fB = (b._emscripten_bind_btSoftBody_transform_1 = function () { + return (fB = b._emscripten_bind_btSoftBody_transform_1 = b.asm.Ny).apply(null, arguments); + }), + gB = (b._emscripten_bind_btSoftBody_translate_1 = function () { + return (gB = b._emscripten_bind_btSoftBody_translate_1 = b.asm.Oy).apply(null, arguments); + }), + hB = (b._emscripten_bind_btSoftBody_rotate_1 = function () { + return (hB = b._emscripten_bind_btSoftBody_rotate_1 = b.asm.Py).apply(null, arguments); + }), + iB = (b._emscripten_bind_btSoftBody_scale_1 = function () { + return (iB = b._emscripten_bind_btSoftBody_scale_1 = b.asm.Qy).apply(null, arguments); + }), + jB = (b._emscripten_bind_btSoftBody_generateClusters_1 = function () { + return (jB = b._emscripten_bind_btSoftBody_generateClusters_1 = b.asm.Ry).apply(null, arguments); + }), + kB = (b._emscripten_bind_btSoftBody_generateClusters_2 = function () { + return (kB = b._emscripten_bind_btSoftBody_generateClusters_2 = b.asm.Sy).apply(null, arguments); + }), + lB = (b._emscripten_bind_btSoftBody_generateBendingConstraints_2 = function () { + return (lB = b._emscripten_bind_btSoftBody_generateBendingConstraints_2 = b.asm.Ty).apply(null, arguments); + }), + mB = (b._emscripten_bind_btSoftBody_upcast_1 = function () { + return (mB = b._emscripten_bind_btSoftBody_upcast_1 = b.asm.Uy).apply(null, arguments); + }), + nB = (b._emscripten_bind_btSoftBody_getRestLengthScale_0 = function () { + return (nB = b._emscripten_bind_btSoftBody_getRestLengthScale_0 = b.asm.Vy).apply(null, arguments); + }), + oB = (b._emscripten_bind_btSoftBody_setRestLengthScale_1 = function () { + return (oB = b._emscripten_bind_btSoftBody_setRestLengthScale_1 = b.asm.Wy).apply(null, arguments); + }), + pB = (b._emscripten_bind_btSoftBody_setAnisotropicFriction_2 = function () { + return (pB = b._emscripten_bind_btSoftBody_setAnisotropicFriction_2 = b.asm.Xy).apply(null, arguments); + }), + qB = (b._emscripten_bind_btSoftBody_getCollisionShape_0 = function () { + return (qB = b._emscripten_bind_btSoftBody_getCollisionShape_0 = b.asm.Yy).apply(null, arguments); + }), + rB = (b._emscripten_bind_btSoftBody_setContactProcessingThreshold_1 = function () { + return (rB = b._emscripten_bind_btSoftBody_setContactProcessingThreshold_1 = b.asm.Zy).apply(null, arguments); + }), + sB = (b._emscripten_bind_btSoftBody_setActivationState_1 = function () { + return (sB = b._emscripten_bind_btSoftBody_setActivationState_1 = b.asm._y).apply(null, arguments); + }), + tB = (b._emscripten_bind_btSoftBody_forceActivationState_1 = function () { + return (tB = b._emscripten_bind_btSoftBody_forceActivationState_1 = b.asm.$y).apply(null, arguments); + }), + uB = (b._emscripten_bind_btSoftBody_activate_0 = function () { + return (uB = b._emscripten_bind_btSoftBody_activate_0 = b.asm.az).apply(null, arguments); + }), + vB = (b._emscripten_bind_btSoftBody_activate_1 = function () { + return (vB = b._emscripten_bind_btSoftBody_activate_1 = b.asm.bz).apply(null, arguments); + }), + wB = (b._emscripten_bind_btSoftBody_isActive_0 = function () { + return (wB = b._emscripten_bind_btSoftBody_isActive_0 = b.asm.cz).apply(null, arguments); + }), + xB = (b._emscripten_bind_btSoftBody_isKinematicObject_0 = function () { + return (xB = b._emscripten_bind_btSoftBody_isKinematicObject_0 = b.asm.dz).apply(null, arguments); + }), + yB = (b._emscripten_bind_btSoftBody_isStaticObject_0 = function () { + return (yB = b._emscripten_bind_btSoftBody_isStaticObject_0 = b.asm.ez).apply(null, arguments); + }), + zB = (b._emscripten_bind_btSoftBody_isStaticOrKinematicObject_0 = function () { + return (zB = b._emscripten_bind_btSoftBody_isStaticOrKinematicObject_0 = b.asm.fz).apply(null, arguments); + }), + AB = (b._emscripten_bind_btSoftBody_getRestitution_0 = function () { + return (AB = b._emscripten_bind_btSoftBody_getRestitution_0 = b.asm.gz).apply(null, arguments); + }), + BB = (b._emscripten_bind_btSoftBody_getFriction_0 = function () { + return (BB = b._emscripten_bind_btSoftBody_getFriction_0 = b.asm.hz).apply(null, arguments); + }), + CB = (b._emscripten_bind_btSoftBody_getRollingFriction_0 = function () { + return (CB = b._emscripten_bind_btSoftBody_getRollingFriction_0 = b.asm.iz).apply(null, arguments); + }), + DB = (b._emscripten_bind_btSoftBody_setRestitution_1 = function () { + return (DB = b._emscripten_bind_btSoftBody_setRestitution_1 = b.asm.jz).apply(null, arguments); + }), + EB = (b._emscripten_bind_btSoftBody_setFriction_1 = function () { + return (EB = b._emscripten_bind_btSoftBody_setFriction_1 = b.asm.kz).apply(null, arguments); + }), + FB = (b._emscripten_bind_btSoftBody_setRollingFriction_1 = function () { + return (FB = b._emscripten_bind_btSoftBody_setRollingFriction_1 = b.asm.lz).apply(null, arguments); + }), + GB = (b._emscripten_bind_btSoftBody_getWorldTransform_0 = function () { + return (GB = b._emscripten_bind_btSoftBody_getWorldTransform_0 = b.asm.mz).apply(null, arguments); + }), + HB = (b._emscripten_bind_btSoftBody_getCollisionFlags_0 = function () { + return (HB = b._emscripten_bind_btSoftBody_getCollisionFlags_0 = b.asm.nz).apply(null, arguments); + }), + IB = (b._emscripten_bind_btSoftBody_setCollisionFlags_1 = function () { + return (IB = b._emscripten_bind_btSoftBody_setCollisionFlags_1 = b.asm.oz).apply(null, arguments); + }), + JB = (b._emscripten_bind_btSoftBody_setWorldTransform_1 = function () { + return (JB = b._emscripten_bind_btSoftBody_setWorldTransform_1 = b.asm.pz).apply(null, arguments); + }), + KB = (b._emscripten_bind_btSoftBody_setCollisionShape_1 = function () { + return (KB = b._emscripten_bind_btSoftBody_setCollisionShape_1 = b.asm.qz).apply(null, arguments); + }), + LB = (b._emscripten_bind_btSoftBody_setCcdMotionThreshold_1 = function () { + return (LB = b._emscripten_bind_btSoftBody_setCcdMotionThreshold_1 = b.asm.rz).apply(null, arguments); + }), + MB = (b._emscripten_bind_btSoftBody_setCcdSweptSphereRadius_1 = function () { + return (MB = b._emscripten_bind_btSoftBody_setCcdSweptSphereRadius_1 = b.asm.sz).apply(null, arguments); + }), + NB = (b._emscripten_bind_btSoftBody_getUserIndex_0 = function () { + return (NB = b._emscripten_bind_btSoftBody_getUserIndex_0 = b.asm.tz).apply(null, arguments); + }), + OB = (b._emscripten_bind_btSoftBody_setUserIndex_1 = function () { + return (OB = b._emscripten_bind_btSoftBody_setUserIndex_1 = b.asm.uz).apply(null, arguments); + }), + PB = (b._emscripten_bind_btSoftBody_getUserPointer_0 = function () { + return (PB = b._emscripten_bind_btSoftBody_getUserPointer_0 = b.asm.vz).apply(null, arguments); + }), + QB = (b._emscripten_bind_btSoftBody_setUserPointer_1 = function () { + return (QB = b._emscripten_bind_btSoftBody_setUserPointer_1 = b.asm.wz).apply(null, arguments); + }), + RB = (b._emscripten_bind_btSoftBody_getBroadphaseHandle_0 = function () { + return (RB = b._emscripten_bind_btSoftBody_getBroadphaseHandle_0 = b.asm.xz).apply(null, arguments); + }), + SB = (b._emscripten_bind_btSoftBody_get_m_cfg_0 = function () { + return (SB = b._emscripten_bind_btSoftBody_get_m_cfg_0 = b.asm.yz).apply(null, arguments); + }), + TB = (b._emscripten_bind_btSoftBody_set_m_cfg_1 = function () { + return (TB = b._emscripten_bind_btSoftBody_set_m_cfg_1 = b.asm.zz).apply(null, arguments); + }), + UB = (b._emscripten_bind_btSoftBody_get_m_nodes_0 = function () { + return (UB = b._emscripten_bind_btSoftBody_get_m_nodes_0 = b.asm.Az).apply(null, arguments); + }), + VB = (b._emscripten_bind_btSoftBody_set_m_nodes_1 = function () { + return (VB = b._emscripten_bind_btSoftBody_set_m_nodes_1 = b.asm.Bz).apply(null, arguments); + }), + WB = (b._emscripten_bind_btSoftBody_get_m_faces_0 = function () { + return (WB = b._emscripten_bind_btSoftBody_get_m_faces_0 = b.asm.Cz).apply(null, arguments); + }), + XB = (b._emscripten_bind_btSoftBody_set_m_faces_1 = function () { + return (XB = b._emscripten_bind_btSoftBody_set_m_faces_1 = b.asm.Dz).apply(null, arguments); + }), + YB = (b._emscripten_bind_btSoftBody_get_m_materials_0 = function () { + return (YB = b._emscripten_bind_btSoftBody_get_m_materials_0 = b.asm.Ez).apply(null, arguments); + }), + ZB = (b._emscripten_bind_btSoftBody_set_m_materials_1 = function () { + return (ZB = b._emscripten_bind_btSoftBody_set_m_materials_1 = b.asm.Fz).apply(null, arguments); + }), + $B = (b._emscripten_bind_btSoftBody_get_m_anchors_0 = function () { + return ($B = b._emscripten_bind_btSoftBody_get_m_anchors_0 = b.asm.Gz).apply(null, arguments); + }), + aC = (b._emscripten_bind_btSoftBody_set_m_anchors_1 = function () { + return (aC = b._emscripten_bind_btSoftBody_set_m_anchors_1 = b.asm.Hz).apply(null, arguments); + }), + bC = (b._emscripten_bind_btSoftBody___destroy___0 = function () { + return (bC = b._emscripten_bind_btSoftBody___destroy___0 = b.asm.Iz).apply(null, arguments); + }), + cC = (b._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_0 = function () { + return (cC = b._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_0 = b.asm.Jz).apply(null, arguments); + }), + dC = (b._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_1 = function () { + return (dC = b._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_1 = b.asm.Kz).apply(null, arguments); + }), + eC = (b._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration___destroy___0 = function () { + return (eC = b._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration___destroy___0 = b.asm.Lz).apply(null, arguments); + }), + fC = (b._emscripten_bind_btDefaultSoftBodySolver_btDefaultSoftBodySolver_0 = function () { + return (fC = b._emscripten_bind_btDefaultSoftBodySolver_btDefaultSoftBodySolver_0 = b.asm.Mz).apply(null, arguments); + }), + gC = (b._emscripten_bind_btDefaultSoftBodySolver___destroy___0 = function () { + return (gC = b._emscripten_bind_btDefaultSoftBodySolver___destroy___0 = b.asm.Nz).apply(null, arguments); + }), + hC = (b._emscripten_bind_btSoftBodyArray_size_0 = function () { + return (hC = b._emscripten_bind_btSoftBodyArray_size_0 = b.asm.Oz).apply(null, arguments); + }), + iC = (b._emscripten_bind_btSoftBodyArray_at_1 = function () { + return (iC = b._emscripten_bind_btSoftBodyArray_at_1 = b.asm.Pz).apply(null, arguments); + }), + jC = (b._emscripten_bind_btSoftBodyArray___destroy___0 = function () { + return (jC = b._emscripten_bind_btSoftBodyArray___destroy___0 = b.asm.Qz).apply(null, arguments); + }), + kC = (b._emscripten_bind_btSoftRigidDynamicsWorld_btSoftRigidDynamicsWorld_5 = function () { + return (kC = b._emscripten_bind_btSoftRigidDynamicsWorld_btSoftRigidDynamicsWorld_5 = b.asm.Rz).apply(null, arguments); + }), + lC = (b._emscripten_bind_btSoftRigidDynamicsWorld_addSoftBody_3 = function () { + return (lC = b._emscripten_bind_btSoftRigidDynamicsWorld_addSoftBody_3 = b.asm.Sz).apply(null, arguments); + }), + mC = (b._emscripten_bind_btSoftRigidDynamicsWorld_removeSoftBody_1 = function () { + return (mC = b._emscripten_bind_btSoftRigidDynamicsWorld_removeSoftBody_1 = b.asm.Tz).apply(null, arguments); + }), + nC = (b._emscripten_bind_btSoftRigidDynamicsWorld_removeCollisionObject_1 = function () { + return (nC = b._emscripten_bind_btSoftRigidDynamicsWorld_removeCollisionObject_1 = b.asm.Uz).apply(null, arguments); + }), + oC = (b._emscripten_bind_btSoftRigidDynamicsWorld_getWorldInfo_0 = function () { + return (oC = b._emscripten_bind_btSoftRigidDynamicsWorld_getWorldInfo_0 = b.asm.Vz).apply(null, arguments); + }), + pC = (b._emscripten_bind_btSoftRigidDynamicsWorld_getSoftBodyArray_0 = function () { + return (pC = b._emscripten_bind_btSoftRigidDynamicsWorld_getSoftBodyArray_0 = b.asm.Wz).apply(null, arguments); + }), + qC = (b._emscripten_bind_btSoftRigidDynamicsWorld_getDispatcher_0 = function () { + return (qC = b._emscripten_bind_btSoftRigidDynamicsWorld_getDispatcher_0 = b.asm.Xz).apply(null, arguments); + }), + rC = (b._emscripten_bind_btSoftRigidDynamicsWorld_rayTest_3 = function () { + return (rC = b._emscripten_bind_btSoftRigidDynamicsWorld_rayTest_3 = b.asm.Yz).apply(null, arguments); + }), + sC = (b._emscripten_bind_btSoftRigidDynamicsWorld_getPairCache_0 = function () { + return (sC = b._emscripten_bind_btSoftRigidDynamicsWorld_getPairCache_0 = b.asm.Zz).apply(null, arguments); + }), + tC = (b._emscripten_bind_btSoftRigidDynamicsWorld_getDispatchInfo_0 = function () { + return (tC = b._emscripten_bind_btSoftRigidDynamicsWorld_getDispatchInfo_0 = b.asm._z).apply(null, arguments); + }), + uC = (b._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_1 = function () { + return (uC = b._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_1 = b.asm.$z).apply(null, arguments); + }), + vC = (b._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_2 = function () { + return (vC = b._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_2 = b.asm.aA).apply(null, arguments); + }), + wC = (b._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_3 = function () { + return (wC = b._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_3 = b.asm.bA).apply(null, arguments); + }), + xC = (b._emscripten_bind_btSoftRigidDynamicsWorld_getBroadphase_0 = function () { + return (xC = b._emscripten_bind_btSoftRigidDynamicsWorld_getBroadphase_0 = b.asm.cA).apply(null, arguments); + }), + yC = (b._emscripten_bind_btSoftRigidDynamicsWorld_convexSweepTest_5 = function () { + return (yC = b._emscripten_bind_btSoftRigidDynamicsWorld_convexSweepTest_5 = b.asm.dA).apply(null, arguments); + }), + zC = (b._emscripten_bind_btSoftRigidDynamicsWorld_contactPairTest_3 = function () { + return (zC = b._emscripten_bind_btSoftRigidDynamicsWorld_contactPairTest_3 = b.asm.eA).apply(null, arguments); + }), + AC = (b._emscripten_bind_btSoftRigidDynamicsWorld_contactTest_2 = function () { + return (AC = b._emscripten_bind_btSoftRigidDynamicsWorld_contactTest_2 = b.asm.fA).apply(null, arguments); + }), + BC = (b._emscripten_bind_btSoftRigidDynamicsWorld_updateSingleAabb_1 = function () { + return (BC = b._emscripten_bind_btSoftRigidDynamicsWorld_updateSingleAabb_1 = b.asm.gA).apply(null, arguments); + }), + CC = (b._emscripten_bind_btSoftRigidDynamicsWorld_setDebugDrawer_1 = function () { + return (CC = b._emscripten_bind_btSoftRigidDynamicsWorld_setDebugDrawer_1 = b.asm.hA).apply(null, arguments); + }), + DC = (b._emscripten_bind_btSoftRigidDynamicsWorld_getDebugDrawer_0 = function () { + return (DC = b._emscripten_bind_btSoftRigidDynamicsWorld_getDebugDrawer_0 = b.asm.iA).apply(null, arguments); + }), + EC = (b._emscripten_bind_btSoftRigidDynamicsWorld_debugDrawWorld_0 = function () { + return (EC = b._emscripten_bind_btSoftRigidDynamicsWorld_debugDrawWorld_0 = b.asm.jA).apply(null, arguments); + }), + FC = (b._emscripten_bind_btSoftRigidDynamicsWorld_debugDrawObject_3 = function () { + return (FC = b._emscripten_bind_btSoftRigidDynamicsWorld_debugDrawObject_3 = b.asm.kA).apply(null, arguments); + }), + GC = (b._emscripten_bind_btSoftRigidDynamicsWorld_setGravity_1 = function () { + return (GC = b._emscripten_bind_btSoftRigidDynamicsWorld_setGravity_1 = b.asm.lA).apply(null, arguments); + }), + HC = (b._emscripten_bind_btSoftRigidDynamicsWorld_getGravity_0 = function () { + return (HC = b._emscripten_bind_btSoftRigidDynamicsWorld_getGravity_0 = b.asm.mA).apply(null, arguments); + }), + IC = (b._emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_1 = function () { + return (IC = b._emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_1 = b.asm.nA).apply(null, arguments); + }), + JC = (b._emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_3 = function () { + return (JC = b._emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_3 = b.asm.oA).apply(null, arguments); + }), + KC = (b._emscripten_bind_btSoftRigidDynamicsWorld_removeRigidBody_1 = function () { + return (KC = b._emscripten_bind_btSoftRigidDynamicsWorld_removeRigidBody_1 = b.asm.pA).apply(null, arguments); + }), + LC = (b._emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_1 = function () { + return (LC = b._emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_1 = b.asm.qA).apply(null, arguments); + }), + MC = (b._emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_2 = function () { + return (MC = b._emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_2 = b.asm.rA).apply(null, arguments); + }), + NC = (b._emscripten_bind_btSoftRigidDynamicsWorld_removeConstraint_1 = function () { + return (NC = b._emscripten_bind_btSoftRigidDynamicsWorld_removeConstraint_1 = b.asm.sA).apply(null, arguments); + }), + OC = (b._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_1 = function () { + return (OC = b._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_1 = b.asm.tA).apply(null, arguments); + }), + PC = (b._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_2 = function () { + return (PC = b._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_2 = b.asm.uA).apply(null, arguments); + }), + QC = (b._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_3 = function () { + return (QC = b._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_3 = b.asm.vA).apply(null, arguments); + }), + RC = (b._emscripten_bind_btSoftRigidDynamicsWorld_setContactAddedCallback_1 = function () { + return (RC = b._emscripten_bind_btSoftRigidDynamicsWorld_setContactAddedCallback_1 = b.asm.wA).apply(null, arguments); + }), + SC = (b._emscripten_bind_btSoftRigidDynamicsWorld_setContactProcessedCallback_1 = function () { + return (SC = b._emscripten_bind_btSoftRigidDynamicsWorld_setContactProcessedCallback_1 = b.asm.xA).apply(null, arguments); + }), + TC = (b._emscripten_bind_btSoftRigidDynamicsWorld_setContactDestroyedCallback_1 = function () { + return (TC = b._emscripten_bind_btSoftRigidDynamicsWorld_setContactDestroyedCallback_1 = b.asm.yA).apply(null, arguments); + }), + UC = (b._emscripten_bind_btSoftRigidDynamicsWorld_addAction_1 = function () { + return (UC = b._emscripten_bind_btSoftRigidDynamicsWorld_addAction_1 = b.asm.zA).apply(null, arguments); + }), + VC = (b._emscripten_bind_btSoftRigidDynamicsWorld_removeAction_1 = function () { + return (VC = b._emscripten_bind_btSoftRigidDynamicsWorld_removeAction_1 = b.asm.AA).apply(null, arguments); + }), + WC = (b._emscripten_bind_btSoftRigidDynamicsWorld_getSolverInfo_0 = function () { + return (WC = b._emscripten_bind_btSoftRigidDynamicsWorld_getSolverInfo_0 = b.asm.BA).apply(null, arguments); + }), + XC = (b._emscripten_bind_btSoftRigidDynamicsWorld_setInternalTickCallback_1 = function () { + return (XC = b._emscripten_bind_btSoftRigidDynamicsWorld_setInternalTickCallback_1 = b.asm.CA).apply(null, arguments); + }), + YC = (b._emscripten_bind_btSoftRigidDynamicsWorld_setInternalTickCallback_2 = function () { + return (YC = b._emscripten_bind_btSoftRigidDynamicsWorld_setInternalTickCallback_2 = b.asm.DA).apply(null, arguments); + }), + ZC = (b._emscripten_bind_btSoftRigidDynamicsWorld_setInternalTickCallback_3 = function () { + return (ZC = b._emscripten_bind_btSoftRigidDynamicsWorld_setInternalTickCallback_3 = b.asm.EA).apply(null, arguments); + }), + $C = (b._emscripten_bind_btSoftRigidDynamicsWorld___destroy___0 = function () { + return ($C = b._emscripten_bind_btSoftRigidDynamicsWorld___destroy___0 = b.asm.FA).apply(null, arguments); + }), + aD = (b._emscripten_bind_btSoftBodyHelpers_btSoftBodyHelpers_0 = function () { + return (aD = b._emscripten_bind_btSoftBodyHelpers_btSoftBodyHelpers_0 = b.asm.GA).apply(null, arguments); + }), + bD = (b._emscripten_bind_btSoftBodyHelpers_CreateRope_5 = function () { + return (bD = b._emscripten_bind_btSoftBodyHelpers_CreateRope_5 = b.asm.HA).apply(null, arguments); + }), + cD = (b._emscripten_bind_btSoftBodyHelpers_CreatePatch_9 = function () { + return (cD = b._emscripten_bind_btSoftBodyHelpers_CreatePatch_9 = b.asm.IA).apply(null, arguments); + }), + dD = (b._emscripten_bind_btSoftBodyHelpers_CreatePatchUV_10 = function () { + return (dD = b._emscripten_bind_btSoftBodyHelpers_CreatePatchUV_10 = b.asm.JA).apply(null, arguments); + }), + eD = (b._emscripten_bind_btSoftBodyHelpers_CreateEllipsoid_4 = function () { + return (eD = b._emscripten_bind_btSoftBodyHelpers_CreateEllipsoid_4 = b.asm.KA).apply(null, arguments); + }), + fD = (b._emscripten_bind_btSoftBodyHelpers_CreateFromTriMesh_5 = function () { + return (fD = b._emscripten_bind_btSoftBodyHelpers_CreateFromTriMesh_5 = b.asm.LA).apply(null, arguments); + }), + gD = (b._emscripten_bind_btSoftBodyHelpers_CreateFromConvexHull_4 = function () { + return (gD = b._emscripten_bind_btSoftBodyHelpers_CreateFromConvexHull_4 = b.asm.MA).apply(null, arguments); + }), + hD = (b._emscripten_bind_btSoftBodyHelpers___destroy___0 = function () { + return (hD = b._emscripten_bind_btSoftBodyHelpers___destroy___0 = b.asm.NA).apply(null, arguments); + }), + iD = (b._emscripten_enum_PHY_ScalarType_PHY_FLOAT = function () { + return (iD = b._emscripten_enum_PHY_ScalarType_PHY_FLOAT = b.asm.OA).apply(null, arguments); + }), + jD = (b._emscripten_enum_PHY_ScalarType_PHY_DOUBLE = function () { + return (jD = b._emscripten_enum_PHY_ScalarType_PHY_DOUBLE = b.asm.PA).apply(null, arguments); + }), + kD = (b._emscripten_enum_PHY_ScalarType_PHY_INTEGER = function () { + return (kD = b._emscripten_enum_PHY_ScalarType_PHY_INTEGER = b.asm.QA).apply(null, arguments); + }), + lD = (b._emscripten_enum_PHY_ScalarType_PHY_SHORT = function () { + return (lD = b._emscripten_enum_PHY_ScalarType_PHY_SHORT = b.asm.RA).apply(null, arguments); + }), + mD = (b._emscripten_enum_PHY_ScalarType_PHY_FIXEDPOINT88 = function () { + return (mD = b._emscripten_enum_PHY_ScalarType_PHY_FIXEDPOINT88 = b.asm.SA).apply(null, arguments); + }), + nD = (b._emscripten_enum_PHY_ScalarType_PHY_UCHAR = function () { + return (nD = b._emscripten_enum_PHY_ScalarType_PHY_UCHAR = b.asm.TA).apply(null, arguments); + }), + oD = (b._emscripten_enum_eGIMPACT_SHAPE_TYPE_CONST_GIMPACT_COMPOUND_SHAPE = function () { + return (oD = b._emscripten_enum_eGIMPACT_SHAPE_TYPE_CONST_GIMPACT_COMPOUND_SHAPE = b.asm.UA).apply(null, arguments); + }), + pD = (b._emscripten_enum_eGIMPACT_SHAPE_TYPE_CONST_GIMPACT_TRIMESH_SHAPE_PART = function () { + return (pD = b._emscripten_enum_eGIMPACT_SHAPE_TYPE_CONST_GIMPACT_TRIMESH_SHAPE_PART = b.asm.VA).apply(null, arguments); + }), + qD = (b._emscripten_enum_eGIMPACT_SHAPE_TYPE_CONST_GIMPACT_TRIMESH_SHAPE = function () { + return (qD = b._emscripten_enum_eGIMPACT_SHAPE_TYPE_CONST_GIMPACT_TRIMESH_SHAPE = b.asm.WA).apply(null, arguments); + }), + rD = (b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_ERP = function () { + return (rD = b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_ERP = b.asm.XA).apply(null, arguments); + }), + sD = (b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_STOP_ERP = function () { + return (sD = b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_STOP_ERP = b.asm.YA).apply(null, arguments); + }), + tD = (b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_CFM = function () { + return (tD = b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_CFM = b.asm.ZA).apply(null, arguments); + }), + uD = (b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_STOP_CFM = function () { + return (uD = b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_STOP_CFM = b.asm._A).apply(null, arguments); + }); + b._malloc = function () { + return (b._malloc = b.asm.aB).apply(null, arguments); + }; + b.UTF8ToString = ua; + b.addFunction = function (a, c) { + if (!oa) { + oa = new WeakMap(); + for (var d = Aa.length, e = 0; e < 0 + d; e++) { + var g = Ra(e); + g && oa.set(g, e); + } + } + if (oa.has(a)) return oa.get(a); + if (na.length) d = na.pop(); + else { + try { + Aa.grow(1); + } catch (T) { + if (!(T instanceof RangeError)) throw T; + throw 'Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.'; + } + d = Aa.length - 1; + } + try { + (e = d), Aa.set(e, a), (Sa[e] = a); + } catch (T) { + if (!(T instanceof TypeError)) throw T; + if ('function' == typeof WebAssembly.Function) { + g = { i: 'i32', j: 'i64', f: 'f32', d: 'f64' }; + var n = { parameters: [], results: 'v' == c[0] ? [] : [g[c[0]]] }; + for (e = 1; e < c.length; ++e) n.parameters.push(g[c[e]]); + e = new WebAssembly.Function(n, a); + } else { + g = [1, 0, 1, 96]; + n = c.slice(0, 1); + c = c.slice(1); + var D = { i: 127, j: 126, f: 125, d: 124 }; + g.push(c.length); + for (e = 0; e < c.length; ++e) g.push(D[c[e]]); + 'v' == n ? g.push(0) : (g = g.concat([1, D[n]])); + g[1] = g.length - 2; + c = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0].concat(g, [2, 7, 1, 1, 101, 1, 102, 0, 0, 7, 5, 1, 1, 102, 0, 0])); + c = new WebAssembly.Module(c); + e = new WebAssembly.Instance(c, { e: { f: a } }).exports.f; + } + c = d; + Aa.set(c, e); + Sa[c] = e; + } + oa.set(a, d); + return d; + }; + var vD; + Ja = function wD() { + vD || xD(); + vD || (Ja = wD); + }; + function xD() { + function a() { + if (!vD && ((vD = !0), (b.calledRun = !0), !sa)) { + Fa = !0; + Qa(Ca); + aa(b); + if (b.onRuntimeInitialized) b.onRuntimeInitialized(); + if (b.postRun) + for ('function' == typeof b.postRun && (b.postRun = [b.postRun]); b.postRun.length; ) { + var c = b.postRun.shift(); + Ea.unshift(c); + } + Qa(Ea); + } + } + if (!(0 < Ha)) { + if (b.preRun) for ('function' == typeof b.preRun && (b.preRun = [b.preRun]); b.preRun.length; ) Ga(); + Qa(Ba); + 0 < Ha || + (b.setStatus + ? (b.setStatus('Running...'), + setTimeout(function () { + setTimeout(function () { + b.setStatus(''); + }, 1); + a(); + }, 1)) + : a()); + } + } + b.run = xD; + if (b.preInit) for ('function' == typeof b.preInit && (b.preInit = [b.preInit]); 0 < b.preInit.length; ) b.preInit.pop()(); + xD(); + function f() {} + f.prototype = Object.create(f.prototype); + f.prototype.constructor = f; + f.prototype.cB = f; + f.dB = {}; + b.WrapperObject = f; + function h(a) { + return (a || f).dB; + } + b.getCache = h; + function k(a, c) { + var d = h(c), + e = d[a]; + if (e) return e; + e = Object.create((c || f).prototype); + e.bB = a; + return (d[a] = e); + } + b.wrapPointer = k; + b.castObject = function (a, c) { + return k(a.bB, c); + }; + b.NULL = k(0); + b.destroy = function (a) { + if (!a.__destroy__) throw 'Error: Cannot destroy object. (Did you create it yourself?)'; + a.__destroy__(); + delete h(a.cB)[a.bB]; + }; + b.compare = function (a, c) { + return a.bB === c.bB; + }; + b.getPointer = function (a) { + return a.bB; + }; + b.getClass = function (a) { + return a.cB; + }; + var yD = 0, + zD = 0, + AD = 0, + BD = [], + CD = 0; + function DD() { + if (CD) { + for (var a = 0; a < BD.length; a++) b._free(BD[a]); + BD.length = 0; + b._free(yD); + yD = 0; + zD += CD; + CD = 0; + } + yD || ((zD += 128), (yD = b._malloc(zD)) || qa(void 0)); + AD = 0; + } + function ED(a, c) { + yD || qa(void 0); + a = a.length * c.BYTES_PER_ELEMENT; + a = (a + 7) & -8; + AD + a >= zD ? (0 < a || qa(void 0), (CD += a), (c = b._malloc(a)), BD.push(c)) : ((c = yD + AD), (AD += a)); + return c; + } + function FD(a, c, d) { + d >>>= 0; + switch (c.BYTES_PER_ELEMENT) { + case 2: + d >>>= 1; + break; + case 4: + d >>>= 2; + break; + case 8: + d >>>= 3; + } + for (var e = 0; e < a.length; e++) c[d + e] = a[e]; + } + function GD(a) { + if ('string' === typeof a) { + for (var c = 0, d = 0; d < a.length; ++d) { + var e = a.charCodeAt(d); + 55296 <= e && 57343 >= e && (e = (65536 + ((e & 1023) << 10)) | (a.charCodeAt(++d) & 1023)); + 127 >= e ? ++c : (c = 2047 >= e ? c + 2 : 65535 >= e ? c + 3 : c + 4); + } + c = Array(c + 1); + e = c.length; + d = 0; + if (0 < e) { + e = d + e - 1; + for (var g = 0; g < a.length; ++g) { + var n = a.charCodeAt(g); + if (55296 <= n && 57343 >= n) { + var D = a.charCodeAt(++g); + n = (65536 + ((n & 1023) << 10)) | (D & 1023); + } + if (127 >= n) { + if (d >= e) break; + c[d++] = n; + } else { + if (2047 >= n) { + if (d + 1 >= e) break; + c[d++] = 192 | (n >> 6); + } else { + if (65535 >= n) { + if (d + 2 >= e) break; + c[d++] = 224 | (n >> 12); + } else { + if (d + 3 >= e) break; + c[d++] = 240 | (n >> 18); + c[d++] = 128 | ((n >> 12) & 63); + } + c[d++] = 128 | ((n >> 6) & 63); + } + c[d++] = 128 | (n & 63); + } + } + c[d] = 0; + } + a = ED(c, wa); + FD(c, wa, a); + return a; + } + return a; + } + function HD(a) { + if ('object' === typeof a) { + var c = ED(a, ya); + FD(a, ya, c); + return c; + } + return a; + } + function l() { + throw 'cannot construct a btCollisionShape, no constructor in IDL'; + } + l.prototype = Object.create(f.prototype); + l.prototype.constructor = l; + l.prototype.cB = l; + l.dB = {}; + b.btCollisionShape = l; + l.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Wa(c, a); + }; + l.prototype.getLocalScaling = function () { + return k(Xa(this.bB), m); + }; + l.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Ya(d, a, c); + }; + l.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Za(c, a); + }; + l.prototype.getMargin = function () { + return $a(this.bB); + }; + l.prototype.__destroy__ = function () { + ab(this.bB); + }; + function ID() { + throw 'cannot construct a btCollisionWorld, no constructor in IDL'; + } + ID.prototype = Object.create(f.prototype); + ID.prototype.constructor = ID; + ID.prototype.cB = ID; + ID.dB = {}; + b.btCollisionWorld = ID; + ID.prototype.getDispatcher = function () { + return k(bb(this.bB), JD); + }; + ID.prototype.rayTest = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + cb(e, a, c, d); + }; + ID.prototype.getPairCache = function () { + return k(db(this.bB), KD); + }; + ID.prototype.getDispatchInfo = function () { + return k(eb(this.bB), p); + }; + ID.prototype.addCollisionObject = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + void 0 === c ? fb(e, a) : void 0 === d ? gb(e, a, c) : hb(e, a, c, d); + }; + ID.prototype.removeCollisionObject = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ib(c, a); + }; + ID.prototype.getBroadphase = function () { + return k(jb(this.bB), LD); + }; + ID.prototype.convexSweepTest = function (a, c, d, e, g) { + var n = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + kb(n, a, c, d, e, g); + }; + ID.prototype.contactPairTest = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + lb(e, a, c, d); + }; + ID.prototype.contactTest = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + mb(d, a, c); + }; + ID.prototype.updateSingleAabb = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + nb(c, a); + }; + ID.prototype.setDebugDrawer = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ob(c, a); + }; + ID.prototype.getDebugDrawer = function () { + return k(pb(this.bB), MD); + }; + ID.prototype.debugDrawWorld = function () { + qb(this.bB); + }; + ID.prototype.debugDrawObject = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + rb(e, a, c, d); + }; + ID.prototype.__destroy__ = function () { + sb(this.bB); + }; + function q() { + throw 'cannot construct a btCollisionObject, no constructor in IDL'; + } + q.prototype = Object.create(f.prototype); + q.prototype.constructor = q; + q.prototype.cB = q; + q.dB = {}; + b.btCollisionObject = q; + q.prototype.setAnisotropicFriction = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + tb(d, a, c); + }; + q.prototype.getCollisionShape = function () { + return k(ub(this.bB), l); + }; + q.prototype.setContactProcessingThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + vb(c, a); + }; + q.prototype.setActivationState = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + wb(c, a); + }; + q.prototype.forceActivationState = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + xb(c, a); + }; + q.prototype.activate = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + void 0 === a ? yb(c) : zb(c, a); + }; + q.prototype.isActive = function () { + return !!Ab(this.bB); + }; + q.prototype.isKinematicObject = function () { + return !!Bb(this.bB); + }; + q.prototype.isStaticObject = function () { + return !!Cb(this.bB); + }; + q.prototype.isStaticOrKinematicObject = function () { + return !!Db(this.bB); + }; + q.prototype.getRestitution = function () { + return Eb(this.bB); + }; + q.prototype.getFriction = function () { + return Fb(this.bB); + }; + q.prototype.getRollingFriction = function () { + return Gb(this.bB); + }; + q.prototype.setRestitution = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Hb(c, a); + }; + q.prototype.setFriction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ib(c, a); + }; + q.prototype.setRollingFriction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Jb(c, a); + }; + q.prototype.getWorldTransform = function () { + return k(Kb(this.bB), r); + }; + q.prototype.getCollisionFlags = function () { + return Lb(this.bB); + }; + q.prototype.setCollisionFlags = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Mb(c, a); + }; + q.prototype.setWorldTransform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Nb(c, a); + }; + q.prototype.setCollisionShape = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ob(c, a); + }; + q.prototype.setCcdMotionThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Pb(c, a); + }; + q.prototype.setCcdSweptSphereRadius = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Qb(c, a); + }; + q.prototype.getUserIndex = function () { + return Rb(this.bB); + }; + q.prototype.setUserIndex = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Sb(c, a); + }; + q.prototype.getUserPointer = function () { + return k(Tb(this.bB), ND); + }; + q.prototype.setUserPointer = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ub(c, a); + }; + q.prototype.getBroadphaseHandle = function () { + return k(Vb(this.bB), OD); + }; + q.prototype.__destroy__ = function () { + Wb(this.bB); + }; + function PD() { + throw 'cannot construct a btConcaveShape, no constructor in IDL'; + } + PD.prototype = Object.create(l.prototype); + PD.prototype.constructor = PD; + PD.prototype.cB = PD; + PD.dB = {}; + b.btConcaveShape = PD; + PD.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Xb(c, a); + }; + PD.prototype.getLocalScaling = function () { + return k(Yb(this.bB), m); + }; + PD.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Zb(d, a, c); + }; + PD.prototype.__destroy__ = function () { + $b(this.bB); + }; + function QD() { + throw 'cannot construct a btCollisionAlgorithm, no constructor in IDL'; + } + QD.prototype = Object.create(f.prototype); + QD.prototype.constructor = QD; + QD.prototype.cB = QD; + QD.dB = {}; + b.btCollisionAlgorithm = QD; + QD.prototype.__destroy__ = function () { + ac(this.bB); + }; + function RD() { + throw 'cannot construct a btTypedConstraint, no constructor in IDL'; + } + RD.prototype = Object.create(f.prototype); + RD.prototype.constructor = RD; + RD.prototype.cB = RD; + RD.dB = {}; + b.btTypedConstraint = RD; + RD.prototype.enableFeedback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + bc(c, a); + }; + RD.prototype.getBreakingImpulseThreshold = function () { + return cc(this.bB); + }; + RD.prototype.setBreakingImpulseThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ec(c, a); + }; + RD.prototype.getParam = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return fc(d, a, c); + }; + RD.prototype.setParam = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + gc(e, a, c, d); + }; + RD.prototype.__destroy__ = function () { + hc(this.bB); + }; + function SD() { + throw 'cannot construct a btDynamicsWorld, no constructor in IDL'; + } + SD.prototype = Object.create(ID.prototype); + SD.prototype.constructor = SD; + SD.prototype.cB = SD; + SD.dB = {}; + b.btDynamicsWorld = SD; + SD.prototype.addAction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ic(c, a); + }; + SD.prototype.removeAction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + jc(c, a); + }; + SD.prototype.getSolverInfo = function () { + return k(kc(this.bB), t); + }; + SD.prototype.setInternalTickCallback = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + void 0 === c ? lc(e, a) : void 0 === d ? mc(e, a, c) : nc(e, a, c, d); + }; + SD.prototype.getDispatcher = function () { + return k(oc(this.bB), JD); + }; + SD.prototype.rayTest = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + pc(e, a, c, d); + }; + SD.prototype.getPairCache = function () { + return k(qc(this.bB), KD); + }; + SD.prototype.getDispatchInfo = function () { + return k(rc(this.bB), p); + }; + SD.prototype.addCollisionObject = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + void 0 === c ? sc(e, a) : void 0 === d ? tc(e, a, c) : uc(e, a, c, d); + }; + SD.prototype.removeCollisionObject = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + vc(c, a); + }; + SD.prototype.getBroadphase = function () { + return k(wc(this.bB), LD); + }; + SD.prototype.convexSweepTest = function (a, c, d, e, g) { + var n = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + xc(n, a, c, d, e, g); + }; + SD.prototype.contactPairTest = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + yc(e, a, c, d); + }; + SD.prototype.contactTest = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + zc(d, a, c); + }; + SD.prototype.updateSingleAabb = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ac(c, a); + }; + SD.prototype.setDebugDrawer = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Bc(c, a); + }; + SD.prototype.getDebugDrawer = function () { + return k(Cc(this.bB), MD); + }; + SD.prototype.debugDrawWorld = function () { + Dc(this.bB); + }; + SD.prototype.debugDrawObject = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + Ec(e, a, c, d); + }; + SD.prototype.__destroy__ = function () { + Fc(this.bB); + }; + function MD() { + throw 'cannot construct a btIDebugDraw, no constructor in IDL'; + } + MD.prototype = Object.create(f.prototype); + MD.prototype.constructor = MD; + MD.prototype.cB = MD; + MD.dB = {}; + b.btIDebugDraw = MD; + MD.prototype.drawLine = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + Gc(e, a, c, d); + }; + MD.prototype.drawContactPoint = function (a, c, d, e, g) { + var n = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + Hc(n, a, c, d, e, g); + }; + MD.prototype.reportErrorWarning = function (a) { + var c = this.bB; + DD(); + a = a && 'object' === typeof a ? a.bB : GD(a); + Ic(c, a); + }; + MD.prototype.draw3dText = function (a, c) { + var d = this.bB; + DD(); + a && 'object' === typeof a && (a = a.bB); + c = c && 'object' === typeof c ? c.bB : GD(c); + Jc(d, a, c); + }; + MD.prototype.setDebugMode = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Kc(c, a); + }; + MD.prototype.getDebugMode = function () { + return Lc(this.bB); + }; + MD.prototype.__destroy__ = function () { + Mc(this.bB); + }; + function m(a, c, d) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + this.bB = void 0 === a ? Nc() : void 0 === c ? _emscripten_bind_btVector3_btVector3_1(a) : void 0 === d ? _emscripten_bind_btVector3_btVector3_2(a, c) : Oc(a, c, d); + h(m)[this.bB] = this; + } + m.prototype = Object.create(f.prototype); + m.prototype.constructor = m; + m.prototype.cB = m; + m.dB = {}; + b.btVector3 = m; + m.prototype.length = m.prototype.length = function () { + return Pc(this.bB); + }; + m.prototype.x = m.prototype.x = function () { + return Qc(this.bB); + }; + m.prototype.y = m.prototype.y = function () { + return Rc(this.bB); + }; + m.prototype.z = m.prototype.z = function () { + return Sc(this.bB); + }; + m.prototype.setX = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Tc(c, a); + }; + m.prototype.setY = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Uc(c, a); + }; + m.prototype.setZ = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Vc(c, a); + }; + m.prototype.setValue = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + Wc(e, a, c, d); + }; + m.prototype.normalize = m.prototype.normalize = function () { + Xc(this.bB); + }; + m.prototype.rotate = m.prototype.rotate = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return k(Yc(d, a, c), m); + }; + m.prototype.dot = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return Zc(c, a); + }; + m.prototype.op_mul = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k($c(c, a), m); + }; + m.prototype.op_add = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(ad(c, a), m); + }; + m.prototype.op_sub = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(bd(c, a), m); + }; + m.prototype.__destroy__ = function () { + cd(this.bB); + }; + function TD() { + throw 'cannot construct a btQuadWord, no constructor in IDL'; + } + TD.prototype = Object.create(f.prototype); + TD.prototype.constructor = TD; + TD.prototype.cB = TD; + TD.dB = {}; + b.btQuadWord = TD; + TD.prototype.x = TD.prototype.x = function () { + return dd(this.bB); + }; + TD.prototype.y = TD.prototype.y = function () { + return ed(this.bB); + }; + TD.prototype.z = TD.prototype.z = function () { + return fd(this.bB); + }; + TD.prototype.w = TD.prototype.w = function () { + return gd(this.bB); + }; + TD.prototype.setX = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hd(c, a); + }; + TD.prototype.setY = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + jd(c, a); + }; + TD.prototype.setZ = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + kd(c, a); + }; + TD.prototype.setW = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ld(c, a); + }; + TD.prototype.__destroy__ = function () { + md(this.bB); + }; + function UD() { + throw 'cannot construct a btMotionState, no constructor in IDL'; + } + UD.prototype = Object.create(f.prototype); + UD.prototype.constructor = UD; + UD.prototype.cB = UD; + UD.dB = {}; + b.btMotionState = UD; + UD.prototype.getWorldTransform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + nd(c, a); + }; + UD.prototype.setWorldTransform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + od(c, a); + }; + UD.prototype.__destroy__ = function () { + pd(this.bB); + }; + function u() { + throw 'cannot construct a RayResultCallback, no constructor in IDL'; + } + u.prototype = Object.create(f.prototype); + u.prototype.constructor = u; + u.prototype.cB = u; + u.dB = {}; + b.RayResultCallback = u; + u.prototype.hasHit = function () { + return !!qd(this.bB); + }; + u.prototype.get_m_collisionFilterGroup = u.prototype.eB = function () { + return rd(this.bB); + }; + u.prototype.set_m_collisionFilterGroup = u.prototype.gB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + sd(c, a); + }; + Object.defineProperty(u.prototype, 'm_collisionFilterGroup', { get: u.prototype.eB, set: u.prototype.gB }); + u.prototype.get_m_collisionFilterMask = u.prototype.fB = function () { + return td(this.bB); + }; + u.prototype.set_m_collisionFilterMask = u.prototype.hB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ud(c, a); + }; + Object.defineProperty(u.prototype, 'm_collisionFilterMask', { get: u.prototype.fB, set: u.prototype.hB }); + u.prototype.get_m_closestHitFraction = u.prototype.iB = function () { + return vd(this.bB); + }; + u.prototype.set_m_closestHitFraction = u.prototype.jB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + wd(c, a); + }; + Object.defineProperty(u.prototype, 'm_closestHitFraction', { get: u.prototype.iB, set: u.prototype.jB }); + u.prototype.get_m_collisionObject = u.prototype.mB = function () { + return k(xd(this.bB), q); + }; + u.prototype.set_m_collisionObject = u.prototype.tB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + yd(c, a); + }; + Object.defineProperty(u.prototype, 'm_collisionObject', { get: u.prototype.mB, set: u.prototype.tB }); + u.prototype.get_m_flags = u.prototype.kB = function () { + return zd(this.bB); + }; + u.prototype.set_m_flags = u.prototype.lB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ad(c, a); + }; + Object.defineProperty(u.prototype, 'm_flags', { get: u.prototype.kB, set: u.prototype.lB }); + u.prototype.__destroy__ = function () { + Bd(this.bB); + }; + function VD() { + throw 'cannot construct a ContactResultCallback, no constructor in IDL'; + } + VD.prototype = Object.create(f.prototype); + VD.prototype.constructor = VD; + VD.prototype.cB = VD; + VD.dB = {}; + b.ContactResultCallback = VD; + VD.prototype.addSingleResult = function (a, c, d, e, g, n, D) { + var T = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + n && 'object' === typeof n && (n = n.bB); + D && 'object' === typeof D && (D = D.bB); + return Cd(T, a, c, d, e, g, n, D); + }; + VD.prototype.__destroy__ = function () { + Dd(this.bB); + }; + function v() { + throw 'cannot construct a ConvexResultCallback, no constructor in IDL'; + } + v.prototype = Object.create(f.prototype); + v.prototype.constructor = v; + v.prototype.cB = v; + v.dB = {}; + b.ConvexResultCallback = v; + v.prototype.hasHit = function () { + return !!Ed(this.bB); + }; + v.prototype.get_m_collisionFilterGroup = v.prototype.eB = function () { + return Fd(this.bB); + }; + v.prototype.set_m_collisionFilterGroup = v.prototype.gB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Gd(c, a); + }; + Object.defineProperty(v.prototype, 'm_collisionFilterGroup', { get: v.prototype.eB, set: v.prototype.gB }); + v.prototype.get_m_collisionFilterMask = v.prototype.fB = function () { + return Hd(this.bB); + }; + v.prototype.set_m_collisionFilterMask = v.prototype.hB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Id(c, a); + }; + Object.defineProperty(v.prototype, 'm_collisionFilterMask', { get: v.prototype.fB, set: v.prototype.hB }); + v.prototype.get_m_closestHitFraction = v.prototype.iB = function () { + return Jd(this.bB); + }; + v.prototype.set_m_closestHitFraction = v.prototype.jB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Kd(c, a); + }; + Object.defineProperty(v.prototype, 'm_closestHitFraction', { get: v.prototype.iB, set: v.prototype.jB }); + v.prototype.__destroy__ = function () { + Ld(this.bB); + }; + function WD() { + throw 'cannot construct a btConvexShape, no constructor in IDL'; + } + WD.prototype = Object.create(l.prototype); + WD.prototype.constructor = WD; + WD.prototype.cB = WD; + WD.dB = {}; + b.btConvexShape = WD; + WD.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Md(c, a); + }; + WD.prototype.getLocalScaling = function () { + return k(Nd(this.bB), m); + }; + WD.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Od(d, a, c); + }; + WD.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Pd(c, a); + }; + WD.prototype.getMargin = function () { + return Qd(this.bB); + }; + WD.prototype.__destroy__ = function () { + Rd(this.bB); + }; + function XD(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = Sd(a, c); + h(XD)[this.bB] = this; + } + XD.prototype = Object.create(l.prototype); + XD.prototype.constructor = XD; + XD.prototype.cB = XD; + XD.dB = {}; + b.btCapsuleShape = XD; + XD.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Td(c, a); + }; + XD.prototype.getMargin = function () { + return Ud(this.bB); + }; + XD.prototype.getUpAxis = function () { + return Vd(this.bB); + }; + XD.prototype.getRadius = function () { + return Wd(this.bB); + }; + XD.prototype.getHalfHeight = function () { + return Xd(this.bB); + }; + XD.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Yd(c, a); + }; + XD.prototype.getLocalScaling = function () { + return k(Zd(this.bB), m); + }; + XD.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + $d(d, a, c); + }; + XD.prototype.__destroy__ = function () { + ae(this.bB); + }; + function YD(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = be(a); + h(YD)[this.bB] = this; + } + YD.prototype = Object.create(l.prototype); + YD.prototype.constructor = YD; + YD.prototype.cB = YD; + YD.dB = {}; + b.btCylinderShape = YD; + YD.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ce(c, a); + }; + YD.prototype.getMargin = function () { + return de(this.bB); + }; + YD.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ee(c, a); + }; + YD.prototype.getLocalScaling = function () { + return k(fe(this.bB), m); + }; + YD.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + ge(d, a, c); + }; + YD.prototype.__destroy__ = function () { + he(this.bB); + }; + function ZD(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = ie(a, c); + h(ZD)[this.bB] = this; + } + ZD.prototype = Object.create(l.prototype); + ZD.prototype.constructor = ZD; + ZD.prototype.cB = ZD; + ZD.dB = {}; + b.btConeShape = ZD; + ZD.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + je(c, a); + }; + ZD.prototype.getLocalScaling = function () { + return k(ke(this.bB), m); + }; + ZD.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + le(d, a, c); + }; + ZD.prototype.__destroy__ = function () { + me(this.bB); + }; + function $D() { + throw 'cannot construct a btStridingMeshInterface, no constructor in IDL'; + } + $D.prototype = Object.create(f.prototype); + $D.prototype.constructor = $D; + $D.prototype.cB = $D; + $D.dB = {}; + b.btStridingMeshInterface = $D; + $D.prototype.setScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ne(c, a); + }; + $D.prototype.__destroy__ = function () { + oe(this.bB); + }; + function aE() { + throw 'cannot construct a btTriangleMeshShape, no constructor in IDL'; + } + aE.prototype = Object.create(PD.prototype); + aE.prototype.constructor = aE; + aE.prototype.cB = aE; + aE.dB = {}; + b.btTriangleMeshShape = aE; + aE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + pe(c, a); + }; + aE.prototype.getLocalScaling = function () { + return k(qe(this.bB), m); + }; + aE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + re(d, a, c); + }; + aE.prototype.__destroy__ = function () { + se(this.bB); + }; + function bE() { + throw 'cannot construct a btPrimitiveManagerBase, no constructor in IDL'; + } + bE.prototype = Object.create(f.prototype); + bE.prototype.constructor = bE; + bE.prototype.cB = bE; + bE.dB = {}; + b.btPrimitiveManagerBase = bE; + bE.prototype.is_trimesh = function () { + return !!te(this.bB); + }; + bE.prototype.get_primitive_count = function () { + return ue(this.bB); + }; + bE.prototype.get_primitive_box = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + ve(d, a, c); + }; + bE.prototype.get_primitive_triangle = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + we(d, a, c); + }; + bE.prototype.__destroy__ = function () { + xe(this.bB); + }; + function w() { + throw 'cannot construct a btGImpactShapeInterface, no constructor in IDL'; + } + w.prototype = Object.create(PD.prototype); + w.prototype.constructor = w; + w.prototype.cB = w; + w.dB = {}; + b.btGImpactShapeInterface = w; + w.prototype.updateBound = function () { + ye(this.bB); + }; + w.prototype.postUpdate = function () { + ze(this.bB); + }; + w.prototype.getShapeType = function () { + return Ae(this.bB); + }; + w.prototype.getName = function () { + return ua(Be(this.bB)); + }; + w.prototype.getGImpactShapeType = function () { + return Ce(this.bB); + }; + w.prototype.getPrimitiveManager = function () { + return k(De(this.bB), bE); + }; + w.prototype.getNumChildShapes = function () { + return Ee(this.bB); + }; + w.prototype.childrenHasTransform = function () { + return !!Fe(this.bB); + }; + w.prototype.needsRetrieveTriangles = function () { + return !!Ge(this.bB); + }; + w.prototype.needsRetrieveTetrahedrons = function () { + return !!He(this.bB); + }; + w.prototype.getBulletTriangle = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Ie(d, a, c); + }; + w.prototype.getBulletTetrahedron = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Je(d, a, c); + }; + w.prototype.getChildShape = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Ke(c, a), l); + }; + w.prototype.getChildTransform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Le(c, a), r); + }; + w.prototype.setChildTransform = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Me(d, a, c); + }; + w.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ne(c, a); + }; + w.prototype.getLocalScaling = function () { + return k(Oe(this.bB), m); + }; + w.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Pe(d, a, c); + }; + w.prototype.__destroy__ = function () { + Qe(this.bB); + }; + function cE() { + throw 'cannot construct a btActivatingCollisionAlgorithm, no constructor in IDL'; + } + cE.prototype = Object.create(QD.prototype); + cE.prototype.constructor = cE; + cE.prototype.cB = cE; + cE.dB = {}; + b.btActivatingCollisionAlgorithm = cE; + cE.prototype.__destroy__ = function () { + Re(this.bB); + }; + function dE(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = void 0 === a ? Se() : Te(a); + h(dE)[this.bB] = this; + } + dE.prototype = Object.create(f.prototype); + dE.prototype.constructor = dE; + dE.prototype.cB = dE; + dE.dB = {}; + b.btDefaultCollisionConfiguration = dE; + dE.prototype.__destroy__ = function () { + Ue(this.bB); + }; + function JD() { + throw 'cannot construct a btDispatcher, no constructor in IDL'; + } + JD.prototype = Object.create(f.prototype); + JD.prototype.constructor = JD; + JD.prototype.cB = JD; + JD.dB = {}; + b.btDispatcher = JD; + JD.prototype.getNumManifolds = function () { + return Ve(this.bB); + }; + JD.prototype.getManifoldByIndexInternal = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(We(c, a), eE); + }; + JD.prototype.__destroy__ = function () { + Xe(this.bB); + }; + function fE(a, c, d, e, g) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + this.bB = void 0 === e ? Ye(a, c, d) : void 0 === g ? _emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_4(a, c, d, e) : Ze(a, c, d, e, g); + h(fE)[this.bB] = this; + } + fE.prototype = Object.create(RD.prototype); + fE.prototype.constructor = fE; + fE.prototype.cB = fE; + fE.dB = {}; + b.btGeneric6DofConstraint = fE; + fE.prototype.setLinearLowerLimit = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + $e(c, a); + }; + fE.prototype.setLinearUpperLimit = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + af(c, a); + }; + fE.prototype.setAngularLowerLimit = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + bf(c, a); + }; + fE.prototype.setAngularUpperLimit = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + cf(c, a); + }; + fE.prototype.getFrameOffsetA = function () { + return k(df(this.bB), r); + }; + fE.prototype.enableFeedback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ef(c, a); + }; + fE.prototype.getBreakingImpulseThreshold = function () { + return ff(this.bB); + }; + fE.prototype.setBreakingImpulseThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + gf(c, a); + }; + fE.prototype.getParam = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return hf(d, a, c); + }; + fE.prototype.setParam = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + jf(e, a, c, d); + }; + fE.prototype.__destroy__ = function () { + kf(this.bB); + }; + function x(a, c, d, e) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + this.bB = lf(a, c, d, e); + h(x)[this.bB] = this; + } + x.prototype = Object.create(SD.prototype); + x.prototype.constructor = x; + x.prototype.cB = x; + x.dB = {}; + b.btDiscreteDynamicsWorld = x; + x.prototype.setGravity = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + mf(c, a); + }; + x.prototype.getGravity = function () { + return k(nf(this.bB), m); + }; + x.prototype.addRigidBody = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + void 0 === c ? of(e, a) : void 0 === d ? _emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_2(e, a, c) : pf(e, a, c, d); + }; + x.prototype.removeRigidBody = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + qf(c, a); + }; + x.prototype.addConstraint = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + void 0 === c ? rf(d, a) : sf(d, a, c); + }; + x.prototype.removeConstraint = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + tf(c, a); + }; + x.prototype.stepSimulation = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + return void 0 === c ? uf(e, a) : void 0 === d ? vf(e, a, c) : wf(e, a, c, d); + }; + x.prototype.setContactAddedCallback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + xf(c, a); + }; + x.prototype.setContactProcessedCallback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + yf(c, a); + }; + x.prototype.setContactDestroyedCallback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + zf(c, a); + }; + x.prototype.getDispatcher = function () { + return k(Af(this.bB), JD); + }; + x.prototype.rayTest = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + Bf(e, a, c, d); + }; + x.prototype.getPairCache = function () { + return k(Cf(this.bB), KD); + }; + x.prototype.getDispatchInfo = function () { + return k(Df(this.bB), p); + }; + x.prototype.addCollisionObject = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + void 0 === c ? Ef(e, a) : void 0 === d ? Ff(e, a, c) : Gf(e, a, c, d); + }; + x.prototype.removeCollisionObject = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Hf(c, a); + }; + x.prototype.getBroadphase = function () { + return k(If(this.bB), LD); + }; + x.prototype.convexSweepTest = function (a, c, d, e, g) { + var n = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + Jf(n, a, c, d, e, g); + }; + x.prototype.contactPairTest = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + Kf(e, a, c, d); + }; + x.prototype.contactTest = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Lf(d, a, c); + }; + x.prototype.updateSingleAabb = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Mf(c, a); + }; + x.prototype.setDebugDrawer = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Nf(c, a); + }; + x.prototype.getDebugDrawer = function () { + return k(Of(this.bB), MD); + }; + x.prototype.debugDrawWorld = function () { + Pf(this.bB); + }; + x.prototype.debugDrawObject = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + Qf(e, a, c, d); + }; + x.prototype.addAction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Rf(c, a); + }; + x.prototype.removeAction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Sf(c, a); + }; + x.prototype.getSolverInfo = function () { + return k(Tf(this.bB), t); + }; + x.prototype.setInternalTickCallback = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + void 0 === c ? Uf(e, a) : void 0 === d ? Vf(e, a, c) : Wf(e, a, c, d); + }; + x.prototype.__destroy__ = function () { + Xf(this.bB); + }; + function gE() { + throw 'cannot construct a btVehicleRaycaster, no constructor in IDL'; + } + gE.prototype = Object.create(f.prototype); + gE.prototype.constructor = gE; + gE.prototype.cB = gE; + gE.dB = {}; + b.btVehicleRaycaster = gE; + gE.prototype.castRay = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + Yf(e, a, c, d); + }; + gE.prototype.__destroy__ = function () { + Zf(this.bB); + }; + function hE() { + throw 'cannot construct a btActionInterface, no constructor in IDL'; + } + hE.prototype = Object.create(f.prototype); + hE.prototype.constructor = hE; + hE.prototype.cB = hE; + hE.dB = {}; + b.btActionInterface = hE; + hE.prototype.updateAction = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + $f(d, a, c); + }; + hE.prototype.__destroy__ = function () { + ag(this.bB); + }; + function y() { + this.bB = bg(); + h(y)[this.bB] = this; + } + y.prototype = Object.create(q.prototype); + y.prototype.constructor = y; + y.prototype.cB = y; + y.dB = {}; + b.btGhostObject = y; + y.prototype.getNumOverlappingObjects = function () { + return cg(this.bB); + }; + y.prototype.getOverlappingObject = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(dg(c, a), q); + }; + y.prototype.setAnisotropicFriction = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + eg(d, a, c); + }; + y.prototype.getCollisionShape = function () { + return k(fg(this.bB), l); + }; + y.prototype.setContactProcessingThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + gg(c, a); + }; + y.prototype.setActivationState = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hg(c, a); + }; + y.prototype.forceActivationState = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ig(c, a); + }; + y.prototype.activate = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + void 0 === a ? jg(c) : kg(c, a); + }; + y.prototype.isActive = function () { + return !!lg(this.bB); + }; + y.prototype.isKinematicObject = function () { + return !!mg(this.bB); + }; + y.prototype.isStaticObject = function () { + return !!ng(this.bB); + }; + y.prototype.isStaticOrKinematicObject = function () { + return !!og(this.bB); + }; + y.prototype.getRestitution = function () { + return pg(this.bB); + }; + y.prototype.getFriction = function () { + return qg(this.bB); + }; + y.prototype.getRollingFriction = function () { + return rg(this.bB); + }; + y.prototype.setRestitution = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + sg(c, a); + }; + y.prototype.setFriction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + tg(c, a); + }; + y.prototype.setRollingFriction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ug(c, a); + }; + y.prototype.getWorldTransform = function () { + return k(vg(this.bB), r); + }; + y.prototype.getCollisionFlags = function () { + return wg(this.bB); + }; + y.prototype.setCollisionFlags = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + xg(c, a); + }; + y.prototype.setWorldTransform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + yg(c, a); + }; + y.prototype.setCollisionShape = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + zg(c, a); + }; + y.prototype.setCcdMotionThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ag(c, a); + }; + y.prototype.setCcdSweptSphereRadius = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Bg(c, a); + }; + y.prototype.getUserIndex = function () { + return Cg(this.bB); + }; + y.prototype.setUserIndex = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Dg(c, a); + }; + y.prototype.getUserPointer = function () { + return k(Eg(this.bB), ND); + }; + y.prototype.setUserPointer = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Fg(c, a); + }; + y.prototype.getBroadphaseHandle = function () { + return k(Gg(this.bB), OD); + }; + y.prototype.__destroy__ = function () { + Hg(this.bB); + }; + function iE() { + throw 'cannot construct a btSoftBodySolver, no constructor in IDL'; + } + iE.prototype = Object.create(f.prototype); + iE.prototype.constructor = iE; + iE.prototype.cB = iE; + iE.dB = {}; + b.btSoftBodySolver = iE; + iE.prototype.__destroy__ = function () { + Ig(this.bB); + }; + function ND() { + throw 'cannot construct a VoidPtr, no constructor in IDL'; + } + ND.prototype = Object.create(f.prototype); + ND.prototype.constructor = ND; + ND.prototype.cB = ND; + ND.dB = {}; + b.VoidPtr = ND; + ND.prototype.__destroy__ = function () { + Jg(this.bB); + }; + function jE() { + this.bB = Kg(); + h(jE)[this.bB] = this; + } + jE.prototype = Object.create(MD.prototype); + jE.prototype.constructor = jE; + jE.prototype.cB = jE; + jE.dB = {}; + b.DebugDrawer = jE; + jE.prototype.drawLine = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + Lg(e, a, c, d); + }; + jE.prototype.drawContactPoint = function (a, c, d, e, g) { + var n = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + Mg(n, a, c, d, e, g); + }; + jE.prototype.reportErrorWarning = function (a) { + var c = this.bB; + DD(); + a = a && 'object' === typeof a ? a.bB : GD(a); + Ng(c, a); + }; + jE.prototype.draw3dText = function (a, c) { + var d = this.bB; + DD(); + a && 'object' === typeof a && (a = a.bB); + c = c && 'object' === typeof c ? c.bB : GD(c); + Og(d, a, c); + }; + jE.prototype.setDebugMode = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Pg(c, a); + }; + jE.prototype.getDebugMode = function () { + return Qg(this.bB); + }; + jE.prototype.__destroy__ = function () { + Rg(this.bB); + }; + function z(a, c, d, e) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + this.bB = void 0 === a ? Sg() : void 0 === c ? _emscripten_bind_btVector4_btVector4_1(a) : void 0 === d ? _emscripten_bind_btVector4_btVector4_2(a, c) : void 0 === e ? _emscripten_bind_btVector4_btVector4_3(a, c, d) : Tg(a, c, d, e); + h(z)[this.bB] = this; + } + z.prototype = Object.create(m.prototype); + z.prototype.constructor = z; + z.prototype.cB = z; + z.dB = {}; + b.btVector4 = z; + z.prototype.w = z.prototype.w = function () { + return Ug(this.bB); + }; + z.prototype.setValue = function (a, c, d, e) { + var g = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + Vg(g, a, c, d, e); + }; + z.prototype.length = z.prototype.length = function () { + return Wg(this.bB); + }; + z.prototype.x = z.prototype.x = function () { + return Xg(this.bB); + }; + z.prototype.y = z.prototype.y = function () { + return Yg(this.bB); + }; + z.prototype.z = z.prototype.z = function () { + return Zg(this.bB); + }; + z.prototype.setX = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + $g(c, a); + }; + z.prototype.setY = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ah(c, a); + }; + z.prototype.setZ = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + bh(c, a); + }; + z.prototype.normalize = z.prototype.normalize = function () { + ch(this.bB); + }; + z.prototype.rotate = z.prototype.rotate = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return k(dh(d, a, c), m); + }; + z.prototype.dot = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return eh(c, a); + }; + z.prototype.op_mul = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(fh(c, a), m); + }; + z.prototype.op_add = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(gh(c, a), m); + }; + z.prototype.op_sub = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(hh(c, a), m); + }; + z.prototype.__destroy__ = function () { + ih(this.bB); + }; + function A(a, c, d, e) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + this.bB = jh(a, c, d, e); + h(A)[this.bB] = this; + } + A.prototype = Object.create(TD.prototype); + A.prototype.constructor = A; + A.prototype.cB = A; + A.dB = {}; + b.btQuaternion = A; + A.prototype.setValue = function (a, c, d, e) { + var g = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + kh(g, a, c, d, e); + }; + A.prototype.setEulerZYX = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + lh(e, a, c, d); + }; + A.prototype.setRotation = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + mh(d, a, c); + }; + A.prototype.normalize = A.prototype.normalize = function () { + nh(this.bB); + }; + A.prototype.length2 = function () { + return oh(this.bB); + }; + A.prototype.length = A.prototype.length = function () { + return ph(this.bB); + }; + A.prototype.dot = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return qh(c, a); + }; + A.prototype.normalized = function () { + return k(rh(this.bB), A); + }; + A.prototype.getAxis = function () { + return k(sh(this.bB), m); + }; + A.prototype.inverse = A.prototype.inverse = function () { + return k(th(this.bB), A); + }; + A.prototype.getAngle = function () { + return uh(this.bB); + }; + A.prototype.getAngleShortestPath = function () { + return vh(this.bB); + }; + A.prototype.angle = A.prototype.angle = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return wh(c, a); + }; + A.prototype.angleShortestPath = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return xh(c, a); + }; + A.prototype.op_add = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(yh(c, a), A); + }; + A.prototype.op_sub = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(zh(c, a), A); + }; + A.prototype.op_mul = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Ah(c, a), A); + }; + A.prototype.op_mulq = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Bh(c, a), A); + }; + A.prototype.op_div = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Ch(c, a), A); + }; + A.prototype.x = A.prototype.x = function () { + return Dh(this.bB); + }; + A.prototype.y = A.prototype.y = function () { + return Eh(this.bB); + }; + A.prototype.z = A.prototype.z = function () { + return Fh(this.bB); + }; + A.prototype.w = A.prototype.w = function () { + return Gh(this.bB); + }; + A.prototype.setX = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Hh(c, a); + }; + A.prototype.setY = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ih(c, a); + }; + A.prototype.setZ = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Jh(c, a); + }; + A.prototype.setW = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Kh(c, a); + }; + A.prototype.__destroy__ = function () { + Lh(this.bB); + }; + function kE() { + throw 'cannot construct a btMatrix3x3, no constructor in IDL'; + } + kE.prototype = Object.create(f.prototype); + kE.prototype.constructor = kE; + kE.prototype.cB = kE; + kE.dB = {}; + b.btMatrix3x3 = kE; + kE.prototype.setEulerZYX = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + Mh(e, a, c, d); + }; + kE.prototype.getRotation = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Nh(c, a); + }; + kE.prototype.getRow = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Oh(c, a), m); + }; + kE.prototype.__destroy__ = function () { + Ph(this.bB); + }; + function r(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = void 0 === a ? Qh() : void 0 === c ? _emscripten_bind_btTransform_btTransform_1(a) : Rh(a, c); + h(r)[this.bB] = this; + } + r.prototype = Object.create(f.prototype); + r.prototype.constructor = r; + r.prototype.cB = r; + r.dB = {}; + b.btTransform = r; + r.prototype.setIdentity = function () { + Sh(this.bB); + }; + r.prototype.setOrigin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Th(c, a); + }; + r.prototype.setRotation = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Uh(c, a); + }; + r.prototype.getOrigin = function () { + return k(Vh(this.bB), m); + }; + r.prototype.getRotation = function () { + return k(Wh(this.bB), A); + }; + r.prototype.getBasis = function () { + return k(Xh(this.bB), kE); + }; + r.prototype.setFromOpenGLMatrix = function (a) { + var c = this.bB; + DD(); + 'object' == typeof a && (a = HD(a)); + Yh(c, a); + }; + r.prototype.inverse = r.prototype.inverse = function () { + return k(Zh(this.bB), r); + }; + r.prototype.op_mul = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k($h(c, a), r); + }; + r.prototype.__destroy__ = function () { + ai(this.bB); + }; + function lE(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = void 0 === a ? bi() : void 0 === c ? ci(a) : di(a, c); + h(lE)[this.bB] = this; + } + lE.prototype = Object.create(UD.prototype); + lE.prototype.constructor = lE; + lE.prototype.cB = lE; + lE.dB = {}; + b.btDefaultMotionState = lE; + lE.prototype.getWorldTransform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ei(c, a); + }; + lE.prototype.setWorldTransform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + fi(c, a); + }; + lE.prototype.get_m_graphicsWorldTrans = lE.prototype.dD = function () { + return k(gi(this.bB), r); + }; + lE.prototype.set_m_graphicsWorldTrans = lE.prototype.VF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hi(c, a); + }; + Object.defineProperty(lE.prototype, 'm_graphicsWorldTrans', { get: lE.prototype.dD, set: lE.prototype.VF }); + lE.prototype.__destroy__ = function () { + ii(this.bB); + }; + function mE() { + throw 'cannot construct a btCollisionObjectWrapper, no constructor in IDL'; + } + mE.prototype = Object.create(f.prototype); + mE.prototype.constructor = mE; + mE.prototype.cB = mE; + mE.dB = {}; + b.btCollisionObjectWrapper = mE; + mE.prototype.getWorldTransform = function () { + return k(ji(this.bB), r); + }; + mE.prototype.getCollisionObject = function () { + return k(ki(this.bB), q); + }; + mE.prototype.getCollisionShape = function () { + return k(li(this.bB), l); + }; + function B(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = mi(a, c); + h(B)[this.bB] = this; + } + B.prototype = Object.create(u.prototype); + B.prototype.constructor = B; + B.prototype.cB = B; + B.dB = {}; + b.ClosestRayResultCallback = B; + B.prototype.hasHit = function () { + return !!ni(this.bB); + }; + B.prototype.get_m_rayFromWorld = B.prototype.FB = function () { + return k(oi(this.bB), m); + }; + B.prototype.set_m_rayFromWorld = B.prototype.PB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + pi(c, a); + }; + Object.defineProperty(B.prototype, 'm_rayFromWorld', { get: B.prototype.FB, set: B.prototype.PB }); + B.prototype.get_m_rayToWorld = B.prototype.GB = function () { + return k(qi(this.bB), m); + }; + B.prototype.set_m_rayToWorld = B.prototype.QB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ri(c, a); + }; + Object.defineProperty(B.prototype, 'm_rayToWorld', { get: B.prototype.GB, set: B.prototype.QB }); + B.prototype.get_m_hitNormalWorld = B.prototype.oB = function () { + return k(si(this.bB), m); + }; + B.prototype.set_m_hitNormalWorld = B.prototype.vB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ti(c, a); + }; + Object.defineProperty(B.prototype, 'm_hitNormalWorld', { get: B.prototype.oB, set: B.prototype.vB }); + B.prototype.get_m_hitPointWorld = B.prototype.pB = function () { + return k(ui(this.bB), m); + }; + B.prototype.set_m_hitPointWorld = B.prototype.wB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + vi(c, a); + }; + Object.defineProperty(B.prototype, 'm_hitPointWorld', { get: B.prototype.pB, set: B.prototype.wB }); + B.prototype.get_m_collisionFilterGroup = B.prototype.eB = function () { + return wi(this.bB); + }; + B.prototype.set_m_collisionFilterGroup = B.prototype.gB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + xi(c, a); + }; + Object.defineProperty(B.prototype, 'm_collisionFilterGroup', { get: B.prototype.eB, set: B.prototype.gB }); + B.prototype.get_m_collisionFilterMask = B.prototype.fB = function () { + return yi(this.bB); + }; + B.prototype.set_m_collisionFilterMask = B.prototype.hB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + zi(c, a); + }; + Object.defineProperty(B.prototype, 'm_collisionFilterMask', { get: B.prototype.fB, set: B.prototype.hB }); + B.prototype.get_m_closestHitFraction = B.prototype.iB = function () { + return Ai(this.bB); + }; + B.prototype.set_m_closestHitFraction = B.prototype.jB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Bi(c, a); + }; + Object.defineProperty(B.prototype, 'm_closestHitFraction', { get: B.prototype.iB, set: B.prototype.jB }); + B.prototype.get_m_collisionObject = B.prototype.mB = function () { + return k(Ci(this.bB), q); + }; + B.prototype.set_m_collisionObject = B.prototype.tB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Di(c, a); + }; + Object.defineProperty(B.prototype, 'm_collisionObject', { get: B.prototype.mB, set: B.prototype.tB }); + B.prototype.get_m_flags = B.prototype.kB = function () { + return Ei(this.bB); + }; + B.prototype.set_m_flags = B.prototype.lB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Fi(c, a); + }; + Object.defineProperty(B.prototype, 'm_flags', { get: B.prototype.kB, set: B.prototype.lB }); + B.prototype.__destroy__ = function () { + Gi(this.bB); + }; + function nE() { + throw 'cannot construct a btConstCollisionObjectArray, no constructor in IDL'; + } + nE.prototype = Object.create(f.prototype); + nE.prototype.constructor = nE; + nE.prototype.cB = nE; + nE.dB = {}; + b.btConstCollisionObjectArray = nE; + nE.prototype.size = nE.prototype.size = function () { + return Hi(this.bB); + }; + nE.prototype.at = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Ii(c, a), q); + }; + nE.prototype.__destroy__ = function () { + Ji(this.bB); + }; + function oE() { + throw 'cannot construct a btScalarArray, no constructor in IDL'; + } + oE.prototype = Object.create(f.prototype); + oE.prototype.constructor = oE; + oE.prototype.cB = oE; + oE.dB = {}; + b.btScalarArray = oE; + oE.prototype.size = oE.prototype.size = function () { + return Ki(this.bB); + }; + oE.prototype.at = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return Li(c, a); + }; + oE.prototype.__destroy__ = function () { + Mi(this.bB); + }; + function C(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = Ni(a, c); + h(C)[this.bB] = this; + } + C.prototype = Object.create(u.prototype); + C.prototype.constructor = C; + C.prototype.cB = C; + C.dB = {}; + b.AllHitsRayResultCallback = C; + C.prototype.hasHit = function () { + return !!Oi(this.bB); + }; + C.prototype.get_m_collisionObjects = C.prototype.MC = function () { + return k(Pi(this.bB), nE); + }; + C.prototype.set_m_collisionObjects = C.prototype.DF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Qi(c, a); + }; + Object.defineProperty(C.prototype, 'm_collisionObjects', { get: C.prototype.MC, set: C.prototype.DF }); + C.prototype.get_m_rayFromWorld = C.prototype.FB = function () { + return k(Ri(this.bB), m); + }; + C.prototype.set_m_rayFromWorld = C.prototype.PB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Si(c, a); + }; + Object.defineProperty(C.prototype, 'm_rayFromWorld', { get: C.prototype.FB, set: C.prototype.PB }); + C.prototype.get_m_rayToWorld = C.prototype.GB = function () { + return k(Ti(this.bB), m); + }; + C.prototype.set_m_rayToWorld = C.prototype.QB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ui(c, a); + }; + Object.defineProperty(C.prototype, 'm_rayToWorld', { get: C.prototype.GB, set: C.prototype.QB }); + C.prototype.get_m_hitNormalWorld = C.prototype.oB = function () { + return k(Vi(this.bB), pE); + }; + C.prototype.set_m_hitNormalWorld = C.prototype.vB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Wi(c, a); + }; + Object.defineProperty(C.prototype, 'm_hitNormalWorld', { get: C.prototype.oB, set: C.prototype.vB }); + C.prototype.get_m_hitPointWorld = C.prototype.pB = function () { + return k(Xi(this.bB), pE); + }; + C.prototype.set_m_hitPointWorld = C.prototype.wB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Yi(c, a); + }; + Object.defineProperty(C.prototype, 'm_hitPointWorld', { get: C.prototype.pB, set: C.prototype.wB }); + C.prototype.get_m_hitFractions = C.prototype.iD = function () { + return k(Zi(this.bB), oE); + }; + C.prototype.set_m_hitFractions = C.prototype.$F = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + $i(c, a); + }; + Object.defineProperty(C.prototype, 'm_hitFractions', { get: C.prototype.iD, set: C.prototype.$F }); + C.prototype.get_m_collisionFilterGroup = C.prototype.eB = function () { + return aj(this.bB); + }; + C.prototype.set_m_collisionFilterGroup = C.prototype.gB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + bj(c, a); + }; + Object.defineProperty(C.prototype, 'm_collisionFilterGroup', { get: C.prototype.eB, set: C.prototype.gB }); + C.prototype.get_m_collisionFilterMask = C.prototype.fB = function () { + return cj(this.bB); + }; + C.prototype.set_m_collisionFilterMask = C.prototype.hB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + dj(c, a); + }; + Object.defineProperty(C.prototype, 'm_collisionFilterMask', { get: C.prototype.fB, set: C.prototype.hB }); + C.prototype.get_m_closestHitFraction = C.prototype.iB = function () { + return ej(this.bB); + }; + C.prototype.set_m_closestHitFraction = C.prototype.jB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + fj(c, a); + }; + Object.defineProperty(C.prototype, 'm_closestHitFraction', { get: C.prototype.iB, set: C.prototype.jB }); + C.prototype.get_m_collisionObject = C.prototype.mB = function () { + return k(gj(this.bB), q); + }; + C.prototype.set_m_collisionObject = C.prototype.tB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hj(c, a); + }; + Object.defineProperty(C.prototype, 'm_collisionObject', { get: C.prototype.mB, set: C.prototype.tB }); + C.prototype.get_m_flags = C.prototype.kB = function () { + return ij(this.bB); + }; + C.prototype.set_m_flags = C.prototype.lB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + jj(c, a); + }; + Object.defineProperty(C.prototype, 'm_flags', { get: C.prototype.kB, set: C.prototype.lB }); + C.prototype.__destroy__ = function () { + kj(this.bB); + }; + function E() { + throw 'cannot construct a btManifoldPoint, no constructor in IDL'; + } + E.prototype = Object.create(f.prototype); + E.prototype.constructor = E; + E.prototype.cB = E; + E.dB = {}; + b.btManifoldPoint = E; + E.prototype.getPositionWorldOnA = function () { + return k(lj(this.bB), m); + }; + E.prototype.getPositionWorldOnB = function () { + return k(mj(this.bB), m); + }; + E.prototype.getAppliedImpulse = function () { + return nj(this.bB); + }; + E.prototype.getDistance = function () { + return oj(this.bB); + }; + E.prototype.get_m_localPointA = E.prototype.yD = function () { + return k(pj(this.bB), m); + }; + E.prototype.set_m_localPointA = E.prototype.pG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + qj(c, a); + }; + Object.defineProperty(E.prototype, 'm_localPointA', { get: E.prototype.yD, set: E.prototype.pG }); + E.prototype.get_m_localPointB = E.prototype.zD = function () { + return k(rj(this.bB), m); + }; + E.prototype.set_m_localPointB = E.prototype.qG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + sj(c, a); + }; + Object.defineProperty(E.prototype, 'm_localPointB', { get: E.prototype.zD, set: E.prototype.qG }); + E.prototype.get_m_positionWorldOnB = E.prototype.QD = function () { + return k(tj(this.bB), m); + }; + E.prototype.set_m_positionWorldOnB = E.prototype.HG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + uj(c, a); + }; + Object.defineProperty(E.prototype, 'm_positionWorldOnB', { get: E.prototype.QD, set: E.prototype.HG }); + E.prototype.get_m_positionWorldOnA = E.prototype.PD = function () { + return k(vj(this.bB), m); + }; + E.prototype.set_m_positionWorldOnA = E.prototype.GG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + wj(c, a); + }; + Object.defineProperty(E.prototype, 'm_positionWorldOnA', { get: E.prototype.PD, set: E.prototype.GG }); + E.prototype.get_m_normalWorldOnB = E.prototype.KD = function () { + return k(xj(this.bB), m); + }; + E.prototype.set_m_normalWorldOnB = E.prototype.BG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + yj(c, a); + }; + Object.defineProperty(E.prototype, 'm_normalWorldOnB', { get: E.prototype.KD, set: E.prototype.BG }); + E.prototype.get_m_userPersistentData = E.prototype.rE = function () { + return zj(this.bB); + }; + E.prototype.set_m_userPersistentData = E.prototype.jH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Aj(c, a); + }; + Object.defineProperty(E.prototype, 'm_userPersistentData', { get: E.prototype.rE, set: E.prototype.jH }); + E.prototype.__destroy__ = function () { + Bj(this.bB); + }; + function qE() { + this.bB = Cj(); + h(qE)[this.bB] = this; + } + qE.prototype = Object.create(VD.prototype); + qE.prototype.constructor = qE; + qE.prototype.cB = qE; + qE.dB = {}; + b.ConcreteContactResultCallback = qE; + qE.prototype.addSingleResult = function (a, c, d, e, g, n, D) { + var T = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + n && 'object' === typeof n && (n = n.bB); + D && 'object' === typeof D && (D = D.bB); + return Dj(T, a, c, d, e, g, n, D); + }; + qE.prototype.__destroy__ = function () { + Ej(this.bB); + }; + function rE() { + throw 'cannot construct a LocalShapeInfo, no constructor in IDL'; + } + rE.prototype = Object.create(f.prototype); + rE.prototype.constructor = rE; + rE.prototype.cB = rE; + rE.dB = {}; + b.LocalShapeInfo = rE; + rE.prototype.get_m_shapePart = rE.prototype.ZD = function () { + return Fj(this.bB); + }; + rE.prototype.set_m_shapePart = rE.prototype.QG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Gj(c, a); + }; + Object.defineProperty(rE.prototype, 'm_shapePart', { get: rE.prototype.ZD, set: rE.prototype.QG }); + rE.prototype.get_m_triangleIndex = rE.prototype.nE = function () { + return Hj(this.bB); + }; + rE.prototype.set_m_triangleIndex = rE.prototype.fH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ij(c, a); + }; + Object.defineProperty(rE.prototype, 'm_triangleIndex', { get: rE.prototype.nE, set: rE.prototype.fH }); + rE.prototype.__destroy__ = function () { + Jj(this.bB); + }; + function F(a, c, d, e, g) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + this.bB = Kj(a, c, d, e, g); + h(F)[this.bB] = this; + } + F.prototype = Object.create(f.prototype); + F.prototype.constructor = F; + F.prototype.cB = F; + F.dB = {}; + b.LocalConvexResult = F; + F.prototype.get_m_hitCollisionObject = F.prototype.DB = function () { + return k(Lj(this.bB), q); + }; + F.prototype.set_m_hitCollisionObject = F.prototype.NB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Mj(c, a); + }; + Object.defineProperty(F.prototype, 'm_hitCollisionObject', { get: F.prototype.DB, set: F.prototype.NB }); + F.prototype.get_m_localShapeInfo = F.prototype.AD = function () { + return k(Nj(this.bB), rE); + }; + F.prototype.set_m_localShapeInfo = F.prototype.rG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Oj(c, a); + }; + Object.defineProperty(F.prototype, 'm_localShapeInfo', { get: F.prototype.AD, set: F.prototype.rG }); + F.prototype.get_m_hitNormalLocal = F.prototype.kD = function () { + return k(Pj(this.bB), m); + }; + F.prototype.set_m_hitNormalLocal = F.prototype.bG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Qj(c, a); + }; + Object.defineProperty(F.prototype, 'm_hitNormalLocal', { get: F.prototype.kD, set: F.prototype.bG }); + F.prototype.get_m_hitPointLocal = F.prototype.mD = function () { + return k(Rj(this.bB), m); + }; + F.prototype.set_m_hitPointLocal = F.prototype.dG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Sj(c, a); + }; + Object.defineProperty(F.prototype, 'm_hitPointLocal', { get: F.prototype.mD, set: F.prototype.dG }); + F.prototype.get_m_hitFraction = F.prototype.hD = function () { + return Tj(this.bB); + }; + F.prototype.set_m_hitFraction = F.prototype.ZF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Uj(c, a); + }; + Object.defineProperty(F.prototype, 'm_hitFraction', { get: F.prototype.hD, set: F.prototype.ZF }); + F.prototype.__destroy__ = function () { + Vj(this.bB); + }; + function G(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = Wj(a, c); + h(G)[this.bB] = this; + } + G.prototype = Object.create(v.prototype); + G.prototype.constructor = G; + G.prototype.cB = G; + G.dB = {}; + b.ClosestConvexResultCallback = G; + G.prototype.hasHit = function () { + return !!Xj(this.bB); + }; + G.prototype.get_m_hitCollisionObject = G.prototype.DB = function () { + return k(Yj(this.bB), q); + }; + G.prototype.set_m_hitCollisionObject = G.prototype.NB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Zj(c, a); + }; + Object.defineProperty(G.prototype, 'm_hitCollisionObject', { get: G.prototype.DB, set: G.prototype.NB }); + G.prototype.get_m_convexFromWorld = G.prototype.RC = function () { + return k(ak(this.bB), m); + }; + G.prototype.set_m_convexFromWorld = G.prototype.IF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + bk(c, a); + }; + Object.defineProperty(G.prototype, 'm_convexFromWorld', { get: G.prototype.RC, set: G.prototype.IF }); + G.prototype.get_m_convexToWorld = G.prototype.SC = function () { + return k(ck(this.bB), m); + }; + G.prototype.set_m_convexToWorld = G.prototype.JF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + dk(c, a); + }; + Object.defineProperty(G.prototype, 'm_convexToWorld', { get: G.prototype.SC, set: G.prototype.JF }); + G.prototype.get_m_hitNormalWorld = G.prototype.oB = function () { + return k(ek(this.bB), m); + }; + G.prototype.set_m_hitNormalWorld = G.prototype.vB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + fk(c, a); + }; + Object.defineProperty(G.prototype, 'm_hitNormalWorld', { get: G.prototype.oB, set: G.prototype.vB }); + G.prototype.get_m_hitPointWorld = G.prototype.pB = function () { + return k(gk(this.bB), m); + }; + G.prototype.set_m_hitPointWorld = G.prototype.wB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hk(c, a); + }; + Object.defineProperty(G.prototype, 'm_hitPointWorld', { get: G.prototype.pB, set: G.prototype.wB }); + G.prototype.get_m_collisionFilterGroup = G.prototype.eB = function () { + return ik(this.bB); + }; + G.prototype.set_m_collisionFilterGroup = G.prototype.gB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + jk(c, a); + }; + Object.defineProperty(G.prototype, 'm_collisionFilterGroup', { get: G.prototype.eB, set: G.prototype.gB }); + G.prototype.get_m_collisionFilterMask = G.prototype.fB = function () { + return kk(this.bB); + }; + G.prototype.set_m_collisionFilterMask = G.prototype.hB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + lk(c, a); + }; + Object.defineProperty(G.prototype, 'm_collisionFilterMask', { get: G.prototype.fB, set: G.prototype.hB }); + G.prototype.get_m_closestHitFraction = G.prototype.iB = function () { + return mk(this.bB); + }; + G.prototype.set_m_closestHitFraction = G.prototype.jB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + nk(c, a); + }; + Object.defineProperty(G.prototype, 'm_closestHitFraction', { get: G.prototype.iB, set: G.prototype.jB }); + G.prototype.__destroy__ = function () { + ok(this.bB); + }; + function sE(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = void 0 === c ? pk(a) : qk(a, c); + h(sE)[this.bB] = this; + } + sE.prototype = Object.create(WD.prototype); + sE.prototype.constructor = sE; + sE.prototype.cB = sE; + sE.dB = {}; + b.btConvexTriangleMeshShape = sE; + sE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + rk(c, a); + }; + sE.prototype.getLocalScaling = function () { + return k(sk(this.bB), m); + }; + sE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + tk(d, a, c); + }; + sE.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + uk(c, a); + }; + sE.prototype.getMargin = function () { + return vk(this.bB); + }; + sE.prototype.__destroy__ = function () { + wk(this.bB); + }; + function tE(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = xk(a); + h(tE)[this.bB] = this; + } + tE.prototype = Object.create(l.prototype); + tE.prototype.constructor = tE; + tE.prototype.cB = tE; + tE.dB = {}; + b.btBoxShape = tE; + tE.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + yk(c, a); + }; + tE.prototype.getMargin = function () { + return zk(this.bB); + }; + tE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ak(c, a); + }; + tE.prototype.getLocalScaling = function () { + return k(Bk(this.bB), m); + }; + tE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Ck(d, a, c); + }; + tE.prototype.__destroy__ = function () { + Dk(this.bB); + }; + function uE(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = Ek(a, c); + h(uE)[this.bB] = this; + } + uE.prototype = Object.create(XD.prototype); + uE.prototype.constructor = uE; + uE.prototype.cB = uE; + uE.dB = {}; + b.btCapsuleShapeX = uE; + uE.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Fk(c, a); + }; + uE.prototype.getMargin = function () { + return Gk(this.bB); + }; + uE.prototype.getUpAxis = function () { + return Hk(this.bB); + }; + uE.prototype.getRadius = function () { + return Ik(this.bB); + }; + uE.prototype.getHalfHeight = function () { + return Jk(this.bB); + }; + uE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Kk(c, a); + }; + uE.prototype.getLocalScaling = function () { + return k(Lk(this.bB), m); + }; + uE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Mk(d, a, c); + }; + uE.prototype.__destroy__ = function () { + Nk(this.bB); + }; + function vE(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = Ok(a, c); + h(vE)[this.bB] = this; + } + vE.prototype = Object.create(XD.prototype); + vE.prototype.constructor = vE; + vE.prototype.cB = vE; + vE.dB = {}; + b.btCapsuleShapeZ = vE; + vE.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Pk(c, a); + }; + vE.prototype.getMargin = function () { + return Qk(this.bB); + }; + vE.prototype.getUpAxis = function () { + return Rk(this.bB); + }; + vE.prototype.getRadius = function () { + return Sk(this.bB); + }; + vE.prototype.getHalfHeight = function () { + return Tk(this.bB); + }; + vE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Uk(c, a); + }; + vE.prototype.getLocalScaling = function () { + return k(Vk(this.bB), m); + }; + vE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Wk(d, a, c); + }; + vE.prototype.__destroy__ = function () { + Xk(this.bB); + }; + function wE(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = Yk(a); + h(wE)[this.bB] = this; + } + wE.prototype = Object.create(YD.prototype); + wE.prototype.constructor = wE; + wE.prototype.cB = wE; + wE.dB = {}; + b.btCylinderShapeX = wE; + wE.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Zk(c, a); + }; + wE.prototype.getMargin = function () { + return $k(this.bB); + }; + wE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + al(c, a); + }; + wE.prototype.getLocalScaling = function () { + return k(bl(this.bB), m); + }; + wE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + cl(d, a, c); + }; + wE.prototype.__destroy__ = function () { + dl(this.bB); + }; + function xE(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = el(a); + h(xE)[this.bB] = this; + } + xE.prototype = Object.create(YD.prototype); + xE.prototype.constructor = xE; + xE.prototype.cB = xE; + xE.dB = {}; + b.btCylinderShapeZ = xE; + xE.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + fl(c, a); + }; + xE.prototype.getMargin = function () { + return gl(this.bB); + }; + xE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hl(c, a); + }; + xE.prototype.getLocalScaling = function () { + return k(il(this.bB), m); + }; + xE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + jl(d, a, c); + }; + xE.prototype.__destroy__ = function () { + kl(this.bB); + }; + function yE(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = ll(a); + h(yE)[this.bB] = this; + } + yE.prototype = Object.create(l.prototype); + yE.prototype.constructor = yE; + yE.prototype.cB = yE; + yE.dB = {}; + b.btSphereShape = yE; + yE.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ml(c, a); + }; + yE.prototype.getMargin = function () { + return nl(this.bB); + }; + yE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ol(c, a); + }; + yE.prototype.getLocalScaling = function () { + return k(pl(this.bB), m); + }; + yE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + ql(d, a, c); + }; + yE.prototype.__destroy__ = function () { + rl(this.bB); + }; + function zE(a, c, d) { + DD(); + a && 'object' === typeof a && (a = a.bB); + 'object' == typeof c && (c = HD(c)); + d && 'object' === typeof d && (d = d.bB); + this.bB = sl(a, c, d); + h(zE)[this.bB] = this; + } + zE.prototype = Object.create(l.prototype); + zE.prototype.constructor = zE; + zE.prototype.cB = zE; + zE.dB = {}; + b.btMultiSphereShape = zE; + zE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + tl(c, a); + }; + zE.prototype.getLocalScaling = function () { + return k(ul(this.bB), m); + }; + zE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + vl(d, a, c); + }; + zE.prototype.__destroy__ = function () { + wl(this.bB); + }; + function AE(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = xl(a, c); + h(AE)[this.bB] = this; + } + AE.prototype = Object.create(ZD.prototype); + AE.prototype.constructor = AE; + AE.prototype.cB = AE; + AE.dB = {}; + b.btConeShapeX = AE; + AE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + yl(c, a); + }; + AE.prototype.getLocalScaling = function () { + return k(zl(this.bB), m); + }; + AE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Al(d, a, c); + }; + AE.prototype.__destroy__ = function () { + Bl(this.bB); + }; + function BE(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = Cl(a, c); + h(BE)[this.bB] = this; + } + BE.prototype = Object.create(ZD.prototype); + BE.prototype.constructor = BE; + BE.prototype.cB = BE; + BE.dB = {}; + b.btConeShapeZ = BE; + BE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Dl(c, a); + }; + BE.prototype.getLocalScaling = function () { + return k(El(this.bB), m); + }; + BE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Fl(d, a, c); + }; + BE.prototype.__destroy__ = function () { + Gl(this.bB); + }; + function CE() { + throw 'cannot construct a btIntArray, no constructor in IDL'; + } + CE.prototype = Object.create(f.prototype); + CE.prototype.constructor = CE; + CE.prototype.cB = CE; + CE.dB = {}; + b.btIntArray = CE; + CE.prototype.size = CE.prototype.size = function () { + return Hl(this.bB); + }; + CE.prototype.at = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return Il(c, a); + }; + CE.prototype.__destroy__ = function () { + Jl(this.bB); + }; + function DE() { + throw 'cannot construct a btFace, no constructor in IDL'; + } + DE.prototype = Object.create(f.prototype); + DE.prototype.constructor = DE; + DE.prototype.cB = DE; + DE.dB = {}; + b.btFace = DE; + DE.prototype.get_m_indices = DE.prototype.pD = function () { + return k(Kl(this.bB), CE); + }; + DE.prototype.set_m_indices = DE.prototype.gG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ll(c, a); + }; + Object.defineProperty(DE.prototype, 'm_indices', { get: DE.prototype.pD, set: DE.prototype.gG }); + DE.prototype.get_m_plane = DE.prototype.OD = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return Ml(c, a); + }; + DE.prototype.set_m_plane = DE.prototype.FG = function (a, c) { + var d = this.bB; + DD(); + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Nl(d, a, c); + }; + Object.defineProperty(DE.prototype, 'm_plane', { get: DE.prototype.OD, set: DE.prototype.FG }); + DE.prototype.__destroy__ = function () { + Ol(this.bB); + }; + function pE() { + throw 'cannot construct a btVector3Array, no constructor in IDL'; + } + pE.prototype = Object.create(f.prototype); + pE.prototype.constructor = pE; + pE.prototype.cB = pE; + pE.dB = {}; + b.btVector3Array = pE; + pE.prototype.size = pE.prototype.size = function () { + return Pl(this.bB); + }; + pE.prototype.at = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Ql(c, a), m); + }; + pE.prototype.__destroy__ = function () { + Rl(this.bB); + }; + function EE() { + throw 'cannot construct a btFaceArray, no constructor in IDL'; + } + EE.prototype = Object.create(f.prototype); + EE.prototype.constructor = EE; + EE.prototype.cB = EE; + EE.dB = {}; + b.btFaceArray = EE; + EE.prototype.size = EE.prototype.size = function () { + return Sl(this.bB); + }; + EE.prototype.at = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Tl(c, a), DE); + }; + EE.prototype.__destroy__ = function () { + Ul(this.bB); + }; + function FE() { + throw 'cannot construct a btConvexPolyhedron, no constructor in IDL'; + } + FE.prototype = Object.create(f.prototype); + FE.prototype.constructor = FE; + FE.prototype.cB = FE; + FE.dB = {}; + b.btConvexPolyhedron = FE; + FE.prototype.get_m_vertices = FE.prototype.tE = function () { + return k(Vl(this.bB), pE); + }; + FE.prototype.set_m_vertices = FE.prototype.lH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Wl(c, a); + }; + Object.defineProperty(FE.prototype, 'm_vertices', { get: FE.prototype.tE, set: FE.prototype.lH }); + FE.prototype.get_m_faces = FE.prototype.CB = function () { + return k(Xl(this.bB), EE); + }; + FE.prototype.set_m_faces = FE.prototype.MB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Yl(c, a); + }; + Object.defineProperty(FE.prototype, 'm_faces', { get: FE.prototype.CB, set: FE.prototype.MB }); + FE.prototype.__destroy__ = function () { + Zl(this.bB); + }; + function GE(a, c) { + DD(); + 'object' == typeof a && (a = HD(a)); + c && 'object' === typeof c && (c = c.bB); + this.bB = void 0 === a ? $l() : void 0 === c ? am(a) : bm(a, c); + h(GE)[this.bB] = this; + } + GE.prototype = Object.create(l.prototype); + GE.prototype.constructor = GE; + GE.prototype.cB = GE; + GE.dB = {}; + b.btConvexHullShape = GE; + GE.prototype.addPoint = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + void 0 === c ? cm(d, a) : dm(d, a, c); + }; + GE.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + em(c, a); + }; + GE.prototype.getMargin = function () { + return fm(this.bB); + }; + GE.prototype.getNumVertices = function () { + return gm(this.bB); + }; + GE.prototype.initializePolyhedralFeatures = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return !!hm(c, a); + }; + GE.prototype.recalcLocalAabb = function () { + im(this.bB); + }; + GE.prototype.getConvexPolyhedron = function () { + return k(jm(this.bB), FE); + }; + GE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + km(c, a); + }; + GE.prototype.getLocalScaling = function () { + return k(lm(this.bB), m); + }; + GE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + mm(d, a, c); + }; + GE.prototype.__destroy__ = function () { + nm(this.bB); + }; + function HE(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = om(a); + h(HE)[this.bB] = this; + } + HE.prototype = Object.create(f.prototype); + HE.prototype.constructor = HE; + HE.prototype.cB = HE; + HE.dB = {}; + b.btShapeHull = HE; + HE.prototype.buildHull = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return !!pm(c, a); + }; + HE.prototype.numVertices = function () { + return qm(this.bB); + }; + HE.prototype.getVertexPointer = function () { + return k(rm(this.bB), m); + }; + HE.prototype.__destroy__ = function () { + sm(this.bB); + }; + function IE(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = void 0 === a ? tm() : um(a); + h(IE)[this.bB] = this; + } + IE.prototype = Object.create(l.prototype); + IE.prototype.constructor = IE; + IE.prototype.cB = IE; + IE.dB = {}; + b.btCompoundShape = IE; + IE.prototype.addChildShape = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + wm(d, a, c); + }; + IE.prototype.removeChildShape = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + xm(c, a); + }; + IE.prototype.removeChildShapeByIndex = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ym(c, a); + }; + IE.prototype.getNumChildShapes = function () { + return zm(this.bB); + }; + IE.prototype.getChildShape = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Am(c, a), l); + }; + IE.prototype.updateChildTransform = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + void 0 === d ? Bm(e, a, c) : Cm(e, a, c, d); + }; + IE.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Dm(c, a); + }; + IE.prototype.getMargin = function () { + return Em(this.bB); + }; + IE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Fm(c, a); + }; + IE.prototype.getLocalScaling = function () { + return k(Gm(this.bB), m); + }; + IE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Hm(d, a, c); + }; + IE.prototype.__destroy__ = function () { + Im(this.bB); + }; + function JE() { + throw 'cannot construct a btIndexedMesh, no constructor in IDL'; + } + JE.prototype = Object.create(f.prototype); + JE.prototype.constructor = JE; + JE.prototype.cB = JE; + JE.dB = {}; + b.btIndexedMesh = JE; + JE.prototype.get_m_numTriangles = JE.prototype.MD = function () { + return Jm(this.bB); + }; + JE.prototype.set_m_numTriangles = JE.prototype.DG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Km(c, a); + }; + Object.defineProperty(JE.prototype, 'm_numTriangles', { get: JE.prototype.MD, set: JE.prototype.DG }); + JE.prototype.__destroy__ = function () { + Lm(this.bB); + }; + function KE() { + throw 'cannot construct a btIndexedMeshArray, no constructor in IDL'; + } + KE.prototype = Object.create(f.prototype); + KE.prototype.constructor = KE; + KE.prototype.cB = KE; + KE.dB = {}; + b.btIndexedMeshArray = KE; + KE.prototype.size = KE.prototype.size = function () { + return Mm(this.bB); + }; + KE.prototype.at = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Nm(c, a), JE); + }; + KE.prototype.__destroy__ = function () { + Om(this.bB); + }; + function LE(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = void 0 === a ? Pm() : void 0 === c ? Qm(a) : Rm(a, c); + h(LE)[this.bB] = this; + } + LE.prototype = Object.create($D.prototype); + LE.prototype.constructor = LE; + LE.prototype.cB = LE; + LE.dB = {}; + b.btTriangleMesh = LE; + LE.prototype.addTriangle = function (a, c, d, e) { + var g = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + void 0 === e ? Sm(g, a, c, d) : Tm(g, a, c, d, e); + }; + LE.prototype.findOrAddVertex = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return Um(d, a, c); + }; + LE.prototype.addIndex = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Vm(c, a); + }; + LE.prototype.getIndexedMeshArray = function () { + return k(Wm(this.bB), KE); + }; + LE.prototype.setScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Xm(c, a); + }; + LE.prototype.__destroy__ = function () { + Ym(this.bB); + }; + function ME() { + this.bB = Zm(); + h(ME)[this.bB] = this; + } + ME.prototype = Object.create(PD.prototype); + ME.prototype.constructor = ME; + ME.prototype.cB = ME; + ME.dB = {}; + b.btEmptyShape = ME; + ME.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + $m(c, a); + }; + ME.prototype.getLocalScaling = function () { + return k(an(this.bB), m); + }; + ME.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + bn(d, a, c); + }; + ME.prototype.__destroy__ = function () { + cn(this.bB); + }; + function NE(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = dn(a, c); + h(NE)[this.bB] = this; + } + NE.prototype = Object.create(PD.prototype); + NE.prototype.constructor = NE; + NE.prototype.cB = NE; + NE.dB = {}; + b.btStaticPlaneShape = NE; + NE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + en(c, a); + }; + NE.prototype.getLocalScaling = function () { + return k(fn(this.bB), m); + }; + NE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + gn(d, a, c); + }; + NE.prototype.__destroy__ = function () { + hn(this.bB); + }; + function OE(a, c, d) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + this.bB = void 0 === d ? jn(a, c) : kn(a, c, d); + h(OE)[this.bB] = this; + } + OE.prototype = Object.create(aE.prototype); + OE.prototype.constructor = OE; + OE.prototype.cB = OE; + OE.dB = {}; + b.btBvhTriangleMeshShape = OE; + OE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ln(c, a); + }; + OE.prototype.getLocalScaling = function () { + return k(mn(this.bB), m); + }; + OE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + nn(d, a, c); + }; + OE.prototype.__destroy__ = function () { + on(this.bB); + }; + function PE(a, c, d, e, g, n, D, T, Da) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + n && 'object' === typeof n && (n = n.bB); + D && 'object' === typeof D && (D = D.bB); + T && 'object' === typeof T && (T = T.bB); + Da && 'object' === typeof Da && (Da = Da.bB); + this.bB = pn(a, c, d, e, g, n, D, T, Da); + h(PE)[this.bB] = this; + } + PE.prototype = Object.create(PD.prototype); + PE.prototype.constructor = PE; + PE.prototype.cB = PE; + PE.dB = {}; + b.btHeightfieldTerrainShape = PE; + PE.prototype.setMargin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + qn(c, a); + }; + PE.prototype.getMargin = function () { + return rn(this.bB); + }; + PE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + sn(c, a); + }; + PE.prototype.getLocalScaling = function () { + return k(tn(this.bB), m); + }; + PE.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + un(d, a, c); + }; + PE.prototype.__destroy__ = function () { + vn(this.bB); + }; + function QE(a, c, d, e) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + this.bB = wn(a, c, d, e); + h(QE)[this.bB] = this; + } + QE.prototype = Object.create(f.prototype); + QE.prototype.constructor = QE; + QE.prototype.cB = QE; + QE.dB = {}; + b.btAABB = QE; + QE.prototype.invalidate = function () { + xn(this.bB); + }; + QE.prototype.increment_margin = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + yn(c, a); + }; + QE.prototype.copy_with_margin = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + zn(d, a, c); + }; + QE.prototype.__destroy__ = function () { + An(this.bB); + }; + function RE() { + this.bB = Bn(); + h(RE)[this.bB] = this; + } + RE.prototype = Object.create(f.prototype); + RE.prototype.constructor = RE; + RE.prototype.cB = RE; + RE.dB = {}; + b.btPrimitiveTriangle = RE; + RE.prototype.__destroy__ = function () { + Cn(this.bB); + }; + function SE(a, c, d) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + this.bB = Dn(a, c, d); + h(SE)[this.bB] = this; + } + SE.prototype = Object.create(f.prototype); + SE.prototype.constructor = SE; + SE.prototype.cB = SE; + SE.dB = {}; + b.btTriangleShapeEx = SE; + SE.prototype.getAabb = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + En(e, a, c, d); + }; + SE.prototype.applyTransform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Fn(c, a); + }; + SE.prototype.buildTriPlane = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Gn(c, a); + }; + SE.prototype.__destroy__ = function () { + Hn(this.bB); + }; + function TE() { + this.bB = In(); + h(TE)[this.bB] = this; + } + TE.prototype = Object.create(f.prototype); + TE.prototype.constructor = TE; + TE.prototype.cB = TE; + TE.dB = {}; + b.btTetrahedronShapeEx = TE; + TE.prototype.setVertices = function (a, c, d, e) { + var g = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + Jn(g, a, c, d, e); + }; + TE.prototype.__destroy__ = function () { + Kn(this.bB); + }; + function UE() { + throw 'cannot construct a CompoundPrimitiveManager, no constructor in IDL'; + } + UE.prototype = Object.create(bE.prototype); + UE.prototype.constructor = UE; + UE.prototype.cB = UE; + UE.dB = {}; + b.CompoundPrimitiveManager = UE; + UE.prototype.get_primitive_count = function () { + return Ln(this.bB); + }; + UE.prototype.get_primitive_box = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Mn(d, a, c); + }; + UE.prototype.get_primitive_triangle = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Nn(d, a, c); + }; + UE.prototype.is_trimesh = function () { + return !!On(this.bB); + }; + UE.prototype.get_m_compoundShape = UE.prototype.NC = function () { + return k(Pn(this.bB), H); + }; + UE.prototype.set_m_compoundShape = UE.prototype.EF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Qn(c, a); + }; + Object.defineProperty(UE.prototype, 'm_compoundShape', { get: UE.prototype.NC, set: UE.prototype.EF }); + UE.prototype.__destroy__ = function () { + Rn(this.bB); + }; + function H(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = void 0 === a ? Sn() : Tn(a); + h(H)[this.bB] = this; + } + H.prototype = Object.create(w.prototype); + H.prototype.constructor = H; + H.prototype.cB = H; + H.dB = {}; + b.btGImpactCompoundShape = H; + H.prototype.childrenHasTransform = function () { + return !!Un(this.bB); + }; + H.prototype.getPrimitiveManager = function () { + return k(Vn(this.bB), bE); + }; + H.prototype.getCompoundPrimitiveManager = function () { + return k(Wn(this.bB), UE); + }; + H.prototype.getNumChildShapes = function () { + return Xn(this.bB); + }; + H.prototype.addChildShape = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Yn(d, a, c); + }; + H.prototype.getChildShape = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Zn(c, a), l); + }; + H.prototype.getChildAabb = function (a, c, d, e) { + var g = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + $n(g, a, c, d, e); + }; + H.prototype.getChildTransform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(ao(c, a), r); + }; + H.prototype.setChildTransform = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + bo(d, a, c); + }; + H.prototype.calculateLocalInertia = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + co(d, a, c); + }; + H.prototype.getName = function () { + return ua(eo(this.bB)); + }; + H.prototype.getGImpactShapeType = function () { + return fo(this.bB); + }; + H.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + go(c, a); + }; + H.prototype.getLocalScaling = function () { + return k(ho(this.bB), m); + }; + H.prototype.updateBound = function () { + io(this.bB); + }; + H.prototype.postUpdate = function () { + jo(this.bB); + }; + H.prototype.getShapeType = function () { + return ko(this.bB); + }; + H.prototype.needsRetrieveTriangles = function () { + return !!lo(this.bB); + }; + H.prototype.needsRetrieveTetrahedrons = function () { + return !!mo(this.bB); + }; + H.prototype.getBulletTriangle = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + no(d, a, c); + }; + H.prototype.getBulletTetrahedron = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + oo(d, a, c); + }; + H.prototype.__destroy__ = function () { + po(this.bB); + }; + function I(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = void 0 === a ? qo() : ro(a); + h(I)[this.bB] = this; + } + I.prototype = Object.create(bE.prototype); + I.prototype.constructor = I; + I.prototype.cB = I; + I.dB = {}; + b.TrimeshPrimitiveManager = I; + I.prototype.lock = I.prototype.lock = function () { + so(this.bB); + }; + I.prototype.unlock = I.prototype.unlock = function () { + to(this.bB); + }; + I.prototype.is_trimesh = function () { + return !!uo(this.bB); + }; + I.prototype.get_vertex_count = function () { + return vo(this.bB); + }; + I.prototype.get_indices = function (a, c, d, e) { + var g = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + wo(g, a, c, d, e); + }; + I.prototype.get_vertex = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + xo(d, a, c); + }; + I.prototype.get_bullet_triangle = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + yo(d, a, c); + }; + I.prototype.get_m_margin = I.prototype.DD = function () { + return zo(this.bB); + }; + I.prototype.set_m_margin = I.prototype.uG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ao(c, a); + }; + Object.defineProperty(I.prototype, 'm_margin', { get: I.prototype.DD, set: I.prototype.uG }); + I.prototype.get_m_meshInterface = I.prototype.GD = function () { + return k(Bo(this.bB), $D); + }; + I.prototype.set_m_meshInterface = I.prototype.xG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Co(c, a); + }; + Object.defineProperty(I.prototype, 'm_meshInterface', { get: I.prototype.GD, set: I.prototype.xG }); + I.prototype.get_m_part = I.prototype.ND = function () { + return Do(this.bB); + }; + I.prototype.set_m_part = I.prototype.EG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Eo(c, a); + }; + Object.defineProperty(I.prototype, 'm_part', { get: I.prototype.ND, set: I.prototype.EG }); + I.prototype.get_m_lock_count = I.prototype.BD = function () { + return Fo(this.bB); + }; + I.prototype.set_m_lock_count = I.prototype.sG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Go(c, a); + }; + Object.defineProperty(I.prototype, 'm_lock_count', { get: I.prototype.BD, set: I.prototype.sG }); + I.prototype.get_numverts = I.prototype.DE = function () { + return Ho(this.bB); + }; + I.prototype.set_numverts = I.prototype.vH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Io(c, a); + }; + Object.defineProperty(I.prototype, 'numverts', { get: I.prototype.DE, set: I.prototype.vH }); + I.prototype.get_type = I.prototype.HE = function () { + return Jo(this.bB); + }; + I.prototype.set_type = I.prototype.zH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ko(c, a); + }; + Object.defineProperty(I.prototype, 'type', { get: I.prototype.HE, set: I.prototype.zH }); + I.prototype.get_stride = I.prototype.FE = function () { + return Lo(this.bB); + }; + I.prototype.set_stride = I.prototype.xH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Mo(c, a); + }; + Object.defineProperty(I.prototype, 'stride', { get: I.prototype.FE, set: I.prototype.xH }); + I.prototype.get_indexstride = I.prototype.ZB = function () { + return No(this.bB); + }; + I.prototype.set_indexstride = I.prototype.QE = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Oo(c, a); + }; + Object.defineProperty(I.prototype, 'indexstride', { get: I.prototype.ZB, set: I.prototype.QE }); + I.prototype.get_numfaces = I.prototype.CE = function () { + return Po(this.bB); + }; + I.prototype.set_numfaces = I.prototype.uH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Qo(c, a); + }; + Object.defineProperty(I.prototype, 'numfaces', { get: I.prototype.CE, set: I.prototype.uH }); + I.prototype.get_indicestype = I.prototype.$B = function () { + return Ro(this.bB); + }; + I.prototype.set_indicestype = I.prototype.RE = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + So(c, a); + }; + Object.defineProperty(I.prototype, 'indicestype', { get: I.prototype.$B, set: I.prototype.RE }); + I.prototype.__destroy__ = function () { + To(this.bB); + }; + function VE(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = Uo(a, c); + h(VE)[this.bB] = this; + } + VE.prototype = Object.create(w.prototype); + VE.prototype.constructor = VE; + VE.prototype.cB = VE; + VE.dB = {}; + b.btGImpactMeshShapePart = VE; + VE.prototype.getTrimeshPrimitiveManager = function () { + return k(Vo(this.bB), I); + }; + VE.prototype.getVertexCount = function () { + return Wo(this.bB); + }; + VE.prototype.getVertex = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Xo(d, a, c); + }; + VE.prototype.getPart = function () { + return Yo(this.bB); + }; + VE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Zo(c, a); + }; + VE.prototype.getLocalScaling = function () { + return k($o(this.bB), m); + }; + VE.prototype.updateBound = function () { + ap(this.bB); + }; + VE.prototype.postUpdate = function () { + bp(this.bB); + }; + VE.prototype.getShapeType = function () { + return cp(this.bB); + }; + VE.prototype.needsRetrieveTriangles = function () { + return !!dp(this.bB); + }; + VE.prototype.needsRetrieveTetrahedrons = function () { + return !!ep(this.bB); + }; + VE.prototype.getBulletTriangle = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + fp(d, a, c); + }; + VE.prototype.getBulletTetrahedron = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + gp(d, a, c); + }; + VE.prototype.__destroy__ = function () { + hp(this.bB); + }; + function WE(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = ip(a); + h(WE)[this.bB] = this; + } + WE.prototype = Object.create(w.prototype); + WE.prototype.constructor = WE; + WE.prototype.cB = WE; + WE.dB = {}; + b.btGImpactMeshShape = WE; + WE.prototype.getMeshInterface = function () { + return k(jp(this.bB), $D); + }; + WE.prototype.getMeshPartCount = function () { + return kp(this.bB); + }; + WE.prototype.getMeshPart = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(lp(c, a), VE); + }; + WE.prototype.calculateSerializeBufferSize = function () { + return mp(this.bB); + }; + WE.prototype.setLocalScaling = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + np(c, a); + }; + WE.prototype.getLocalScaling = function () { + return k(op(this.bB), m); + }; + WE.prototype.updateBound = function () { + pp(this.bB); + }; + WE.prototype.postUpdate = function () { + qp(this.bB); + }; + WE.prototype.getShapeType = function () { + return rp(this.bB); + }; + WE.prototype.needsRetrieveTriangles = function () { + return !!sp(this.bB); + }; + WE.prototype.needsRetrieveTetrahedrons = function () { + return !!tp(this.bB); + }; + WE.prototype.getBulletTriangle = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + up(d, a, c); + }; + WE.prototype.getBulletTetrahedron = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + vp(d, a, c); + }; + WE.prototype.__destroy__ = function () { + wp(this.bB); + }; + function XE(a, c) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + this.bB = void 0 === a ? xp() : void 0 === c ? _emscripten_bind_btCollisionAlgorithmConstructionInfo_btCollisionAlgorithmConstructionInfo_1(a) : yp(a, c); + h(XE)[this.bB] = this; + } + XE.prototype = Object.create(f.prototype); + XE.prototype.constructor = XE; + XE.prototype.cB = XE; + XE.dB = {}; + b.btCollisionAlgorithmConstructionInfo = XE; + XE.prototype.get_m_dispatcher1 = XE.prototype.XC = function () { + return k(zp(this.bB), JD); + }; + XE.prototype.set_m_dispatcher1 = XE.prototype.OF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ap(c, a); + }; + Object.defineProperty(XE.prototype, 'm_dispatcher1', { get: XE.prototype.XC, set: XE.prototype.OF }); + XE.prototype.get_m_manifold = XE.prototype.CD = function () { + return k(Bp(this.bB), eE); + }; + XE.prototype.set_m_manifold = XE.prototype.tG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Cp(c, a); + }; + Object.defineProperty(XE.prototype, 'm_manifold', { get: XE.prototype.CD, set: XE.prototype.tG }); + XE.prototype.__destroy__ = function () { + Dp(this.bB); + }; + function YE(a, c, d) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + this.bB = Ep(a, c, d); + h(YE)[this.bB] = this; + } + YE.prototype = Object.create(cE.prototype); + YE.prototype.constructor = YE; + YE.prototype.cB = YE; + YE.dB = {}; + b.btGImpactCollisionAlgorithm = YE; + YE.prototype.registerAlgorithm = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Fp(c, a); + }; + YE.prototype.__destroy__ = function () { + Gp(this.bB); + }; + function ZE() { + this.bB = Hp(); + h(ZE)[this.bB] = this; + } + ZE.prototype = Object.create(f.prototype); + ZE.prototype.constructor = ZE; + ZE.prototype.cB = ZE; + ZE.dB = {}; + b.btDefaultCollisionConstructionInfo = ZE; + ZE.prototype.__destroy__ = function () { + Ip(this.bB); + }; + function eE() { + this.bB = Jp(); + h(eE)[this.bB] = this; + } + eE.prototype = Object.create(f.prototype); + eE.prototype.constructor = eE; + eE.prototype.cB = eE; + eE.dB = {}; + b.btPersistentManifold = eE; + eE.prototype.getBody0 = function () { + return k(Kp(this.bB), q); + }; + eE.prototype.getBody1 = function () { + return k(Lp(this.bB), q); + }; + eE.prototype.getNumContacts = function () { + return Mp(this.bB); + }; + eE.prototype.getContactPoint = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Np(c, a), E); + }; + eE.prototype.__destroy__ = function () { + Op(this.bB); + }; + function $E(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = Pp(a); + h($E)[this.bB] = this; + } + $E.prototype = Object.create(JD.prototype); + $E.prototype.constructor = $E; + $E.prototype.cB = $E; + $E.dB = {}; + b.btCollisionDispatcher = $E; + $E.prototype.getNumManifolds = function () { + return Qp(this.bB); + }; + $E.prototype.getManifoldByIndexInternal = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Rp(c, a), eE); + }; + $E.prototype.__destroy__ = function () { + Sp(this.bB); + }; + function aF() { + throw 'cannot construct a btOverlappingPairCallback, no constructor in IDL'; + } + aF.prototype = Object.create(f.prototype); + aF.prototype.constructor = aF; + aF.prototype.cB = aF; + aF.dB = {}; + b.btOverlappingPairCallback = aF; + aF.prototype.__destroy__ = function () { + Tp(this.bB); + }; + function KD() { + throw 'cannot construct a btOverlappingPairCache, no constructor in IDL'; + } + KD.prototype = Object.create(f.prototype); + KD.prototype.constructor = KD; + KD.prototype.cB = KD; + KD.dB = {}; + b.btOverlappingPairCache = KD; + KD.prototype.setInternalGhostPairCallback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Up(c, a); + }; + KD.prototype.getNumOverlappingPairs = function () { + return Vp(this.bB); + }; + KD.prototype.__destroy__ = function () { + Wp(this.bB); + }; + function bF(a, c, d, e, g) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + this.bB = void 0 === d ? Xp(a, c) : void 0 === e ? Yp(a, c, d) : void 0 === g ? Zp(a, c, d, e) : $p(a, c, d, e, g); + h(bF)[this.bB] = this; + } + bF.prototype = Object.create(f.prototype); + bF.prototype.constructor = bF; + bF.prototype.cB = bF; + bF.dB = {}; + b.btAxisSweep3 = bF; + bF.prototype.__destroy__ = function () { + aq(this.bB); + }; + function LD() { + throw 'cannot construct a btBroadphaseInterface, no constructor in IDL'; + } + LD.prototype = Object.create(f.prototype); + LD.prototype.constructor = LD; + LD.prototype.cB = LD; + LD.dB = {}; + b.btBroadphaseInterface = LD; + LD.prototype.getOverlappingPairCache = function () { + return k(bq(this.bB), KD); + }; + LD.prototype.__destroy__ = function () { + cq(this.bB); + }; + function cF() { + throw 'cannot construct a btCollisionConfiguration, no constructor in IDL'; + } + cF.prototype = Object.create(f.prototype); + cF.prototype.constructor = cF; + cF.prototype.cB = cF; + cF.dB = {}; + b.btCollisionConfiguration = cF; + cF.prototype.__destroy__ = function () { + dq(this.bB); + }; + function dF() { + this.bB = eq(); + h(dF)[this.bB] = this; + } + dF.prototype = Object.create(f.prototype); + dF.prototype.constructor = dF; + dF.prototype.cB = dF; + dF.dB = {}; + b.btDbvtBroadphase = dF; + dF.prototype.__destroy__ = function () { + fq(this.bB); + }; + function OD() { + throw 'cannot construct a btBroadphaseProxy, no constructor in IDL'; + } + OD.prototype = Object.create(f.prototype); + OD.prototype.constructor = OD; + OD.prototype.cB = OD; + OD.dB = {}; + b.btBroadphaseProxy = OD; + OD.prototype.get_m_collisionFilterGroup = OD.prototype.eB = function () { + return gq(this.bB); + }; + OD.prototype.set_m_collisionFilterGroup = OD.prototype.gB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hq(c, a); + }; + Object.defineProperty(OD.prototype, 'm_collisionFilterGroup', { get: OD.prototype.eB, set: OD.prototype.gB }); + OD.prototype.get_m_collisionFilterMask = OD.prototype.fB = function () { + return iq(this.bB); + }; + OD.prototype.set_m_collisionFilterMask = OD.prototype.hB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + jq(c, a); + }; + Object.defineProperty(OD.prototype, 'm_collisionFilterMask', { get: OD.prototype.fB, set: OD.prototype.hB }); + OD.prototype.__destroy__ = function () { + kq(this.bB); + }; + function J(a, c, d, e) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + this.bB = void 0 === e ? lq(a, c, d) : mq(a, c, d, e); + h(J)[this.bB] = this; + } + J.prototype = Object.create(f.prototype); + J.prototype.constructor = J; + J.prototype.cB = J; + J.dB = {}; + b.btRigidBodyConstructionInfo = J; + J.prototype.get_m_linearDamping = J.prototype.vD = function () { + return nq(this.bB); + }; + J.prototype.set_m_linearDamping = J.prototype.mG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + oq(c, a); + }; + Object.defineProperty(J.prototype, 'm_linearDamping', { get: J.prototype.vD, set: J.prototype.mG }); + J.prototype.get_m_angularDamping = J.prototype.zC = function () { + return pq(this.bB); + }; + J.prototype.set_m_angularDamping = J.prototype.qF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + qq(c, a); + }; + Object.defineProperty(J.prototype, 'm_angularDamping', { get: J.prototype.zC, set: J.prototype.qF }); + J.prototype.get_m_friction = J.prototype.cD = function () { + return rq(this.bB); + }; + J.prototype.set_m_friction = J.prototype.UF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + sq(c, a); + }; + Object.defineProperty(J.prototype, 'm_friction', { get: J.prototype.cD, set: J.prototype.UF }); + J.prototype.get_m_rollingFriction = J.prototype.WD = function () { + return tq(this.bB); + }; + J.prototype.set_m_rollingFriction = J.prototype.NG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + uq(c, a); + }; + Object.defineProperty(J.prototype, 'm_rollingFriction', { get: J.prototype.WD, set: J.prototype.NG }); + J.prototype.get_m_restitution = J.prototype.UD = function () { + return vq(this.bB); + }; + J.prototype.set_m_restitution = J.prototype.LG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + wq(c, a); + }; + Object.defineProperty(J.prototype, 'm_restitution', { get: J.prototype.UD, set: J.prototype.LG }); + J.prototype.get_m_linearSleepingThreshold = J.prototype.wD = function () { + return xq(this.bB); + }; + J.prototype.set_m_linearSleepingThreshold = J.prototype.nG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + yq(c, a); + }; + Object.defineProperty(J.prototype, 'm_linearSleepingThreshold', { get: J.prototype.wD, set: J.prototype.nG }); + J.prototype.get_m_angularSleepingThreshold = J.prototype.AC = function () { + return zq(this.bB); + }; + J.prototype.set_m_angularSleepingThreshold = J.prototype.rF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Aq(c, a); + }; + Object.defineProperty(J.prototype, 'm_angularSleepingThreshold', { get: J.prototype.AC, set: J.prototype.rF }); + J.prototype.get_m_additionalDamping = J.prototype.uC = function () { + return !!Bq(this.bB); + }; + J.prototype.set_m_additionalDamping = J.prototype.lF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Cq(c, a); + }; + Object.defineProperty(J.prototype, 'm_additionalDamping', { get: J.prototype.uC, set: J.prototype.lF }); + J.prototype.get_m_additionalDampingFactor = J.prototype.vC = function () { + return Dq(this.bB); + }; + J.prototype.set_m_additionalDampingFactor = J.prototype.mF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Eq(c, a); + }; + Object.defineProperty(J.prototype, 'm_additionalDampingFactor', { get: J.prototype.vC, set: J.prototype.mF }); + J.prototype.get_m_additionalLinearDampingThresholdSqr = J.prototype.wC = function () { + return Fq(this.bB); + }; + J.prototype.set_m_additionalLinearDampingThresholdSqr = J.prototype.nF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Gq(c, a); + }; + Object.defineProperty(J.prototype, 'm_additionalLinearDampingThresholdSqr', { get: J.prototype.wC, set: J.prototype.nF }); + J.prototype.get_m_additionalAngularDampingThresholdSqr = J.prototype.tC = function () { + return Hq(this.bB); + }; + J.prototype.set_m_additionalAngularDampingThresholdSqr = J.prototype.kF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Iq(c, a); + }; + Object.defineProperty(J.prototype, 'm_additionalAngularDampingThresholdSqr', { get: J.prototype.tC, set: J.prototype.kF }); + J.prototype.get_m_additionalAngularDampingFactor = J.prototype.sC = function () { + return Jq(this.bB); + }; + J.prototype.set_m_additionalAngularDampingFactor = J.prototype.jF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Kq(c, a); + }; + Object.defineProperty(J.prototype, 'm_additionalAngularDampingFactor', { get: J.prototype.sC, set: J.prototype.jF }); + J.prototype.__destroy__ = function () { + Lq(this.bB); + }; + function K(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = Mq(a); + h(K)[this.bB] = this; + } + K.prototype = Object.create(q.prototype); + K.prototype.constructor = K; + K.prototype.cB = K; + K.dB = {}; + b.btRigidBody = K; + K.prototype.getCenterOfMassTransform = function () { + return k(Nq(this.bB), r); + }; + K.prototype.setCenterOfMassTransform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Oq(c, a); + }; + K.prototype.setSleepingThresholds = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Pq(d, a, c); + }; + K.prototype.getLinearDamping = function () { + return Qq(this.bB); + }; + K.prototype.getAngularDamping = function () { + return Rq(this.bB); + }; + K.prototype.setDamping = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Sq(d, a, c); + }; + K.prototype.setMassProps = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Tq(d, a, c); + }; + K.prototype.getLinearFactor = function () { + return k(Uq(this.bB), m); + }; + K.prototype.setLinearFactor = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Vq(c, a); + }; + K.prototype.applyTorque = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Wq(c, a); + }; + K.prototype.applyLocalTorque = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Xq(c, a); + }; + K.prototype.applyForce = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Yq(d, a, c); + }; + K.prototype.applyCentralForce = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Zq(c, a); + }; + K.prototype.applyCentralLocalForce = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + $q(c, a); + }; + K.prototype.applyTorqueImpulse = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ar(c, a); + }; + K.prototype.applyImpulse = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + br(d, a, c); + }; + K.prototype.applyCentralImpulse = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + cr(c, a); + }; + K.prototype.updateInertiaTensor = function () { + dr(this.bB); + }; + K.prototype.getLinearVelocity = function () { + return k(er(this.bB), m); + }; + K.prototype.getAngularVelocity = function () { + return k(fr(this.bB), m); + }; + K.prototype.setLinearVelocity = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + gr(c, a); + }; + K.prototype.setAngularVelocity = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hr(c, a); + }; + K.prototype.getMotionState = function () { + return k(ir(this.bB), UD); + }; + K.prototype.setMotionState = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + jr(c, a); + }; + K.prototype.getAngularFactor = function () { + return k(kr(this.bB), m); + }; + K.prototype.setAngularFactor = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + lr(c, a); + }; + K.prototype.upcast = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(mr(c, a), K); + }; + K.prototype.getAabb = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + nr(d, a, c); + }; + K.prototype.applyGravity = function () { + or(this.bB); + }; + K.prototype.getGravity = function () { + return k(pr(this.bB), m); + }; + K.prototype.setGravity = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + qr(c, a); + }; + K.prototype.getBroadphaseProxy = function () { + return k(rr(this.bB), OD); + }; + K.prototype.clearForces = function () { + sr(this.bB); + }; + K.prototype.setAnisotropicFriction = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + tr(d, a, c); + }; + K.prototype.getCollisionShape = function () { + return k(ur(this.bB), l); + }; + K.prototype.setContactProcessingThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + vr(c, a); + }; + K.prototype.setActivationState = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + wr(c, a); + }; + K.prototype.forceActivationState = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + xr(c, a); + }; + K.prototype.activate = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + void 0 === a ? yr(c) : zr(c, a); + }; + K.prototype.isActive = function () { + return !!Ar(this.bB); + }; + K.prototype.isKinematicObject = function () { + return !!Br(this.bB); + }; + K.prototype.isStaticObject = function () { + return !!Cr(this.bB); + }; + K.prototype.isStaticOrKinematicObject = function () { + return !!Dr(this.bB); + }; + K.prototype.getRestitution = function () { + return Er(this.bB); + }; + K.prototype.getFriction = function () { + return Fr(this.bB); + }; + K.prototype.getRollingFriction = function () { + return Gr(this.bB); + }; + K.prototype.setRestitution = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Hr(c, a); + }; + K.prototype.setFriction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ir(c, a); + }; + K.prototype.setRollingFriction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Jr(c, a); + }; + K.prototype.getWorldTransform = function () { + return k(Kr(this.bB), r); + }; + K.prototype.getCollisionFlags = function () { + return Lr(this.bB); + }; + K.prototype.setCollisionFlags = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Mr(c, a); + }; + K.prototype.setWorldTransform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Nr(c, a); + }; + K.prototype.setCollisionShape = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Or(c, a); + }; + K.prototype.setCcdMotionThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Pr(c, a); + }; + K.prototype.setCcdSweptSphereRadius = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Qr(c, a); + }; + K.prototype.getUserIndex = function () { + return Rr(this.bB); + }; + K.prototype.setUserIndex = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Sr(c, a); + }; + K.prototype.getUserPointer = function () { + return k(Tr(this.bB), ND); + }; + K.prototype.setUserPointer = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ur(c, a); + }; + K.prototype.getBroadphaseHandle = function () { + return k(Vr(this.bB), OD); + }; + K.prototype.__destroy__ = function () { + Wr(this.bB); + }; + function L() { + this.bB = Xr(); + h(L)[this.bB] = this; + } + L.prototype = Object.create(f.prototype); + L.prototype.constructor = L; + L.prototype.cB = L; + L.dB = {}; + b.btConstraintSetting = L; + L.prototype.get_m_tau = L.prototype.kE = function () { + return Yr(this.bB); + }; + L.prototype.set_m_tau = L.prototype.cH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Zr(c, a); + }; + Object.defineProperty(L.prototype, 'm_tau', { get: L.prototype.kE, set: L.prototype.cH }); + L.prototype.get_m_damping = L.prototype.TC = function () { + return $r(this.bB); + }; + L.prototype.set_m_damping = L.prototype.KF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + as(c, a); + }; + Object.defineProperty(L.prototype, 'm_damping', { get: L.prototype.TC, set: L.prototype.KF }); + L.prototype.get_m_impulseClamp = L.prototype.oD = function () { + return bs(this.bB); + }; + L.prototype.set_m_impulseClamp = L.prototype.fG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + cs(c, a); + }; + Object.defineProperty(L.prototype, 'm_impulseClamp', { get: L.prototype.oD, set: L.prototype.fG }); + L.prototype.__destroy__ = function () { + ds(this.bB); + }; + function eF(a, c, d, e) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + this.bB = void 0 === d ? es(a, c) : void 0 === e ? _emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_3(a, c, d) : gs(a, c, d, e); + h(eF)[this.bB] = this; + } + eF.prototype = Object.create(RD.prototype); + eF.prototype.constructor = eF; + eF.prototype.cB = eF; + eF.dB = {}; + b.btPoint2PointConstraint = eF; + eF.prototype.setPivotA = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hs(c, a); + }; + eF.prototype.setPivotB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + is(c, a); + }; + eF.prototype.getPivotInA = function () { + return k(js(this.bB), m); + }; + eF.prototype.getPivotInB = function () { + return k(ks(this.bB), m); + }; + eF.prototype.enableFeedback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ls(c, a); + }; + eF.prototype.getBreakingImpulseThreshold = function () { + return ms(this.bB); + }; + eF.prototype.setBreakingImpulseThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ns(c, a); + }; + eF.prototype.getParam = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return ps(d, a, c); + }; + eF.prototype.setParam = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + qs(e, a, c, d); + }; + eF.prototype.get_m_setting = eF.prototype.YD = function () { + return k(rs(this.bB), L); + }; + eF.prototype.set_m_setting = eF.prototype.PG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ss(c, a); + }; + Object.defineProperty(eF.prototype, 'm_setting', { get: eF.prototype.YD, set: eF.prototype.PG }); + eF.prototype.__destroy__ = function () { + ts(this.bB); + }; + function fF(a, c, d, e, g) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + this.bB = void 0 === e ? us(a, c, d) : void 0 === g ? _emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_4(a, c, d, e) : vs(a, c, d, e, g); + h(fF)[this.bB] = this; + } + fF.prototype = Object.create(fE.prototype); + fF.prototype.constructor = fF; + fF.prototype.cB = fF; + fF.dB = {}; + b.btGeneric6DofSpringConstraint = fF; + fF.prototype.enableSpring = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + xs(d, a, c); + }; + fF.prototype.setStiffness = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + ys(d, a, c); + }; + fF.prototype.setDamping = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + zs(d, a, c); + }; + fF.prototype.setEquilibriumPoint = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + void 0 === a ? As(d) : void 0 === c ? Bs(d, a) : Cs(d, a, c); + }; + fF.prototype.setLinearLowerLimit = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ds(c, a); + }; + fF.prototype.setLinearUpperLimit = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Es(c, a); + }; + fF.prototype.setAngularLowerLimit = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Fs(c, a); + }; + fF.prototype.setAngularUpperLimit = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Gs(c, a); + }; + fF.prototype.getFrameOffsetA = function () { + return k(Hs(this.bB), r); + }; + fF.prototype.enableFeedback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Is(c, a); + }; + fF.prototype.getBreakingImpulseThreshold = function () { + return Js(this.bB); + }; + fF.prototype.setBreakingImpulseThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ks(c, a); + }; + fF.prototype.getParam = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return Ls(d, a, c); + }; + fF.prototype.setParam = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + Ms(e, a, c, d); + }; + fF.prototype.__destroy__ = function () { + Ns(this.bB); + }; + function gF() { + this.bB = Os(); + h(gF)[this.bB] = this; + } + gF.prototype = Object.create(f.prototype); + gF.prototype.constructor = gF; + gF.prototype.cB = gF; + gF.dB = {}; + b.btSequentialImpulseConstraintSolver = gF; + gF.prototype.__destroy__ = function () { + Ps(this.bB); + }; + function hF(a, c, d, e) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + this.bB = void 0 === d ? Qs(a, c) : void 0 === e ? _emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_3(a, c, d) : Rs(a, c, d, e); + h(hF)[this.bB] = this; + } + hF.prototype = Object.create(RD.prototype); + hF.prototype.constructor = hF; + hF.prototype.cB = hF; + hF.dB = {}; + b.btConeTwistConstraint = hF; + hF.prototype.setLimit = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Ss(d, a, c); + }; + hF.prototype.setAngularOnly = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ts(c, a); + }; + hF.prototype.setDamping = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Us(c, a); + }; + hF.prototype.enableMotor = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Vs(c, a); + }; + hF.prototype.setMaxMotorImpulse = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ws(c, a); + }; + hF.prototype.setMaxMotorImpulseNormalized = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Xs(c, a); + }; + hF.prototype.setMotorTarget = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ys(c, a); + }; + hF.prototype.setMotorTargetInConstraintSpace = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Zs(c, a); + }; + hF.prototype.enableFeedback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + $s(c, a); + }; + hF.prototype.getBreakingImpulseThreshold = function () { + return at(this.bB); + }; + hF.prototype.setBreakingImpulseThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + bt(c, a); + }; + hF.prototype.getParam = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return ct(d, a, c); + }; + hF.prototype.setParam = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + dt(e, a, c, d); + }; + hF.prototype.__destroy__ = function () { + et(this.bB); + }; + function iF(a, c, d, e, g, n, D) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + n && 'object' === typeof n && (n = n.bB); + D && 'object' === typeof D && (D = D.bB); + this.bB = void 0 === d ? ft(a, c) : void 0 === e ? gt(a, c, d) : void 0 === g ? ht(a, c, d, e) : void 0 === n ? it(a, c, d, e, g) : void 0 === D ? jt(a, c, d, e, g, n) : kt(a, c, d, e, g, n, D); + h(iF)[this.bB] = this; + } + iF.prototype = Object.create(RD.prototype); + iF.prototype.constructor = iF; + iF.prototype.cB = iF; + iF.dB = {}; + b.btHingeConstraint = iF; + iF.prototype.setLimit = function (a, c, d, e, g) { + var n = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + void 0 === g ? lt(n, a, c, d, e) : mt(n, a, c, d, e, g); + }; + iF.prototype.enableAngularMotor = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + nt(e, a, c, d); + }; + iF.prototype.setAngularOnly = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ot(c, a); + }; + iF.prototype.enableMotor = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + pt(c, a); + }; + iF.prototype.setMaxMotorImpulse = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + qt(c, a); + }; + iF.prototype.setMotorTarget = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + rt(d, a, c); + }; + iF.prototype.enableFeedback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + st(c, a); + }; + iF.prototype.getBreakingImpulseThreshold = function () { + return tt(this.bB); + }; + iF.prototype.setBreakingImpulseThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ut(c, a); + }; + iF.prototype.getParam = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return vt(d, a, c); + }; + iF.prototype.setParam = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + wt(e, a, c, d); + }; + iF.prototype.__destroy__ = function () { + xt(this.bB); + }; + function jF(a, c, d, e, g) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + this.bB = void 0 === e ? yt(a, c, d) : void 0 === g ? _emscripten_bind_btSliderConstraint_btSliderConstraint_4(a, c, d, e) : zt(a, c, d, e, g); + h(jF)[this.bB] = this; + } + jF.prototype = Object.create(RD.prototype); + jF.prototype.constructor = jF; + jF.prototype.cB = jF; + jF.dB = {}; + b.btSliderConstraint = jF; + jF.prototype.setLowerLinLimit = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + At(c, a); + }; + jF.prototype.setUpperLinLimit = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Bt(c, a); + }; + jF.prototype.setLowerAngLimit = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ct(c, a); + }; + jF.prototype.setUpperAngLimit = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Dt(c, a); + }; + jF.prototype.setPoweredLinMotor = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Et(c, a); + }; + jF.prototype.setMaxLinMotorForce = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ft(c, a); + }; + jF.prototype.setTargetLinMotorVelocity = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Gt(c, a); + }; + jF.prototype.enableFeedback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ht(c, a); + }; + jF.prototype.getBreakingImpulseThreshold = function () { + return It(this.bB); + }; + jF.prototype.setBreakingImpulseThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Jt(c, a); + }; + jF.prototype.getParam = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return Kt(d, a, c); + }; + jF.prototype.setParam = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + Lt(e, a, c, d); + }; + jF.prototype.__destroy__ = function () { + Mt(this.bB); + }; + function kF(a, c, d, e) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + this.bB = Nt(a, c, d, e); + h(kF)[this.bB] = this; + } + kF.prototype = Object.create(RD.prototype); + kF.prototype.constructor = kF; + kF.prototype.cB = kF; + kF.dB = {}; + b.btFixedConstraint = kF; + kF.prototype.enableFeedback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ot(c, a); + }; + kF.prototype.getBreakingImpulseThreshold = function () { + return Pt(this.bB); + }; + kF.prototype.setBreakingImpulseThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Qt(c, a); + }; + kF.prototype.getParam = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return Rt(d, a, c); + }; + kF.prototype.setParam = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + St(e, a, c, d); + }; + kF.prototype.__destroy__ = function () { + Tt(this.bB); + }; + function lF() { + throw 'cannot construct a btConstraintSolver, no constructor in IDL'; + } + lF.prototype = Object.create(f.prototype); + lF.prototype.constructor = lF; + lF.prototype.cB = lF; + lF.dB = {}; + b.btConstraintSolver = lF; + lF.prototype.__destroy__ = function () { + Ut(this.bB); + }; + function p() { + throw 'cannot construct a btDispatcherInfo, no constructor in IDL'; + } + p.prototype = Object.create(f.prototype); + p.prototype.constructor = p; + p.prototype.cB = p; + p.dB = {}; + b.btDispatcherInfo = p; + p.prototype.get_m_timeStep = p.prototype.mE = function () { + return Vt(this.bB); + }; + p.prototype.set_m_timeStep = p.prototype.eH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Wt(c, a); + }; + Object.defineProperty(p.prototype, 'm_timeStep', { get: p.prototype.mE, set: p.prototype.eH }); + p.prototype.get_m_stepCount = p.prototype.dE = function () { + return Xt(this.bB); + }; + p.prototype.set_m_stepCount = p.prototype.WG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Yt(c, a); + }; + Object.defineProperty(p.prototype, 'm_stepCount', { get: p.prototype.dE, set: p.prototype.WG }); + p.prototype.get_m_dispatchFunc = p.prototype.VC = function () { + return Zt(this.bB); + }; + p.prototype.set_m_dispatchFunc = p.prototype.MF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + $t(c, a); + }; + Object.defineProperty(p.prototype, 'm_dispatchFunc', { get: p.prototype.VC, set: p.prototype.MF }); + p.prototype.get_m_timeOfImpact = p.prototype.lE = function () { + return au(this.bB); + }; + p.prototype.set_m_timeOfImpact = p.prototype.dH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + bu(c, a); + }; + Object.defineProperty(p.prototype, 'm_timeOfImpact', { get: p.prototype.lE, set: p.prototype.dH }); + p.prototype.get_m_useContinuous = p.prototype.oE = function () { + return !!cu(this.bB); + }; + p.prototype.set_m_useContinuous = p.prototype.gH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + du(c, a); + }; + Object.defineProperty(p.prototype, 'm_useContinuous', { get: p.prototype.oE, set: p.prototype.gH }); + p.prototype.get_m_enableSatConvex = p.prototype.$C = function () { + return !!eu(this.bB); + }; + p.prototype.set_m_enableSatConvex = p.prototype.RF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + fu(c, a); + }; + Object.defineProperty(p.prototype, 'm_enableSatConvex', { get: p.prototype.$C, set: p.prototype.RF }); + p.prototype.get_m_enableSPU = p.prototype.ZC = function () { + return !!gu(this.bB); + }; + p.prototype.set_m_enableSPU = p.prototype.QF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hu(c, a); + }; + Object.defineProperty(p.prototype, 'm_enableSPU', { get: p.prototype.ZC, set: p.prototype.QF }); + p.prototype.get_m_useEpa = p.prototype.qE = function () { + return !!iu(this.bB); + }; + p.prototype.set_m_useEpa = p.prototype.iH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ju(c, a); + }; + Object.defineProperty(p.prototype, 'm_useEpa', { get: p.prototype.qE, set: p.prototype.iH }); + p.prototype.get_m_allowedCcdPenetration = p.prototype.xC = function () { + return ku(this.bB); + }; + p.prototype.set_m_allowedCcdPenetration = p.prototype.oF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + lu(c, a); + }; + Object.defineProperty(p.prototype, 'm_allowedCcdPenetration', { get: p.prototype.xC, set: p.prototype.oF }); + p.prototype.get_m_useConvexConservativeDistanceUtil = p.prototype.pE = function () { + return !!mu(this.bB); + }; + p.prototype.set_m_useConvexConservativeDistanceUtil = p.prototype.hH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + nu(c, a); + }; + Object.defineProperty(p.prototype, 'm_useConvexConservativeDistanceUtil', { get: p.prototype.pE, set: p.prototype.hH }); + p.prototype.get_m_convexConservativeDistanceThreshold = p.prototype.QC = function () { + return ou(this.bB); + }; + p.prototype.set_m_convexConservativeDistanceThreshold = p.prototype.HF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + pu(c, a); + }; + Object.defineProperty(p.prototype, 'm_convexConservativeDistanceThreshold', { get: p.prototype.QC, set: p.prototype.HF }); + p.prototype.__destroy__ = function () { + qu(this.bB); + }; + function t() { + throw 'cannot construct a btContactSolverInfo, no constructor in IDL'; + } + t.prototype = Object.create(f.prototype); + t.prototype.constructor = t; + t.prototype.cB = t; + t.dB = {}; + b.btContactSolverInfo = t; + t.prototype.get_m_splitImpulse = t.prototype.aE = function () { + return !!ru(this.bB); + }; + t.prototype.set_m_splitImpulse = t.prototype.TG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + su(c, a); + }; + Object.defineProperty(t.prototype, 'm_splitImpulse', { get: t.prototype.aE, set: t.prototype.TG }); + t.prototype.get_m_splitImpulsePenetrationThreshold = t.prototype.bE = function () { + return tu(this.bB); + }; + t.prototype.set_m_splitImpulsePenetrationThreshold = t.prototype.UG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + uu(c, a); + }; + Object.defineProperty(t.prototype, 'm_splitImpulsePenetrationThreshold', { get: t.prototype.bE, set: t.prototype.UG }); + t.prototype.get_m_numIterations = t.prototype.LD = function () { + return vu(this.bB); + }; + t.prototype.set_m_numIterations = t.prototype.CG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + wu(c, a); + }; + Object.defineProperty(t.prototype, 'm_numIterations', { get: t.prototype.LD, set: t.prototype.CG }); + t.prototype.__destroy__ = function () { + xu(this.bB); + }; + function M() { + this.bB = yu(); + h(M)[this.bB] = this; + } + M.prototype = Object.create(f.prototype); + M.prototype.constructor = M; + M.prototype.cB = M; + M.dB = {}; + b.btVehicleTuning = M; + M.prototype.get_m_suspensionStiffness = M.prototype.sB = function () { + return zu(this.bB); + }; + M.prototype.set_m_suspensionStiffness = M.prototype.zB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Au(c, a); + }; + Object.defineProperty(M.prototype, 'm_suspensionStiffness', { get: M.prototype.sB, set: M.prototype.zB }); + M.prototype.get_m_suspensionCompression = M.prototype.eE = function () { + return Bu(this.bB); + }; + M.prototype.set_m_suspensionCompression = M.prototype.XG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Cu(c, a); + }; + Object.defineProperty(M.prototype, 'm_suspensionCompression', { get: M.prototype.eE, set: M.prototype.XG }); + M.prototype.get_m_suspensionDamping = M.prototype.fE = function () { + return Du(this.bB); + }; + M.prototype.set_m_suspensionDamping = M.prototype.YG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Eu(c, a); + }; + Object.defineProperty(M.prototype, 'm_suspensionDamping', { get: M.prototype.fE, set: M.prototype.YG }); + M.prototype.get_m_maxSuspensionTravelCm = M.prototype.rB = function () { + return Fu(this.bB); + }; + M.prototype.set_m_maxSuspensionTravelCm = M.prototype.yB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Gu(c, a); + }; + Object.defineProperty(M.prototype, 'm_maxSuspensionTravelCm', { get: M.prototype.rB, set: M.prototype.yB }); + M.prototype.get_m_frictionSlip = M.prototype.nB = function () { + return Hu(this.bB); + }; + M.prototype.set_m_frictionSlip = M.prototype.uB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Iu(c, a); + }; + Object.defineProperty(M.prototype, 'm_frictionSlip', { get: M.prototype.nB, set: M.prototype.uB }); + M.prototype.get_m_maxSuspensionForce = M.prototype.qB = function () { + return Ju(this.bB); + }; + M.prototype.set_m_maxSuspensionForce = M.prototype.xB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ku(c, a); + }; + Object.defineProperty(M.prototype, 'm_maxSuspensionForce', { get: M.prototype.qB, set: M.prototype.xB }); + function mF() { + throw 'cannot construct a btVehicleRaycasterResult, no constructor in IDL'; + } + mF.prototype = Object.create(f.prototype); + mF.prototype.constructor = mF; + mF.prototype.cB = mF; + mF.dB = {}; + b.btVehicleRaycasterResult = mF; + mF.prototype.get_m_hitPointInWorld = mF.prototype.lD = function () { + return k(Lu(this.bB), m); + }; + mF.prototype.set_m_hitPointInWorld = mF.prototype.cG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Mu(c, a); + }; + Object.defineProperty(mF.prototype, 'm_hitPointInWorld', { get: mF.prototype.lD, set: mF.prototype.cG }); + mF.prototype.get_m_hitNormalInWorld = mF.prototype.jD = function () { + return k(Nu(this.bB), m); + }; + mF.prototype.set_m_hitNormalInWorld = mF.prototype.aG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ou(c, a); + }; + Object.defineProperty(mF.prototype, 'm_hitNormalInWorld', { get: mF.prototype.jD, set: mF.prototype.aG }); + mF.prototype.get_m_distFraction = mF.prototype.YC = function () { + return Pu(this.bB); + }; + mF.prototype.set_m_distFraction = mF.prototype.PF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Qu(c, a); + }; + Object.defineProperty(mF.prototype, 'm_distFraction', { get: mF.prototype.YC, set: mF.prototype.PF }); + mF.prototype.__destroy__ = function () { + Ru(this.bB); + }; + function nF(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = Su(a); + h(nF)[this.bB] = this; + } + nF.prototype = Object.create(gE.prototype); + nF.prototype.constructor = nF; + nF.prototype.cB = nF; + nF.dB = {}; + b.btDefaultVehicleRaycaster = nF; + nF.prototype.castRay = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + Tu(e, a, c, d); + }; + nF.prototype.__destroy__ = function () { + Uu(this.bB); + }; + function N() { + throw 'cannot construct a RaycastInfo, no constructor in IDL'; + } + N.prototype = Object.create(f.prototype); + N.prototype.constructor = N; + N.prototype.cB = N; + N.dB = {}; + b.RaycastInfo = N; + N.prototype.get_m_contactNormalWS = N.prototype.OC = function () { + return k(Vu(this.bB), m); + }; + N.prototype.set_m_contactNormalWS = N.prototype.FF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Wu(c, a); + }; + Object.defineProperty(N.prototype, 'm_contactNormalWS', { get: N.prototype.OC, set: N.prototype.FF }); + N.prototype.get_m_contactPointWS = N.prototype.PC = function () { + return k(Xu(this.bB), m); + }; + N.prototype.set_m_contactPointWS = N.prototype.GF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Yu(c, a); + }; + Object.defineProperty(N.prototype, 'm_contactPointWS', { get: N.prototype.PC, set: N.prototype.GF }); + N.prototype.get_m_suspensionLength = N.prototype.gE = function () { + return Zu(this.bB); + }; + N.prototype.set_m_suspensionLength = N.prototype.ZG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + $u(c, a); + }; + Object.defineProperty(N.prototype, 'm_suspensionLength', { get: N.prototype.gE, set: N.prototype.ZG }); + N.prototype.get_m_hardPointWS = N.prototype.gD = function () { + return k(av(this.bB), m); + }; + N.prototype.set_m_hardPointWS = N.prototype.YF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + bv(c, a); + }; + Object.defineProperty(N.prototype, 'm_hardPointWS', { get: N.prototype.gD, set: N.prototype.YF }); + N.prototype.get_m_wheelDirectionWS = N.prototype.vE = function () { + return k(cv(this.bB), m); + }; + N.prototype.set_m_wheelDirectionWS = N.prototype.nH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + dv(c, a); + }; + Object.defineProperty(N.prototype, 'm_wheelDirectionWS', { get: N.prototype.vE, set: N.prototype.nH }); + N.prototype.get_m_wheelAxleWS = N.prototype.uE = function () { + return k(ev(this.bB), m); + }; + N.prototype.set_m_wheelAxleWS = N.prototype.mH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + fv(c, a); + }; + Object.defineProperty(N.prototype, 'm_wheelAxleWS', { get: N.prototype.uE, set: N.prototype.mH }); + N.prototype.get_m_isInContact = N.prototype.rD = function () { + return !!gv(this.bB); + }; + N.prototype.set_m_isInContact = N.prototype.iG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hv(c, a); + }; + Object.defineProperty(N.prototype, 'm_isInContact', { get: N.prototype.rD, set: N.prototype.iG }); + N.prototype.get_m_groundObject = N.prototype.fD = function () { + return iv(this.bB); + }; + N.prototype.set_m_groundObject = N.prototype.XF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + jv(c, a); + }; + Object.defineProperty(N.prototype, 'm_groundObject', { get: N.prototype.fD, set: N.prototype.XF }); + N.prototype.__destroy__ = function () { + kv(this.bB); + }; + function O() { + throw 'cannot construct a btWheelInfoConstructionInfo, no constructor in IDL'; + } + O.prototype = Object.create(f.prototype); + O.prototype.constructor = O; + O.prototype.cB = O; + O.dB = {}; + b.btWheelInfoConstructionInfo = O; + O.prototype.get_m_chassisConnectionCS = O.prototype.JC = function () { + return k(lv(this.bB), m); + }; + O.prototype.set_m_chassisConnectionCS = O.prototype.AF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + mv(c, a); + }; + Object.defineProperty(O.prototype, 'm_chassisConnectionCS', { get: O.prototype.JC, set: O.prototype.AF }); + O.prototype.get_m_wheelDirectionCS = O.prototype.IB = function () { + return k(nv(this.bB), m); + }; + O.prototype.set_m_wheelDirectionCS = O.prototype.SB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ov(c, a); + }; + Object.defineProperty(O.prototype, 'm_wheelDirectionCS', { get: O.prototype.IB, set: O.prototype.SB }); + O.prototype.get_m_wheelAxleCS = O.prototype.HB = function () { + return k(pv(this.bB), m); + }; + O.prototype.set_m_wheelAxleCS = O.prototype.RB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + qv(c, a); + }; + Object.defineProperty(O.prototype, 'm_wheelAxleCS', { get: O.prototype.HB, set: O.prototype.RB }); + O.prototype.get_m_suspensionRestLength = O.prototype.iE = function () { + return rv(this.bB); + }; + O.prototype.set_m_suspensionRestLength = O.prototype.aH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + sv(c, a); + }; + Object.defineProperty(O.prototype, 'm_suspensionRestLength', { get: O.prototype.iE, set: O.prototype.aH }); + O.prototype.get_m_maxSuspensionTravelCm = O.prototype.rB = function () { + return tv(this.bB); + }; + O.prototype.set_m_maxSuspensionTravelCm = O.prototype.yB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + uv(c, a); + }; + Object.defineProperty(O.prototype, 'm_maxSuspensionTravelCm', { get: O.prototype.rB, set: O.prototype.yB }); + O.prototype.get_m_wheelRadius = O.prototype.wE = function () { + return vv(this.bB); + }; + O.prototype.set_m_wheelRadius = O.prototype.oH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + wv(c, a); + }; + Object.defineProperty(O.prototype, 'm_wheelRadius', { get: O.prototype.wE, set: O.prototype.oH }); + O.prototype.get_m_suspensionStiffness = O.prototype.sB = function () { + return xv(this.bB); + }; + O.prototype.set_m_suspensionStiffness = O.prototype.zB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + yv(c, a); + }; + Object.defineProperty(O.prototype, 'm_suspensionStiffness', { get: O.prototype.sB, set: O.prototype.zB }); + O.prototype.get_m_wheelsDampingCompression = O.prototype.JB = function () { + return zv(this.bB); + }; + O.prototype.set_m_wheelsDampingCompression = O.prototype.TB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Av(c, a); + }; + Object.defineProperty(O.prototype, 'm_wheelsDampingCompression', { get: O.prototype.JB, set: O.prototype.TB }); + O.prototype.get_m_wheelsDampingRelaxation = O.prototype.KB = function () { + return Bv(this.bB); + }; + O.prototype.set_m_wheelsDampingRelaxation = O.prototype.UB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Cv(c, a); + }; + Object.defineProperty(O.prototype, 'm_wheelsDampingRelaxation', { get: O.prototype.KB, set: O.prototype.UB }); + O.prototype.get_m_frictionSlip = O.prototype.nB = function () { + return Dv(this.bB); + }; + O.prototype.set_m_frictionSlip = O.prototype.uB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ev(c, a); + }; + Object.defineProperty(O.prototype, 'm_frictionSlip', { get: O.prototype.nB, set: O.prototype.uB }); + O.prototype.get_m_maxSuspensionForce = O.prototype.qB = function () { + return Fv(this.bB); + }; + O.prototype.set_m_maxSuspensionForce = O.prototype.xB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Gv(c, a); + }; + Object.defineProperty(O.prototype, 'm_maxSuspensionForce', { get: O.prototype.qB, set: O.prototype.xB }); + O.prototype.get_m_bIsFrontWheel = O.prototype.BB = function () { + return !!Hv(this.bB); + }; + O.prototype.set_m_bIsFrontWheel = O.prototype.LB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Iv(c, a); + }; + Object.defineProperty(O.prototype, 'm_bIsFrontWheel', { get: O.prototype.BB, set: O.prototype.LB }); + O.prototype.__destroy__ = function () { + Jv(this.bB); + }; + function P(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = Kv(a); + h(P)[this.bB] = this; + } + P.prototype = Object.create(f.prototype); + P.prototype.constructor = P; + P.prototype.cB = P; + P.dB = {}; + b.btWheelInfo = P; + P.prototype.getSuspensionRestLength = function () { + return Lv(this.bB); + }; + P.prototype.updateWheel = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Mv(d, a, c); + }; + P.prototype.get_m_suspensionStiffness = P.prototype.sB = function () { + return Nv(this.bB); + }; + P.prototype.set_m_suspensionStiffness = P.prototype.zB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ov(c, a); + }; + Object.defineProperty(P.prototype, 'm_suspensionStiffness', { get: P.prototype.sB, set: P.prototype.zB }); + P.prototype.get_m_frictionSlip = P.prototype.nB = function () { + return Pv(this.bB); + }; + P.prototype.set_m_frictionSlip = P.prototype.uB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Qv(c, a); + }; + Object.defineProperty(P.prototype, 'm_frictionSlip', { get: P.prototype.nB, set: P.prototype.uB }); + P.prototype.get_m_engineForce = P.prototype.aD = function () { + return Rv(this.bB); + }; + P.prototype.set_m_engineForce = P.prototype.SF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Sv(c, a); + }; + Object.defineProperty(P.prototype, 'm_engineForce', { get: P.prototype.aD, set: P.prototype.SF }); + P.prototype.get_m_rollInfluence = P.prototype.VD = function () { + return Tv(this.bB); + }; + P.prototype.set_m_rollInfluence = P.prototype.MG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Uv(c, a); + }; + Object.defineProperty(P.prototype, 'm_rollInfluence', { get: P.prototype.VD, set: P.prototype.MG }); + P.prototype.get_m_suspensionRestLength1 = P.prototype.jE = function () { + return Vv(this.bB); + }; + P.prototype.set_m_suspensionRestLength1 = P.prototype.bH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Wv(c, a); + }; + Object.defineProperty(P.prototype, 'm_suspensionRestLength1', { get: P.prototype.jE, set: P.prototype.bH }); + P.prototype.get_m_wheelsRadius = P.prototype.xE = function () { + return Xv(this.bB); + }; + P.prototype.set_m_wheelsRadius = P.prototype.pH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Yv(c, a); + }; + Object.defineProperty(P.prototype, 'm_wheelsRadius', { get: P.prototype.xE, set: P.prototype.pH }); + P.prototype.get_m_wheelsDampingCompression = P.prototype.JB = function () { + return Zv(this.bB); + }; + P.prototype.set_m_wheelsDampingCompression = P.prototype.TB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + $v(c, a); + }; + Object.defineProperty(P.prototype, 'm_wheelsDampingCompression', { get: P.prototype.JB, set: P.prototype.TB }); + P.prototype.get_m_wheelsDampingRelaxation = P.prototype.KB = function () { + return aw(this.bB); + }; + P.prototype.set_m_wheelsDampingRelaxation = P.prototype.UB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + bw(c, a); + }; + Object.defineProperty(P.prototype, 'm_wheelsDampingRelaxation', { get: P.prototype.KB, set: P.prototype.UB }); + P.prototype.get_m_steering = P.prototype.cE = function () { + return cw(this.bB); + }; + P.prototype.set_m_steering = P.prototype.VG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + dw(c, a); + }; + Object.defineProperty(P.prototype, 'm_steering', { get: P.prototype.cE, set: P.prototype.VG }); + P.prototype.get_m_maxSuspensionForce = P.prototype.qB = function () { + return ew(this.bB); + }; + P.prototype.set_m_maxSuspensionForce = P.prototype.xB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + fw(c, a); + }; + Object.defineProperty(P.prototype, 'm_maxSuspensionForce', { get: P.prototype.qB, set: P.prototype.xB }); + P.prototype.get_m_maxSuspensionTravelCm = P.prototype.rB = function () { + return gw(this.bB); + }; + P.prototype.set_m_maxSuspensionTravelCm = P.prototype.yB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hw(c, a); + }; + Object.defineProperty(P.prototype, 'm_maxSuspensionTravelCm', { get: P.prototype.rB, set: P.prototype.yB }); + P.prototype.get_m_wheelsSuspensionForce = P.prototype.yE = function () { + return iw(this.bB); + }; + P.prototype.set_m_wheelsSuspensionForce = P.prototype.qH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + jw(c, a); + }; + Object.defineProperty(P.prototype, 'm_wheelsSuspensionForce', { get: P.prototype.yE, set: P.prototype.qH }); + P.prototype.get_m_bIsFrontWheel = P.prototype.BB = function () { + return !!kw(this.bB); + }; + P.prototype.set_m_bIsFrontWheel = P.prototype.LB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + lw(c, a); + }; + Object.defineProperty(P.prototype, 'm_bIsFrontWheel', { get: P.prototype.BB, set: P.prototype.LB }); + P.prototype.get_m_raycastInfo = P.prototype.TD = function () { + return k(mw(this.bB), N); + }; + P.prototype.set_m_raycastInfo = P.prototype.KG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + nw(c, a); + }; + Object.defineProperty(P.prototype, 'm_raycastInfo', { get: P.prototype.TD, set: P.prototype.KG }); + P.prototype.get_m_chassisConnectionPointCS = P.prototype.KC = function () { + return k(ow(this.bB), m); + }; + P.prototype.set_m_chassisConnectionPointCS = P.prototype.BF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + pw(c, a); + }; + Object.defineProperty(P.prototype, 'm_chassisConnectionPointCS', { get: P.prototype.KC, set: P.prototype.BF }); + P.prototype.get_m_worldTransform = P.prototype.zE = function () { + return k(qw(this.bB), r); + }; + P.prototype.set_m_worldTransform = P.prototype.rH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + rw(c, a); + }; + Object.defineProperty(P.prototype, 'm_worldTransform', { get: P.prototype.zE, set: P.prototype.rH }); + P.prototype.get_m_wheelDirectionCS = P.prototype.IB = function () { + return k(sw(this.bB), m); + }; + P.prototype.set_m_wheelDirectionCS = P.prototype.SB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + tw(c, a); + }; + Object.defineProperty(P.prototype, 'm_wheelDirectionCS', { get: P.prototype.IB, set: P.prototype.SB }); + P.prototype.get_m_wheelAxleCS = P.prototype.HB = function () { + return k(uw(this.bB), m); + }; + P.prototype.set_m_wheelAxleCS = P.prototype.RB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + vw(c, a); + }; + Object.defineProperty(P.prototype, 'm_wheelAxleCS', { get: P.prototype.HB, set: P.prototype.RB }); + P.prototype.get_m_rotation = P.prototype.XD = function () { + return ww(this.bB); + }; + P.prototype.set_m_rotation = P.prototype.OG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + xw(c, a); + }; + Object.defineProperty(P.prototype, 'm_rotation', { get: P.prototype.XD, set: P.prototype.OG }); + P.prototype.get_m_deltaRotation = P.prototype.UC = function () { + return yw(this.bB); + }; + P.prototype.set_m_deltaRotation = P.prototype.LF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + zw(c, a); + }; + Object.defineProperty(P.prototype, 'm_deltaRotation', { get: P.prototype.UC, set: P.prototype.LF }); + P.prototype.get_m_brake = P.prototype.DC = function () { + return Aw(this.bB); + }; + P.prototype.set_m_brake = P.prototype.uF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Bw(c, a); + }; + Object.defineProperty(P.prototype, 'm_brake', { get: P.prototype.DC, set: P.prototype.uF }); + P.prototype.get_m_clippedInvContactDotSuspension = P.prototype.LC = function () { + return Cw(this.bB); + }; + P.prototype.set_m_clippedInvContactDotSuspension = P.prototype.CF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Dw(c, a); + }; + Object.defineProperty(P.prototype, 'm_clippedInvContactDotSuspension', { get: P.prototype.LC, set: P.prototype.CF }); + P.prototype.get_m_suspensionRelativeVelocity = P.prototype.hE = function () { + return Ew(this.bB); + }; + P.prototype.set_m_suspensionRelativeVelocity = P.prototype.$G = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Fw(c, a); + }; + Object.defineProperty(P.prototype, 'm_suspensionRelativeVelocity', { get: P.prototype.hE, set: P.prototype.$G }); + P.prototype.get_m_skidInfo = P.prototype.$D = function () { + return Gw(this.bB); + }; + P.prototype.set_m_skidInfo = P.prototype.SG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Hw(c, a); + }; + Object.defineProperty(P.prototype, 'm_skidInfo', { get: P.prototype.$D, set: P.prototype.SG }); + P.prototype.__destroy__ = function () { + Iw(this.bB); + }; + function oF(a, c, d, e) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + this.bB = void 0 === e ? Jw(a, c, d) : Kw(a, c, d, e); + h(oF)[this.bB] = this; + } + oF.prototype = Object.create(hE.prototype); + oF.prototype.constructor = oF; + oF.prototype.cB = oF; + oF.dB = {}; + b.btKinematicCharacterController = oF; + oF.prototype.setUpAxis = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Lw(c, a); + }; + oF.prototype.setWalkDirection = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Mw(c, a); + }; + oF.prototype.setVelocityForTimeInterval = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Nw(d, a, c); + }; + oF.prototype.warp = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ow(c, a); + }; + oF.prototype.preStep = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Pw(c, a); + }; + oF.prototype.playerStep = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Qw(d, a, c); + }; + oF.prototype.setFallSpeed = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Rw(c, a); + }; + oF.prototype.setJumpSpeed = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Sw(c, a); + }; + oF.prototype.setMaxJumpHeight = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Tw(c, a); + }; + oF.prototype.canJump = function () { + return !!Uw(this.bB); + }; + oF.prototype.jump = function () { + Vw(this.bB); + }; + oF.prototype.setGravity = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ww(c, a); + }; + oF.prototype.getGravity = function () { + return Xw(this.bB); + }; + oF.prototype.setMaxSlope = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Yw(c, a); + }; + oF.prototype.getMaxSlope = function () { + return Zw(this.bB); + }; + oF.prototype.getGhostObject = function () { + return k($w(this.bB), Q); + }; + oF.prototype.setUseGhostSweepTest = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ax(c, a); + }; + oF.prototype.onGround = function () { + return !!bx(this.bB); + }; + oF.prototype.setUpInterpolate = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + cx(c, a); + }; + oF.prototype.updateAction = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + dx(d, a, c); + }; + oF.prototype.__destroy__ = function () { + ex(this.bB); + }; + function R(a, c, d) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + this.bB = fx(a, c, d); + h(R)[this.bB] = this; + } + R.prototype = Object.create(hE.prototype); + R.prototype.constructor = R; + R.prototype.cB = R; + R.dB = {}; + b.btRaycastVehicle = R; + R.prototype.applyEngineForce = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + gx(d, a, c); + }; + R.prototype.setSteeringValue = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + hx(d, a, c); + }; + R.prototype.getWheelTransformWS = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(ix(c, a), r); + }; + R.prototype.updateWheelTransform = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + jx(d, a, c); + }; + R.prototype.addWheel = function (a, c, d, e, g, n, D) { + var T = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + n && 'object' === typeof n && (n = n.bB); + D && 'object' === typeof D && (D = D.bB); + return k(kx(T, a, c, d, e, g, n, D), P); + }; + R.prototype.getNumWheels = function () { + return lx(this.bB); + }; + R.prototype.getRigidBody = function () { + return k(mx(this.bB), K); + }; + R.prototype.getWheelInfo = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(nx(c, a), P); + }; + R.prototype.setBrake = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + ox(d, a, c); + }; + R.prototype.setCoordinateSystem = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + px(e, a, c, d); + }; + R.prototype.getCurrentSpeedKmHour = function () { + return qx(this.bB); + }; + R.prototype.getChassisWorldTransform = function () { + return k(rx(this.bB), r); + }; + R.prototype.rayCast = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return sx(c, a); + }; + R.prototype.updateVehicle = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + tx(c, a); + }; + R.prototype.resetSuspension = function () { + ux(this.bB); + }; + R.prototype.getSteeringValue = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return vx(c, a); + }; + R.prototype.updateWheelTransformsWS = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + void 0 === c ? wx(d, a) : xx(d, a, c); + }; + R.prototype.setPitchControl = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + yx(c, a); + }; + R.prototype.updateSuspension = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + zx(c, a); + }; + R.prototype.updateFriction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ax(c, a); + }; + R.prototype.getRightAxis = function () { + return Bx(this.bB); + }; + R.prototype.getUpAxis = function () { + return Cx(this.bB); + }; + R.prototype.getForwardAxis = function () { + return Dx(this.bB); + }; + R.prototype.getForwardVector = function () { + return k(Ex(this.bB), m); + }; + R.prototype.getUserConstraintType = function () { + return Fx(this.bB); + }; + R.prototype.setUserConstraintType = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Gx(c, a); + }; + R.prototype.setUserConstraintId = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Hx(c, a); + }; + R.prototype.getUserConstraintId = function () { + return Ix(this.bB); + }; + R.prototype.updateAction = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Jx(d, a, c); + }; + R.prototype.__destroy__ = function () { + Kx(this.bB); + }; + function Q() { + this.bB = Lx(); + h(Q)[this.bB] = this; + } + Q.prototype = Object.create(y.prototype); + Q.prototype.constructor = Q; + Q.prototype.cB = Q; + Q.dB = {}; + b.btPairCachingGhostObject = Q; + Q.prototype.setAnisotropicFriction = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + Mx(d, a, c); + }; + Q.prototype.getCollisionShape = function () { + return k(Nx(this.bB), l); + }; + Q.prototype.setContactProcessingThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Ox(c, a); + }; + Q.prototype.setActivationState = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Px(c, a); + }; + Q.prototype.forceActivationState = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Qx(c, a); + }; + Q.prototype.activate = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + void 0 === a ? Rx(c) : Sx(c, a); + }; + Q.prototype.isActive = function () { + return !!Tx(this.bB); + }; + Q.prototype.isKinematicObject = function () { + return !!Ux(this.bB); + }; + Q.prototype.isStaticObject = function () { + return !!Vx(this.bB); + }; + Q.prototype.isStaticOrKinematicObject = function () { + return !!Wx(this.bB); + }; + Q.prototype.getRestitution = function () { + return Xx(this.bB); + }; + Q.prototype.getFriction = function () { + return Yx(this.bB); + }; + Q.prototype.getRollingFriction = function () { + return Zx(this.bB); + }; + Q.prototype.setRestitution = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + $x(c, a); + }; + Q.prototype.setFriction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ay(c, a); + }; + Q.prototype.setRollingFriction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + by(c, a); + }; + Q.prototype.getWorldTransform = function () { + return k(cy(this.bB), r); + }; + Q.prototype.getCollisionFlags = function () { + return dy(this.bB); + }; + Q.prototype.setCollisionFlags = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ey(c, a); + }; + Q.prototype.setWorldTransform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + fy(c, a); + }; + Q.prototype.setCollisionShape = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + gy(c, a); + }; + Q.prototype.setCcdMotionThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hy(c, a); + }; + Q.prototype.setCcdSweptSphereRadius = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + iy(c, a); + }; + Q.prototype.getUserIndex = function () { + return jy(this.bB); + }; + Q.prototype.setUserIndex = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ky(c, a); + }; + Q.prototype.getUserPointer = function () { + return k(ly(this.bB), ND); + }; + Q.prototype.setUserPointer = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + my(c, a); + }; + Q.prototype.getBroadphaseHandle = function () { + return k(ny(this.bB), OD); + }; + Q.prototype.getNumOverlappingObjects = function () { + return oy(this.bB); + }; + Q.prototype.getOverlappingObject = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(py(c, a), q); + }; + Q.prototype.__destroy__ = function () { + qy(this.bB); + }; + function pF() { + this.bB = ry(); + h(pF)[this.bB] = this; + } + pF.prototype = Object.create(f.prototype); + pF.prototype.constructor = pF; + pF.prototype.cB = pF; + pF.dB = {}; + b.btGhostPairCallback = pF; + pF.prototype.__destroy__ = function () { + sy(this.bB); + }; + function S() { + this.bB = ty(); + h(S)[this.bB] = this; + } + S.prototype = Object.create(f.prototype); + S.prototype.constructor = S; + S.prototype.cB = S; + S.dB = {}; + b.btSoftBodyWorldInfo = S; + S.prototype.get_air_density = S.prototype.VB = function () { + return uy(this.bB); + }; + S.prototype.set_air_density = S.prototype.ME = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + vy(c, a); + }; + Object.defineProperty(S.prototype, 'air_density', { get: S.prototype.VB, set: S.prototype.ME }); + S.prototype.get_water_density = S.prototype.JE = function () { + return wy(this.bB); + }; + S.prototype.set_water_density = S.prototype.BH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + xy(c, a); + }; + Object.defineProperty(S.prototype, 'water_density', { get: S.prototype.JE, set: S.prototype.BH }); + S.prototype.get_water_offset = S.prototype.LE = function () { + return yy(this.bB); + }; + S.prototype.set_water_offset = S.prototype.DH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + zy(c, a); + }; + Object.defineProperty(S.prototype, 'water_offset', { get: S.prototype.LE, set: S.prototype.DH }); + S.prototype.get_m_maxDisplacement = S.prototype.FD = function () { + return Ay(this.bB); + }; + S.prototype.set_m_maxDisplacement = S.prototype.wG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + By(c, a); + }; + Object.defineProperty(S.prototype, 'm_maxDisplacement', { get: S.prototype.FD, set: S.prototype.wG }); + S.prototype.get_water_normal = S.prototype.KE = function () { + return k(Cy(this.bB), m); + }; + S.prototype.set_water_normal = S.prototype.CH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Dy(c, a); + }; + Object.defineProperty(S.prototype, 'water_normal', { get: S.prototype.KE, set: S.prototype.CH }); + S.prototype.get_m_broadphase = S.prototype.EC = function () { + return k(Ey(this.bB), LD); + }; + S.prototype.set_m_broadphase = S.prototype.vF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Fy(c, a); + }; + Object.defineProperty(S.prototype, 'm_broadphase', { get: S.prototype.EC, set: S.prototype.vF }); + S.prototype.get_m_dispatcher = S.prototype.WC = function () { + return k(Gy(this.bB), JD); + }; + S.prototype.set_m_dispatcher = S.prototype.NF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Hy(c, a); + }; + Object.defineProperty(S.prototype, 'm_dispatcher', { get: S.prototype.WC, set: S.prototype.NF }); + S.prototype.get_m_gravity = S.prototype.eD = function () { + return k(Iy(this.bB), m); + }; + S.prototype.set_m_gravity = S.prototype.WF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Jy(c, a); + }; + Object.defineProperty(S.prototype, 'm_gravity', { get: S.prototype.eD, set: S.prototype.WF }); + S.prototype.__destroy__ = function () { + Ky(this.bB); + }; + function U() { + throw 'cannot construct a Face, no constructor in IDL'; + } + U.prototype = Object.create(f.prototype); + U.prototype.constructor = U; + U.prototype.cB = U; + U.dB = {}; + b.Face = U; + U.prototype.get_m_n = U.prototype.EB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Ly(c, a), Node); + }; + U.prototype.set_m_n = U.prototype.OB = function (a, c) { + var d = this.bB; + DD(); + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + My(d, a, c); + }; + Object.defineProperty(U.prototype, 'm_n', { get: U.prototype.EB, set: U.prototype.OB }); + U.prototype.get_m_normal = U.prototype.JD = function () { + return k(Ny(this.bB), m); + }; + U.prototype.set_m_normal = U.prototype.AG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Oy(c, a); + }; + Object.defineProperty(U.prototype, 'm_normal', { get: U.prototype.JD, set: U.prototype.AG }); + U.prototype.get_m_ra = U.prototype.SD = function () { + return Py(this.bB); + }; + U.prototype.set_m_ra = U.prototype.JG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Qy(c, a); + }; + Object.defineProperty(U.prototype, 'm_ra', { get: U.prototype.SD, set: U.prototype.JG }); + U.prototype.__destroy__ = function () { + Ry(this.bB); + }; + function qF() { + throw 'cannot construct a tFaceArray, no constructor in IDL'; + } + qF.prototype = Object.create(f.prototype); + qF.prototype.constructor = qF; + qF.prototype.cB = qF; + qF.dB = {}; + b.tFaceArray = qF; + qF.prototype.size = qF.prototype.size = function () { + return Sy(this.bB); + }; + qF.prototype.at = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Ty(c, a), U); + }; + qF.prototype.__destroy__ = function () { + Uy(this.bB); + }; + function Node() { + throw 'cannot construct a Node, no constructor in IDL'; + } + Node.prototype = Object.create(f.prototype); + Node.prototype.constructor = Node; + Node.prototype.cB = Node; + Node.dB = {}; + b.Node = Node; + Node.prototype.get_m_x = Node.prototype.AE = function () { + return k(Vy(this.bB), m); + }; + Node.prototype.set_m_x = Node.prototype.sH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Wy(c, a); + }; + Object.defineProperty(Node.prototype, 'm_x', { get: Node.prototype.AE, set: Node.prototype.sH }); + Node.prototype.get_m_q = Node.prototype.RD = function () { + return k(Xy(this.bB), m); + }; + Node.prototype.set_m_q = Node.prototype.IG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Yy(c, a); + }; + Object.defineProperty(Node.prototype, 'm_q', { get: Node.prototype.RD, set: Node.prototype.IG }); + Node.prototype.get_m_v = Node.prototype.sE = function () { + return k(Zy(this.bB), m); + }; + Node.prototype.set_m_v = Node.prototype.kH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + $y(c, a); + }; + Object.defineProperty(Node.prototype, 'm_v', { get: Node.prototype.sE, set: Node.prototype.kH }); + Node.prototype.get_m_f = Node.prototype.bD = function () { + return k(az(this.bB), m); + }; + Node.prototype.set_m_f = Node.prototype.TF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + bz(c, a); + }; + Object.defineProperty(Node.prototype, 'm_f', { get: Node.prototype.bD, set: Node.prototype.TF }); + Node.prototype.get_m_n = Node.prototype.EB = function () { + return k(cz(this.bB), m); + }; + Node.prototype.set_m_n = Node.prototype.OB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + dz(c, a); + }; + Object.defineProperty(Node.prototype, 'm_n', { get: Node.prototype.EB, set: Node.prototype.OB }); + Node.prototype.get_m_im = Node.prototype.nD = function () { + return ez(this.bB); + }; + Node.prototype.set_m_im = Node.prototype.eG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + fz(c, a); + }; + Object.defineProperty(Node.prototype, 'm_im', { get: Node.prototype.nD, set: Node.prototype.eG }); + Node.prototype.get_m_area = Node.prototype.BC = function () { + return gz(this.bB); + }; + Node.prototype.set_m_area = Node.prototype.sF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hz(c, a); + }; + Object.defineProperty(Node.prototype, 'm_area', { get: Node.prototype.BC, set: Node.prototype.sF }); + Node.prototype.__destroy__ = function () { + iz(this.bB); + }; + function rF() { + throw 'cannot construct a tNodeArray, no constructor in IDL'; + } + rF.prototype = Object.create(f.prototype); + rF.prototype.constructor = rF; + rF.prototype.cB = rF; + rF.dB = {}; + b.tNodeArray = rF; + rF.prototype.size = rF.prototype.size = function () { + return jz(this.bB); + }; + rF.prototype.at = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(kz(c, a), Node); + }; + rF.prototype.__destroy__ = function () { + lz(this.bB); + }; + function V() { + throw 'cannot construct a Material, no constructor in IDL'; + } + V.prototype = Object.create(f.prototype); + V.prototype.constructor = V; + V.prototype.cB = V; + V.dB = {}; + b.Material = V; + V.prototype.get_m_kLST = V.prototype.tD = function () { + return mz(this.bB); + }; + V.prototype.set_m_kLST = V.prototype.kG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + nz(c, a); + }; + Object.defineProperty(V.prototype, 'm_kLST', { get: V.prototype.tD, set: V.prototype.kG }); + V.prototype.get_m_kAST = V.prototype.sD = function () { + return oz(this.bB); + }; + V.prototype.set_m_kAST = V.prototype.jG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + pz(c, a); + }; + Object.defineProperty(V.prototype, 'm_kAST', { get: V.prototype.sD, set: V.prototype.jG }); + V.prototype.get_m_kVST = V.prototype.uD = function () { + return qz(this.bB); + }; + V.prototype.set_m_kVST = V.prototype.lG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + rz(c, a); + }; + Object.defineProperty(V.prototype, 'm_kVST', { get: V.prototype.uD, set: V.prototype.lG }); + V.prototype.get_m_flags = V.prototype.kB = function () { + return sz(this.bB); + }; + V.prototype.set_m_flags = V.prototype.lB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + tz(c, a); + }; + Object.defineProperty(V.prototype, 'm_flags', { get: V.prototype.kB, set: V.prototype.lB }); + V.prototype.__destroy__ = function () { + uz(this.bB); + }; + function sF() { + throw 'cannot construct a tMaterialArray, no constructor in IDL'; + } + sF.prototype = Object.create(f.prototype); + sF.prototype.constructor = sF; + sF.prototype.cB = sF; + sF.dB = {}; + b.tMaterialArray = sF; + sF.prototype.size = sF.prototype.size = function () { + return vz(this.bB); + }; + sF.prototype.at = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(wz(c, a), V); + }; + sF.prototype.__destroy__ = function () { + xz(this.bB); + }; + function W() { + throw 'cannot construct a Anchor, no constructor in IDL'; + } + W.prototype = Object.create(f.prototype); + W.prototype.constructor = W; + W.prototype.cB = W; + W.dB = {}; + b.Anchor = W; + W.prototype.get_m_node = W.prototype.HD = function () { + return k(yz(this.bB), Node); + }; + W.prototype.set_m_node = W.prototype.yG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + zz(c, a); + }; + Object.defineProperty(W.prototype, 'm_node', { get: W.prototype.HD, set: W.prototype.yG }); + W.prototype.get_m_local = W.prototype.xD = function () { + return k(Az(this.bB), m); + }; + W.prototype.set_m_local = W.prototype.oG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Bz(c, a); + }; + Object.defineProperty(W.prototype, 'm_local', { get: W.prototype.xD, set: W.prototype.oG }); + W.prototype.get_m_body = W.prototype.CC = function () { + return k(Cz(this.bB), K); + }; + W.prototype.set_m_body = W.prototype.tF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Dz(c, a); + }; + Object.defineProperty(W.prototype, 'm_body', { get: W.prototype.CC, set: W.prototype.tF }); + W.prototype.get_m_influence = W.prototype.qD = function () { + return Ez(this.bB); + }; + W.prototype.set_m_influence = W.prototype.hG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Fz(c, a); + }; + Object.defineProperty(W.prototype, 'm_influence', { get: W.prototype.qD, set: W.prototype.hG }); + W.prototype.get_m_c0 = W.prototype.FC = function () { + return k(Gz(this.bB), kE); + }; + W.prototype.set_m_c0 = W.prototype.wF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Hz(c, a); + }; + Object.defineProperty(W.prototype, 'm_c0', { get: W.prototype.FC, set: W.prototype.wF }); + W.prototype.get_m_c1 = W.prototype.GC = function () { + return k(Iz(this.bB), m); + }; + W.prototype.set_m_c1 = W.prototype.xF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Jz(c, a); + }; + Object.defineProperty(W.prototype, 'm_c1', { get: W.prototype.GC, set: W.prototype.xF }); + W.prototype.get_m_c2 = W.prototype.HC = function () { + return Kz(this.bB); + }; + W.prototype.set_m_c2 = W.prototype.yF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Lz(c, a); + }; + Object.defineProperty(W.prototype, 'm_c2', { get: W.prototype.HC, set: W.prototype.yF }); + W.prototype.__destroy__ = function () { + Mz(this.bB); + }; + function tF() { + throw 'cannot construct a tAnchorArray, no constructor in IDL'; + } + tF.prototype = Object.create(f.prototype); + tF.prototype.constructor = tF; + tF.prototype.cB = tF; + tF.dB = {}; + b.tAnchorArray = tF; + tF.prototype.size = tF.prototype.size = function () { + return Nz(this.bB); + }; + tF.prototype.at = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(Oz(c, a), W); + }; + tF.prototype.clear = tF.prototype.clear = function () { + Pz(this.bB); + }; + tF.prototype.push_back = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Qz(c, a); + }; + tF.prototype.pop_back = function () { + Rz(this.bB); + }; + tF.prototype.__destroy__ = function () { + Sz(this.bB); + }; + function X() { + throw 'cannot construct a Config, no constructor in IDL'; + } + X.prototype = Object.create(f.prototype); + X.prototype.constructor = X; + X.prototype.cB = X; + X.dB = {}; + b.Config = X; + X.prototype.get_kVCF = X.prototype.rC = function () { + return Tz(this.bB); + }; + X.prototype.set_kVCF = X.prototype.iF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Uz(c, a); + }; + Object.defineProperty(X.prototype, 'kVCF', { get: X.prototype.rC, set: X.prototype.iF }); + X.prototype.get_kDP = X.prototype.eC = function () { + return Vz(this.bB); + }; + X.prototype.set_kDP = X.prototype.WE = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Wz(c, a); + }; + Object.defineProperty(X.prototype, 'kDP', { get: X.prototype.eC, set: X.prototype.WE }); + X.prototype.get_kDG = X.prototype.dC = function () { + return Xz(this.bB); + }; + X.prototype.set_kDG = X.prototype.VE = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + Yz(c, a); + }; + Object.defineProperty(X.prototype, 'kDG', { get: X.prototype.dC, set: X.prototype.VE }); + X.prototype.get_kLF = X.prototype.gC = function () { + return Zz(this.bB); + }; + X.prototype.set_kLF = X.prototype.YE = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + $z(c, a); + }; + Object.defineProperty(X.prototype, 'kLF', { get: X.prototype.gC, set: X.prototype.YE }); + X.prototype.get_kPR = X.prototype.iC = function () { + return aA(this.bB); + }; + X.prototype.set_kPR = X.prototype.$E = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + bA(c, a); + }; + Object.defineProperty(X.prototype, 'kPR', { get: X.prototype.iC, set: X.prototype.$E }); + X.prototype.get_kVC = X.prototype.qC = function () { + return cA(this.bB); + }; + X.prototype.set_kVC = X.prototype.hF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + dA(c, a); + }; + Object.defineProperty(X.prototype, 'kVC', { get: X.prototype.qC, set: X.prototype.hF }); + X.prototype.get_kDF = X.prototype.cC = function () { + return eA(this.bB); + }; + X.prototype.set_kDF = X.prototype.UE = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + fA(c, a); + }; + Object.defineProperty(X.prototype, 'kDF', { get: X.prototype.cC, set: X.prototype.UE }); + X.prototype.get_kMT = X.prototype.hC = function () { + return gA(this.bB); + }; + X.prototype.set_kMT = X.prototype.ZE = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hA(c, a); + }; + Object.defineProperty(X.prototype, 'kMT', { get: X.prototype.hC, set: X.prototype.ZE }); + X.prototype.get_kCHR = X.prototype.bC = function () { + return iA(this.bB); + }; + X.prototype.set_kCHR = X.prototype.TE = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + jA(c, a); + }; + Object.defineProperty(X.prototype, 'kCHR', { get: X.prototype.bC, set: X.prototype.TE }); + X.prototype.get_kKHR = X.prototype.fC = function () { + return kA(this.bB); + }; + X.prototype.set_kKHR = X.prototype.XE = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + lA(c, a); + }; + Object.defineProperty(X.prototype, 'kKHR', { get: X.prototype.fC, set: X.prototype.XE }); + X.prototype.get_kSHR = X.prototype.jC = function () { + return mA(this.bB); + }; + X.prototype.set_kSHR = X.prototype.aF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + nA(c, a); + }; + Object.defineProperty(X.prototype, 'kSHR', { get: X.prototype.jC, set: X.prototype.aF }); + X.prototype.get_kAHR = X.prototype.aC = function () { + return oA(this.bB); + }; + X.prototype.set_kAHR = X.prototype.SE = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + pA(c, a); + }; + Object.defineProperty(X.prototype, 'kAHR', { get: X.prototype.aC, set: X.prototype.SE }); + X.prototype.get_kSRHR_CL = X.prototype.mC = function () { + return qA(this.bB); + }; + X.prototype.set_kSRHR_CL = X.prototype.dF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + rA(c, a); + }; + Object.defineProperty(X.prototype, 'kSRHR_CL', { get: X.prototype.mC, set: X.prototype.dF }); + X.prototype.get_kSKHR_CL = X.prototype.kC = function () { + return sA(this.bB); + }; + X.prototype.set_kSKHR_CL = X.prototype.bF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + tA(c, a); + }; + Object.defineProperty(X.prototype, 'kSKHR_CL', { get: X.prototype.kC, set: X.prototype.bF }); + X.prototype.get_kSSHR_CL = X.prototype.oC = function () { + return uA(this.bB); + }; + X.prototype.set_kSSHR_CL = X.prototype.fF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + vA(c, a); + }; + Object.defineProperty(X.prototype, 'kSSHR_CL', { get: X.prototype.oC, set: X.prototype.fF }); + X.prototype.get_kSR_SPLT_CL = X.prototype.nC = function () { + return wA(this.bB); + }; + X.prototype.set_kSR_SPLT_CL = X.prototype.eF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + xA(c, a); + }; + Object.defineProperty(X.prototype, 'kSR_SPLT_CL', { get: X.prototype.nC, set: X.prototype.eF }); + X.prototype.get_kSK_SPLT_CL = X.prototype.lC = function () { + return yA(this.bB); + }; + X.prototype.set_kSK_SPLT_CL = X.prototype.cF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + zA(c, a); + }; + Object.defineProperty(X.prototype, 'kSK_SPLT_CL', { get: X.prototype.lC, set: X.prototype.cF }); + X.prototype.get_kSS_SPLT_CL = X.prototype.pC = function () { + return AA(this.bB); + }; + X.prototype.set_kSS_SPLT_CL = X.prototype.gF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + BA(c, a); + }; + Object.defineProperty(X.prototype, 'kSS_SPLT_CL', { get: X.prototype.pC, set: X.prototype.gF }); + X.prototype.get_maxvolume = X.prototype.BE = function () { + return CA(this.bB); + }; + X.prototype.set_maxvolume = X.prototype.tH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + DA(c, a); + }; + Object.defineProperty(X.prototype, 'maxvolume', { get: X.prototype.BE, set: X.prototype.tH }); + X.prototype.get_timescale = X.prototype.GE = function () { + return EA(this.bB); + }; + X.prototype.set_timescale = X.prototype.yH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + FA(c, a); + }; + Object.defineProperty(X.prototype, 'timescale', { get: X.prototype.GE, set: X.prototype.yH }); + X.prototype.get_viterations = X.prototype.IE = function () { + return GA(this.bB); + }; + X.prototype.set_viterations = X.prototype.AH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + HA(c, a); + }; + Object.defineProperty(X.prototype, 'viterations', { get: X.prototype.IE, set: X.prototype.AH }); + X.prototype.get_piterations = X.prototype.EE = function () { + return IA(this.bB); + }; + X.prototype.set_piterations = X.prototype.wH = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + JA(c, a); + }; + Object.defineProperty(X.prototype, 'piterations', { get: X.prototype.EE, set: X.prototype.wH }); + X.prototype.get_diterations = X.prototype.YB = function () { + return KA(this.bB); + }; + X.prototype.set_diterations = X.prototype.PE = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + LA(c, a); + }; + Object.defineProperty(X.prototype, 'diterations', { get: X.prototype.YB, set: X.prototype.PE }); + X.prototype.get_citerations = X.prototype.WB = function () { + return MA(this.bB); + }; + X.prototype.set_citerations = X.prototype.NE = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + NA(c, a); + }; + Object.defineProperty(X.prototype, 'citerations', { get: X.prototype.WB, set: X.prototype.NE }); + X.prototype.get_collisions = X.prototype.XB = function () { + return OA(this.bB); + }; + X.prototype.set_collisions = X.prototype.OE = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + PA(c, a); + }; + Object.defineProperty(X.prototype, 'collisions', { get: X.prototype.XB, set: X.prototype.OE }); + X.prototype.__destroy__ = function () { + QA(this.bB); + }; + function Y(a, c, d, e) { + DD(); + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + 'object' == typeof e && (e = HD(e)); + this.bB = RA(a, c, d, e); + h(Y)[this.bB] = this; + } + Y.prototype = Object.create(q.prototype); + Y.prototype.constructor = Y; + Y.prototype.cB = Y; + Y.dB = {}; + b.btSoftBody = Y; + Y.prototype.checkLink = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return !!SA(d, a, c); + }; + Y.prototype.checkFace = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + return !!TA(e, a, c, d); + }; + Y.prototype.appendMaterial = function () { + return k(UA(this.bB), V); + }; + Y.prototype.appendNode = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + VA(d, a, c); + }; + Y.prototype.appendLink = function (a, c, d, e) { + var g = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + WA(g, a, c, d, e); + }; + Y.prototype.appendFace = function (a, c, d, e) { + var g = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + XA(g, a, c, d, e); + }; + Y.prototype.appendTetra = function (a, c, d, e, g) { + var n = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + YA(n, a, c, d, e, g); + }; + Y.prototype.appendAnchor = function (a, c, d, e) { + var g = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + ZA(g, a, c, d, e); + }; + Y.prototype.addForce = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + void 0 === c ? $A(d, a) : aB(d, a, c); + }; + Y.prototype.addAeroForceToNode = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + bB(d, a, c); + }; + Y.prototype.getTotalMass = function () { + return cB(this.bB); + }; + Y.prototype.setTotalMass = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + dB(d, a, c); + }; + Y.prototype.setMass = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + eB(d, a, c); + }; + Y.prototype.transform = Y.prototype.transform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + fB(c, a); + }; + Y.prototype.translate = Y.prototype.translate = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + gB(c, a); + }; + Y.prototype.rotate = Y.prototype.rotate = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + hB(c, a); + }; + Y.prototype.scale = Y.prototype.scale = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + iB(c, a); + }; + Y.prototype.generateClusters = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return void 0 === c ? jB(d, a) : kB(d, a, c); + }; + Y.prototype.generateBendingConstraints = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + return lB(d, a, c); + }; + Y.prototype.upcast = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(mB(c, a), Y); + }; + Y.prototype.getRestLengthScale = function () { + return nB(this.bB); + }; + Y.prototype.setRestLengthScale = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + oB(c, a); + }; + Y.prototype.setAnisotropicFriction = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + pB(d, a, c); + }; + Y.prototype.getCollisionShape = function () { + return k(qB(this.bB), l); + }; + Y.prototype.setContactProcessingThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + rB(c, a); + }; + Y.prototype.setActivationState = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + sB(c, a); + }; + Y.prototype.forceActivationState = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + tB(c, a); + }; + Y.prototype.activate = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + void 0 === a ? uB(c) : vB(c, a); + }; + Y.prototype.isActive = function () { + return !!wB(this.bB); + }; + Y.prototype.isKinematicObject = function () { + return !!xB(this.bB); + }; + Y.prototype.isStaticObject = function () { + return !!yB(this.bB); + }; + Y.prototype.isStaticOrKinematicObject = function () { + return !!zB(this.bB); + }; + Y.prototype.getRestitution = function () { + return AB(this.bB); + }; + Y.prototype.getFriction = function () { + return BB(this.bB); + }; + Y.prototype.getRollingFriction = function () { + return CB(this.bB); + }; + Y.prototype.setRestitution = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + DB(c, a); + }; + Y.prototype.setFriction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + EB(c, a); + }; + Y.prototype.setRollingFriction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + FB(c, a); + }; + Y.prototype.getWorldTransform = function () { + return k(GB(this.bB), r); + }; + Y.prototype.getCollisionFlags = function () { + return HB(this.bB); + }; + Y.prototype.setCollisionFlags = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + IB(c, a); + }; + Y.prototype.setWorldTransform = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + JB(c, a); + }; + Y.prototype.setCollisionShape = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + KB(c, a); + }; + Y.prototype.setCcdMotionThreshold = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + LB(c, a); + }; + Y.prototype.setCcdSweptSphereRadius = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + MB(c, a); + }; + Y.prototype.getUserIndex = function () { + return NB(this.bB); + }; + Y.prototype.setUserIndex = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + OB(c, a); + }; + Y.prototype.getUserPointer = function () { + return k(PB(this.bB), ND); + }; + Y.prototype.setUserPointer = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + QB(c, a); + }; + Y.prototype.getBroadphaseHandle = function () { + return k(RB(this.bB), OD); + }; + Y.prototype.get_m_cfg = Y.prototype.IC = function () { + return k(SB(this.bB), X); + }; + Y.prototype.set_m_cfg = Y.prototype.zF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + TB(c, a); + }; + Object.defineProperty(Y.prototype, 'm_cfg', { get: Y.prototype.IC, set: Y.prototype.zF }); + Y.prototype.get_m_nodes = Y.prototype.ID = function () { + return k(UB(this.bB), rF); + }; + Y.prototype.set_m_nodes = Y.prototype.zG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + VB(c, a); + }; + Object.defineProperty(Y.prototype, 'm_nodes', { get: Y.prototype.ID, set: Y.prototype.zG }); + Y.prototype.get_m_faces = Y.prototype.CB = function () { + return k(WB(this.bB), qF); + }; + Y.prototype.set_m_faces = Y.prototype.MB = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + XB(c, a); + }; + Object.defineProperty(Y.prototype, 'm_faces', { get: Y.prototype.CB, set: Y.prototype.MB }); + Y.prototype.get_m_materials = Y.prototype.ED = function () { + return k(YB(this.bB), sF); + }; + Y.prototype.set_m_materials = Y.prototype.vG = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + ZB(c, a); + }; + Object.defineProperty(Y.prototype, 'm_materials', { get: Y.prototype.ED, set: Y.prototype.vG }); + Y.prototype.get_m_anchors = Y.prototype.yC = function () { + return k($B(this.bB), tF); + }; + Y.prototype.set_m_anchors = Y.prototype.pF = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + aC(c, a); + }; + Object.defineProperty(Y.prototype, 'm_anchors', { get: Y.prototype.yC, set: Y.prototype.pF }); + Y.prototype.__destroy__ = function () { + bC(this.bB); + }; + function uF(a) { + a && 'object' === typeof a && (a = a.bB); + this.bB = void 0 === a ? cC() : dC(a); + h(uF)[this.bB] = this; + } + uF.prototype = Object.create(dE.prototype); + uF.prototype.constructor = uF; + uF.prototype.cB = uF; + uF.dB = {}; + b.btSoftBodyRigidBodyCollisionConfiguration = uF; + uF.prototype.__destroy__ = function () { + eC(this.bB); + }; + function vF() { + this.bB = fC(); + h(vF)[this.bB] = this; + } + vF.prototype = Object.create(iE.prototype); + vF.prototype.constructor = vF; + vF.prototype.cB = vF; + vF.dB = {}; + b.btDefaultSoftBodySolver = vF; + vF.prototype.__destroy__ = function () { + gC(this.bB); + }; + function wF() { + throw 'cannot construct a btSoftBodyArray, no constructor in IDL'; + } + wF.prototype = Object.create(f.prototype); + wF.prototype.constructor = wF; + wF.prototype.cB = wF; + wF.dB = {}; + b.btSoftBodyArray = wF; + wF.prototype.size = wF.prototype.size = function () { + return hC(this.bB); + }; + wF.prototype.at = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + return k(iC(c, a), Y); + }; + wF.prototype.__destroy__ = function () { + jC(this.bB); + }; + function Z(a, c, d, e, g) { + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + this.bB = kC(a, c, d, e, g); + h(Z)[this.bB] = this; + } + Z.prototype = Object.create(x.prototype); + Z.prototype.constructor = Z; + Z.prototype.cB = Z; + Z.dB = {}; + b.btSoftRigidDynamicsWorld = Z; + Z.prototype.addSoftBody = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + lC(e, a, c, d); + }; + Z.prototype.removeSoftBody = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + mC(c, a); + }; + Z.prototype.removeCollisionObject = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + nC(c, a); + }; + Z.prototype.getWorldInfo = function () { + return k(oC(this.bB), S); + }; + Z.prototype.getSoftBodyArray = function () { + return k(pC(this.bB), wF); + }; + Z.prototype.getDispatcher = function () { + return k(qC(this.bB), JD); + }; + Z.prototype.rayTest = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + rC(e, a, c, d); + }; + Z.prototype.getPairCache = function () { + return k(sC(this.bB), KD); + }; + Z.prototype.getDispatchInfo = function () { + return k(tC(this.bB), p); + }; + Z.prototype.addCollisionObject = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + void 0 === c ? uC(e, a) : void 0 === d ? vC(e, a, c) : wC(e, a, c, d); + }; + Z.prototype.getBroadphase = function () { + return k(xC(this.bB), LD); + }; + Z.prototype.convexSweepTest = function (a, c, d, e, g) { + var n = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + yC(n, a, c, d, e, g); + }; + Z.prototype.contactPairTest = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + zC(e, a, c, d); + }; + Z.prototype.contactTest = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + AC(d, a, c); + }; + Z.prototype.updateSingleAabb = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + BC(c, a); + }; + Z.prototype.setDebugDrawer = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + CC(c, a); + }; + Z.prototype.getDebugDrawer = function () { + return k(DC(this.bB), MD); + }; + Z.prototype.debugDrawWorld = function () { + EC(this.bB); + }; + Z.prototype.debugDrawObject = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + FC(e, a, c, d); + }; + Z.prototype.setGravity = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + GC(c, a); + }; + Z.prototype.getGravity = function () { + return k(HC(this.bB), m); + }; + Z.prototype.addRigidBody = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + void 0 === c ? IC(e, a) : void 0 === d ? _emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_2(e, a, c) : JC(e, a, c, d); + }; + Z.prototype.removeRigidBody = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + KC(c, a); + }; + Z.prototype.addConstraint = function (a, c) { + var d = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + void 0 === c ? LC(d, a) : MC(d, a, c); + }; + Z.prototype.removeConstraint = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + NC(c, a); + }; + Z.prototype.stepSimulation = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + return void 0 === c ? OC(e, a) : void 0 === d ? PC(e, a, c) : QC(e, a, c, d); + }; + Z.prototype.setContactAddedCallback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + RC(c, a); + }; + Z.prototype.setContactProcessedCallback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + SC(c, a); + }; + Z.prototype.setContactDestroyedCallback = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + TC(c, a); + }; + Z.prototype.addAction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + UC(c, a); + }; + Z.prototype.removeAction = function (a) { + var c = this.bB; + a && 'object' === typeof a && (a = a.bB); + VC(c, a); + }; + Z.prototype.getSolverInfo = function () { + return k(WC(this.bB), t); + }; + Z.prototype.setInternalTickCallback = function (a, c, d) { + var e = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + void 0 === c ? XC(e, a) : void 0 === d ? YC(e, a, c) : ZC(e, a, c, d); + }; + Z.prototype.__destroy__ = function () { + $C(this.bB); + }; + function xF() { + this.bB = aD(); + h(xF)[this.bB] = this; + } + xF.prototype = Object.create(f.prototype); + xF.prototype.constructor = xF; + xF.prototype.cB = xF; + xF.dB = {}; + b.btSoftBodyHelpers = xF; + xF.prototype.CreateRope = function (a, c, d, e, g) { + var n = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + return k(bD(n, a, c, d, e, g), Y); + }; + xF.prototype.CreatePatch = function (a, c, d, e, g, n, D, T, Da) { + var dc = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + n && 'object' === typeof n && (n = n.bB); + D && 'object' === typeof D && (D = D.bB); + T && 'object' === typeof T && (T = T.bB); + Da && 'object' === typeof Da && (Da = Da.bB); + return k(cD(dc, a, c, d, e, g, n, D, T, Da), Y); + }; + xF.prototype.CreatePatchUV = function (a, c, d, e, g, n, D, T, Da, dc) { + var yF = this.bB; + DD(); + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + n && 'object' === typeof n && (n = n.bB); + D && 'object' === typeof D && (D = D.bB); + T && 'object' === typeof T && (T = T.bB); + Da && 'object' === typeof Da && (Da = Da.bB); + 'object' == typeof dc && (dc = HD(dc)); + return k(dD(yF, a, c, d, e, g, n, D, T, Da, dc), Y); + }; + xF.prototype.CreateEllipsoid = function (a, c, d, e) { + var g = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + return k(eD(g, a, c, d, e), Y); + }; + xF.prototype.CreateFromTriMesh = function (a, c, d, e, g) { + var n = this.bB; + DD(); + a && 'object' === typeof a && (a = a.bB); + 'object' == typeof c && (c = HD(c)); + if ('object' == typeof d && 'object' === typeof d) { + var D = ED(d, xa); + FD(d, xa, D); + d = D; + } + e && 'object' === typeof e && (e = e.bB); + g && 'object' === typeof g && (g = g.bB); + return k(fD(n, a, c, d, e, g), Y); + }; + xF.prototype.CreateFromConvexHull = function (a, c, d, e) { + var g = this.bB; + a && 'object' === typeof a && (a = a.bB); + c && 'object' === typeof c && (c = c.bB); + d && 'object' === typeof d && (d = d.bB); + e && 'object' === typeof e && (e = e.bB); + return k(gD(g, a, c, d, e), Y); + }; + xF.prototype.__destroy__ = function () { + hD(this.bB); + }; + (function () { + function a() { + b.PHY_FLOAT = iD(); + b.PHY_DOUBLE = jD(); + b.PHY_INTEGER = kD(); + b.PHY_SHORT = lD(); + b.PHY_FIXEDPOINT88 = mD(); + b.PHY_UCHAR = nD(); + b.CONST_GIMPACT_COMPOUND_SHAPE = oD(); + b.CONST_GIMPACT_TRIMESH_SHAPE_PART = pD(); + b.CONST_GIMPACT_TRIMESH_SHAPE = qD(); + b.BT_CONSTRAINT_ERP = rD(); + b.BT_CONSTRAINT_STOP_ERP = sD(); + b.BT_CONSTRAINT_CFM = tD(); + b.BT_CONSTRAINT_STOP_CFM = uD(); + } + Fa ? a() : Ca.unshift(a); + })(); + b.CONTACT_ADDED_CALLBACK_SIGNATURE = 'iiiiiiii'; + b.CONTACT_DESTROYED_CALLBACK_SIGNATURE = 'ii'; + b.CONTACT_PROCESSED_CALLBACK_SIGNATURE = 'iiii'; + b.INTERNAL_TICK_CALLBACK_SIGNATURE = 'vif'; + //this.Ammo=b; + return Ammo.ready; + }; +})(); + +var La = `data:application/wasm;base64,AGFzbQEAAAABwQVTYAF/AGABfwF/YAJ/fwF/YAJ/fwBgBH9/f38AYAN/f38AYAF/AX1gA39/fwF/YAJ/fQBgBX9/f39/AGAEf39/fwF/YAABf2ADf39/AX1gA39/fQBgBH9/f30AYAN/fX8AYAZ/f39/f38AYAJ/fwF9YAZ/f39/f30AYAV/f39/fwF/YAN/fX0AYAR/f31/AGAGf39/f39/AX9gBX9/f39/AX1gCn9/f39/f39/f38AYAt/f39/fX19fX9/fQBgAX0BfWAKf39/f39/f39/fwF9YAAAYAN/f30Bf2AHf39/f39/fwBgCX9/f39/f39/fwF/YAJ/fQF/YAx/f39/fX19fX1/fX8AYAZ/fX1/f38AYAJ9fQF/YAR/fX99AX9gCn9/f39/f39/f38Bf2AHf39/f39/fwF/YAZ/f399f38AYAh/f39/f39/fwF9YAR/fX9/AGAJf39/f39/f39/AX1gAn19AX1gBH9/f38BfWAFf39/f30AYAV/f31/fwF9YAR/fX19AGAGf39/fX9/AX1gAn99AX1gAXwBfWAFf39/fX8AYAV/f39/fQF/YAZ/fX19fX0AYAV/fX19fQBgBH9/fX0AYAV/f31/fwBgAX8BfGAEfX19fQF/YAl/f39/f39/f38AYAN/f38BfGALf39/f39/f399fX0AYAV9fX19fQF9YAJ8fwF8YA1/f39/f39/f39/f39/AX9gCX9/f39/fX9/fwBgBX99f39/AGADf31/AX9gAn1/AX9gBn99fX1/fwBgBn9/f39/fQF9YAh/f39/f39/fwBgB39/f399fX8AYAl/f39/f39/f30AYAt/f39/f39/f39/fwF/YAN9fX0Bf2AIf39/f319f38Bf2AEf399fwF/YAR9f39/AX9gA31/fwF/YAR/f399AX9gCX9/f319fX9/fwF/YAF9AX8CJQYBYQFhAAIBYQFiAAcBYQFjABwBYQFkAAEBYQFlAAcBYQFmADwDpg6kDgQAAAcBBwABBQUcAAUBAwEFDwAaGgUJAwEFAwErAQAaGhEGCAEHBQEFCzIyKwEHCAYAAgMAAwEAABoJAAAFAwUEHQkeAQQHAxUMCAYDBQUACh4ABTMAFwUEAAUAAwMDEQYBBgoHAAQSAQEEERERBQYBAQADCBoJAgUTPR4GAAMFAwEIAAgIBggDAwEI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AMMIAmxvAMIIAm1vAMEIAm5vAMAIAm9vAL8IAnBvAL4IAnFvAL0IAnJvALwIAnNvALsIAnRvALoIAnVvALkIAnZvALgIAndvALcIAnhvALYIAnlvALUIAnpvALQIAkFvALMIAkJvALIIAkNvALEIAkRvALAIAkVvAK8IAkZvABgCR28ArggCSG8AdwJJbwCtCAJKbwCsCAJLbwCrCAJMbwCqCAJNbwCpCAJObwCoCAJPbwCnCAJQbwClCAJRbwCkCAJSbwCjCAJTbwCiCAJUbwChCAJVbwCgCAJWbwCfCAJXbwCeCAJYbwCdCAJZbwCcCAJabwCbCAJfbwCaCAIkbwCZCAJhcACYCAJicACXCAJjcACWCAJkcACVCAJlcACUCAJmcACTCAJncACSCAJocACRCAJpcACQCAJqcACPCAJrcAB2AmxwAI4IAm1wAKUBAm5wAKQBAm9wAHoCcHAAowECcXAAoQECcnAAnAECc3AAmwECdHAAmgECdXAAmQECdnAAmAECd3AAlwECeHAAlgECeXAAlQECenAAlAECQXAAkwECQnAAkgECQ3AAkQECRHAAdwJFcACQAQJGcACPAQJHcACOAQJIcABiAklwAI0BAkpwAIoBAktwADwCTHAAOwJNcAA8Ak5wADsCT3AAdgJQcACJAQJRcACNCAJScADSAQJTcADRAQJUcAA2AlVwADUCVnAAjAECV3AAiwECWHAAGAJZcACMCAJacACLCAJfcACKCAIkcACJCAJhcQCICAJicQCHCAJjcQBSAmRxAFECZXEAUAJmcQBPAmdxAE4CaHEApggCaXEAhggCanEABwJrcQCFCAJscQCECAJtcQCDCAJucQCCCAJvcQCBCAJwcQCACAJxcQD/BwJycQD+BwJzcQCjBAJ0cQCdBAJ1cQCbBAJ2cQCXBAJ3cQDgAQJ4cQBSAnlxAFECenEAUAJBcQBPAkJxAE4CQ3EABwJEcQD9BwJFcQAHAkZxAPwHAkdxAPsHAkhxAPoHAklxAPkHAkpxAPgHAktxAPcHAkxxAPYHAk1xAPUHAk5xAPQHAk9xAPMHAlBxAFICUXEAUQJScQBQAlNxAE8CVHEATgJVcQAHAlZxAPIHAldxAPEHAlhxAPAHAllxAO8HAlpxAO4HAl9xAO0HAiRxAOwHAmFyAOsHAmJyAOoHAmNyAOkHAmRyAOgHAmVyAOcHAmZyAOYHAmdyAFICaHIAUQJpcgBQAmpyAE8Ca3IATgJscgAHAm1yAOUHAm5yAOQHAm9yAHoCcHIA4wcCcXIA4gcCcnIA4QcCc3IA4AcCdHIA3wcCdXIA3gcCdnIAUgJ3cgBRAnhyAFACeXIATwJ6cgBOAkFyAAcCQnIA3QcCQ3IAUgJEcgBRAkVyAFACRnIATwJHcgBOAkhyAAcCSXIABwJKcgDSAQJLcgDRAQJMcgCoAQJNcgCdAQJOcgCyAQJPcgCxAQJQcgB1AlFyAIgBAlJyANwHAlNyANsHAlRyANoHAlVyANkHAlZyANgHAldyANcHAlhyANYHAllyANUHAlpyANADAl9yAM8DAiRyANQHAmFzANMHAmJzAKcCAmNzAKYCAmRzABgCZXMA0gcCZnMA0QcCZ3MA0AcCaHMAzwcCaXMAzgMCanMAzQMCa3MAGAJscwDOBwJtcwDSAQJucwDRAQJvcwA2AnBzADUCcXMAjAECcnMAiwECc3MAdQJ0cwCIAQJ1cwDJAwJ2cwDMAwJ3cwDLAwJ4cwDKAwJ5cwAqAnpzANMBAkFzAKIBAkJzAKABAkNzAKUCAkRzAKQCAkVzABgCRnMAzQcCR3MA+QMCSHMABwJJcwAqAkpzANMBAktzAKIBAkxzAKABAk1zAKUCAk5zAKQCAk9zAO8DAlBzAO4DAlFzALICAlJzAO0DAlNzAOwDAlRzAOsDAlVzAMwHAlZzAMsHAldzAMgDAlhzAMcDAllzABgCWnMAKgJfcwDTAQIkcwCiAQJhdACgAQJidADnAwJjdADmAwJkdADGAwJldADFAwJmdADEAwJndADDAwJodADCAwJpdADBAwJqdADAAwJrdAC/AwJsdAC+AwJtdAC9AwJudAC8AwJvdAC7AwJwdAC6AwJxdAC5AwJydAC4AwJzdAC3AwJ0dADKBwJ1dADJBwJ2dAAYAnd0AMgHAnh0AMcHAnl0AMYHAnp0AMUHAkF0AMQHAkJ0AIwJAkN0AMMHAkR0AMIHAkV0AMEHAkZ0AMAHAkd0AL8HAkh0AL4HAkl0AL0HAkp0ALwHAkt0ALsHAkx0ALoHAk10ALkHAk50AP4IAk90ALgHAlB0AO8IAlF0ALcHAlJ0ALYHAlN0ALUHAlR0ALQHAlV0ALMHAlZ0ALIHAld0ALEHAlh0ALAHAll0AK8HAlp0ACoCX3QArgcCJHQArQcCYXUArAcCYnUAtgMCY3UAqwcCZHUAqgcCZXUAqQcCZnUAqAcCZ3UApwcCaHUApgcCaXUApQcCanUApAcCa3UAowcCbHUAogcCbXUAoQcCbnUAoAcCb3UAnwcCcHUAngcCcXUAnQcCcnUAnAcCc3UAmwcCdHUAGAJ1dQCaBwJ2dQCZBwJ3dQCYBwJ4dQCnAQJ5dQCXBwJ6dQCWBwJBdQCVBwJCdQCUBwJDdQCTBwJEdQCSBwJFdQCRBwJGdQCQBwJHdQCPBwJIdQCOBwJJdQCNBwJKdQCMBwJLdQCLBwJMdQCKBwJNdQCJBwJOdQCIBwJPdQCHBwJQdQC4AgJRdQAHAlJ1AIYHAlN1AIUHAlR1AIQHAlV1AIMHAlZ1AIIHAld1AIEHAlh1AIAHAll1AP8GAlp1AP4GAl91AP0GAiR1APwGAmF2APsGAmJ2APoGAmN2APkGAmR2APgGAmV2APcGAmZ2APYGAmd2APUGAmh2APQGAml2APMGAmp2APIGAmt2APEGAmx2APAGAm12AO8GAm52AO4GAm92AO0GAnB2AOwGAnF2AOoGAnJ2AOkGAnN2AOgGAnR2ALgCAnV2AAcCdnYA5wYCd3YApQECeHYApAECeXYAegJ6dgCjAQJBdgChAQJCdgCcAQJDdgCbAQJEdgCaAQJFdgCZAQJGdgCYAQJHdgCXAQJIdgCWAQJJdgCVAQJKdgCUAQJLdgCTAQJMdgCSAQJNdgCRAQJOdgB3Ak92AJABAlB2AI8BAlF2AI4BAlJ2AGICU3YAjQECVHYAigECVXYAPAJWdgA7Ald2ADwCWHYAOwJZdgB2Alp2APgDAl92APcDAiR2AIkBAmF3AOYGAmJ3AAcCY3cA5QYCZHcA0gECZXcA0QECZncANgJndwA1Amh3AIwBAml3AIsBAmp3AHUCa3cAiAECbHcAogECbXcAoAECbncA2gMCb3cA2QMCcHcA5AYCcXcA4wYCcncAsQICc3cAsAICdHcA4gYCdXcA4QYCdncA4AYCd3cAswICeHcA8AMCeXcApwICencApgICQXcAGAJCdwAtAkN3AN8GAkR3AD4CRXcAnAMCRncA5QMCR3cArgICSHcA5AMCSXcAsQICSncAsAICS3cA6gMCTHcA6QMCTXcA6AMCTncA3gYCT3cA3QYCUHcA3AYCUXcAqgICUncAqQICU3cAGAJUdwAtAlV3ANsGAlZ3AD4CV3cANgJYdwA1All3AIwBAlp3AIsBAl93AHUCJHcAiAECYXgAhAICYngAggICY3gAGAJkeAAtAmV4ANQBAmZ4AD4CZ3gAnwECaHgAngECaXgAqAICangA2gYCa3gAzgMCbHgAzQMCbXgAtAMCbngAswMCb3gAqwUCcHgA2QYCcXgA2AYCcngA1wYCc3gAqgICdHgAqQICdXgAGAJ2eAAtAnd4ANYGAnh4AD0CeXgA1QYCengA1AYCQXgAPgJCeAA2AkN4ADUCRHgAjAECRXgAiwECRngAdQJHeACIAQJIeADJAwJJeADMAwJKeADLAwJLeADKAwJMeAC0AwJNeACzAwJOeADQAwJPeADPAwJQeAClAgJReACkAgJSeACnAgJTeACmAgJUeADjAwJVeADiAwJWeACtAwJXeACsAwJYeADGAwJZeADFAwJaeADEAwJfeADDAwIkeADCAwJheQDBAwJieQDAAwJjeQC/AwJkeQC+AwJleQC9AwJmeQC8AwJneQC7AwJoeQC6AwJpeQC5AwJqeQC4AwJreQC3AwJseQDSCQJteQDTBgJueQDrBgJveQDSBgJweQDIAwJxeQDHAwJyeQDRBgJzeQDQBgJ0eQDPBgJ1eQDOBgJ2eQDNBgJ3eQDMBgJ4eQDLBgJ5eQDKBgJ6eQDJBgJBeQDIBgJCeQDHBgJDeQDGBgJEeQDFBgJFeQDEBgJGeQDDBgJHeQDCBgJIeQDBBgJJeQDABgJKeQC/BgJLeQC+BgJMeQC9BgJNeQC8BgJOeQC7BgJPeQC6BgJQeQC5BgJReQC3BgJSeQC2BgJTeQC1BgJUeQC0BgJVeQCzBgJWeQCyBgJXeQCxBgJYeQClAQJZeQCkAQJaeQB6Al95AKMBAiR5AKEBAmF6AJwBAmJ6AJsBAmN6AJoBAmR6AJkBAmV6AJgBAmZ6AJcBAmd6AJYBAmh6AJUBAml6AJQBAmp6AJMBAmt6AJIBAmx6AJEBAm16AHcCbnoAkAECb3oAjwECcHoAjgECcXoAYgJyegCNAQJzegCKAQJ0egA8AnV6ADsCdnoAPAJ3egA7Anh6AHYCeXoAsAYCenoArwYCQXoArgYCQnoArQYCQ3oArAYCRHoAqwYCRXoAqgYCRnoAqQYCR3oAqAYCSHoApwYCSXoA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f3zZEsCgEDGMIQAMAgtEGC1EVPshGcBEGC1EVPshGUAgBEEAThsgAaAQMCEADAELIANBgICA/AdPBEAgACAAkyEADAELAkACQAJAAkAgACACQQhqEIgEQQNxDgMAAQIDCyACKwMIEDAhAAwDCyACKwMIEDEhAAwCCyACKwMImhAwIQAMAQsgAisDCBAxjCEACyACQRBqJAAgAAvoAgIDfwF8IwBBEGsiASQAAn0gALwiA0H/////B3EiAkHan6T6A00EQEMAAIA/IAJBgICAzANJDQEaIAC7EDEMAQsgAkHRp+2DBE0EQCAAuyEEIAJB5JfbgARPBEBEGC1EVPshCcBEGC1EVPshCUAgA0EAThsgBKAQMYwMAgsgA0EASARAIAREGC1EVPsh+T+gEDAMAgtEGC1EVPsh+T8gBKEQMAwBCyACQdXjiIcETQRAIAJB4Nu/hQRPBEBEGC1EVPshGcBEGC1EVPshGUAgA0EAThsgALugEDEMAgsgA0EASARARNIhM3982RLAIAC7oRAwDAILIAC7RNIhM3982RLAoBAwDAELIAAgAJMgAkGAgID8B08NABoCQAJAAkACQCAAIAFBCGoQiARBA3EOAwABAgMLIAErAwgQMQwDCyABKwMImhAwDAILIAErAwgQMYwMAQsgASsDCBAwCyEAIAFBEGokACAAC3cBAX8jAEEgayIDJAAgAyABNgIcIAMgAjYCGCADIAMoAhwqAgAgAygCGCoCAJQ4AhQgAyADKAIcKgIEIAMoAhgqAgCUOAIQIAMgAygCHCoCCCADKAIYKgIAlDgCDCAAIANBFGogA0EQaiADQQxqEAYgA0EgaiQAC8gHAgh/AX0gACgC0AUiBSACQegAbGohByAFIAFB6ABsaiEFAkACQCAERQ0AIAAoAtwFIgRBAEwNACAAKALkBSIIKAIMIQEgBSAIKAIIIgZGIAEgB0ZxDQFBASECIAYgB0YgASAFRnENAQNAAkAgAiIBIARGDQAgCCABQTRsaiICKAIMIQYgBSACKAIIIglGIAYgB0ZxDQAgAUEBaiECIAcgCUcNASAFIAZHDQELCyABIARIDQELQQAhCEEAIQYjAEEwayIBJAAgAUEANgIoIAFCADcDICABQgA3AxggAUIANwMQIAFCADcDCCABQgA3AwAgAyAAKALwBigCACADGyELAkAgACgC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AgwhACACKAIQQQJ0IAFqIAUgAigCEEECdCAAaioCAJIgAioCDJQ4AgALIAIoAjggAkEgaiIAIABBBGogAEEIaiAAQQxqEHwgAkFAayQACywBAX8jAEEQayIBJAAgASAANgIMIwBBEGsgASgCDCIANgIMIAFBEGokACAAC9YDAQZ/AkACQCABvCIFQQF0IgJFDQAgBUH/////B3FBgICA/AdLDQAgALwiB0EXdkH/AXEiA0H/AUcNAQsgACABlCIAIACVDwsgAiAHQQF0IgRPBEAgAEMAAAAAlCAAIAIgBEYbDwsgBUEXdkH/AXEhAgJ/IANFBEBBACEDIAdBCXQiBEEATgRAA0AgA0EBayEDIARBAXQiBEEATg0ACwsgB0EBIANrdAwBCyAHQf///wNxQYCAgARyCyEEAn8gAkUEQEEAIQIgBUEJdCIGQQBOBEADQCACQQFrIQIgBkEBdCIGQQBODQALCyAFQQEgAmt0DAELIAVB////A3FBgICABHILIQUgAiADSARAA0ACQCAEIAVrIgZBAEgEQCAEIQYMAQsgBCAFRw0AIABDAAAAAJQPCyAGQQF0IQQgA0EBayIDIAJKDQALIAIhAwsCQCAEIAVrIgJBAEgEQCAEIQIMAQsgBCAFRw0AIABDAAAAAJQPCwJAIAJB////A0sEQCACIQYMAQsDQCADQQFrIQMgAkGAgIACSSEEIAJBAXQiBiECIAQNAAsLIAdBgICAgHhxIQIgA0EASgR/IAZBgICABGsgA0EXdHIFIAZBASADa3YLIAJyvgtOAQF/IABBoPsANgIAIAAoAjQiAQRAIAEgASgCACgCABEBABogACgCNCIBBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIAALJAAgAARAQciFAkHIhQIoAgBBAWo2AgAgAEH80wEoAgARAAALCyYBAX8jAEEQayIBJAAgASAAOAIMIAEqAgwQGSEAIAFBEGokACAACyYBAX8jAEEQayIBJAAgASAAOAIMIAEqAgwQGiEAIAFBEGokACAAC0QBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwiACoCCCACKAIIIgEqAgiUIAAqAgAgASoCAJQgACoCBCABKgIElJKSCzMCAX8BfSMAQRBrIgEkACABIAA2AgwgASgCDCIAIAAoAgAoAjARBgAhAiABQRBqJAAgAgs5AQF/IwBBEGsiAiQAIAIgADYCDCACIAE4AgggAigCDCIAIAIqAgggACgCACgCLBEIACACQRBqJAALFQEBfyMAQRBrIgEgADYCDCABKAIMC3QBAX8gAkUEQCAAKAIEIAEoAgRGDwsgACABRgRAQQEPCyABKAIEIgItAAAhAQJAIAAoAgQiAy0AACIARQ0AIAAgAUcNAANAIAItAAEhASADLQABIgBFDQEgAkEBaiECIANBAWohAyAAIAFGDQALCyAAIAFGC4QEAgR/En0jAEEwayIDJAAgASgCeCEEIAMgASgCACABKAJ8IgZBAXVqIgUgAiAFKAIAIARqKAIAIAQgBkEBcRsRBQAgASgCBCABKAJ8IgVBAXVqIQQgAioCCIwhByACKgIEjCEIIAIqAgCMIQkgASgCeCECIAQoAgAgAmooAgAgAiAFQQFxGyECIAEqAhAhCiABKgIMIQsgASoCICEMIAEqAhghDSABKgIcIQ4gASoCMCEPIAEqAighECABKgIsIREgASoCCCESIANBADYCHCADIA8gB5QgECAJlCARIAiUkpI4AhggAyAMIAeUIA0gCZQgDiAIlJKSOAIUIAMgCiAHlCASIAmUIAsgCJSSkjgCECADQSBqIAQgA0EQaiACEQUAIAEqAmghCiABQUBrKgIAIQsgASoCPCEMIAEqAmwhDSABKgJQIQ4gASoCSCEPIAEqAkwhECABKgJwIREgASoCYCESIAEqAlghEyABKgJcIRQgASoCOCEVIAMqAighByADKgIgIQggAyoCJCEJIAMqAgAhFiADKgIEIRcgAyoCCCEYIABBADYCDCAAIBggESAHIBKUIAggE5QgCSAUlJKSkpM4AgggACAXIA0gByAOlCAIIA+UIAkgEJSSkpKTOAIEIAAgFiAKIAcgC5QgCCAVlCAJIAyUkpKSkzgCACADQTBqJAALNgEBfyMAQRBrIgEkACABIAA2AgwjAEEQayIAIAEoAgw2AgwgACgCDCgCBCEAIAFBEGokACAAC7kHAgR/D30CQCAAKALsBSIDQQBMDQADQCABKgIwIQsgASoCCCEMIAEqAgAhDSABKgIEIQ4gASoCNCEPIAEqAhghECABKgIQIQogASoCFCERIAEqAjghByABKgIoIQkgASoCICEIIAEqAiQhEiAAIANBAWsiBUG4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NwKYASAAQgA3AqABIABCADcCqAECQCADBEAgACADKQIENwIAIAAgAykCDDcCCCAAIAMpAhw3AhggACADKQIUNwIQIAAgAykCLDcCKCAAIAMpAiQ3AiAgACADKQI8NwI4IAAgAykCNDcCMCADKgLgAiEHIAMqAuQCIQggAyoC3AIhCSADKgLYAiEGIAAgAzYC8AEgAEEANgKMASAAIAYgCJQ4AogBIAAgBiAHlDgChAEgACAGIAmUOAKAASAAIAMpAqgENwJoIAAgAykCoAQ3AmAgACADKQLkAjcCeCAAIAMpAtwCNwJwIAAgAykCwAI3ArgBIAAgAykCuAI3ArABIAAgAykC0AI3AsgBIAAgAykCyAI3AsABIAMqAqADIQcgAyoCpAMhCCADKgKcAyEJIAMqAtgCIQYgAEEANgLcASAAIAYgCJQgApQ4AtgBIAAgBiAHlCAClDgC1AEgACAGIAmUIAKUOALQASADKgKYAiEJIAMqAqgCIQogAyoCjAIhCyADKgKcAiEMIAMqAqwCIQ0gAyoCiAIhDiAAIAMqArACIAMqArQDIgaUIAMqApACIAMqAqwDIgeUIAMqArADIgggAyoCoAKUkpIgApQ4AugBIAAgDSAGlCALIAeUIAggDJSSkiAClDgC5AEgACAKIAaUIA4gB5QgCSAIlJKSIAKUOALgAQwBCyAAQgA3AgQgAEGAgID8AzYCACAAQQA2AvABIABCADcCgAEgAEKAgID8g4CAwD83AnAgAEKAgID8g4CAwD83AmAgAEIANwKwASAAQgA3AgwgAEIANwIYIABBgICA/AM2AhQgAEIANwIgIABCADcCLCAAQYCAgPwDNgIoIABCADcCNCAAQQA2AjwgAEIANwKIASAAQoCAgPwDNwJ4IABCgICA/AM3AmggAEEANgLoASAAQgA3AuABIABCADcC2AEgAEIANwLQASAAQgA3AsgBIABCADcCwAEgAEIANwK4AQsgAEEANgLsASABIAQ2AtQBDAELIAAoArwBIgRBAE4NACAAIAAoAgg2ArwBIAVBCGoiAUEAQfQBEAkaIABBBGogARDDBCIBQgA3AlggAUIANwJQIAFCADcCSCABQgA3AkAgAUIANwKQASABQgA3ApgBIAFCADcCoAEgAUIANwKoASABQgA3AgQgAUGAgID8AzYCACABQgA3AgwgAUIA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IAVBAmoiBSAIIAhBBHQiCyABKAIQaigCDCIKayAKQQBOG0EAEEkgACABIAIgAyAEQQJqIgQgBiAGQQR0IgogACgCEGooAgwiCWsgCUEAThsgCEEAEEkgACABIAIgAyAEIAYgACgCECAKaigCDCIAayAAQQBOGyAFIAggASgCECALaigCDCIAayAAQQBOG0EAEEkLIAdBQGskAAtSACAAQiM3AgQgAEG87wA2AgAgAEGKro/pAzYCLCAAQoCAgPwDNwIUIABCgICA/IOAgMA/NwIMIABBoO0ANgIAIABBADYCNCAAQaD7ADYCACAACwMAAQu7AQEBfwJAIAAoAgQiAwRAIABBADYCBAwBC0HEhQJBxIUCKAIAQQFqNgIAQSxBEEH40wEoAgARAgAiA0IANwIAIANBADYCKCADQgA3AiAgA0IANwIYIANCADcCECADQgA3AggLIAMgAjYCJCADQQA2AiAgA0EANgIoIAMgASkCADcCACADIAEpAgg3AgggAyABKQIQNwIQIAMgASkCGDcCGCAAIAAoAgAgAxC5ASAAIAAoAgxBAWo2AgwgAwtIAQF/IwBBEGsiAiAANgIMIAJBADYCCCACIAE2AgQgAiACKAIINgIAA0AgAigCACACKAIESARAIAIgAigCAEEBajYCAAwBCwsLUQEBfyMAQRBrIgQkACAEIAA2AgwgBCABNgIIIAQgAjgCBCAEIAM2AgAgBCgCDCIAIAQoAgggBCoCBCAEKAIAIAAoAgAoAhwRFQAgBEEQaiQAC0sCAX8BfSMAQRBrIgMkACADIAA2AgwgAyABNgIIIAMgAjYCBCADKAIMIgAgAygCCCADKAIEIAAoAgAoAiARDAAhBCADQRBqJAAgBAtMAQF/IwBBEGsiAiQAIAIgADYCDCACIAE4AgggAioCCCEBIwBBEGsiACACKAIMNgIMIAAgATgCCCAAKAIMIAAqAgg4AhAgAkEQaiQACzgCAX8BfSMAQRBrIgEkACABIAA2AgwjAEEQayIAIAEoAgw2AgwgACgCDCoCECECIAFBEGokACACC1IBAX8jAEEQayICJAAgAiAANgIMIAIgAToACyACLQALQQFxIQEjAEEQayIAIAIoAgw2AgwgACABOgALIAAoAgwgAC0AC0EBcToAFSACQRBqJAALdwEBfyMAQSBrIgMkACADIAE2AhwgAyACNgIYIAMgAygCHCoCACADKAIYKgIAlDgCFCADIAMoAhwqAgQgAygCGCoCBJQ4AhAgAyADKAIcKgIIIAMoAhgqAgiUOAIMIAAgA0EUaiADQRBqIANBDGoQBiADQSBqJAALmwMCAX8BfSMAQSBrIgMkACADIAA2AhwgAyABNgIYIAMgAjYCFAJ9IAMoAhwiACgCLEEBRgRAIAMgACgCJCADKAIYIAAoAjBsajYCECADKAIQKwMAAnwjAEEQayIBIABBDGoiADYCDCABKAIMKgIAuwuitiEEIAEgAygCFDYCDCABKAIMIAQ4AgAgAygCECsDCAJ8IAEgADYCDCABKAIMKgIEuwuitiEEIAEgAygCFDYCDCABKAIMIAQ4AgQgAygCECsDEAJ8IAEgADYCDCABKAIMKgIIuwuitgwBCyADIAAoAiQgAygCGCAAKAIwbGo2AgwgAygCDCoCAAJ9IwBBEGsiASAAQQxqIgA2AgwgASgCDCoCAAuUIQQgASADKAIUNgIMIAEoAgwgBDgCACADKAIMKgIEAn0gASAANgIMIAEoAgwqAgQLlCEEIAEgAygCFDYCDCABKAIMIAQ4AgQgAygCDCoCCAJ9IAEgADYCDCABKAIMKgIIC5QLIQQjAEEQayIAIAMoAhQ2AgwgACgCDCAEOAIIIANBIGokAAsvAQF/IwBBEGsiASQAIAEgADYCDCMAQRBrIAEoAgwiADYCDCAAEM4BIAFBEGokAAv4BwIJfw99IAIqAgQiFCACKgIIIhZDAAAAAJQiEpMiEEMAAIA/IAIqAgAiE0MAAAAAlCAUQwAAAICUIg2SIhUgFZQgECAQlCASIBOTIhAgEJSSkpEiGJUiEZQgFEMAAAAAlCAWkyIOQwAAgD8gDSATkiINIA2UIA4gDpQgEiATQwAAAICUkiIOIA6UkpKRIhKVIg+UIBIgGF0iBBsiEiAUlCATIBAgEZQgDiAPlCAEGyIQlJMhGCAVIBGUIA0gD5QgBBsiFSATlCAWIBKUkyEZIBAgFpQgFCAVlJMhGiADKAIMIQkgAUEATCEKAn8DQEF/IQUgCkUEQCACKgIIIREgAioCBCEOIAIqAgAhDUEAIQQDQAJAIAkgBEECdGooAgBFDQAgBUF/RwRAIAAgBEEEdGoiAyoCCCARlCADKgIAIA2UIA4gAyoCBJSSkiAAIAVBBHRqIgMqAgggEZQgAyoCACANlCAOIAMqAgSUkpJeRQ0BCyAEIQULIARBAWoiBCABRw0ACwtBfyEHQQAhBCAJIAVBAnRqIgsoAgBBA0YEQCAFDwsCQANAIAchBiAEIgyyIhFDNfqOPJQiDRAaIQ4gDRAZIQ1BfyEHIApFBEAgFiAVIA2UIBggDpSSQ83MzDyUkiEPIBQgECANlCAZIA6UkkPNzMw8lJIhFyATIBIgDZQgGiAOlJJDzczMPJSSIQ5BACEEA0ACQCAJIARBAnRqKAIARQ0AIAdBf0cEQCAAIARBBHRqIgMqAgggD5QgAyoCACAOlCAXIAMqAgSUkpIgACAHQQR0aiIDKgIIIA+UIAMqAgAgDpQgFyADKgIElJKSXkUNAQsgBCEHCyAEQQFqIgQgAUcNAAsLIAUgBkYgBSAHRnENAQJAIAZBf0YNACAGIAdGDQAgEUMAACDCkiIOIBFfRQ0AA0AgDkM1+o48lCIPEBohDSAPEBkhDwJAIApFBEAgFiAVIA+UIBggDZSSQ83MzDyUkiEXIBQgECAPlCAZIA2UkkPNzMw8lJIhGyATIBIgD5QgGiANlJJDzczMPJSSIQ1BfyEDQQAhBANAAkAgCSAEQQJ0aigCAEUNACADQX9HBEAgACAEQQR0aiIIKgIIIBeUIAgqAgAgDZQgGyAIKgIElJKSIAAgA0EEdGoiCCoCCCAXlCAIKgIAIA2UIBsgCCoCBJSSkl5FDQELIAQhAwsgBEEBaiIEIAFHDQALIAUgBkcEQCADIQYMAgsgBSADIgZGDQUMAQsgBSAGcSEDQX8iBiADQX9GDQYaCyAOQwAAoECSIg4gEV8NAAsLIAxBLWohBCAMQbwCSQ0ACyALQQA2AgAMAQsLIAULIQYgC0EDNgIAIAYL7AUCA38IfSMAQYABayIHJAACQCABRQ0AAkAgASgCKEUNACACIAZOIAZBAE5xDQAgACABKAIkIAJBAWoiCCADIAQgBSAGEFcgACABKAIoIAggAyAEIAUgBhBXCyACIAVIDQAgASoCFCEKIAEqAhghCyABKAIoIQUgASoCECEMIAEqAgAhDyABKgIEIQ0gASoCCCEOIAdBADYCfCAHQQA2AmwgB0EANgJcIAdBADYCTCAHQQA2AjwgB0EANgIsIAdBADYCHCAHIA4gC5JDAAAAP5QiECALIA6TQwAAAD+UIg6SIgs4AnggByANIAqSQwAAAD+UIhEgCiANk0MAAAA/lCINkiIKOAJ0IAcgCzgCaCAHIAo4AmQgByALOAJYIAcgESANkyINOAJUIAcgCzgCSCAHIA04AkQgByAQIA6TIgs4AjggByAKOAI0IAcgCzgCKCAHIAo4AiQgByALOAIYIAcgDTgCFCAHQQA2AgwgByAPIAySQwAAAD+UIg4gDCAPk0MAAAA/lCIMkyIKOAJwIAcgDiAMkiIMOAJgIAcgDDgCUCAHIAo4AkAgByAKOAIwIAcgDDgCICAHIAw4AhAgByAKOAIAIAcgCzgCCCAHIA04AgQgACAHIAdBEGoiAiADIAQgBRsiASAAKAIAKAIIEQQAIAAgAiAHQSBqIgMgASAAKAIAKAIIEQQAIAAgAyAHQTBqIgQgASAAKAIAKAIIEQQAIAAgBCAHIAEgACgCACgCCBEEACAAIAdBQGsiBSAHQdAAaiIGIAEgACgCACgCCBEEACAAIAYgB0HgAGoiCCABIAAoAgAoAggRBAAgACAIIAdB8ABqIgkgASAAKAIAKAIIEQQAIAAgCSAFIAEgACgCACgCCBEEACAAIAcgBSABIAAoAgAoAggRBAAgACACIAYgASAAKAIAKAIIEQQAIAAgAyAIIAEgACgCACgCCBEEACAAIAQgCSABIAAoAgAoAggRBAALIAdBgAFqJAALMgEBfyMAQRBrIgEkACABIAA2AgwgASgCDCIAEMAEIwBBEGsgAEEwajYCDCABQRBqJAAL+AQBB30CQCACKgJkIgYgAioCcCAGIAIqAnSUkyACKgIYIgcgACoCSJQgAioCECIIIAAqAkCUIAIqAhQiCSAAKgJElJKSIAIqAgggACoCWJQgAioCACAAKgJQlCACKgIEIAAqAlSUkpKSIAIqAmwiBJSTIAIqAjggASoCSJQgAioCMCABKgJAlCACKgI0IAEqAkSUkpIgAioCKCABKgJYlCACKgIgIAEqAlCUIAIqAiQgASoCVJSSkpIgBJSTIgOSIgQgAioCeCIFXQRAIAUgBpMhAyAFIQQMAQsgBCACKgJ8IgVeRQ0AIAUgBpMhAyAFIQQLIAIgBDgCZCAAKALwAQRAIAAgACoCcCADIAggACoCgAGUlJQgACoCQJI4AkAgACADIAkgACoChAGUlCAAKgJ0lCAAKgJEkjgCRCAAIAMgByAAKgKIAZSUIAAqAniUIAAqAkiSOAJIIAIqAkghBCACKgJEIQUgACADIAAqAmCUIAIqAkCUIAAqAlCSOAJQIAAqAmghBiAAIAUgAyAAKgJklJQgACoCVJI4AlQgACAEIAMgBpSUIAAqAliSOAJYCyABKALwAQRAIAIqAjghBCACKgI0IQUgASABKgJwIAMgAioCMCABKgKAAZSUlCABKgJAkjgCQCABIAMgBSABKgKEAZSUIAEqAnSUIAEqAkSSOAJEIAEgAyAEIAEqAogBlJQgASoCeJQgASoCSJI4AkggAioCWCEEIAIqAlQhBSABIAMgASoCYJQgAioCUJQgASoCUJI4AlAgASoCaCEGIAEgBSADIAEqAmSUlCABKgJUkjgCVCABIAQgAyAGlJQgASoCWJI4AlgLC4oFAgp9AX8jAEEQayIPJAAgACoCNCEFIAAqAjghBiAAKgIwIQkgASoCACEHIAEqAgQhCCABKgIIIQogBEEANgI8IAQgBiAKIAOUkjgCOCAEIAUgCCADlJI4AjQgBCAJIAcgA5SSOAIwAn1D2w9JPyADlSACKgIIIgsgC5QgAioCACIMIAyUIAIqAgQiDSANlJKSkSIFIAUgA5RD2w9JP14bIgVDbxKDOl0EQCADQwAAAD+UIAUgAyADlCADlEOrqqq8lCAFlJSSDAELIAVDAAAAP5QgA5QQGSAFlQshBiAAIA8QICAPKgIIIQkgDyoCACEHIA8qAgQhCCAPKgIMIQogBEEANgIsIARBADYCHCAEQQA2AgwgBCAHIAsgBpQiC5QgCCAFIAOUQwAAAD+UEBoiA5QgCiANIAaUIgWUkpIgCSAMIAaUIgaUkyIMQwAAgD8gAyAKlCAHIAaUkyAFIAiUkyALIAmUkyINIA2UIAYgCJQgAyAJlCALIAqUkpIgBSAHlJMiDiAOlCAFIAmUIAMgB5QgBiAKlJKSIAsgCJSTIgcgB5QgDCAMlJKSkpGVIgOUIgUgDiADlCIJQwAAAEAgDSADlCIGIAaUIAkgCZQgByADlCIDIAOUIAUgBZSSkpKVIgiUIgeUIgogBiADIAiUIguUIgySOAIkIAQgAyAHlCINIAYgBSAIlCIIlCIOkzgCICAEIAogDJM4AhggBCADIAiUIgogBiAHlCIGkjgCECAEIA0gDpI4AgggBCAKIAaTOAIEIARDAACAPyADIAuUIgMgBSAIlCIFkpM4AiggBEMAAIA/IAMgCSAHlCIDkpM4AhQgBEMAAIA/IAUgA5KTOAIAIA9BEGokAAu9AgIBfwF9IwBB4ABrIgEkACAAQQE6AFhBkOkBLQAARQRAQbToAUIANwIAQbDoAUGAgID8AzYCAEG86AFCADcCAEHI6AFCADcDAEHE6AFBgICA/AM2AgBB0OgBQgA3AwBB5OgBQgA3AgBB4OgBQYCAgPx7NgIAQdjoAUKAgID8AzcDAEHs6AFCADcCAEH46AFCADcDAEH06AFBgICA/Hs2AgBBgOkBQgA3AwBBiOkBQoCAgPwLNwMAQZDpAUEBOgAACyAAQbDoASABQQBB4AAQCSIBQQYgACgCACgCTBEEACAAIAEqAgAgACoCLCICkjgCSCAAIAEqAjAgApM4AjggACACIAEqAhSSOAJMIAAgASoCRCACkzgCPCAAIAIgASoCKJI4AlAgAEFAayABKgJYIAKTOAIAIAFB4ABqJAALBwBDAACAPwuiAQEBfyMAQSBrIgMkACADIAE2AhwgAyACNgIYIAMgAygCHCIBKgIEIAMoAhgiAioCCJQgASoCCCACKgIElIySOAIUIAMgASoCCCADKAIYKgIAlCABKgIAIAMoAhgqAgiUjJI4AhAgAyABKgIAIAMoAhgqAgSUIAEqAgQgAygCGCoCAJSMkjgCDCAAIANBFGogA0EQaiADQQxqEAYgA0EgaiQAC5wHAgp/Bn0gAQRAIAIqAhghDiACKgIUIQ8gAioCECEQIAIqAgghESACKgIEIRIgAioCACETQcSFAkHEhQIoAgBBAWo2AgBBgAJBEEH40wEoAgARAgAiACABNgIAQcAAIQVBASECA0ACfwJAAkACQCAAIAJBAWsiAUECdCIKaigCACIHKgIAIBBfRQ0AIAcqAhAgE2BFDQAgByoCBCAPX0UNACAHKgIUIBJgRQ0AIAcqAgggDl9FDQAgByoCGCARYEUNACAHKAIoBEAgASAFRw0CIAIgBUEBdEEBIAUbIgZKDQIgBgR/QcSFAkHEhQIoAgBBAWo2AgAgBkECdEEQQfjTASgCABECAAVBAAshAQJAIAVFDQBBACELQQAhBCAFQQFrQQNPBEAgBUF8cSENQQAhCANAIAEgBEECdCIJaiAAIAlqKAIANgIAIAEgCUEEciIMaiAAIAxqKAIANgIAIAEgCUEIciIMaiAAIAxqKAIANgIAIAEgCUEMciIJaiAAIAlqKAIANgIAIARBBGohBCAIQQRqIgggDUcNAAsLIAVBA3EiBUUNAANAIAEgBEECdCIIaiAAIAhqKAIANgIAIARBAWohBCALQQFqIgsgBUcNAAsLIAAEQEHIhQJByIUCKAIAQQFqNgIAIABB/NMBKAIAEQAACwwDCyADIAcgAygCACgCDBEDAAsgAQwCCyAFIQYgACEBCyABIApqIAcoAiQ2AgACQCACIAZHBEAgBiEFIAEhAAwBCyACQQF0IgUgAkwEQCACIQUgASEADAELQcSFAkHEhQIoAgBBAWo2AgAgAkEDdEEQQfjTASgCABECACEAAkAgAkEATA0AQQAhC0EAIQYgAkEBa0EDTwRAIAJBfHEhCUEAIQgDQCAAIAZBAnQiBGogASAEaigCADYCACAAIARBBHIiCmogASAKaigCADYCACAAIARBCHIiCmogASAKaigCADYCACAAIARBDHIiBGogASAEaigCADYCACAGQQRqIQYgCEEEaiIIIAlHDQALCyACQQNxIgRFDQADQCAAIAZBAnQiCGogASAIaigCADYCACAGQQFqIQYgC0EBaiILIARHDQALCyABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIAAgAkECdGogBygCKDYCACACQQFqCyICQQBKDQALIAAEQEHIhQJByIUCKAIAQQFqNgIAIABB/NMBKAIAEQAACwsLAwABCzABAX8jAEEQayIDJAAgAyABNgIMIAMgAjYCCCAAIAMoAgggAygCDBAbIANBEGokAAspAQF/IwBBEGsiASQAIAEgADYCDCABKAIMIgAQIRogABAMIAFBEGokAAs5AQF/IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCDCIAIAIoAgggACgCACgCDBEDACACQRBqJAALSgEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgwiACACKAIIEJcCIAAgAigCCCIBKQIwNwIwIAAgASkCODcCOCACQRBqJAALVQEBfyMAQRBrIgIkACACIAE2AgwgAiACKAIMKgIAjDgCCCACIAIoAgwqAgSMOAIEIAIgAigCDCoCCIw4AgAgACACQQhqIAJBBGogAhAGIAJBEGokAAuoAQIB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BSAAQQA2AvgFIABCADcC8AUgAEEBOgCQBiAAQQA2AowGIABCADcChAYgAEEBOgCkBiAAQQE6ALgGIABBADYCoAYgAEIANwKYBiAAQQE6AMwGIABBADYCtAYgAEIANwKsBiAAQQE6AOAGIABBADYCyAYgAEIANwLABiAAQQE6APQGIABBADYC3AYgAEIANwLUBiAAQQA2AvAGIABCADcC6AYgAEGgB2oQbiERIABB3AdqEG4aIABBmAhqEG4aIABB4AhqQQA2AgAgAEHkCGpBAToAACAAQfgIakEBOgAAIABB2AhqQgA3AgAgAEH0CGpBADYCACAAQeAJakEBOgAAIABB7AhqQgA3AgAgAEHcCWpBADYCACAAQdQJakIANwIAIABCgICAgICAgMA/NwKgAiAAQQg2AuwBIABBADsB2AMgAEIANwKoAiAAQgA3ArACIABBADYCuAIgAEEANgLcAyAAQQE2AoQDIABCgICAgMAANwL8AiAAQoCAgIAQNwL0AiAAQoCAgPyDgIDAPzcC7AIgAEKAgID4g4CAgD83AuQCIABCgICA+IOAgIA/NwLcAiAAQs2Zs+6DgIDAPzcC1AIgAEKAgID8s+bMmT83AswCIABCgICA/NOZs+Y9NwLEAiAAQs2Zs/IDNwK8AiAAQgA3ApAEIABCADcCiAQgAEGAgID8AzYCmAQgAEIANwKcBCAAQgA3AqQEIABBgICA/AM2AqwEIABCADcCsAQgAEIANwK4BCAAQoCAgPwDNwLABCAAQYCAgPwDNgLIBCAAQgA3AswEIABCADcC1AQgAEGAgID8AzYC3AQgAEIANwLgBCAAQgA3AugEIABBAToAnAcgAEEANgL4BiAAQoCAgPwDNwLwBCAAQQA2AqgFIABCADcClAcgAEIANwKMByAAQgA3AoQHIABCADcC/AYgAEIANwIIIABBgICA/AM2AgQgAEIANwIQIABCADcCHCAAQYCAgPwDNgIYIABCADcCJCAAQgA3AjAgAEGAgID8AzYCLCAAQgA3AjggAEFAa0EANgIAAkAgACgClAMiAUUNACAALQCYA0UNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYClAMgAEEBOgCYAyAAQgA3AowDAkAgACgCqAMiAUUNACAALQCsA0UNACABBEBByIUCQciF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C0IBAX8jAEEQayIBJAAgASAANgIMIAEoAgwiAARAQciFAkHIhQIoAgBBAWo2AgAgAEH80wEoAgARAAALIAFBEGokAAtHAQF/IAAgARC6ARogACgCBCICBEBByIUCQciFAigCAEEBajYCACACQfzTASgCABEAAAsgACABNgIEIAAgACgCDEEBazYCDAuDAQEEfwJAIAAgARC6ASIDRQRAQQAhAwwBCyAAKAIIIgVBAE4EQCAFRQ0BA0AgAygCICIGRQ0CIAYhAyAFIARBAWoiBEcNAAsMAQsgACgCACEDCyABIAIpAgA3AgAgASACKQIYNwIYIAEgAikCEDcCECABIAIpAgg3AgggACADIAEQuQEL7wMBCX8jAEEgayIDJAACQCAAKAIAIgJFDQAgACgCDCABIAFBAEgbIgdBAEwNAANAQQAhBSACQShqIgYoAgAEQANAAkAgAiACKAIgIgFPBEAgAiEBDAELIAEoAigiBCACRiEJIAEgAiAER0ECdCIKaigCJCEIIAEoAiAiBAR/IAQgBCgCKCABRkECdGpBJGoFIAALIAI2AgAgCCACNgIgIAEgAjYCICACIAQ2AiAgASACKAIkNgIkIAEgBigCADYCKCACKAIkIAE2AiAgBigCACABNgIgIAJBJGoiBCAJQQJ0aiABNgIAIAQgCmogCDYCACADIAFBGGopAgA3AxggAyABQRBqKQIANwMQIAMgAUEIaikCADcDCCADIAEpAgA3AwAgASACQRhqKQIANwIYIAEgAkEQaikCADcCECABIAJBCGopAgA3AgggASACKQIANwIAIAIgAykDGDcCGCACIAMpAxA3AhAgAiADKQMINwIIIAIgAykDADcCAAsgACgCECAFdiECIAVBAWpBH3EhBSABIAJBAXFBAnRqKAIkIgJBKGoiBigCAA0ACwsgACACELoBIQEgACAAKAIAQQAgARsgAhC5ASAAIAAoAhBBAWo2AhAgB0EBayIHRQ0BIAAoAgAhAgwACwALIANBIGokAAsEAEEBCyQBAX8jAEEQayICIAA2AgwgAiABOAIIIAIoAgwgAioCCDgCDAsyAQF/IwBBEGsiASQAIAEgADYCDCABKAIMIgAEQCAAIAAoAgAoAggRAAALIAFBEGokAAtNAQF/IwBBEGsiAiQAIAIgADYCDCACIAE4AgggAioCCCEBIwBBEGsiACACKAIMNgIMIAAgATgCCCAAKAIMIAAqAgg4AvgBIAJBEGokAAskAQF/IwBBEGsiAiAANgIMIAIgATgCCCACKAIMIAIqAgg4AggLGAEBfyMAQRBrIgEgADYCDCABKAIMKgIIC00BAX8jAEEQayICJAAgAiAANgIMIAIgATgCCCACKgIIIQEjAEEQayIAIAIoAgw2AgwgACABOAIIIAAoAgwgACoCCDgC/AEgAkEQaiQAC2oBAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCACKAIIIQEjAEEQayIAJAAgACACKAIMNgIMIAAgATYCCCAAKAIMIgEgASgChAJBAWo2AoQCIAFBBGogACgCCBBEIABBEGokACACQRBqJAALTQEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgghASMAQRBrIgAgAigCDDYCDCAAIAE2AgggACgCDCAAKAIINgLMASACQRBqJAALNwEBfyMAQRBrIgEkACABIAA2AgwjAEEQayIAIAEoAgw2AgwgACgCDCgCzAEhACABQRBqJAAgAAteAQJ/IwBBEGsiAiQAIAIgADYCDCACIAE4AgggAioCCCEBIwBBEGsiACACKAIMNgIMIAAgATgCCCAAKAIMIgMgAygChAJBAWo2AoQCIAMgACoCCDgC6AEgAkEQaiQAC14BAn8jAEEQayICJAAgAiAANgIMIAIgATgCCCACKgIIIQEjAEEQayIAIAIoAgw2AgwgACABOAIIIAAoAgwiAyADKAKEAkEBajYChAIgAyAAKgIIOALgASACQRBqJAALXgECfyMAQRBrIgIkACACIAA2AgwgAiABOAIIIAIqAgghASMAQRBrIgAgAigCDDYCDCAAIAE4AgggACgCDCIDIAMoAoQCQQFqNgKEAiADIAAqAgg4AuQBIAJBEGokAAs5AgF/AX0jAEEQayIBJAAgASAANgIMIwBBEGsiACABKAIMNgIMIAAoAgwqAugBIQIgAUEQaiQAIAILOQIBfwF9IwBBEGsiASQAIAEgADYCDCMAQRBrIgAgASgCDDYCDCAAKAIMKgLgASECIAFBEGokACACCzkCAX8BfSMAQRBrIgEkACABIAA2AgwjAEEQayIAIAEoAgw2AgwgACgCDCoC5AEhAiABQRBqJAAgAgs9AQF/IwBBEGsiASQAIAEgADYCDCMAQRBrIgAgASgCDDYCDCAAKAIMKALMAUEDcUEARyEAIAFBEGokACAACzoBAX8jAEEQayIBJAAgASAANgIMIwBBEGsiACABKAIMNgIMIAAoAgwoAswBQQFxIQAgAUEQaiQAIAALPQEBfyMAQRBrIgEkACABIAA2AgwjAEEQayIAIAEoAgw2AgwgACgCDCgCzAFBAnFBAEchACABQRBqJAAgAAtxAQR/IwBBEGsiASQAIAEgADYCDCMAQRBrIgAkACAAIAEoAgw2AgwjAEEQayICIAAoAgwiBDYCDCACKAIMKALYAUECRwRAIwBBEGsiAiAENgIMIAIoAgwoAtgBQQVHIQMLIABBEGokACABQRBqJAAgAwsxAQF/IwBBEGsiAiQAIAIgADYCDCACIAE6AAsgAigCDCACLQALQQFxEDkgAkEQaiQACyQBAX8jAEEQayIBJAAgASAANgIMIAEoAgxBABA5IAFBEGokAAskAQF/IwBBEGsiAiAANgIMIAIgATYCCCACKAIMIAIoAgg2AgQLJAEBfyMAQRBrIgIgADYCDCACIAE2AgggAigCDCACKAIINgIACxgBAX8jAEEQayIBIAA2AgwgASgCDCgCAAs1AQF/IwBBEGsiAiAANgIMIAIgATYCCCACKAIMIgAgAigCCCIBKQIANwIQIAAgASkCCDcCGAswAQF/IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCDCACKAIINgLYASACQRBqJAALGAEBfyMAQRBrIgEgADYCDCABKAIMQRBqC0UBAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCACKAIIIQAgAigCDCIBKALYAUF+cUEERwRAIAEgADYC2AELIAJBEGokAAs3AQF/IwBBEGsiASQAIAEgADYCDCMAQRBrIgAgASgCDDYCDCAAKAIMKALAASEAIAFBEGokACAAC4ECAQF/IwBBEGsiAyQAIAMgADYCDCADIAE2AgggAyACNgIEIAMoAgghASADKAIEIQIjAEEQayIAJAAgACADKAIMNgIMIAAgATYCCCAAIAI2AgQgACgCDCIBIAAoAggiAikCADcCpAEgASACKQIINwKsASAAAn8jAEEQayICIAAoAgg2AgxBASACKAIMKgIAQwAAgD9cDQAaIwBBEGsiAiAAKAIINgIMQQEgAigCDCoCBEMAAIA/XA0AGiMAQRBrIgIgACgCCDYCDCACKAIMKgIIQwAAgD9cC0EBcToAAyABIAAoAgRBACAALQADQQFxGzYCtAEgAEEQaiQAIANBEGokAAueAQEBfyMAQTBrIgokACAKIAA2AiwgCiABNgIoIAogAjYCJCAKIAM2AiAgCiAENgIcIAogBTYCGCAKIAY2AhQgCiAHNgIQIAogCDYCDCAKIAk2AgggCigCLCIAIAooAiggCigCJCAKKAIgEAYgAEEQaiAKKAIcIAooAhggCigCFBAGIABBIGogCigCECAKKAIMIAooAggQBiAKQTBqJAALOQEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIAAoAgAoAhARAwAgAkEQaiQACxgBAX8jAEEQayIBIAA2AgwgASgCDCgCBAuhAQEBfUMAAIA/IQUCQCABIAJeDQBDAAAAACEFIAEgAlsNACADIASVIgNDAAAAAF0EQAJAIAAgAWBFDQAgASADkyAAXkUNACABIACTIAOVDwtDAAAAAEMAAIA/IAAgAV0bDwsgA0MAAAAAXkUNAAJAIAAgAl9FDQAgAiADkyAAXUUNACACIACTIAOVDwtDAAAAAEMAAIA/IAAgAl4bIQULIAULqBcDGn0BfAx/IAEqAjQhGCABKgI4IRkgACoCYCEMIAAqAmQhDSAAKgJoIQ8gASoCFCEDIAEqAhghByAAQUBrKgIAIRAgACoCUCEOIAAqAjQhESAAKgJEIRIgACoCVCEUIAAqAjghEyABKgIkIQQgACoCSCEVIAEqAighCCAAKgJYIRYgASoCMCEaIAEqAgghBSABKgIAIQkgASoCBCEKIAEqAhAhBiAAKgIwIRcgASoCICELIABB5AhqQQA2AgAgAEHUCGpBADYCACAAQcQIakEANgIAIABBtAhqQQA2AgAgAEHQCGoiASAWIAiUIBMgC5QgFSAElJKSOAIAIABBzAhqIh4gFCAIlCARIAuUIBIgBJSSkjgCACAAQcgIaiIfIA4gCJQgFyALlCAQIASUkpI4AgAgAEHACGoiICAWIAeUIBMgBpQgFSADlJKSOAIAIABBvAhqIiEgFCAHlCARIAaUIBIgA5SSkjgCACAAQbgIaiIiIA4gB5QgFyAGlCAQIAOUkpI4AgAgAEGwCGoiIyAWIAWUIBMgCZQgCiAVlJKSOAIAIABBrAhqIiQgFCAFlCARIAmUIAogEpSSkjgCACAAIA4gBZQgFyAJlCAQIAqUkpI4AqgIIABB4AhqIiUgGSAPIAiUIAwgC5QgBCANlJKSkjgCACAAQdwIaiImIBggDyAHlCAMIAaUIAMgDZSSkpI4AgAgAEHYCGoiJyAaIA8gBZQgDCAJlCAKIA2UkpKSOAIAIAIqAjQhGCACKgI4IRkgACoCoAEhDCAAKgKkASENIAAqAqgBIQ8gAioCFCEDIAIqAhghByAAKgKAASEQIAAqApABIQ4gACoCdCERIAAqAoQBIRIgACoClAEhFCAAKgJ4IRMgACoCiAEhFSACKgIkIQQgACoCmAEhFiACKgIoIQggAioCMCEaIAIqAgghBSACKgIAIQkgAioCBCEKIAIqAhAhBiAAKgJwIRcgAioCICELIABBpAlqQQA2AgAgAEGUCWpBADYCACAAQYQJakEANgIAIABB9AhqQQA2AgAgAEGQCWogFiAIlCATIAuUIBUgBJSSkjgCACAAQYwJaiAUIAiUIBEgC5QgEiAElJKSOAIAIABBiAlqIA4gCJQgFyALlCAQIASUkpI4AgAgAEGACWogFiAHlCATIAaUIBUgA5SSkjgCACAAQfwIaiAUIAeUIBEgBpQgEiADlJKSOAIAIABB+AhqIA4gB5QgFyAGlCAQIAOUkpI4AgAgAEHwCGogFiAFlCATIAmUIAogFZSSkjgCACAAQewIaiAUIAWUIBEgCZQgCiASlJKSOAIAIAAgDiAFlCAXIAmUIBAgCpSSkjgC6AggAEGgCWoiAiAZIA8gCJQgDCALlCAEIA2UkpKSOAIAIABBnAlqIiggGCAPIAeUIAwgBpQgAyANlJKSkjgCACAAQZgJaiIpIBogDyAFlCAMIAmUIAogDZSSkpI4AgAgAEH0CWpBADYCACAAQfAJaiAAKgKoCCIEICEqAgAiCZQgIioCACIKICQqAgAiCJSTQwAAgD8gIyoCACIFIAogHioCACIGlCAfKgIAIgsgCZSTIgeUIAQgCSABKgIAIgyUIAYgICoCACINlJMiEZQgCCANIAuUIAwgCpSTIhKUkpKVIgOUIAIqAgAgJSoCAJMiD5QgByADlCApKgIAICcqAgCTIhCUICgqAgAgJioCAJMiDiAIIAuUIAYgBJSTIAOUlJKSIgc4AgAgAEHsCWogBSAKlCANIASUkyADlCAPlCASIAOUIBCUIA4gBCAMlCALIAWUkyADlJSSkiIEOAIAIAAgCCANlCAJIAWUkyADlCAPlCARIAOUIBCUIA4gBSAGlCAMIAiUkyADlJSSkiIDOALoCSAAIAM4AsgGAn0gACoCqAUiCCAAKgK4BSIFXkUEQCADIAhdBEAgAEECNgLYBiADIAiTDAILIAMgBV4EQCAAQQE2AtgGIAMgBZMMAgsLIABBADYC2AZDAAAAAAshAyAAIAQ4AswGIAAgAzgCuAYCfSAAKgKsBSIDIAAqArwFIgheRQRAAkAgAyAEXkUEQCAEIAheRQ0BIABBATYC3AYgBCAIkwwDCyAAQQI2AtwGIAQgA5MMAgsLIABBADYC3AZDAAAAAAshAyAAIAc4AtAGIAAgAzgCvAYgAAJ9IAAqArAFIgMgACoCwAUiBF5FBEACQCADIAdeRQRAIAQgB11FDQEgAEEBNgLgBiAHIASTDAMLIABBAjYC4AYgByADkwwCCwsgAEEANgLgBkMAAAAACzgCwAYgAEGMCWoqAgAiDyAAQbAIaioCACIHIABBuAhqKgIAIgmUIABBwAhqKgIAIgQgACoCqAgiBpSTQwAAgD8gByAJIABBzAhqKgIAIgyUIABByAhqKgIAIg0gAEG8CGoqAgAiCpSTIhOUIAYgCiAAQdAIaioCACIIlCAMIASUkyIFlCAAQawIaioCACILIAQgDZQgCCAJlJMiDpSSkpUiA5QiFZQgAEHsCGoqAgAiECAOIAOUIhaUIAYgCJQgDSAHlJMgA5QiFyAAQfwIaioCACIOlJKSIREgDyALIASUIAogB5STIAOUIhiUIBAgBSADlCIZlCAHIAyUIAggC5STIAOUIhogDpSSkiESIAeMIRsgBIwhHAJ9AkAgAEGICWoqAgAiBSAGIAqUIAkgC5STIAOUIhSUIAAqAugIIgkgEyADlCITlCAAQfgIaioCACIKIAsgDZQgDCAGlJMgA5QiA5SSkiIGQwAAgD9dBEAgBkMAAIC/XgRAIAAgDyAUlCAQIBOUIAMgDpSSkowgAEGQCWoqAgAgFJQgAEHwCGoqAgAgE5QgAyAAQYAJaioCAJSSkhAyOAKoCSAAQawJagJ9IAZDAACAv5dDAACAP5YiA7wiAkH/////B3EiAUGAgID8A08EQCADu0QYLURU+yH5P6JEAAAAAAAAcDigtiABQYCAgPwDRg0BGkMAAAAAIAMgA5OVDAELAkAgAUH////3A00EQCABQYCAgARrQYCAgMgDSQ0BIAMgAyADlCIGIAZDa9MNvJRDuhMvvZKUQ3WqKj6SIAaUIAZDruU0v5RDAACAP5KVlCADkgwCC0QYLURU+yH5P0MAAIA/IAOLk0MAAAA/lCIDu58iHSAdIAMgA0Nr0w28lEO6Ey+9kpRDdaoqPpIgA5QgA0Ou5TS/lEMAAIA/kpW7oqAiHSAdoKG2IgMgA4wgAkEAThshAwsgAws4AgAgBSAVlCAJIBaUIAogF5SSkowgBSAYlCAJIBmUIAogGpSSkhAyDAMLIABBrAlqQdufpP57NgIAIAAgEiAREDKMOAKoCQwBCyAAQawJakHbn6T+AzYCACAAIBIgERAyOAKoCQtDAAAAAAshAyAAQdQJakEANgIAIABBsAlqIAM4AgAgAEHkCWpBADYCACAAQcQJakEANgIAIABB0AlqIAcgCpQgCSAclJIiA0MAAIA/IAMgA5QgBCAFlCAKIAiUkyIGIAaUIAggCZQgBSAblJIiCyALlJKSkZUiDJQ4AgAgAEHMCWogCyAMlDgCACAAQcgJaiAGIAyUOAIAIABB4AlqIAkgC5QgBiAKlJMiDEMAAIA/IAwgDJQgCiADlCALIAWUkyIKIAqUIAUgBpQgAyAJlJMiBSAFlJKSkZUiCZQ4AgAgAEHcCWogBSAJlDgCACAAQdgJaiAKIAmUOAIAIABBwAlqIAYgBJQgByALlJMiBUMAAIA/IAUgBZQgCyAIlCAEIAOUkyIEIASUIAMgB5QgCCAGlJMiAyADlJKSkZUiB5Q4AgAgAEG8CWogAyAHlDgCACAAIAQgB5Q4ArgJIAAtAJUKBEAgACAAKAIcKgLYAiIHQwAAADRdIAAoAiAqAtgCIgNDAAAANF1yOgCACiAAIAMgByADkiIDlUMAAAA/IANDAAAAAF4bIgM4AvgJIABDAACAPyADkzgC/AkLC9EHAgt/BX0jAEHgAGsiBCQAIAAoAgwiAiAAKAIIQQRqIARB0ABqIgMgBEFAayIFIAIoAgAoAggRBAAgASgCRCICIAAoAggoArwBIAMgBSABKAIYIAIoAgAoAhARCQAgASgCGCICIAAoAggoApwCIAFBHGogAiACKAIAKAIgEQQAIAAgACgCCCIBKQI0NwJcIAAgASkCPDcCZAJAIAEoApwCIgEgASgCACgCJBEBAEEATARAQQAhBQwBCyAAQYABaiEJQQAhBQNAAkAgACgChAEiAkEATg0AIAAoAogBQQBIBEACQCAAKAKMASIBRQ0AIAAtAJABRQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACwsgAEEBOgCQASAAQgA3AogBC0EAIQNBACACIgFrQQNxIgYEQANAIAAoAowBIAFBAnRqQQA2AgAgAUEBaiEBIANBAWoiAyAGRw0ACwsgAkF8Sw0AA0AgAUECdCICIAAoAowBakEANgIAIAIgACgCjAFqQQA2AgQgAiAAKAKMAWpBADYCCCACIAAoAowBakEANgIMIAFBBGoiAQ0ACwsgAEEANgKEASAAKAIIKAKcAiIBIAEoAgAoAhwRAQAoAgwgB0EEdGoiASgCBCgCACECAkAgASgCACgCACIDQQAgAy0AzAFBBHEbDQAgAkEAIAItAMwBQQRxGw0AIAEoAggiAQRAIAEgCSABKAIAKAIQEQMACyAAKAKEASIKQQBMDQAgACgCCCELIAAoAowBIQxBACECA0AgDCACQQJ0aigCACIGKALsBSIIQQBKBEBDAACAv0MAAIA/IAYoAuQFIAtGGyENQQAhAwNAIAYgA0G4AWxqIgEqAlQiDkMAAAAAXQRAIA4gD10EQCABKgJEIQ8gASoCSCEQIAEqAkwhESAAQQA2AqQBIAAgDSARlDgCoAEgACANIBCUOAKcASAAIA0gD5Q4ApgBIAYoAuwFIQggDiEPCyABKgJMIRAgASoCSCERIAAgDiANIAEqAkSUlEPNzEw+lCAAKgJckjgCXCAAIA4gDSARlJRDzcxMPpQgACoCYJI4AmAgACAOIA0gEJSUQ83MTD6UIAAqAmSSOAJkQQEhBQsgA0EBaiIDIAhIDQALCyACQQFqIgIgCkcNAAsLIAAoAggoApwCIgEgASgCACgCJBEBACAHQQFqIgdKDQALCyAAKAIIIQEgBCAAKQJkNwM4IAQgACkCXDcDMCABIAEoAoQCQQFqNgKEAiABIAQpAzg3AjwgASAEKQMwNwI0IARB4ABqJAAgBQuHCAIYfQF/IAQgBC0AEEFwcSIdOgAQIAMqAggiGiABKgIIIguTIg8gACoCCCIKIAuTIgWUIAMqAgAiGyABKgIAIgyTIhAgACoCACIIIAyTIgaUIAMqAgQiHCABKgIEIg2TIhEgACoCBCISIA2TIgeUkpIhCSAEAn0CQCACKgIIIhcgC5MiEyAFlCACKgIAIhggDJMiFCAGlCACKgIEIhkgDZMiFSAHlJKSIgZDAAAAAF9FDQAgCUMAAAAAX0UNACAEIAEpAgA3AgAgBCABKQIINwIIIAQgHUEBcjoAEEMAAAAAIQZDAAAAACEFQwAAgD8MAQsgDyAKIBeTIgWUIBAgCCAYkyIHlCARIBIgGZMiDpSSkiEWAkAgEyAFlCAUIAeUIBUgDpSSkiIHQwAAAABgRQ0AIAcgFmBFDQAgBCACKQIANwIAIAQgAikCCDcCCCAEIB1BAnI6ABBDAACAPyEGQwAAAAAhBUMAAAAADAELIAYgFpQgCSAHlJMhDgJAIAdDAAAAAF9FDQAgBkMAAAAAYEUNAEMAAAAAIQUgDkMAAAAAX0UNACAEQQA2AgwgBCAdQQNyOgAQIAQgCyATIAYgBiAHk5UiBpSSOAIIIAQgDSAVIAaUkjgCBCAEIAwgFCAGlJI4AgBDAACAPyAGkwwBCyATIAogGpMiBZQgFCAIIBuTIgiUIBUgEiAckyISlJKSIQoCQCAPIAWUIBAgCJQgESASlJKSIgVDAAAAAGBFDQAgBSAKYEUNACAEIAMpAgA3AgAgBCADKQIINwIIIAQgHUEEcjoAEEMAAIA/IQVDAAAAACEGQwAAAAAMAQsgCiAJlCAFIAaUkyEIAkAgBUMAAAAAX0UNACAJQwAAAABgRQ0AQwAAAAAhBiAIQwAAAABfRQ0AIARBADYCDCAEIB1BBXI6ABAgBCALIA8gCSAJIAWTlSIFlJI4AgggBCANIBEgBZSSOAIEIAQgDCAQIAWUkjgCAEMAAIA/IAWTDAELAkAgByAFlCAWIAqUkyIJQwAAAABfRQ0AIBYgB5MiBkMAAAAAYEUNACAKIAWTIgVDAAAAAGBFDQAgBEEANgIMIAQgHUEGcjoAECAEIBcgGiAXkyAGIAYgBZKVIgWUkjgCCCAEIBkgHCAZkyAFlJI4AgQgBCAYIBsgGJMgBZSSOAIAQwAAgD8gBZMhBkMAAAAADAELIARBADYCDCAEIB1BB3I6ABAgBCAPIA5DAACAPyAOIAkgCJKSlSIGlCIFlCALIBMgCCAGlCIGlJKSOAIIIAQgESAFlCANIBUgBpSSkjgCBCAEIBAgBZQgDCAUIAaUkpI4AgBDAACAPyAGkyAFkws4AhQgBEEANgIgIAQgBTgCHCAEIAY4AhgLMQEBfyMAQRBrIgEkACABIAA2AgwgASgCDCIAIAAoAgAoAiQRAQAhACABQRBqJAAgAAvABQIDfwl9IAAoAshIIgUEQCAFKAIwIgYEQCAGIAUoAiw2AiwLIAUoAiwiBgRAIAYgBSgCMDYCMAsgBSAAKALISEYEQCAAIAUoAjA2AshICyAAQczIAGoiBiAGKAIAQQFrNgIAIAVBADYCLCAFIAAoAsBINgIwIAAoAsBIIgYEQCAGIAU2AiwLIAAgBTYCwEggAEHEyABqIgYgBigCAEEBajYCACAFIAM2AhwgBSACNgIYIAUgATYCFCAFQQA6ADcgAioCGCELIAMqAhghDyABKgIYIQggAyoCFCEMIAEqAhQhCiACKgIUIQ0gAioCECEOIAMqAhAhECABKgIQIQkgBUEANgIMIAUgDiAJkyIOIAwgCpMiDJQgECAJkyIJIA0gCpMiDZSTIgo4AgggBSALIAiTIgsgCZQgDyAIkyIJIA6UkyIIOAIEIAUgDSAJlCAMIAuUkyIJOAIAQQIhBwJAIAogCpQgCSAJlCAIIAiUkpKRIghDF7fROF5FDQACQCAFIAEgAiAFQRBqIgYQ2QINACAFIAIgAyAGENkCDQAgBSADIAEgBhDZAg0AIAUgASoCGCAFKgIIlCABKgIQIAUqAgCUIAEqAhQgBSoCBJSSkiAIlTgCEAsgBUMAAIA/IAiVIgggBSoCAJQ4AgAgBSAIIAUqAgSUOAIEIAUgCCAFKgIIlDgCCCAEBEAgBQ8LQQMhByAGKgIAQ6zFJ7dgRQ0AIAUPCyAAIAc2AgAgBSgCMCIBBEAgASAFKAIsNgIsCyAFKAIsIgEEQCABIAUoAjA2AjALIAUgACgCwEhGBEAgACAFKAIwNgLASAsgACAAKALESEEBazYCxEggBUEANgIsIAUgACgCyEg2AjAgACgCyEgiAQRAIAEgBTYCLAsgACAFNgLISCAAIAAoAsxIQQFqNgLMSEEADwsgAEEFNgIAQQAL+icDD38YfQF+IwBBgARrIggkAAJAIAMgAygCACgCUBEBAEECRgRAIABBJEEcIAUbaiIGIAMoApgBIglBAWsiBzYCACAJRQ0BA0AgACABIAIgAygCoAEgB0ECdGooAgAgBCAFEK8BIAYgBigCACIJQQFrIgc2AgAgCQ0ACwwBCyADIAMoAgAoAlARAQAhByAEKAIEIQYCQCAHQQFHDQAgBkEcRw0AIwBBkAFrIgYkACAGIAEoAgwiBykCCDcDWCAGIAcpAgA3A1AgBiAHKQIYNwNoIAYgBykCEDcDYCAGIAcpAig3A3ggBiAHKQIgNwNwIAYgBykCODcDiAEgBiAHKQIwNwOAASACKAIMIgcqAjQhGSAHKgI4IRogByoCFCEYIAcqAhghGyAHKgIIIRwgByoCACEeIAcqAgQhHyAHKgIwISAgByoCECEhIAYgByoCKCAEKgI4IhWUIAcqAiAgBCoCMCIWlCAHKgIkIAQqAjQiF5SSkiIdOAJIIAYgGyAVlCAhIBaUIBggF5SSkiIYOAJEIAYgHCAVlCAeIBaUIB8gF5SSkiIbOAJAIAYgGiAVlCAgIBaUIBkgF5SSkiAEKgJAkiIWOAJMIAMgBkHQAGogBkEgaiAGQTBqIAMoAgAoAggRBAAgBiAEIAQoAgAoAjARBgAiFSAGKgI0kiIXOAI0IAYgFSAGKgI4kiIZOAI4IAYgBioCJCAVkyIcOAIkIAYgFSAGKgIwkiIaOAIwIAYgBioCICAVkyIeOAIgIAYgBioCKCAVkyIVOAIoAkAgFiAdIBUgGZJDAAAAP5QiFZQgGyAeIBqSQwAAAD+UIh6UIBwgF5JDAAAAP5QiHCAYlJKSIh8gGSAVkyAdi5QgGiAekyAbi5QgFyAckyAYi5SSkiIVkkO9N4Y1kl4NACAWQ703hjWSIB8gFZNgRQ0AIAMgAygCACgCcBEAACADIAMoAgAoAjARBgAhFSAEIAQoAgAoAjARBgAhFiADKAK4ASIHBEAgFSAWkiEbA0AgAygCtAEgB0EBayIHIAMoAsABbGohBAJ9IAMoArwBQQFGBEAgBCsDCCADKgKgAbuitiEVIAQrAwAgAyoCnAG7orYhFiAEKwMQIAMqAqQBu6K2DAELIAYgBCoCACADKgKcAZQiFjgCECAGIAQqAgQgAyoCoAGUIhU4AhQgBCoCCCADKgKkAZQLIRcgBkEANgIcIAYgFyAGKgJolCAWIAYqAmCUIBUgBioCZJSSkiAGKgKEAZIiGTgCFCAGKgJEIR0gBiAXIAYqAliUIBYgBioCUJQgFSAGKgJUlJKSIAYqAoABkiIaOAIQIAYqAkAhGCAGIBcgBioCeJQgFiAGKgJwlCAVIAYqAnSUkpIgBioCiAGSIhU4AhgCQCAVIAYqAkgiFpQgGiAYlCAZIB2UkpIgBioCTJMgG5MiFUMAAAAAXUUNACAFBEAgBkEANgIMIAYgFow4AgggBiAdjDgCBCAGIBiMOAIAIAAoAhAiBCAAKAIcIAAoAhggBCgCACgCCBEFACAAKAIQIgQgACgCJCAAKAIgIAQoAgAoAgwRBQAgACgCDCIERQRAIAAgACgCBCIEIAIoAgggASgCCCAEKAIAKAIMEQcAIgQ2AgwLIAAoAhAiCSAENgIEIAkgBiAGQRBqIBUgCSgCACgCEBEOAAwBCyAAKAIQIgQgACgCHCAAKAIYIAQoAgAoAggRBQAgACgCECIEIAAoAiQgACgCICAEKAIAKAIMEQUAIAAoAgwiBEUEQCAAIAAoAgQiBCABKAIIIAIoAgggBCgCACgCDBEHACIENgIMCyAAKAIQIgkgBDYCBCAJIAZBQGsgBkEQaiAVIAkoAgAoAhARDgALIAcNAAsLIAMgAygCACgCdBEAAAsgBkGQAWokAAwBCyAGQR9GBEAjAEHgAGsiBiQAIAQoAhAiCgRAIAIoAgwiByoCOCErIAcqAjQhLCAHKgIoIRUgByoCJCEWIAcqAhghFyAHKgIUIR0gByoCMCEqIAcqAiAhGCAHKgIQIRsgByoCCCEZIAcqAgQhGiAHKgIAIRwgACgCECEJA0AgBCgCGCAKQQFrIgpB0ABsaiIHKAJAIQsgByoCOCEeIAcqAjAhHyAHKgI0ISAgByoCICEhIAcqAgAhIiAHKgIQISMgByoCJCEkIAcqAgQhJSAHKgIUISYgByoCKCEnIAcqAgghKCAHKgIYISkgBkEANgJcIAZBADYCTCAGQQA2AjwgBkEANgIsIAYgJyAVlCAoIBiUIBYgKZSSkjgCSCAGICQgFZQgJSAYlCAWICaUkpI4AkQgBiAhIBWUICIgGJQgFiAjlJKSOAJAIAYgJyAXlCAoIBuUIB0gKZSSkjgCOCAGICQgF5QgJSAblCAdICaUkpI4AjQgBiAhIBeUICIgG5QgHSAjlJKSOAIwIAYgJyAZlCAoIByUIBogKZSSkjgCKCAGICQgGZQgJSAclCAaICaUkpI4AiQgBiAhIBmUICIgHJQgGiAjlJKSOAIgIAYgKyAeIBWUIB8gGJQgFiAglJKSkjgCWCAGICwgHiAXlCAfIBuUIB0gIJSSkpI4AlQgBiAqIB4gGZQgHyAclCAaICCUkpKSOAJQIAIoAgghByAGIAo2AhwgBkF/NgIYIAYgBzYCECAGIAs2AgwgBiACNgIIIAYgBkEgajYCFCAHIAkoAggiDCgCCEYEfyAJQQhqBSAJKAIMIQwgCUEMagsgBkEIaiIHNgIAIAAgASAHIAMgCyAFEK8BIAAoAhAiCUEIQQwgCSgCCCgCCCAGKAIQRhtqIAw2AgAgCg0ACwsgBkHgAGokAAwBCyAGQRVrQQhNBEAjAEGAAWsiBiQAIAYgBToAdCAGIAM2AnAgBiAANgJkIAZB0IgBNgJgIAYgATYCaCAGIAI2AmwgBiAEIAQoAgAoAjARBgA4AnggAigCDCIAKgI0IR4gACoCOCEfIAEoAgwiASoCNCEgIAEqAjghISAAKgIUIRUgACoCJCEWIAEqAhQhIiABKgIkISMgASoCGCEkIAAqAhghFyABKgIoISUgACoCKCEdIAEqAiAhJiAAKgIgIRggASoCACEnIAAqAgAhGyABKgIQISggACoCECEZIAAqAjAhKiABKgIwISkgACoCBCEaIAEqAgQhKyABKgIIISwgACoCCCEcIAZBADYCXCAGQQA2AkwgBkEANgI8IAYgJSAdlCAsIByUIBcgJJSSkjgCSCAGICMgHZQgKyAclCAXICKUkpI4AkQgBiAlIBaUICwgGpQgFSAklJKSOAI4IAYgIyAWlCArIBqUIBUgIpSSkjgCNCAGIBwgKowiKpQgFyAelJMgHSAflJMgISAdlCApIByUIBcgIJSSkpI4AlggBiAaICqUIBUgHpSTIBYgH5STICEgFpQgKSAalCAVICCUkpKSOAJUIAZBADYCLCAGICYgGJQgJyAblCAZICiUkpI4AiAgBiAmIB2UICcgHJQgFyAolJKSOAJAIAYgJiAWlCAnIBqUIBUgKJSSkjgCMCAGICUgGJQgLCAblCAZICSUkpI4AiggBiAjIBiUICsgG5QgGSAilJKSOAIkIAYgGyAqlCAZIB6UkyAYIB+UkyAhIBiUICkgG5QgGSAglJKSkjgCUCADIAZBIGogBkEQaiIAIAYgAygCACgCCBEEACAEIAZB4ABqIAAgBiAEKAIAKAJAEQQAIAZBgAFqJAAMAQsgCCABKAIMIgYpAgg3A8gDIAggBikCADcDwAMgCCAGKQIYNwPYAyAIIAYpAhA3A9ADIAggBikCKDcD6AMgCCAGKQIgNwPgAyAIIAYpAjg3A/gDIAggBikCMDcD8AMgCCACKAIMIgYpAgg3A4gDIAggBikCADcDgAMgCCAGKQIYNwOYAyAIIAYpAhA3A5ADIAggBikCKDcDqAMgCCAGKQIgNwOgAyAIIAYpAjg3A7gDIAggBikCMDcDsAMgCEEANgL0AiAIQQE6APgCIAhCADcC7AIgCEHAA2ohByAIQYADaiEJIAhB6AJqIQojAEHgAGsiBiQAAkAgAygCRARAIAcqAhQhFSAHKgIkIRYgByoCNCEeIAcqAhghFyAHKgI4IR8gByoCKCEdIAcqAiAhGCAHKgIAIRsgByoCECEZIAcqAgQhGiAHKgIIIRwgByoCMCEgIAZBADYCPCAGIBwgIIwiIJQgFyAelJMgHSAflJMgHSAJKgI4IiGUIBwgCSoCMCIilCAXIAkqAjQiI5SSkpI4AjggBiAaICCUIBUgHpSTIBYgH5STIBYgIZQgGiAilCAVICOUkpKSOAI0IAYgGyAglCAZIB6UkyAYIB+UkyAYICGUIBsgIpQgGSAjlJKSkjgCMCAJKgIUIR4gCSoCJCEfIAkqAhghICAJKgIoISEgCSoCICEiIAkqAgAhIyAJKgIQISQgCSoCBCElIAkqAgghJiAGQQA2AiwgBkEANgIcIAYgISAdlCAmIByUIBcgIJSSkjgCKCAGIB8gHZQgJSAclCAXIB6UkpI4AiQgBiAhIBaUICYgGpQgFSAglJKSOAIYIAYgHyAWlCAlIBqUIBUgHpSSkjgCFCAGQQA2AgwgBiAiIB2UICMgHJQgFyAklJKSOAIgIAYgIiAWlCAjIBqUIBUgJJSSkjgCECAGICEgGJQgJiAblCAZICCUkpI4AgggBiAfIBiUICUgG5QgGSAelJKSOAIEIAYgIiAYlCAjIBuUIBkgJJSSkjgCACAEIAYgBkFAayIHIAZB0ABqIAQoAgAoAggRBAAgA0HEAGogByAKEO8EDAELIAQgCSAGQUBrIAZB0ABqIAQoAgAoAggRBAAgAyADKAIAKAJYEQEAIg5FDQAgBkEQaiETA0AgAyAOQQFrIg4gByAGIBMgAygCACgCeBEJAAJAIAYqAkAgBioCEF4NACAGKgJQIAYqAgBdDQAgBioCRCAGKgIUXg0AIAYqAlQgBioCBF0NACAGKgJIIAYqAhheDQAgBioCWCAGKgIIXQ0AAkAgCigCBCIEIAooAghHDQAgBCAEQQF0QQEgBBsiD04NAAJAIA9FBEBBACELDAELQcSFAkHEhQIoAgBBAWo2AgAgD0ECdEEQQfjTASgCABECACELIAooAgQhBAsgCigCDCEJAkACQCAEQQBKBEBBACERQQAhDCAEQQFrQQNPBEAgBEF8cSEUQQAhEgNAIAsgDEECdCINaiAJIA1qKAIANgIAIAsgDUEEciIQaiAJIBBqKAIANgIAIAsgDUEIciIQaiAJIBBqKAIANgIAIAsgDUEMciINaiAJIA1qKAIANgIAIAxBBGohDCASQQRqIhIgFEcNAAsLIARBA3EiBEUNAQNAIAsgDEECdCINaiAJIA1qKAIANgIAIAxBAWohDCARQQFqIhEgBEcNAAsMAQsgCUUNAQsgCi0AEEEAIAkbBEBByIUCQciFAigCAEEBajYCACAJQfzTASgCABEAAAsgCigCBCEECyAKIAs2AgwgCkEBOgAQIAogDzYCCAsgCigCDCAEQQJ0aiAONgIAIAogCigCBEEBajYCBAsgDg0ACwsgBkHgAGokACAIKALsAgRAIAMgAygCACgCcBEAACAIQUBrQQRyEEoaIAhCADcCfCAIQQE2AkggCEIANwKEASAIQgA3AowBIAhCADcClAEgCEIANwKcASAIQgA3AqQBIAhBuA82AkQgCEGsAWoQ/gEgCEEENgKIAiAIQYSIATYC3AIgCEG0hwE2AtQCIAhB7IYBNgLMAiAIQYgjNgKsASAIIAM2AkAgCCADIAMoAgAoAmARAQAEfyAIQdQCagUgCEHcAmogCEHMAmogCCgCQCIEIAQoAgAoAmQRAQAbCyIENgLkAiAEIAhBQGs2AgQgAyADKAIAKAJcEQEAIQYCQCAIKALsAiIERQ0AIARBAWshBCAFBEADQCAAIAgoAvQCIAQiBUECdGooAgAiBDYCICAIKALkAiIHIAQgBygCACgCABECACEHIAYEQCAIIAMgBCADKAIAKAKEAREFAAsgACkCGCEtIAEoAgwhCSABKAIIIQQgCCAHNgIEIAggBDYCCCAIIAk2AgwgCCABNgIAIAggLUIgiTcDECAAKAIQIgdBCEEMIAQgBygCCCIHKAIIRhtqIAg2AgAgACACIAgQ4wIgACgCECAHNgIIIAVBAWshBCAFDQAMAgsACyAGBEADQCAAIAgoAvQCIAQiBUECdGooAgAiBDYCGCAIKALkAiIGIAQgBigCACgCABECACEGIAggAyAEIAMoAgAoAoQBEQUAIAApAhghLSABKAIMIQcgASgCCCEEIAggBjYCBCAIIAQ2AgggCCAHNgIMIAggATYCACAIIC1CIIk3AxAgACgCECIGQQhBDCAEIAYoAggiBigCCEYbaiAINgIAIAAgCCACEOMCIAAoAhAgBjYCCCAFQQFrIQQgBQ0ADAILAAsDQCAAIAgoAvQCIAQiBUECdGooAgAiBDYCGCAIKALkAiIGIAQgBigCACgCABECACEGIAApAhghLSABKAIMIQcgASgCCCEEIAggATYCACAIIAY2AgQgCCAENgIIIAggBzYCDCAIIC1CIIk3AxAgACgCECIGQQhBDCAEIAYoAggiBigCCEYbaiAINgIAIAAgCCACEOMCIAAoAhAgBjYCCCAFQQFrIQQgBQ0ACwsgAyADKAIAKAJ0EQAAIAhBrAFqECMaIAhBQGtBBHIQIxoLIAgoAvQCIgBFDQAgCC0A+AJFDQAgAARAQciFAkHIhQIoAgBBAWo2AgAgAEH80wEoAgARAAALCyAIQYAEaiQACwQAQQALJAEBfyMAQRBrIgIgADYCDCACIAE2AgggAigCDCACKAIINgIICxgBAX8jAEEQayIBIAA2AgwgASgCDCgCCAuuAwEJfwJAIAAoAgwiAkUNACAALQAIRQ0AAkAgASgCBCIDIAEoAghHDQAgAyADQQF0QQEgAxsiBk4NACAGBEBBxIUCQcSFAigCAEEBajYCACAGQQJ0QRBB+NMBKAIAEQIAIQUgASgCBCEDCwJAIANBAEwNAEEAIQIgA0EBa0EDTwRAIANBfHEhBwNAIAUgAkECdCIEaiABKAIMIARqKAIANgIAIAUgBEEEciIIaiABKAIMIAhqKAIANgIAIAUgBEEIciIIaiABKAIMIAhqKAIANgIAIAUgBEEMciIEaiABKAIMIARqKAIANgIAIAJBBGohAiAJQQRqIgkgB0cNAAsLIANBA3EiBEUNAANAIAUgAkECdCIHaiABKAIMIAdqKAIANgIAIAJBAWohAiAKQQFqIgogBEcNAAsLAkAgASgCDCICRQ0AIAEtABBFDQAgAgRAQciFAkHIhQIoAgBBAWo2AgAgAkH80wEoAgARAAALIAEoAgQhAwsgASAFNgIMIAFBAToAECABIAY2AgggACgCDCECCyABKAIMIANBAnRqIAI2AgAgASADQQFqNgIECwsqAQF/IwBBEGsiASQAIAEgADYCDCABKAIMIgAEQCAAEIMBCyABQRBqJAALxgEBBH8gASgCvAEiAwRAIAAoAkQiAiACKAIAKAIkEQEAIgIgAyAAKAIYIAIoAgAoAigRBQAgACgCRCICIAMgACgCGCACKAIAKAIMEQUAIAFBADYCvAELAkAgACgCCCICQQBMDQAgACgCECEEQQAhAwNAIAEgBCADQQJ0aiIFKAIARwRAIANBAWoiAyACRw0BDAILCyACIANMDQAgBSAEIAJBAWsiA0ECdCICaigCADYCACAAKAIQIAJqIAE2AgAgACADNgIICwvwAQAgAEIANwK8ASAAQoCAgICw7YKv3QA3ArQBIABCgICA/IOAgMA/NwKkASAAQYCAgPwDNgL0ASAAQgE3AuwBIABCADcC5AEgAEKAgICAgICAgD83AtwBIABC/////x83AtQBIABCgYCAgHA3AswBIABCADcC+AEgAEGAgID8AzYCBCAAQoCAgPwDNwKsASAAQfwzNgIAIABCADcCxAEgAEIANwKAAiAAQgA3AhAgAEIANwIIIABCADcCHCAAQYCAgPwDNgIYIABCADcCJCAAQgA3AjAgAEGAgID8AzYCLCAAQgA3AjggAEFAa0EANgIAC6YKAQx/AkAgAUUNACACRQ0AAkAgACgCGEH/AEoNACAAKAIcQf8ASg0AQcSFAkHEhQIoAgBBAWo2AgBBgAhBEEH40wEoAgARAgAhCAJAIAAoAhgiBkEATA0AIAZBAWtBA08EQCAGQXxxIQwDQCAIIAlBA3QiBWogACgCICAFaikCADcCACAIIAVBCHIiCmogACgCICAKaikCADcCACAIIAVBEHIiCmogACgCICAKaikCADcCACAIIAVBGHIiBWogACgCICAFaikCADcCACAJQQRqIQkgBEEEaiIEIAxHDQALCyAGQQNxIgRFDQADQCAIIAlBA3QiBWogACgCICAFaikCADcCACAJ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IABBADsBNCAGKAJMIgBBADYBACAGLwEGIQEgAEEAOwEGIAAgATsBBCAGQbApNgIAC3ABAn8jAEEQayIBJAAgASAANgIMIAEgASgCDCICEJgCOAIIIwBBEGsiACQAIAAgAjYCDCAAIAFBCGo2AgggACgCDCECIABDAACAPyAAKAIIKgIAlTgCBCACIABBBGoQ+wIaIABBEGokACABQRBqJAALVAEBfyMAQRBrIgEkACABIAA2AggjAEEQayIAIAEoAgg2AgwCQCAAKAIMKALsAUEERgRAIAEgASgCCDYCDAwBCyABQQA2AgwLIAFBEGokACABKAIMCzcBAX8jAEEQayIBJAAgASAANgIMIwBBEGsgASgCDCIANgIMIwBBEGsgAEEQajYCDCABQRBqJAALTAEBfyMAQRBrIgIkACACIAA2AgwgAiABOAIIIAIqAgghASMAQRBrIgAgAigCDDYCDCAAIAE4AgggACgCDCAAKgIIOAIIIAJBEGokAAtMAQF/IwBBEGsiAiQAIAIgADYCDCACIAE4AgggAioCCCEBIwBBEGsiACACKAIMNgIMIAAgATgCCCAAKAIMIAAqAgg4AgQgAkEQaiQAC1IBAn8jAEEQayIBJAAgASAANgIMIwBBEGsiACQAIAAgASgCDDYCDCAAKAIMKAJEIgIgAigCACgCJBEBACECIABBEGokACACIQAgAUEQaiQAIAALTAEBfyMAQRBrIgIkACACIAA2AgwgAiABOAIIIAIqAgghASMAQRBrIgAgAigCDDYCDCAAIAE4AgggACgCDCAAKgIIOAIAIAJBEGokAAs7AgF/AX0jAEEQayIBJAAgASAANgIMIwBBEGsiACABKAIMNgIMIAAoAgxBCGoqAgAhAiABQRBqJAAgAgv0BAEDfyMAQdAAayIDJAAgAyAANgJMIAMgATYCSCADIAI2AkQgAygCSCEEIAMoAkQhAiMAQTBrIgEkACABIANBEGoiBTYCLCABIAQ2AiggASACNgIkIAEgASgCJAJ/IwBBEGsiAiABKAIoNgIMIAJBADYCCCACKAIMIAIoAghBBHRqCxBzOAIgIAEgASgCJAJ/IwBBEGsiAiABKAIoNgIMIAJBADYCCCACKAIMIAIoAghBBHRqCxByOAIcIAEgASgCJAJ/IwBBEGsiAiABKAIoNgIMIAJBADYCCCACKAIM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IBMoAgRHDQACQCACKAJYIgEgACgCWCIDSg0AIAEgA0YgAigCXCAAKAJcSnENACAAIQILIBMgAjYCBAsgEygCACEJIBIoAgAhCwJAIBMoAgQiBygCWCASKAIEIgwoAlgiBGsiAUEASgRAIAchACAMIQIDQCAAIgMoAlwhBCABIQgDQAJAIAQgAigCXCIBayEQIAIoAgQiACACRg0AIAAoAlwgAWsiCkEASg0AIAAoAlgiASACKAJYIg1HBEAgASANayINQQBODQEgCCAKbCANIBBsSg0BCyADKAJYIAFrIQggACECDAELCyADKAIEIgAgA0YNAiAAKAJYIgogAigCWGsiAUEATA0CIAAoAlwgBGsiBEEATg0CIAogAygCWCINRg0AIAogDWsiCkEATg0CIAQgCGwgCiAQbEgNAAsMAQsgAUEASARAIAchAyAMIQADQCADKAJcIRAgAygCACEEA0AgASEIIBAgACICKAJcIg5rIQoCQCADIARGDQAgBCgCXCAQayIBQQBIDQAgBCgCWCIAIAMoAlgiDUcEQCAAIA1rIg1BAE4NASABIAhsIAogDWxKDQELIAAgAigCWGshASAEIQMgAiEADAILIAIoAgAiACACRg0DIAMoAlggACgCWCINayIBQQBODQMgACgCXCAOayIOQQBMDQMgDSACKAJYIhFGDQAgDSARayINQQBODQMgCCAObCAKIA1sSA0ACwsMAQsgDCgCXCEBIAwhAANAAkAgACICKAIEIgAgDEYNACAAKAJYIARHDQAgASAAKAJcIgFODQELCyAHKAJcIQEgByEAA0AgACIDKAIAIgAgB0YNASAAKAJYIARHDQEgASAAKAJcIgFMDQALCwJAIAsoAlgiECAJKAJYayIIQQBKBEAgCSEBIAshAANAIAEiBCgCXCEKIAghEANAAkAgCiAAKAJcIghrIQ0gACgCACIBIABGDQAgASgCXCAIayIOQQBKDQAgACgCWCIRIAEoAlgiCEcEQCARIAhrIhFBAE4NASAOIBBsIA0gEWxKDQELIAggBCgCWGshECABIQAMAQsLIAQoAgAiASAERg0CIAAoAlggASgCWCIOayIIQQBMDQIgASgCXCAKayIKQQBODQIgBCgCWCIRIA5GDQAgESAOayIOQQBODQIgCiAQbCANIA5sSA0ACwwBCyAIQQBIBEAgCSEE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AgARAAALCyACQQA2AjQgAkEBOgA4IAJCADcCLAJAIAIoAiAiAUUNACACLQAkRQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACwsgAkEANgIgIAJBAToAJCACQgA3AhgCQCACKAIMIgFFDQAgAi0AEEUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLQQAhASACQQA2AgwgAkEBOgAQIAJCADcCBCACBEBByIUCQciFAigCAEEBajYCACACQfzTASgCABEAAAsCQCAAQdgIaigCACIDQQBMDQAgACgC4AghBQNAIAIgBSABQQJ0aiIEKAIARwRAIAFBAWoiASADRw0BDAILCyABIANODQAgBCAFIANBAWsiBEECdCIBaigCADYCACAAKALgCCABaiACNgIAIAAgBDYC2AgLC4sEAgF/Dn0jAEFAaiIDJAAgAUEAOgBUIAMgACgCdCIAKQIMNwMIIAMgACkCBDcDACADIAApAhw3AxggAyAAKQIUNwMQIAMgACkCLDcDKCADIAApAiQ3AyAgAyAAKQI8NwM4IAMgACkCNDcDMAJAIAJFDQAgACgC4AMiAEUNACAAIAMgACgCACgCCBEDAAsgAyoCNCEQIAMqAhghByADKgIUIQggAyoCOCEEIAMqAighCSADKgIkIQogAyoCMCERIAMqAgghCyADKgIEIQwgAyoCACENIAMqAhAhDiADKgIgIQ8gAUEANgIwIAEgBCAJIAEqAqQBIgSUIA8gASoCnAEiBZQgCiABKgKgASIGlJKSkjgCLCABIBAgBCAHlCAFIA6UIAYgCJSSkpI4AiggASARIAQgC5QgBSANlCAGIAyUkpKSOAIkIAFBQGtBADYCACABIAkgASoCtAEiBJQgDyABKgKsASIFlCAKIAEqArABIgaUkpI4AjwgASAHIASUIA4gBZQgBiAIlJKSOAI4IAEgCyAElCANIAWUIAwgBpSSkjgCNCABKgLEASEEIAEqAsABIQUgASoCvAEhBiABQQA2AlAgASAJIASUIA8gBpQgCiAFlJKSOAJMIAEgByAElCAOIAaUIAggBZSSkjgCSCABIAsgBJQgDSAGlCAMIAWUkpI4AkQgA0FAayQAC+gHASZ9IAAgACgCkAEgAUGcAmxqIgAgAhDLAiAAQQA2AogBIABBADYC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hQIoAgBBAWo2AgAgA0H80wEoAgARAAALIAAgAjYCPCAAQQE6AEAgACABNgI4CyACIAdBAnRqQQAgASAHa0ECdBAJGgsgACABNgI0IAFBAEoEQCAAKAIoQf8BIAkQCRogACgCPEH/ASAJEAkaCyAIQQBMDQAgACgCPCEDIAAoAhAhBiAAKAIoIQJBACEEA0AgAyAEQQJ0aiACIAAoAgxBAWsgBiAEQQxsaiIBKAIEQRB0IAEoAgByIgEgAUEPdEF/c2oiAUEKdSABc0EJbCIBQQZ1IAFzIgEgAUELdEF/c2oiAUEQdSABc3FBAnRqIgEoAgA2AgAgASAENgIAIARBAWoiBCAIRw0ACwsL0AwBCH8gAEGc0AA2AgBBxIUCQcSFAigCAEEBajYCAEHoAkEQQfjTASgCABECACICQZfuxsYDNgK0AiACIAItAMwCQfABcToAzAIgACACNgIYIAEoAhQhAkHEhQJBxIUCKAIAQQFqNgIAQQRBEEH40wEoAgARAgAiBEH4jwFBmJEBIAIbQQhqNgIAIAAgBDYCHEHEhQJBxIUCKAIAQQFqNgIAQRhBEEH40wEoAgARAgAhAiAAKAIYIQQgACgCHCEDIAJCgICAgDA3AhAgAkEAOgAEIAIgBDYCDCACIAM2AgggAkG0xAA2AgAgACACNgIgQcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQZDRADYCACACQQA6AAQgACACNgIkQcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQYzSADYCACACQQA6AAQgACACNgIoQcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQejSADYCACACQQA6AAQgACACNgIsQcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQbjTADYCACACQQA6AAQgACACNgIwQcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQZDUADYCACACQQA6AAQgACACNgI0QcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQeTUADYCACACQQA6AAQgACACNgI4QcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQajVADYCACACQQA6AAQgACACNgI8QcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQfzVADYCACACQQA6AAQgACACNgJMQcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQfzVADYCACAAIAI2AlAgAkEBOgAEQcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQdDWADYCACACQQA6AAQgACACNgJIQcSFAkHEhQIoAgBBAWo2AgBBEEEQQfjTASgCABECACICQgE3AgggAkGc1wA2AgAgAkEAOgAEIAAgAjYCWEHEhQJBxIUCKAIAQQFqNgIAQRBBEEH40wEoAgARAgAiAkIBNwIIIAJBnNcANgIAIAAgAjYCVCACQQE6AAQgASgCECEGAkAgASgCACICBEAgACACNgIIIABBADoADAwBCyAAQQE6AAxBxIUCQcSFAigCAEEBajYCAEEUQRBB+NMBKAIAEQIAIgUgASgCCCICNgIEIAVBhAY2AgBBxIUCQcSFAigCAEEBajYCACAFIAJBhAZsQRBB+NMBKAIAEQIAIgI2AgwgBSACNgIQIAUgBSgCBCIINgIIAkAgCEEBayIERQ0AIAUoAgAhAyAEQQdxIgkEQANAIAIgAiADaiICNgIAIARBAWshBCAHQQFqIgcgCUcNAAsLIAhBAmtBB0kNAANAIAIgAiADaiICNgIAIAIgAiADaiICNgIAIAIgAiADaiICNgIAIAIgAiADaiICNgIAIAIgAiADaiICNgIAIAIgAiADaiICNgIAIAIgAiADaiICNgIAIAIgAiADaiICNgIAIARBCGsiBA0ACwsgAkEANgIAIAAgBTYCCAsgASgCBCICBEAgACACNgIQIABBADoAFA8LIABBAToAFEHEhQJBxIUCKAIAQQFqNgIAQRRBEEH40wEoAgARAgAiAyABKAIMIgE2AgQgAyAGQSQgBkEkShsiAkHQACACQdAASxsiAjYCAEHEhQJBxIUCKAIAQQFqNgIAIAMgASACbEEQQfjTASgCABECACICNgIMIAMgAjYCECADIAMoAgQiBTYCCAJAIAVBAWsiBEUNACADKAIAIQEgBEEHcSIGBEBBACEHA0AgAiABIAJqIgI2AgAgBEEBayEEIAdBAWoiByAGRw0ACwsgBUECa0EHSQ0AA0AgAiABIAJqIgI2AgAgAiABIAJqIgI2AgAgAiABIAJqIgI2AgAg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IAAqAoQBOAKQASABIAAqAogBOAKUASABIAAqAowBOAKYASABIAAqApABOAKcASABIAAqApQBOAKgASABIAAqApgBOAKkASABIAAqApwBOAKoASABIAAqAqABOAKsASABIAAqAqQBOAKwASABIAAqAqgBOAK0ASABIAAqAqwBOAK4ASABIAAqArABOAK8ASABIAAoArQBNgLgASAAKgK4ASEFIAFBADYCACABIAU4AsABIAIgACgCwAEgAigCACgCHBECACEDIAFBADYCCCABIAM2AgQgASAAKALMATYC5AEgASAAKALQATYC6AEgASAAKALUATYC7AEgASAAKALYATYC8AEgASAAKgLcATgCxAEgASAAKgLgATgCyAEgASAAKgLoATgCzAEgASAAKgLkATgC0AEgASAAKALsATYC9AEgASACIAIgACACKAIAKAIoEQIAIgMgAigCACgCHBECACIENgIMIAQEQCACIAMgAigCACgCMBEDAAsgASAAKgL0ATgC1AEgASAAKgL4ATgC2AEgASAAKgL8ATgC3AEgASAAKAKAAjYC+AFB3hsLBwAgACgCCAurAgEFfyAAQQA6ABwgAEEANgIYIABBADYCSCAAQQE6ABQgAEH0LjYCACAAQQA2AhAgAEEBOgAwIABCADcCCCAAQQA2AiwgAEEBOgBEIABCADcCJCAAQUBrQQA2AgAgAEIANwI4QcSFAkHEhQIoAgBBAWo2AgBBIEEQQfjTASgCABECACEDIAAoAggiBUEASgRAA0AgAyAEQQR0IgJqIgEgACgCECACaiICKAIANgIAIAEgAigCBDYCBCABIAIoAgg2AgggASACKAIMNgIMIARBAWoiBCAFRw0ACwsCQCAAKAIQIgFFDQAgAC0AFEUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIAAgAzYCECAAQQE6ABQgAEECNgIMIAAQuQULBABBAQtNAQF/QcyFAkEIEA0iADYCACAAQQAQABpB1IUCQgA3AgBB0IUCQYcTNgIAQdyFAkIANwIAQeSFAkIANwIAQeyFAkIANwIAQdCFAhDfAQsIACAAKAKIAQuZDAINfwZ9IwBBIGsiDiQAIAEEQAJAIAAoAiwiDEH/AEoNACAAKAIwQf8ATARAQcSFAkHEhQIoAgBBAWo2AgBBgARBEEH4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qwEBAX8jAEEgayIDJAAgAyAANgIcIANBADYCGCADIAE2AhQgAyACNgIQIAMoAhwhASADIAMoAhg2AgwDQCADKAIMIAMoAhRIBEAgAygCECADKAIMQQR0aiECIwBBEGsiAEEQNgIMIAAgAjYCCCAAKAIIIgAgASgCDCADKAIMQQR0aiICKQIANwIAIAAgAikCCDcCCCADIAMoAgxBAWo2AgwMAQsLIANBIGokAAugAQECfyMAQRBrIgIkACACIAA2AgggAiABNgIEIAIoAgghAQJAIAIoAgQEQCACKAIEIQMjAEEQayIAJAAgACABNgIMIAAgAzYCCCAAQQA2AgQgACgCCEECdCEBQcSFAkHEhQIoAgBBAWo2AgAgAUEQQfjTASgCABECACEBIABBEGokACACIAE2AgwMAQsgAkEANgIMCyACQRBqJAAgAigCDAuoAQEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIwBBEGsiASACKAIMIgA2AgwgASgCDCgCCCACKAIISARAIAIgACACKAIIEJ8DNgIEIwBBEGsiASAANgIMIAAgASgCDCgCBCACKAIEEJ0DIwBBEGsiASAANgIMIAAgASgCDCgCBBBNIAAQOiAAQQE6ABAgACACKAIENgIMIAAgAigCCDYCCAsgAkEQaiQAC8ECAQR/IwBBEGsiAiQAIAIgADYCDCACIAE2AggjAEEQayIBIAIoAgwiADYCDCABKAIMKAIIIAIoAghIBEAgAigCCCEDIwBBEGsiASQAIAEgADYCCCABIAM2AgQgASgCCCEEAkAgASgCBARAIAEoAgQhBSMAQRBrIgMkACADIAQ2AgwgAyAFNgIIIANBADYCBCADKAIIQQR0IQRBxIUCQcSFAigCAEEBajYCACAEQRBB+NMBKAIAEQIAIQQgA0EQaiQAIAEgBDYCDAwBCyABQQA2AgwLIAFBEGokACACIAEoAgw2AgQjAEEQayIBIAA2AgwgACABKAIMKAIEIAIoAgQQngMjAEEQayIBIAA2AgwgACABKAIMKAIEEE0gABA6IABBAToAECAAIAIoAgQ2AgwgACACKAIINgIICyACQRBqJAALqAEBAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCMAQRBrIgEgAigCDCIANgIMIAEoAgwoAgggAigCCEgEQCACIAAgAigCCBCf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DCADKAIUQcgAahBUIAAgAygCECADKAIUQdgAahBUIAMoAhQiASAAKgIEIAEoAgAoAiwRCAAgA0EgaiQAC9oBAQJ/IwBBMGsiASQAIAEgADYCLCMAQRBrIgIgASgCLCIANgIMIAIoAgxB/CY2AgAgAEGcJzYCACACIABBDGo2AgwgAEEANgIIIABBADYCHCAAQwrXIzw4AgQgAUMAAIA/OAIUIAFDAACAPzgCECABQwAAgD84AgwgAUEYaiABQRRqIAFBEGogAUEMahAGIAAgASkCGDcCDCAAIAEpAiA3AhQgAEEANgIgIABBADYCJCAAQQA2AiggAEEANgIwIABBADYCNCAAQQA2AjggAEEANgI8IAFBMGokAAs3AQF/IwBBEGsiASQAIAEgADYCDCMAQRBrIgAgASgCDDYCDCAAKAIMQZABaiEAIAFBEGokACAAC7kBAQR/IwBBEGsiAiQAIAIgADYCDCACIAE6AAsgAigCDCIAEK0CIABB2IkBNgIAIwBBEGsiASQAIAEgAEGQAWoiBDYCDCMAQRBrIgUgASgCDCIDNgIMIAUoAgxB/CY2AgAgA0H4JTYCACADQQA2AgQgAUEQaiQAIABBmAFqEFUgAEGsAWoQVSAAIAA2ApQBIwBBEGsiASAAQcQAajYCDCABIAQ2AgggASgCDCABKAIINgJIIAJBEGokAAtdAQN/IwBBEGsiASQAIAEgADYCCCABIAEoAggiADYCDCAAQTBqIQMgACECA0AjAEEQayACNgIMIAMgAkEQaiICRw0ACyAAQTBqECEaIABDCtcjPDgCQCABQRBqJAALuwEBAn8jAEEQayICJAAgAiAANgIMIwBBEGsiASACKAIMIgA2AgwgASgCDEP//39/OAIAIwBBEGsiASAANgIMIAEoAgxD//9/fzgCBCMAQRBrIgEgADYCDCABKAIMQ///f384AggjAEEQayIBIABBEGoiADYCDCABKAIMQ///f/84AgAjAEEQayIBIAA2AgwgASgCDEP//3//OAIEIwBBEGsiASAANgIMIAEoAgxD//9//zgCCCACQRBqJAAL9A4BAX8jAEEgayIFJAAgBSAANgIYIAUgATYCFCAFIAI2AhAgBSADNgIMIAUgBDgCCCAFIAUoAhgiADYCHCMAQRBrIgEgADYCDCABIABBEGo2AgwCfSABIAUoAhQ2AgwgASgCDCoCAAJ9IAEgBSgCEDYCDCABKAIMKgIAAn0gASAFKAIMNgIMIAEoAgwqAgALXgRAIwBBEGsiASAFKAIMNgIMIAEoAgwqAgAMAQsjAEEQayIBIAUoAhA2AgwgASgCDCoCAAteBEACfSMAQRBrIgEgBSgCEDYCDCABKAIMKgIAAn0gASAFKAIMNgIMIAEoAgwqAgALXgRAIwBBEGsiASAFKAIMNgIMIAEoAgwqAgAMAQsjAEEQayIBIAUoAhA2AgwgASgCDCoCAAsMAQsjAEEQayIBIAUoAhQ2AgwgASgCDCoCAAshBCMAQRBrIgEgADYCDCABKAIMIAQ4AgACfSABIAUoAhQ2AgwgASgCDCoCBAJ9IAEgBSgCEDYCDCABKAIMKgIEAn0gASAFKAIMNgIMIAEoAgwqAgQLXgRAIwBBEGsiASAFKAIMNgIMIAEoAgwqAgQMAQsjAEEQayIBIAUoAhA2AgwgASgCDCoCBAteBEACfSMAQRBrIgEgBSgCEDYCDCABKAIMKgIEAn0gASAFKAIMNgIMIAEoAgwqAgQLXgRAIwBBEGsiASAFKAIMNgIMIAEoAgwqAgQMAQsjAEEQayIBIAUoAhA2AgwgASgCDCoCBAsMAQsjAEEQayIBIAUoAhQ2AgwgASgCDCoCBAshBCMAQRBrIgEgADYCDCABKAIMIAQ4AgQCfSABIAUoAhQ2AgwgASgCDCoCCAJ9IAEgBSgCEDYCDCABKAIMKgIIAn0gASAFKAIMNgIMIAEoAgwqAggLXgRAIwBBEGsiASAFKAIMNgIMIAEoAgwqAggMAQsjAEEQayIBIAUoAhA2AgwgASgCDCoCCAteBEACfSMAQRBrIgEgBSgCEDYCDCABKAIMKgIIAn0gASAFKAIMNgIMIAEoAgwqAggLXgRAIwBBEGsiASAFKAIMNgIMIAEoAgwqAggMAQsjAEEQayIBIAUoAhA2AgwgASgCDCoCCAsMAQsjAEEQayIBIAUoAhQ2AgwgASgCDCoCCAshBCMAQRBrIgEgADYCDCABKAIMIAQ4AggCfSABIAUoAhQ2AgwgASgCDCoCAAJ9IAEgBSgCEDYCDCABKAIMKgIAAn0gASAFKAIMNgIMIAEoAgwqAgALXQRAIwBBEGsiASAFKAIMNgIMIAEoAgwqAgAMAQsjAEEQayIBIAUoAhA2AgwgASgCDCoCAAtdBEACfSMAQRBrIgEgBSgCEDYCDCABKAIMKgIAAn0gASAFKAIMNgIMIAEoAgwqAgALXQRAIwBBEGsiASAFKAIMNgIMIAEoAgwqAgAMAQsjAEEQayIBIAUoAhA2AgwgASgCDCoCAAsMAQsjAEEQayIBIAUoAhQ2AgwgASgCDCoCAAshBCMAQRBrIgEgAEEQajYCDCABKAIMIAQ4AgACfSABIAUoAhQ2AgwgASgCDCoCBAJ9IAEgBSgCEDYCDCABKAIMKgIEAn0gASAFKAIMNgIMIAEoAgwqAgQLXQRAIwBBEGsiASAFKAIMNgIMIAEoAgwqAgQMAQsjAEEQayIBIAUoAhA2AgwgASgCDCoCBAtdBEACfSMAQRBrIgEgBSgCEDYCDCABKAIMKgIEAn0gASAFKAIMNgIMIAEoAgwqAgQLXQRAIwBBEGsiASAFKAIMNgIMIAEoAgwqAgQMAQsjAEEQayIBIAUoAhA2AgwgASgCDCoCBAsMAQsjAEEQayIBIAUoAhQ2AgwgASgCDCoCBAshBCMAQRBrIgEgAEEQajYCDCABKAIMIAQ4AgQCfSABIAUoAhQ2AgwgASgCDCoCCAJ9IAEgBSgCEDYCDCABKAIMKgIIAn0gASAFKAIMNgIMIAEoAgwqAggLXQRAIwBBEGsiASAFKAIMNgIMIAEoAgwqAggMAQsjAEEQayIBIAUoAhA2AgwgASgCDCoCCAtdBEACfSMAQRBrIgEgBSgCEDYCDCABKAIMKgIIAn0gASAFKAIMNgIMIAEoAgwqAggLXQRAIwBBEGsiASAFKAIMNgIMIAEoAgwqAggMAQsjAEEQayIBIAUoAhA2AgwgASgCDCoCCAsMAQsjAEEQayIBIAUoAhQ2AgwgASgCDCoCCAshBCMAQRBrIgIiASAAQRBqIgM2AgwgASgCDCAEOAIIIAUqAgghBCACIgEgADYCDCABKAIMIgEgASoCACAEkzgCACAFKgIIIQQgAiIBIAA2AgwgASgCDCIBIAEqAgQgBJM4AgQgBSoCCCEEIAIiASAANgIMIAEoAgwiASABKgIIIASTOAIIIAUqAgghBCACIgEgAzYCDCABKAIMIgEgASoCACAEkjgCACAFKgIIIQQgAiIBIAM2AgwgASgCDCIBIAEqAgQgBJI4AgQgBSoCCCEEIAIiASADNgIMIAEoAgwiACAAKgIIIASSOAIIIAVBIGokAAskAQF/IwBBEGsiAiAANgIMIAIgATgCCCACKAIMIAIqAgg4AigLGAEBfyMAQRBrIgEgADYCDCABKAIMKgIoCzUBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIgEpAgA3AhggACABKQIINwIgCzUBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIgEpAgA3AgggACABKQIINwIQCzUBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIgEpAgA3AiAgACABKQIINwIoCxgBAX8jAEEQayIBIAA2AgwgASgCDEEgagsZAQF/IwBBEGsiASAANgIMIAEoAgxByABqCzUBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIgEpAgA3AjggACABKQIINwJACxgBAX8jAEEQayIBIAA2AgwgASgCDEE4ags1AQF/IwBBEGsiAiAANgIMIAIgATYCCCACKAIMIgAgAigCCCIBKQIANwJEIAAgASkCCDcCTAsZAQF/IwBBEGsiASAANgIMIAEoAgxBxABqCzUBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIgEpAgA3AjQgACABKQIINwI8CzUBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIgEpAgA3AiQgACABKQIINwIsCxgBAX8jAEEQayIBIAA2AgwgASgCDEEkags1AQF/IwBBEGsiAiAANgIMIAIgATYCCCACKAIMIgAgAigCCCIBKQIANwIUIAAgASkCCDcCHAtFAQF/IwBBEGsiASAANgIMIAEoAgwiAEGMDDYCACAAQwAAgD84AgQgAEEANgIIIABBATsBDCAAQf//AzsBDiAAQQA2AhALywIBB38jAEHgAGsiBCQAIAQgADYCXCAEIAE2AlggBCgCWCIIIQIjAEEQayIBJAAgASAEQShqIgc2AgwgASACNgIIIwBBEGsiBSABKAIIIgI2AgwgByAFKAIMAn8jAEEQayIGIAJBEGoiBTYCDCAGKAIMCwJ/IwBBEGsiAyACQSBqIgY2AgwgAygCDAsCfyMAQRBrIgMgAjYCDCADKAIMQQRqCwJ/IwBBEGsiAyAFNgIMIAMoAgxBBGoLAn8jAEEQ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Bn8gACABEPcCIABB2K0BNgIAQcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQbCuATYCACACQQA6AAQgACACNgJcQcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQYCvATYCACACQQA6AAQgACACNgJgQcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQYCvATYCACAAIAI2AmQgAkEBOgAEQcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQdCvATYCACACQQA6AAQgACACNgJoQcSFAkHEhQIoAgBBAWo2AgBBCEEQQfjTASgCABECACICQaSwATYCACAAIAI2AmwgAkEBOgAEAkAgAC0AFEUNACAAKAIQIgJFDQAgAigCAEGbAUoNACACKAIQIgIEQEHIhQJByIUCKAIAQQFqNgIAIAJB/NMBKAIAEQAACyAAKAIQIgIEQEHIhQJByIUCKAIAQQFqNgIAIAJB/NMBKAIAEQAAC0HEhQJBxIUCKAIAQQFqNgIAQRRBEEH40wEoAgARAgAiAyABKAIMIgE2AgQgA0GcATYCAEHEhQJBxIUCKAIAQQFqNgIAIAMgAUGcAWxBEEH40wEoAgARAgAiATYCDCADIAE2AhAgAyADKAIEIgU2AggCQCAFQQFrIgRFDQAgAygCACECIARBB3EiBgRAA0AgASABIAJqIgE2AgAgBEEBayEEIAdBAWoiByAGRw0ACwsgBUECa0EHSQ0AA0AgASABIAJqIgE2AgAgASABIAJqIgE2AgAgASABIAJqIgE2AgAgASABIAJqIgE2AgAgASABIAJqIgE2AgAgASABIAJqIgE2AgAgASABIAJqIgE2AgAgASABIAJqIgE2AgAgBEEIayIEDQALCyABQQA2AgAgACADNgIQCwuwAQICfwF9IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCCCEBIwBBEGsiACQAIAAgAigCDDYCDCAAIAE2AgggACgCDCEBIABBADYCBANAIAAoAgRBA0gEQCMAQRBrIgMgACgCCDYCDCADKAIMIAAoAgRBAnRqKgIAEOIBIQQgAUHkBmogACgCBEEGdGogBDgCBCAAIAAoAgRBAWo2AgQMAQsLIABBEGokACACQRBqJAALtwIBAX8CQCAAKAIMIgFF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IQEgCEEEaiIIIAdHDQALCyAGQQNxIgpFDQADQCACIAFBAnQiBmogAygCICAGaigCADYCACABQQFqIQEgBUEBaiIFIApHDQALCwJAIAMoAiAiAUUNACADLQAkRQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACwsgAyACNgIgIANBAToAJCADIAQ2AhwgACgCyAUiAUEATA0BIAMoAhghBUEAIQoDQCAAKALQBSAKQegAbGohCwJAIAQgBUcNACAEQQF0QQEgBBsiAiAETARAIAQhBQwBCwJAAn8gAkUEQEEAIQYgBAwBC0HEhQJBxIUCKAIAQQFqNgIAIAJBAnRBEEH40wEoAgARAgAhBiADKAIYCyIFQQBMDQBBACEHQQAhASAFQQFrQQNPBEAgBUF8cSEOQQAhCANAIAYgAUECdCIEaiADKAIgIARqKAIANgIAIAYgBEEEciINaiADKAIgIA1qKAIANgIAIAYgBEEIciINaiADKAIgIA1qKAIANgIAIAYgBEEMciIEaiADKAIgIARqKAIANgIAIAFBBGohASAIQQRqIgggDkcNAAsLIAVBA3EiBEUNAANAIAYgAUECdCIIaiADKAIgIAhqKAIANgIAIAFBAWohASAHQQFqIgcgBEcNAAsLAkAgAygCICIBRQ0AIAMtACRFDQAgAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALIAMoAhghBQsgAyAGNgIgIANBAToAJCADIAI2AhwgACgCyAUhASACIQQLIAMoAiAgBUECdGogCzYCACADIAVBAWoiBTYCGCAKQQFqIgogAUgNAAsMAQsgACgChAYiAQRAAkAgASAFTA0AIAEgAEHcCGooAgBKBEBBxIUCQcSFAigCAEEBajYCACABQQJ0QRBB+NMBKAIAEQIAIQICQCAAKALYCCIKQQBMDQBBACEHQQAhAyAKQQFrQQNPBEAgCkF8cSEGQQAhCQNAIAIgA0ECdCIEaiAAKALgCCAEaigCADYCACACIARBBHIiCGogACgC4AggCGooAgA2AgAgAiAEQQhyIghqIAAoAuAIIAhqKAIANgIAIAIgBEEMciIEaiAAKALgCCAEaigCADYCACADQQRqIQMgCUEEaiIJIAZHDQALCyAKQQNxIgRFDQADQCACIANBAnQiCmogACgC4Agg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KQIINwMQIAIgAykCADcDCCADIAEgBkGNzOUAbEHf5rvjA2oiBiAFcEE0bGoiASkCADcCACADIAEoAjA2AjAgAyABKQIoNwIoIAMgASkCIDcCICADIAEpAhg3AhggAyABKQIQNwIQIAMgASkCCDcCCCABIAIoAjg2AjAgASACKQMwNwIoIAEgAikDKDcCICABIAIpAyA3AhggASACKQMYNwIQIAEgAikDEDcCCCABIAIpAwg3AgAgBEEBaiIEIAVHDQALCyAAKALwBSIFQQBKBEBBACEEA0AgAiAAKAL4BSIBIARBLGxqIgNBKGooAgA2AjAgAiADKQIgNwMoIAIgAykCGDcDICACIAMpAhA3AxggAiADKQIINwMQIAIgAykCADcDCCADIAEgBkGNzOUAbEHf5rvjA2oiBiAFcEEsbGoiASkCADcCACADIAEoAig2AiggAyABKQIgNwIgIAMgASkCGDcCGCADIAEpAhA3AhAgAyABKQIINwIIIAEgAigCMDYCKCABIAIpAyg3AiAgASACKQMgNwIYIAEgAikDGDcCECABIAIpAxA3AgggASACKQMINwIAIARBAWoiBCAFRw0ACwsLrg4BAn8gAEHEowE2AgAgACgCwAEiAQRAIAEgASgCACgCBBEAAAsgAEHYCGooAgBBAEoEQANAIABBABDKAiAAKALYCEEASg0ACwsgACgC6AZBAEoEQEEAIQEDQCAAKALwBiABQQJ0aigCACICBEBByIUCQciFAigCAEEBajYCACACQfzTASgCABEAAAsgAUEBaiIBIAAoAugGSA0ACwsgACgC1AZBAEoEQEEAIQEDQCAAKALcBiABQQJ0aigCACICBEBByIUCQciFAigCAEEBajYCACACQfzTASgCABEAAAsgAUEBaiIBIAAoAtQGSA0ACwsCQCAAQdwJaigCACIBRQ0AIABB4AlqLQAARQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACwsgAEEANgLcCSAAQQE6AOAJIABB1AlqQgA3AgACQCAAQfQIaigCACIBRQ0AIABB+AhqLQAARQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACwsgAEEANgL0CCAAQQE6APgIIABB7AhqQgA3AgACQCAAQeAIaigCACIBRQ0AIABB5AhqLQAA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Awg3AhAgASADKQMQNwIYIAEqAggiByABKgI8lCABKgIAIgogASoCNJQgASoCBCIMIAEqAjiUkpIiBEPNzMy9YARAIAFBADYCkAJDAAAgQSEEDAILIAFDAACAvyAElSIEIAcgACgCdCIAKgLIAiIHIAEqAhQgACoCOJMiC5QgASoCECAAKgI0kyINIAAqAswCIg6UkyAAKgLAApKUIAogDiABKgIYIAAqAjyTIgqUIAsgACoC0AIiC5STIAAqArgCkpQgDCALIA2UIAogB5STIAAqArwCkpSSkpQ4ApACDAELIAEqAswBIQUgAUEANgKQAiABIAU4AiAgAUEANgIMIAEgASoCPIw4AgggASABKgI4jDgCBCABIAEqAjSMOAIAQwAAgL8hBUMAAIA/IQQLIAEgBDgCjAIgA0FAayQAIAULkAMBAX8gAEHEogE2AgACQCAAKAKQASIBRQ0AIAAtAJQBRQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACwsgAEEANgKQASAAQQE6AJQBIABCADcCiAECQCAAKAJMIgFFDQAgAC0AUEUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCTCAAQQE6AFAgAEIANwJEAkAgACgCOCIBRQ0AIAAtADxFDQAgAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALCyAAQQA2AjggAEEBOgA8IABCADcCMAJAIAAoAiQiAUUNACAALQAoRQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACwsgAEEANgIkIABBAToAKCAAQgA3AhwCQCAAKAIQIgFFDQAgAC0AFEUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCECAAQQE6ABQgAEIANwIIIAALPQEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIAAoAgAoAigRAgAhACACQRBqJAAgAAt/AQR/AkAgACgC6AMiAkEATA0AIAAoAvADIQQDQCABIAQgA0ECdGoiBSgCAEcEQCADQQFqIgMgAkcNAQwCCwsgAiADTA0AIAUgBCACQQFrIgJBAnQiA2ooAgA2AgAgACgC8AMgA2ogATYCACAAIAI2AugD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CigCHCgC0AEiBEEASARAIAooAiAoAtABIQQLIAdBAWohAiAEIA5IDQALCwJAIAZFBEADQCAIIAUiAkECdGooAgAiBigCHCgC0AEiBEEASARAIAYoAiAoAtABIQQLIAJBAWshBSAEIAlKDQAMAgsACyALKAIgKALQASEJA0AgCCAFIgJBAnRqKAIAIgYoAhwoAtABIgRBAEgEQCAGKAIgKALQASEECyACQQFrIQUgBCAJSg0ACwsCfyACIAdIBEAgAiEFIAcMAQsgDSAGNgIAIAAoAgwgAkECdGogCjYCACACQQFrIQUgB0EBagsiAiAFTARAIAAoAgwhCAwBCwsgBSAMSgRAIAAgASAMIAUQtQQLIAIgA0gNAAsLEQAgACABIAAoAgAoAkQRAwALEQAgACABIAAoAgAoAkARAwALLQACQCABRQ0AIAEoAuwBQQJxRQ0AIAAgASAAKAIAKAJcEQMADwsgACABELUBC0YBAX8jAEEQayIDJAAgAyAANgIMIAMgATYCCCADIAI2AgQgAygCDCIAIAMoAgggAygCBCAAKAIAKAKIAREFACADQRBqJAAL+RACD38TfUHQFxARIAAoAlQiAwRAIAAgASADEQgACyAAIAEgACgCACgCjAERCAAgAEEANgIgIAAgATgCHCAAIAAgACgCACgCFBEBADYCMCMAQdADayICJABB0BMQEUHVFRARIAAoArQCQQBKBEADQCAAKAIYIgMgACgCvAIgCEECdGooAgAgAygCACgCEBEDACAIQQFqIgggACgCtAJIDQALCwJAIAAoArwCIgNFDQAgAC0AwAJFDQAgAwRAQciFAkHIhQIoAgBBAWo2AgAgA0H80wEoAgARAAALCyAAQQA2ArwCIABBAToAwAIgAEIANwK0AhAQIAAoAugBQQBKBEAgAkFAayENQQAhCANAIAAoAvABIAhBAnRqKAIAIgRBgICA/AM2AvQBAkACQCAEKALYAUECaw4EAQAAAQALIAQtAMwBQQNxDQAgBCABIAJBkANqEOcBIAAtACxFDQAgBCoC/AEiESARlCIRQwAAAABbDQAgESACKgLIAyAEKgI8kyISIBKUIAIqAsADIAQqAjSTIhIgEpQgAioCxAMgBCoCOJMiEiASlJKSXUUNAEG7EhARIAQoAsABKAIEQRNMBEBBxP4BQcT+ASgCAEEBajYCACAAKAJEIgMgAygCACgCJBEBACEDIAAoAhghBSACQoCAgPyTgEA3ArQCIAIgBCkCPDcCxAIgAiAEKQI0NwK8AiACIAIpAsgDNwLUAiACIAIpAsADNwLMAiACQQA2AvwCIAJBuKEBNgKwAiACIAM2AogDIAIgBTYCjAMgAkEANgKEAyACIAQ2AoADIAQqAvgBIREgAkH4AWoiBSIDQiM3AgQgA0G87wA2AgAgA0GKro/pAzYCLCADQoCAgPwDNwIUIANCgICA/IOAgMA/NwIMIANBoO0ANgIAIAIgETgCpAIgAiAROAKUAiACQQg2AvwBIAJBhP4ANgL4ASACIAAqAjg4AoQDIAIgBCgCvAEiAy8BBDsBuAIgAiADLwEGOwG6AiACIAIpA5gDNwPAASACIAIpA5ADNwO4ASACIAIpAqgDNwLQASACIAIpAqADNwLIASACIAIpArgDNwLgASACIAIpArADNwLYASACIAIpAsgDNwLwASACIAIpAsADNwLoASACIARBBGoiAykCCDcDwAEgAiADKQIANwO4ASACIAQpAhw3AtABIAIgBCkCFDcCyAEgAiAEKQIsNwLgASACIAQpAiQ3AtgBIAAgBSADIAJBuAFqIAJBsAJqQwAAAAAQbSACKgK0AiIRQwAAgD9dBEAgESACKgLAAyAEKgI0k5QiEyACKgLcAoyUIBEgAioCxAMgBCoCOJOUIhQgAioC4AKUkyARIAIqAsgDIAQqAjyTlCIVIAIqAuQClJMhHyAAKAIYIgMgBCACKAL8AiADKAIAKAIMEQcAIQoCQCAAKAK0AiIFIAAoArgCRw0AIAUgBUEBdEEBIAUbIgtODQACQCALRQRAQQAhBwwBC0HEhQJBxIUCKAIAQQFqNgIAIAtBAnRBEEH40wEoAgARAgAhByAAKAK0AiEFCwJAIAVBAEwNAEEAIQ5BACEDIAVBAWtBA08EQCAFQXxxIRBBACEJA0AgByADQQJ0IgZqIAAoArwCIAZqKAIANgIAIAcgBkEEciIMaiAAKAK8AiAMaigCADYCACAHIAZBCHIiDGogACgCvAIgDGooAgA2AgAgByAGQQxyIgZqIAAoArwCIAZqKAIANgIAIANBBGohAyAJQQRqIgkgEEcNAAsLIAVBA3EiBkUNAANAIAcgA0ECdCIJaiAAKAK8AiAJaigCADYCACADQQFqIQMgDkEBaiIOIAZHDQALCwJAIAAoArwCIgNFDQAgAC0AwAJFDQAgAwRAQciFAkHIhQIoAgBBAWo2AgAgA0H80wEoAgARAAALIAAoArQCIQULIAAgBzYCvAIgAEEBOgDAAiAAIAs2ArgCCyAAKAK8AiAFQQJ0aiAKNgIAIAAgBUEBajYCtAIgAigC/AIiAyoCFCEXIAMqAiQhGCADKgIoIRkgAyoCCCEaIAMqAhghGyADKgI8IREgAyoCNCEgIAMqAjghEiADKgIsIRwgAyoCDCEWIAMqAhwhHSADKgIEIR4gBCoCPCEhIAQqAjQhIiAEKgI4ISMgAkIANwMIIAJBADYCHCACQgA3AwAgAiAcIBUgIZIiFZQgFiATICKSIhOUIB0gFCAjkiIUlJKSIBYgIIwiFpQgHSASlJMgHCARlJOSOAIYIAIgFSAZlCATIBqUIBQgG5SSkiAaIBaUIBsgEpSTIBkgEZSTkjgCFCACIBUgGJQgEyAelCAUIBeUkpIgHiAWlCAXIBKUkyAYIBGUk5I4AhAgDSACKQLcAjcCACANIAIpAuQCNwIIIAJBADoAdCACQQA2AnAgAkEANgJcIAJCADcCVCACIB84AlAgAkIANwKQASACQgA3AogBIAJCADcCgAEgAkIANwJ4IAogCiACEOEEQbgBbGoiA0EANgJgIAMgBCoC4AEgAigC/AIqAuABlEMAACDBl0MAACBBljgCWCADIAQpAjQ3AjQgAyAEKQI8NwI8IANBADYCMCADIBU4AiwgAyAUOAIoIAMgEzgCJAsLEBALIAhBAWoiCCAAKALoAUgNAAsLEBAgAkHQA2okACAAIAAoAgAoAiwRAAAgACAAKAIAKAKUAREAACAAIAE4AmggACAAQdwAaiAAKAIAKAKYAREDACAAIAEgACgCACgCkAERCABBuhQQESAAKAKYAkEASgRAA0AgACgCoAIgD0ECdGooAgAiAyAAIAEgAygCACgCCBENACAPQQFqIg8gACgCmAJIDQALCxAQIAAgASAAKAIAKAKcAREIACAAKAJQIgMEQCAAIAEgAxEIAAsQEAupOgILfxl9QfwYEBEgABCxBQJAIAAgACgCACgCFBEBAEUNACAAIAAoAgAoAhQRAQAiBiAGKAIAKAIwEQEAQYAwcUUNACAAIAAoAgAoAmgRAQAiBkEATA0AA0AgACAGQQFrIgogACgCACgCbBECACECIwBB4AFrIgEkACAAIAAoAgAoAhQRAQAiAyADKAIAKAIwEQEAIQMgACAAKAIAKAIUEQEAIgQgBCgCACgCMBEBACEFAkAgAioCKCIcQwAAAABfDQAgA0GAEHEhBCAFQYAgcSEFAkACQAJAAkACQCACKAIEQQNrDgcAAQIDBAUDBQsgAUIANwKsASABQgA3A7gBIAFBgICA/AM2ArQBIAFCADcDwAEgAUKAgID8AzcDyAEgAUIANwKkASABQYCAgPwDNgKgASACKAIcIgMqAjQhDyADKgIIIRAgAyoCDCERIAMqAjghEiADKgIcIRMgAyoCFCEUIAMqAhghGCADKgI8IRUgAioCtAIhDCADKgIsIRYgAioCrAIhDSADKgIkIRcgAioCsAIhDiADKgIoIRkgAyoCBCEaIAFBADYC3AEgASAVIAwgFpQgDSAXlCAOIBmUkpKSOALYASABIBIgDCATlCANIBSUIA4gGJSSkpI4AtQBIAEgDyAMIBGUIA0gGpQgDiAQlJKSkjgC0AEgACAAKAIAKAIUEQEAIgMgAUGgAWogHCADKAIAKAI4EQ0AIAIoAiAiAyoCNCEPIAMqAgghECADKgIMIREgAyoCOCESIAMqAhwhEyADKgIUIRQgAyoCGCEYIAMqAjwhFSACKgLEAiEMIAMqAiwhFiACKgK8AiENIAMqAiQhFyACKgLAAiEOIAMqAighGSADKgIEIRogAUEANgLcASABIBUgDCAWlCANIBeUIA4gGZSSkpI4AtgBIAEgEiAMIBOUIA0gFJQgDiAYlJKSkjgC1AEgASAPIAwgEZQgDSAalCAOIBCUkpKSOALQASAERQ0EIAAgACgCACgCFBEBACICIAFBoAFqIBwgAigCACgCOBENAAwECyACKAIcIgMqAjQhIiADKgIIIQwgAyoCDCENIAIqAsgEIRggAioCqAQhFSACKgK4BCEWIAMqAjghIyADKgI8ISQgAioC4AQhFyACKgLYBCEZIAIqAtwEIRogAyoCHCEOIAMqAhQhDyADKgIYIRAgAioCzAQhGyACKgKsBCEdIAIqArwEIR4gAioC0AQhHyADKgIsIREgAioCsAQhICADKgIkIRIgAioCwAQhISADKgIoIRMgAyoCBCEUIAFBADYC3AEgAUEANgLMASABQQA2ArwBIAEgHyARlCAgIBKUICEgE5SSkjgCyAEgASAbIBGUIB0gEpQgHiATlJKSOALEASABIB8gDpQgICAPlCAhIBCUkpI4ArgBIAEgGyAOlCAdIA+UIB4gEJSSkjgCtAEgASAkIBcgEZQgGSASlCATIBqUkpKSOALYASABICMgFyAOlCAZIA+UIBAgGpSSkpI4AtQBIAFBADYCrAEgASAYIBGUIBUgEpQgFiATlJKSOALAASABIBggDpQgFSAPlCAWIBCUkpI4ArABIAEgHyANlCAgIBSUIAwgIZSSkjgCqAEgASAbIA2UIB0gFJQgDCAelJKSOAKkASABIBggDZQgFSAUlCAWIAyUkpI4AqABIAEgIiAXIA2UIBkgFJQgDCAalJKSkjgC0AECQCAEBEAgACAAKAIAKAIUEQEAIgMgAUGgAWoiBCAcIAMoAgAoAjgRDQAgAigCICIDKgI0ISIgAyoCOCEjIAMqAjwhJCACKgKgBSEYIAIqApgFIRUgAioCnAUhFiADKgIIIQwgAyoCDCENIAMqAhwhDiADKgIUIQ8gAyoCGCEQIAIqAogFIRcgAioC6AQhGSACKgL4BCEaIAIqAowFIRsgAioC7AQhHSACKgL8BCEeIAIqApAFIR8gAyoCLCERIAIqAvAEISAgAyoCJCESIAIqAoAFISEgAyoCKCETIAMqAgQhFCABQQA2AtwBIAFBADYCzAEgAUEANgK8ASABQQA2AqwBIAEgHyARlCAgIBKUICEgE5SSkjgCyAEgASAbIBGUIB0gEpQgHiATlJKSOALEASABIBcgEZQgGSASlCAaIBOUkpI4AsABIAEgHyAOlCAgIA+UICEgEJSSkjgCuAEgASAbIA6UIB0gD5QgHiAQlJKSOAK0ASABIBcgDpQgGSAPlCAaIBCUkpI4ArABIAEgHyANlCAgIBSUIAwgIZSSkjgCqAEgASAbIA2UIB0gFJQgDCAelJKSOAKkASABIBcgDZQgGSAUlCAaIAyUkpI4AqABIAEgJCAYIBGUIBUgEpQgEyAWlJKSkjgC2AEgASAjIBggDpQgFSAPlCAQIBaUkpKSOALUASABICIgGCANlCAVIBSUIAwgFpSSkpI4AtABIAAgACgCACgCFBEBACIDIAQgHCADKAIAKAI4EQ0ADAELIAIoAiAiAyoCNCEiIAMqAjghIyADKgI8ISQgAioCoAUhGCACKgKYBSEVIAIqApwFIRYgAyoCCCEMIAMqAgwhDSADKgIcIQ4gAyoCFCEPIAMqAhghECACKgKIBSEXIAIqAugEIRkgAioC+AQhGiACKgKMBSEbIAIqAuwEIR0gAioC/AQhHiACKgKQBSEfIAMqAiwhESACKgLwBCEgIAMqAiQhEiACKgKABSEhIAMqAighEyADKgIEIRQgAUEANgLcASABQQA2AswBIAFBADYCvAEgAUEANgKsASABIB8gEZQgICASlCAhIBOUkpI4AsgBIAEgGyARlCAdIBKUIB4gE5SSkjgCxAEgASAXIBGUIBkgEpQgGiATlJKSOALAASABIB8gDpQgICAPlCAhIBCUkpI4ArgBIAEgGyAOlCAdIA+UIB4gEJSSkjgCtAEgASAXIA6UIBkgD5QgGiAQlJKSOAKwASABIB8gDZQgICAUlCAMICGUkpI4AqgBIAEgGyANlCAdIBSUIAwgHpSSkjgCpAEgASAXIA2UIBkgFJQgGiAMlJKSOAKgASABICQgGCARlCAVIBKUIBMgFpSSkpI4AtgBIAEgIyAYIA6UIBUgD5QgECAWlJKSkjgC1AEgASAiIBggDZQgFSAUlCAMIBaUkpKSOALQAQsgAkGwBWoiAhDqASIMIAIQ6wEiDVsNAyAFRQ0DIAEgASoCqAE4AkAgASABKgK4ATgCRCABQQA2AkwgASABKgLIATgCSCABIAEqAqABOAKQASABIAEqArABOAKUASABQQA2ApwBIAEgASoCwAE4ApgBIAAgACgCACgCFBEBACECIAFCADcDiAEgAUIANwOAASACIAFB0AFqIAFBQGsgAUGQAWogHCAcQwAAAAAgDCAMIA1eIgMbQ9sPyUAgDSADGyABQYABaiADRUMAACBBIAIoAgAoAjwRGQAMAwsgAigCHCIDKgI0ISIgAyoCCCEMIAMqAgwhDSACKgLMAiEYIAJBrAJqIgcqAgAhFSACKgK8AiEWIAMqAjghIyADKgI8ISQgAioC5AIhFyACKgLcAiEZIAIqAuACIRogAyoCHCEOIAMqAhQhDyADKgIYIRAgAioC0AIhGyACKgKwAiEdIAIqAsACIR4gAioC1AIhHyADKgIsIREgAioCtAIhICADKgIkIRIgAioCxAIhISADKgIoIRMgAyoCBCEUIAFBADYC3AEgAUEANgLMASABQQA2ArwBIAEgHyARlCAgIBKUICEgE5SSkjgCyAEgASAbIBGUIB0gEpQgHiATlJKSOALEASABIB8gDpQgICAPlCAhIBCUkpI4ArgBIAEgGyAOlCAdIA+UIB4gEJSSkjgCtAEgASAkIBcgEZQgGSASlCATIBqUkpKSOALYASABICMgFyAOlCAZIA+UIBAgGpSSkpI4AtQBIAFBADYCrAEgASAYIBGUIBUgEpQgFiATlJKSOALAASABIBggDpQgFSAPlCAWIBCUkpI4ArABIAEgHyANlCAgIBSUIAwgIZSSkjgCqAEgASAbIA2UIB0gFJQgDCAelJKSOAKkASABIBggDZQgFSAUlCAWIAyUkpI4AqABIAEgIiAXIA2UIBkgFJQgDCAalJKSkjgC0AECQCAEBEAgACAAKAIAKAIUEQEAIgMgAUGgAWoiBCAcIAMoAgAoAjgRDQAgAigCICIDKgI0ISIgAyoCOCEjIAMqAjwhJCACKgKkAyEYIAIqApwDIRUgAioCoAMhFiADKgIIIQwgAyoCDCENIAMqAhwhDiADKgIUIQ8gAyoCGCEQIAIqAowDIRcgAioC7AIhGSACKgL8AiEaIAIqApADIRsgAioC8AIhHSACKgKAAyEeIAIqApQDIR8gAyoCLCERIAIqAvQCISAgAyoCJCESIAIqAoQDISEgAyoCKCETIAMqAgQhFCABQQA2AtwBIAFBADYCzAEgAUEANgK8ASABQQA2AqwBIAEgHyARlCAgIBKUICEgE5SSkjgCyAEgASAbIBGUIB0gEpQgHiATlJKSOALEASABIBcgEZQgGSASlCAaIBOUkpI4AsABIAEgHyAOlCAgIA+UICEgEJSSkjgCuAEgASAbIA6UIB0gD5QgHiAQlJKSOAK0ASABIBcgDpQgGSAPlCAaIBCUkpI4ArABIAEgHyANlCAgIBSUIAwgIZSSkjgCqAEgASAbIA2UIB0gFJQgDCAelJKSOAKkASABIBcgDZQgGSAUlCAaIAyUkpI4AqABIAEgJCAYIBGUIBUgEpQgEyAWlJKSkjgC2AEgASAjIBggDpQgFSAPlCAQIBaUkpKSOALUASABICIgGCANlCAVIBSUIAwgFpSSkpI4AtABIAAgACgCACgCFBEBACIDIAQgHCADKAIAKAI4EQ0ADAELIAIoAiAiAyoCNCEiIAMqAjghIyADKgI8ISQgAioCpAMhGCACKgKcAyEVIAIqAqADIRYgAyoCCCEMIAMqAgwhDSADKgIcIQ4gAyoCFCEPIAMqAhghECACKgKMAyEXIAIqAuwCIRkgAioC/AIhGiACKgKQAyEbIAIqAvACIR0gAioCgAMhHiACKgKUAyEfIAMqAiwhESACKgL0AiEgIAMqAiQhEiACKgKEAyEhIAMqAighEyADKgIEIRQgAUEANgLcASABQQA2AswBIAFBADYCvAEgAUEANgKsASABIB8gEZQgICASlCAhIBOUkpI4AsgBIAEgGyARlCAdIBKUIB4gE5SSkjgCxAEgASAXIBGUIBkgEpQgGiATlJKSOALAASABIB8gDpQgICAPlCAhIBCUkpI4ArgBIAEgGyAOlCAdIA+UIB4gEJSSkjgCtAEgASAXIA6UIBkgD5QgGiAQlJKSOAKwASABIB8gDZQgICAUlCAMICGUkpI4AqgBIAEgGyANlCAdIBSUIAwgHpSSkjgCpAEgASAXIA2UIBkgFJQgGiAMlJKSOAKgASABICQgGCARlCAVIBKUIBMgFpSSkpI4AtgBIAEgIyAYIA6UIBUgD5QgECAWlJKSkjgC1AEgASAiIBggDZQgFSAUlCAMIBaUkpKSOALQAQsgBUUNAiABQZABaiACQ1vHwkAgHBDTBCABQQA2ApwBIAEgASoCmAEiDCABKgLIAZQgASoCkAEiDSABKgLAAZQgASoClAEiDiABKgLEAZSSkiABKgLYAZI4ApgBIAEgDCABKgK4AZQgDSABKgKwAZQgDiABKgK0AZSSkiABKgLUAZI4ApQBIAEgDCABKgKoAZQgDSABKgKgAZQgDiABKgKkAZSSkiABKgLQAZI4ApABIAFB0AFqIQNBACEEA0AgAUFAayIIIAIgBLJD2g/JQJRDAAAAPZQgHBDTBCABQQA2AkwgASABKgJIIgwgASoCyAGUIAEqAkAiDSABKgLAAZQgASoCRCIOIAEqAsQBlJKSIAEqAtgBkjgCSCABIAwgASoCuAGUIA0gASoCsAGUIA4gASoCtAGUkpIgASoC1AGSOAJEIAEgDCABKgKoAZQgDSABKgKgAZQgDiABKgKkAZSSkiABKgLQAZI4AkAgACAAKAIAKAIUEQEAIQUgAUIANwOIASABQgA3A4ABIAUgAUGQAWogCCABQYABaiAFKAIAKAIIEQQAIARBA3FFBEAgACAAKAIAKAIUEQEAIQUgAUIANwOIASABQgA3A4ABIAUgAyABQUBrIAFBgAFqIAUoAgAoAggRBAALIAEgASkDSDcDmAEgASABKQNANwOQASAEQQFqIgRBIEcNAAsgAioCgAQhDCACKgLEAyENAkAgAigCICIEKgLYAkMAAAAAXgRAIAFBQGsgBEEEaiACQewCahDJAQwBCyABQUBrIAIoAhxBBGogBxDJAQsgASABKQNINwOoASABIAEpA1g3A7gBIAEgASkDaDcDyAEgASABKQNANwOgASABIAEpA1A3A7ABIAEgASkDYDcDwAEgAyABKQN4NwIIIAMgASkDcDcCACABIAMpAgg3A0ggASADKQIANwNAIAEgASoCoAE4AoABIAEgASoCsAE4AoQBIAFBADYCjAEgASABKgLAATgCiAEgASABKgKkATgCMCABIAEqArQBOAI0IAFBADYCPCABIAEqAsQBOAI4IAAgACgCACgCFBEBACECIAFCADcDKCABQgA3AyAgAiABQUBrIAFBgAFqIAFBMGogHCAcIAyMIA2TIA0gDJMgAUEgakEBQwAAIEEgAigCACgCPBEZAAwCCyABIAJBsAhqKQIANwOoASABIAJBqAhqIgMpAgA3A6ABIAEgAkHACGopAgA3A7gBIAEgAkG4CGoiBykCADcDsAEgASACQdAIaikCADcDyAEgASACQcgIaiIIKQIANwPAASABIAJB4AhqKQIANwPYASABIAJB2AhqIgkpAgA3A9ABIAQEQCAAIAAoAgAoAhQRAQAiBCABQaABaiILIBwgBCgCACgCOBENACABIAJB8AhqKQIANwOoASABIAJB6AhqKQIANwOgASABIAJBgAlqKQIANwK4ASABIAJB+AhqKQIANwKwASABIAJBkAlqKQIANwLIASABIAJBiAlqKQIANwLAASABIAJBoAlqKQIANwLYASABIAJBmAlqKQIANwLQASAAIAAoAgAoAhQRAQAiBCALIBwgBCgCACgCOBENAAsgBUUNASABIAMpAgg3A6gBIAEgAykCADcDoAEgASAHKQIINwK4ASABIAcpAgA3ArABIAEgCCkCCDcCyAEgASAIKQIANwLAASABIAkpAgg3AtgBIAEgCSkCADcC0AEgASABKgKoATgCQCABIAEqArgBOAJEIAFBADYCTCABIAEqAsgBOAJIIAEgASoCoAE4ApABIAEgASoCsAE4ApQBIAFBADYCnAEgASABKgLAATgCmAEgAioC6AchDCACKgLkByENIAIqAqgHIQ4gAioCpAchDyAAIAAoAgAoAhQRAQAhBSABQgA3A4gBIAFCADcDgAEgBSACQZgJaiIEIAFBQGsgAUGQAWogHENmZmY/lCAPIA4gDSAMIAFBgAFqQwAAIEFBASAFKAIAKAJAESEAIAFBADYCnAEgASABKgLEATgCmAEgASABKgK0ATgClAEgASABKgKkATgCkAEgAkGsCWoqAgAhDyABKgKQASEMIAJBsAlqKgIAIg4QGSENIAEgASoClAEiECAOEBoiEZQgDSAMlJM4AoQBIA8QGSEOIAEgASoCmAEiEiAPEBoiD5QgDCAOIBGUlCAQIA4gDZSUkpI4AogBIAEgDCAPIBGUlCAQIA8gDZSUkiAOIBKUkzgCgAEgASACQfAIaikCADcDqAEgASACQegIaikCADcDoAEgASACQYAJaikCADcCuAEgASACQfgIaikCADcCsAEgASACQZAJaikCADcCyAEgASACQYgJaikCADcCwAEgASAEKQIANwLQASABIAJBoAlqKQIANwLYASABQQA2AjwgASABKgLAAYw4AjggASABKgKwAYw4AjQgASABKgKgAYw4AjACQCACKgLkBiIMIAIqAugGIg1eBEAgACAAKAIAKAIUEQEAIQUgAUIANwMoIAFCADcDICAFIAQgAUEwaiABQYABaiAcIBxD2w9JwEPbD0lAIAFBIGpBAEMAACBBIAUoAgAoAjwRGQAMAQsgDCANXUUNACAAIAAoAgAoAhQRAQAhBSABQgA3AyggAUIANwMgIAUgBCABQTBqIAFBgAFqIBwgHCAMIA0gAUEgakEBQwAAIEEgBSgCACgCPBEZAAsgASADKQIINwOoASABIAMpAgA3A6ABIAEgBykCCDcCuAEgASAHKQIANwKwASABIAgpAgg3AsgBIAEgCCkCADcCwAEgASAJKQIINwLYASABIAkpAgA3AtABIAEgAikCsAU3AyggASACKQKoBTcDICABIAIpAsAFNwMYIAEgAikCuAU3AxAgACAAKAIAKAIUEQEAIQIgAUIANwMIIAFCADcDACACIAFBIGogAUEQaiABQaABaiABIAIoAgAoAkgRCQAMAQsgASACKQLABjcDqAEgASACQbgGaiIDKQIANwOgASABIAIpAtAGNwO4ASABIAIpAsgGNwOwASABIAIpAuAGNwPIASABIAIpAtgGNwPAASABIAIpAvAGNwPYASABIAIpAugGNwPQAQJAIAQEQCAAIAAoAgAoAhQRAQAiBCABQaABaiIHIBwgBCgCACgCOBENACABIAIpAoAHNwOoASABIAIpAvgGNwOgASABIAIpApAHNwK4ASABIAIpAogHNwKwASABIAIpAqAHNwLIASABIAIpApgHNwLAASABIAIpArAHNwLYASABIAIpAqgHNwLQASAAIAAoAgAoAhQRAQAiBCAHIBwgBCgCACgCOBENAAwBCyABIAIpAoAHNwOoASABIAIpAvgGNwOgASABIAIpApAHNwK4ASABIAIpAogHNwKwASABIAIpAqAHNwLIASABIAIpApgHNwLAASABIAIpArAHNwLYASABIAIpAqgHNwLQAQsgBUUNACADIAJB+AZqIAItALQBGyIDKgIwIRAgAyoCCCEVIAMqAgAhDCADKgIEIREgAyoCNCESIAMqAhghFiADKgIQIQ0gAyoCFCETIAMqAjghFCADKgIoIRcgAyoCICEOIAMqAiQhGCACKgK4ASEPIAFBADYCTCABIBQgF0MAAAAAlCIXIA8gDpQgGEMAAAAAlCIZkpKSOAJIIAEgEiAWQwAAAACUIhYgDyANlCATQwAAAACUIhqSkpI4AkQgASAQIBVDAAAAAJQiFSAPIAyUIBFDAAAAAJQiG5KSkjgCQCACKgK8ASEPIAFBADYCnAEgASAUIBcgDyAOlCAZkpKSOAKYASABIBIgFiAPIA2UIBqSkpI4ApQBIAEgECAVIA8gDJQgG5KSkjgCkAEgACAAKAIAKAIUEQEAIQMgAUIANwOIASABQgA3A4ABIAMgAUFAayABQZABaiABQYABaiIEIAMoAgAoAggRBAAgAUEANgKMASABIA44AogBIAEgDTgChAEgASAMOAKAASABQQA2AjwgASAYOAI4IAEgEzgCNCABIBE4AjAgAioCxAEhDCACKgLAASENIAAgACgCACgCFBEBACEDIAFCADcDKCABQgA3AyAgAyACQagHaiAEIAFBMGogHCAcIA0gDCABQSBqQQFDAAAgQSADKAIAKAI8ERkACyABQeABaiQAIAZBAUshASAKIQYg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IAIqAmwiB5STIAIqAjggASoCmAGUIAIqAjAgASoCkAGUIAIqAjQgASoClAGUkpIgAioCKCABKgKoAZQgAioCICABKgKgAZQgAioCJCABKgKkAZSSkpIgB5STIgeSIgkgAyAJXiIKGzgCYCADIAWTIAcgChshAyAAKALwAQRAIAAgACoCcCADIAYgACoCgAGUlJQgACoCkAGSOAKQASAAIAMgCCAAKgKEAZSUIAAqAnSUIAAqApQBkjgClAEgACADIAQgACoCiAGUlCAAKgJ4lCAAKgKYAZI4ApgBIAIqAkghBSACKgJEIQQgACADIAAqAmCUIAIqAkCUIAAqAqABkjgCoAEgACoCaCEGIAAgBCADIAAqAmSUlCAAKgKkAZI4AqQBIAAgBSADIAaUlCAAKgKoAZI4AqgBCyABKALwAUUNACACKgI4IQUgAioCNCEEIAEgASoCcCADIAIqAjAgASoCgAGUlJQgASoCkAGSOAKQASABIAMgBCABKgKEAZSUIAEqAnSUIAEqApQBkjgClAEgASADIAUgASoCiAGUlCABKgJ4lCABKgKYAZI4ApgBIAIqAlghBSACKgJUIQQgASADIAEqAmCUIAIqAlCUIAEqAqABkjgCoAEgASoCaCEGIAEgBCADIAEqAmSUlCABKgKkAZI4AqQBIAEgBSADIAaUlCABKgKoAZI4AqgBCws9AQF/IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCDCIAIAIoAgggACgCACgCfBECACEAIAJBEGokACAAC8oFAQF/IABBrJsBNgIAAkAgACgCsAEiAUUNACAALQC0AUUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCsAEgAEEBOgC0ASAAQgA3AqgBAkAgACgCnAEiAUUNACAALQCgAUUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCnAEgAEEBOgCgASAAQgA3ApQBAkAgACgCiAEiAUUNACAALQCMAUUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCiAEgAEEBOgCMASAAQgA3AoABAkAgACgCdCIBRQ0AIAAtAHhFDQAgAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAAL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lCAJIASUIAogBpSSkjgCjAIgDEGAAmogDCABIAIQ5gQLIQAgDEGQBGokACAAC88CAQN/IABB4IwBNgIAAkAgACgCmAEiAUUNACABIQICQCABQQFxRQ0AIAAoAqABIAFBAWsiAkECdGooAgAiA0UNACADIAMoAgAoAgQRAAALIAFBAUYNAANAIAAoAqABIAJBAnRqQQRrKAIAIgEEQCABIAEoAgAoAgQRAAALIAAoAqABIAJBAmsiAkECdGooAgAiAQRAIAEgASgCACgCBBEAAAsgAg0ACwsCQCAAKAKgASIBRQ0AIAAtAKQBRQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACwsgAEEANgKgASAAQQE6AKQBIABCADcCmAEgAEG0JDYCAAJAIAAoAlQiAUUNACAALQBYRQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACwsgAEEANgJUIABBAToAWCAAQgA3AkwgAAtFAQF/IwBBEGsiAyQAIAMgADYCDCADIAE2AgggAyACNgIEIAMoAgwiACADKAIIIAMoAgQgACgCACgCFBEFACADQRBqJAALEQAgACgCuAEgAUECdGooAgALRQEBfyMAQRBrIgMkACADIAA2AgwgAyABNgIIIAMgAjYCBCADKAIMIgAgAygCCCADKAIEIAAoAgAoAhARBQAgA0EQaiQACwgAIABBkAFqC4UCAQF/IABB2IkBNgIAAkAgACgCuAEiAUUNACAALQC8AUUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCuAEgAEEBOgC8ASAAQgA3ArABAkAgACgCpAEiAUUNACAALQCoAUUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCpAEgAEEBOgCoASAAQgA3ApwBIABBtCQ2AgACQCAAKAJUIgFFDQAgAC0AWEUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCVCAAQQE6AFggAEIANwJMIAALMQEBfyMAQRBrIgEkACABIAA2AgwgASgCDCIAIAAoAgAoAgwRAQAhACABQRBqJAAgAAufCAIHfRV/An8gAEFAayoCACIIIAAqAjAiBSAAKgIgIgMgASoCGCIEIAMgBF4bIgQgBCAFXhsgA5OUQwAAAD+SIgRDAACAT10gBEMAAAAAYHEEQCAEqQwBC0EACyEXAn8gACoCPCIJIAAqAiwiByAAKgIcIgQgASoCFCIGIAQgBl4bIgYgBiAHXhsgBJOUQwAAAD+SIgZDAACAT10gBkMAAAAAYHEEQCAGqQwBC0EACyEYAn8gBSADIAEqAggiBiADIAZeGyIGIAUgBl0bIAOTIAiUQwAAAD+SIgNDAACAT10gA0MAAAAAYHEEQCADqQwBC0EACyERAn8gByAEIAEqAgQiAyADIARdGyIDIAMgB14bIASTIAmUQwAAAD+SIgNDAACAT10gA0MAAAAAYHEEQCADqQwBC0EACyEZAn8gACoCOCIHIAAqAigiBCAAKgIYIgMgASoCECIFIAMgBV4bIgUgBCAFXRsgA5OUQwAAAD+SIgVDAACAT10gBUMAAAAAYHEEQCAFqQwBC0EACyEaAn8gBCADIAEqAgAiBSADIAVeGyIFIAQgBV0bIAOTIAeUQwAAAD+SIgNDAACAT10gA0MAAAAAYHEEQCADqQwBC0EACyEbIAAoAgAiHEEASgRAQQAhAQNAAkACQAJAIAFBBHQiHSAAKAIQaiIKLwEAIBpLDQAgCi8BBiAbSQ0AIAovAQIgGEsNACAKLwEIIBlJDQAgCi8BBCAXTQ0BCyAKKAIMQQBOIRJBACETDAELIAooAgwiFEEATiESIAovAQoiCiARTyETIAogEUkNACAUQQBIDQACQCACKAIEIgsgAigCCEcNACALIAtBAXRBASALGyIPTg0AAkAgD0UEQEEAIQ0MAQtBxIUCQcSFAigCAEEBajYCACAPQQJ0QRBB+NMBKAIAEQIAIQ0gAigCBCELCyACKAIMIQoCQAJAIAtBAEoEQEEAIRVBACEOIAtBAWtBA08EQCALQXxxIR5BACEWA0AgDSAOQQJ0IgxqIAogDGooAgA2AgAgDSAMQQRyIhBqIAogEGooAgA2AgAgDSAMQQhyIhBqIAogEGooAgA2AgAgDSAMQQxyIgxqIAogDGooAgA2AgAgDkEEaiEOIBZBBGoiFiAeRw0ACwsgC0EDcSILRQ0BA0AgDSAOQQJ0IgxqIAogDGooAgA2AgAgDkEBaiEOIBVBAWoiFSALRw0ACwwBCyAKRQ0BCyACLQAQQQAgChsEQEHIhQJByIUCKAIAQQFqNgIAIApB/NMBKAIAEQAACyACKAIEIQsLIAIgDTYCDCACQQE6ABAgAiAPNgIICyACKAIMIAtBAnRqIBQ2AgAgAiACKAIEQQFqNgIECyAcIAFBAWogASAAKAIQIB1qKAIMayASIBNyGyIBSg0ACwsLXQEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgghASMAQRBrIgAgAigCDDYCDCAAIAE2AgggACgCDCIBIAAoAggiACkCADcCBCABIAApAgg3AgwgAkEQaiQAC6UDAQJ/IwBBMGsiAiQAIAAoAjAiAyABKQIANwIEIAMgASkCCDcCDCACQQA2AiwgAkIANwIkIAJBgICA/AM2AiAgAkEQaiIDIAAgAkEgaiIBIAAoAgAoAkQRBQAgACACKgIQIAAqAgySOAIgIAJBgICA/Hs2AiAgAiAAIAEgACgCACgCRBEFACACIAIpAwg3AxggAiACKQMANwMQIAAgAioCECAAKgIMkzgCECACQgA3AyggAkIANwMgIAJBgICA/AM2AiQgAyAAIAEgACgCACgCRBEFACAAIAIqAhQgACoCDJI4AiQgAkGAgID8ezYCJCACIAAgASAAKAIAKAJEEQUAIAIgAikDCDcDGCACIAIpAwA3AxAgACACKgIUIAAqAgyTOAIUIAJCADcDKCACQYCAgPwDNgIoIAJCADcDICADIAAgASAAKAIAKAJEEQUAIAAgAioCGCAAKgIMkjgCKCACQYCAgPx7NgIoIAIgACABIAAoAgAoAkQRBQAgAiACKQMINwMYIAIgAikDADcDECAAIAIqAhggACoCDJM4AhggAkEwaiQAC88CAQF/IABBiIMBNgIAAkAgACgCnAEiAUUNACAALQCgAUUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCnAEgAEEBOgCgASAAQgA3ApQBAkAgACgCiAEiAUUNACAALQCMAUUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCiAEgAEEBOgCMASAAQgA3AoABAkAgACgCdCIBRQ0AIAAtAHhFDQAgAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALCyAAQQA2AnQgAEEBOgB4IABCADcCbAJAIAAoAmAiAUUN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ESkCADcCACADIBEpAjg3AjggAyARKQIwNwIwIAMgESkCKDcCKCADIBEpAiA3AiAgAyARKQIYNwIYIAMgESkCEDcCECADIBEpAgg3AgggFSAXQcAAciIRaiIDIAAoAmAgEWoiESkCADcCACADIBEpAgg3AgggAyARKQIQNwIQIAMgESkCGDcCGCADIBEpAiA3AiAgAyARKQIoNwIoIAMgESkCMDcCMCADIBEpAjg3AjggBEECaiEEIBhBAmoiGCAWRw0ACwsgAkEBcUUNACAVIARBBnQiA2oiAiAAKAJgIANqIgMpAgA3AgAgAiADKQI4NwI4IAIgAykCMDcCMCACIAMpAig3AiggAiADKQIgNwIgIAIgAykCGDcCGCACIAMpAhA3AhAgAiADKQIINwIICwJAIAAoAmAiAkUNACAALQBkRQ0AIAIEQEHIhQJByIUCKAIAQQFqNgIAIAJB/NMBKAIAEQAACwsgACAVNgJgIABBAToAZCAAIBM2AlwLIBMgAUF/c2ohBCATIAFrQQNxIhEEQEEAIQMDQCAAKAJgIAFBBnRqIgJCADcCACACQgA3AjggAkIANwIwIAJCADcCKCACQgA3AiAgAkIANwIYIAJCADcCECACQgA3AgggAUEBaiEBIANBAWoiAyARRw0ACwsgBEEDSQ0AA0AgAUEGdCIDIAAoAmBqIgJCADcCACACQgA3AjggAkIANwIwIAJCADcCKCACQgA3AiAgAkIANwIYIAJCADcCECACQgA3AgggAyAAKAJgaiICQgA3AnggAkIANwJwIAJCADcCaCACQgA3AmAgAkIANwJYIAJCADcCUCACQgA3AkggAkFAa0IANwIAIAMgACgCYGoiAkIANwK4ASACQgA3ArABIAJCADcCqAEgAkIANwKgASACQgA3ApgBIAJCADcCkAEgAkIANwKIASACQgA3AoABIAMgACgCYGoiAkIANwL4ASACQgA3AvABIAJCADcC6AEgAkIANwLgASACQgA3AtgBIAJCADcC0AEgAkIANwLIASACQgA3AsABIAFBBGoiASATRw0ACwsgACATNgJYCyAAQQA2AjggAEEAIBIQ7wICQCAALQA8RQ0AIAAoApgBDQAgACAAKAKcAQR/QQEFQcSFAkHEhQIoAgBBAWo2AgBBIEEQQfjTASgCABECACECAkAgACgCmAEiAUEATA0AQQAhAyABQQFHBEAgAUF+cSEVQQAhEQNAIAIgA0EFdCITaiIEIAAoAqABIBNqIhIpAgA3AgAgBCASKQIYNwIYIAQgEikCEDcCECAEIBIpAgg3AgggAiATQSByIhJqIgQgACgCoAEgEmoiEikCADcCACAEIBIpAgg3AgggBCASKQIQNwIQIAQgEikCGDcCGCADQQJqIQMgEUECaiIRIBVHDQALCyABQQFxRQ0AIAIgA0EFdCIDaiIBIAAoAqABIANqIgMpAgA3AgAgASADKQIYNwIYIAEgAykCEDcCECABIAMpAgg3AggLAkAgACgCoAEiAUUNACAALQCkAUUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIAAgAjYCoAEgAEEBOgCkASAAQQE2ApwBIAAoApgBQQFqCzYCmAEgACgCoAEiASAAKAKIASICLwEAOwEAIAEgAi8BAjsBAiABIAIvAQQ7AQQgASACLwEGOwEGIAEgAi8BCDsBCCACLwEKIQMgAUEANgIMIAEgAzsBCiABQQFBACACKAIMIgFrIAFBAE4bNgIQCyAAIAAoApgBNgKoAQJAIAAoAnQiAUUNACAALQB4RQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACwsgAEEANgJ0IABBAToAeCAAQgA3AmwCQCAAKAJMIgFFDQAgAC0AUEUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCTCAAQQE6AFAgAEIANwJEIBRBMGokAAvZAQAgAEEAOgA8IABBmgI2AjQgAEEANgKQASAAQQE6AFAgAEHk3gA2AgAgAEEANgJMIABBAToAZCAAQgA3AkQgAEEANgJgIABBAToAeCAAQgA3AlggAEEANgJ0IABBAToAjAEgAEIANwJsIABBADYCiAEgAEEBOgCkASAAQgA3AoABIABBADYCoAEgAEEANgKoASAAQgA3ApgBIABC////+////79/NwIEIABC////+w83AgwgAEL////79///v/8ANwIUIABC////+wc3AhwgAEGo+AA2AgAgAAskAQF/IwBBEGsiAiAANgIMIAIgATsBCiACKAIMIAIvAQo7AQoLBQBBwAALGAEBfyMAQRBrIgEgADYCDCABKAIMLgEKCyQBAX8j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jOgANgIAIAAgATYCMCAAQeyDATYCACAAQRU2AgQCQCABIAEoAgAoAigRAQAEQCABIABBEGogAEEgaiABKAIAKAIwEQUADAELIARBADYCLCAEQgA3AiQgBEGAgID8AzYCICAEQRBqIgUgACAEQSBqIgEgACgCACgCRBEFACAAIAQqAhAgACoCDJI4AiAgBEGAgID8ezYCICAEIAAgASAAKAIAKAJEEQUAIAQgBCkDCDcDGCAEIAQpAwA3AxAgACAEKgIQIAAqAgyTOAIQIARCADcDKCAEQgA3AyAgBEGAgID8AzYCJCAFIAAgASAAKAIAKAJEEQUAIAAgBCoCFCAAKgIMkjgCJCAEQYCAgPx7NgIkIAQgACABIAAoAgAoAkQRBQAgBCAEKQMINwMYIAQgBCkDADcDECAAIAQqAhQgACoCDJM4AhQgBEIANwMoIARBgICA/AM2AiggBEIANwMgIAUgACABIAAoAgAoAkQRBQAgACAEKgIYIAAqAgySOAIoIARBgICA/Hs2AiggBCAAIAEgACgCACgCRBEFACAEIAQpAwg3AxggBCAEKQMANwMQIAAgBCoCGCAAKgIMkzgCGAsgBEEwaiQAIABBADoAPSAAIAI6ADwgAEIANwI0IABBpN8ANgIAIABBFTYCBCADBEBBxIUCQcSFAigCAEEBajYCAEGsAUEQQfjTASgCABECACIBEP8EIQIgACABNgI0IAIgACgCMCAALQA8IABBEGogAEEgahD+BCAAQQE6AD0LCwUAQdQACz0BAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCACKAIMIgAgAigCCEEBQX8gACgCACgCJBEEACACQRBqJAALvBYBB38gACAAKAKYATYCqAEgAUEBOgBQIAFBADoAPCABQZoCNgI0IAFB5N4ANgIAIAFBADYCTCABQQE6AGQgAUIANwJEIAFBADYCYCABQQE6AHggAUIANwJYIAFBADYCdCABQQE6AIwBIAFCADcCbCABQQA2AogBIAFBAToApAEgAUEANgKQASABQgA3AoABIAFBADYCoAEgAUIANwKYASABQQA2AqgBIAFC////+wc3AhwgAUL////79///v/8ANwIUIAFC////+w83AgwgAUL////7////v383AgQgACgCOCECIAECfyADBEAgASACQQh0QYCA/AdxIAJBGHRyIAJBCHZBgP4DcSACQRh2cnI2AjggASAALQAHOgAEIAEgAC0ABjoABSABIAAtAAU6AAYgASAALQAEOgAHIAEgAC0ACzoACCABIAAtAAo6AAkgASAALQAJOgAKIAEgAC0ACDoACyABIAAtAA86AAwgASAALQAOOgANIAEgAC0ADToADiABIAAtAAw6AA8gASAALQATOgAQIAEgAC0AEjoAESABIAAtABE6ABIgASAALQAQOgATIAEgAC0AFzoAFCABIAAtABY6ABUgASAALQAVOgAWIAEgAC0AFDoAFyABIAAtABs6ABggASAALQAaOgAZIAEgAC0AGToAGiABIAAtABg6ABsgASAALQAfOgAcIAEgAC0AHjoAHSABIAAtAB06AB4gASAALQAcOgAfIAEgAC0AIzoAICABIAAtACI6ACEgASAALQAhOgAiIAEgAC0AIDoAIyABIAAtACc6ACQgASAALQAmOgAlIAEgAC0AJToAJiABIAAtACQ6ACcgASAALQArOgAoIAEgAC0AKjoAKSABIAAtACk6ACogASAALQAoOgArIAEgAC0ALzoALCABIAAtAC46AC0gASAALQAtOgAuIAEgAC0ALDoALyABIAAtADM6ADAgASAALQAyOgAxIAEgAC0AMToAMiABIAAtADA6ADMgASAAKAKQASICQRh0IAJBCHRBgID8B3FyIAJBCHZBgP4DcSACQRh2cnI2ApABIAAoAqgBIgJBGHQgAkEIdEGAgPwHcXIgAkEIdkGA/gNxIAJBGHZycgwBCyABIAI2AjggASAAKQIMNwIMIAEgACkCBDcCBCABIAApAhw3AhwgASAAKQIUNwIUIAEgACkCLDcCLCABIAApAiQ3AiQgASAAKAKQATYCkAEgACgCqAELNgKoASABIAAtADw6ADwgAUGsAWohByAAKAI4IQYCQCAALQA8BEACQCABKAKIASICRQ0AIAEtAIwBRQ0AIAIEQEHIhQJByIUCKAIAQQFqNgIAIAJB/NMBKAIAEQAACwsgASAHNgKIASABQQA6AIwBAkAgA0UEQCAGQQBMDQEgACgCiAEhCANAIAcgBEEEdCIFaiICIAUgCGoiBS8BADsBACACIAUvAQI7AQIgAiAFLwEEOwEEIAIgBS8BBjsBBiACIAUvAQg7AQggAiAFLwEKOwEKIAIgBSgCDDYCDCAEQQFq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ACAAKAKsAUEBajYCrAEMAQsgAEEEaiAFIARBEGoQhQEgACAAKAKsAUEBajYCrAELIAEoAjQiBUE4aiAAIAEoAjxBAnRqQfwAaiAFGyABKAI4NgIAIAEoAjgiBQRAIAUgASgCNDYCNAsgASACKQIANwIQIAEgAikCCDcCGCABIAMpAgA3AiAgASADKQIINwIoIAEgACgCkAEiAjYCPCABQQA2AjQgASAAIAJBAnRqIgJB/ABqKAIANgI4IAIoAnwiAwRAIAMgATYCNAsgAiABNgJ8AkAgBkUNACAAQQE6AMIBIAAtAMEBDQAgBEGELTYCACAEIAA2AgQgAEFAayICIAIoAgAgASgCMCAEELcBIABBBGogACgCBCABKAIwIAQQtwELIARBMGokAAt3AQF/IwBBMGsiBCQAIAQgAzYCLCAEQawuNgIoIAQgASkCCDcDECAEIAEpAgA3AwggBCACKQIINwMgIAQgAikCADcDGCAAQQRqIAAoAgQgBEEIaiIBIARBKGoiAhBeIABBQGsiACAAKAIAIAEgAhBeIARBMGokAAtwAQR/IwBBEGsiBiQAIAZB5C02AgggBiADNgIMIABBBGogACgCBCABIANBBGoiByADQRRqIgggAyoCICAEIAUgBkEIaiIJEIMDIABBQGsiACAAKAIAIAEgByAIIAMqAiAgBCAFIAkQgwMgBkEQaiQAC5YBAQF/IABBwABBBCABKAI8QQJGG2ogASgCMBCEASABKAI0IgNBOGogACABKAI8QQJ0akH8AGogAxsgASgCODYCACABKAI4IgMEQCADIAEoAjQ2AjQLIAAoAogBIgMgASACIAMoAgAoAhARBQAgAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALIABBAToAwgEL3AIAIwBBMGsiByQAQcSFAkHEhQIoAgBBAWo2AgBBwABBEEH40wEoAgARAgAiAyAGOwEGIAMgBTsBBCADIAQ2AgAgAyABKQIANwIQIAMgASkCCDcCGCADIAIpAgA3AiAgAyACKQIINwIoIANBADYCCCADQgA3AjQgByABKQIINwMYIAcgASkCADcDECAHIAIpAgg3AyggByACKQIANwMgIAMgACgCkAE2AjwgACAAKAK8AUEBaiIBNgK8ASADIAE2AgwgAyAAQQRqIgIgB0EQaiADEEw2AjAg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KAIMKgIICwwBCyMAQRBrIgIgACgCGDYCDCACKAIMKgIICyEDIwBBEGsiAiABNgIMIAIoAgwgAzgCCAJ9IAIgACgCGDYCDCACKAIMKgIAAn0gAiAAKAIUNgIMIAIoAgwqAgACfSACIAAoAhA2AgwgAigCDCoCAAtdBEAjAEEQayICIAAoAhA2AgwgAigCDCoCAAwBCyMAQRBrIgIgACgCFDYCDCACKAIMKgIAC10EQAJ9IwBBEGsiAiAAKAIUNgIMIAIoAgwqAgACfSACIAAoAhA2AgwgAigCDCoCAAtdBEAjAEEQayICIAAoAhA2AgwgAigCDCoCAAwBCyMAQRBrIgIgACgCFDYCDCACKAIMKgIACwwBCyMAQRBrIgIgACgCGDYCDCACKAIMKgIACyEDIwBBEGsiAiABQRBqNgIMIAIoAgwgAzgCAAJ9IAIgACgCGDYCDCACKAIMKgIEAn0gAiAAKAIUNgIMIAIoAgwqAgQCfSACIAAoAhA2AgwgAigCDCoCBAtdBEAjAEEQayICIAAoAhA2AgwgAigCDCoCBAwBCyMAQRBrIgIgACgCFDYCDCACKAIMKgIEC10EQAJ9IwBBEGsiAiAAKAIUNgIMIAIoAgwqAgQCfSACIAAoAhA2AgwgAigCDCoCBAtdBEAjAEEQayICIAAoAhA2AgwgAigCDCoCBAwBCyMAQRBrIgIgACgCFDYCDCACKAIMKgIECwwBCyMAQRBrIgIgACgCGDYCDCACKAIMKgIECyEDIwBBEGsiAiABQRBqNgIMIAIoAgwgAzgCBAJ9IAIgACgCGDYCDCACKAIMKgIIAn0gAiAAKAIUNgIMIAIoAgwqAggCfSACIAAoAhA2AgwgAigCDCoCCAtdBEAjAEEQayICIAAoAhA2AgwgAigCDCoCCAwBCyMAQRBrIgIgACgCFDYCDCACKAIMKgIIC10EQAJ9IwBBEGsiAiAAKAIUNgIMIAIoAgwqAggCfSACIAAoAhA2AgwgAigCDCoCCAtdBEAjAEEQayICIAAoAhA2AgwgAigCDCoCCAwBCyMAQRBrIgIgACgCFDYCDCACKAIMKgIICwwBCyMAQRBrIgIgACgCGDYCDCACKAIMKgIICyEDIwBBEGsiBSICIAFBEGoiBjYCDCACKAIMIAM4AgggACoCDCEDIAUiAiABNgIMIAIoAgwiAiACKgIA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IAIoAgwCfyMAQRBrIgIgBCgCiAM2AgwgAigCDEEEagsCfyMAQRBrIgIgBCgCiAM2AgwgAigCDEEIagsQBiMAQRBrIgMgBCgChAM2AgwgBEHAAWoiAiADKAIMAn8jAEEQayIDIAQoAogDNgIMIAMoAgxBBGoLAn8jAEEQayIDIAQoAoQDNgIMIAMoAgxBCGoLEAYgACABIAIgBCgCgAMgACgCACgCCBEEACMAQRBrIgIgBCgChAM2AgwgBEGwAWoiASACKAIMAn8jAEEQayICIAQoAoQDNgIMIAIoAgxBBGoLAn8jAEEQayICIAQoAogDNgIMIAIoAgxBCGoLEAYjAEEQayIDIAQoAoQDNgIMIARBoAFqIgIgAygCDAJ/IwBBEGsiAyAEKAKEAzYCDCADKAIMQQRqCwJ/IwBBEGsiAyAEKAKEAzYCDCADKAIMQQhqCxAGIAAgASACIAQoAoADIAAoAgAoAggRBAAjAEEQayICIAQoAogDNgIMIARBkAFqIgEgAigCDAJ/IwBBEGsiAiAEKAKEAzYCDCACKAIMQQRqCwJ/IwBBEGsiAiAEKAKIAzYCDCACKAIMQQhqCxAGIwBBEGsiAyAEKAKIAzYCDCAEQYABaiICIAMoAgwCfyMAQRBrIgMgBCgChAM2AgwgAygCDEEEagsCfyMAQRBrIgMgBCgChAM2AgwgAygCDEEIagsQBiAAIAEgAiAEKAKAAyAAKAIAKAIIEQQAIwBBEGsiAiAEKAKIAzYCDCAEQfAAaiIBIAIoAgwCfyMAQRBrIgIgBCgCiAM2AgwgAigCDEEEagsCfyMAQRBrIgIgBCgChAM2AgwgAigCDEEIagsQBiMAQRBrIgMgBCgChAM2AgwgBEHgAGoiAiADKAIMAn8jAEEQayIDIAQoAogDNgIMIAMoAgxBBGoLAn8jAEEQayIDIAQoAoQDNgIMIAMoAgxBCGoLEAYgACABIAIgBCgCgAMgACgCACgCCBEEACMAQRBrIgIgBCgChAM2AgwgBEHQAGoiASACKAIMAn8jAEEQayICIAQoAogDNgIMIAIoAgxBBGoLAn8jAEEQayICIAQoAoQDNgIMIAIoAgxBCGoLEAYjAEEQayIDIAQoAoQDNgIMIARBQGsiAiADKAIMAn8jAEEQayIDIAQoAoQDNgIMIAMoAgxBBGoLAn8jAEEQayIDIAQo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KAIIIAFrQegAbSIQQRRsaiIEKAIEIgBBAEwNACAEKAIMIQJBACEBA0AgDiACIAFBAnRqKAIARwRAIAFBAWoiASAARw0BDAILCyAAIAFHDQELAkAgACAEKAIIRw0AIAAgAEEBdEEBIAAbIg1ODQACQCANRQRAQQAhBwwBC0HEhQJBxIUCKAIAQQFqNgIAIA1BAnRBEEH40wEoAgARAgAhByAEKAIEIQALIAQoAgwhAwJAAkAgAEEASgRAQQAhAkEAIQEgAEEBa0EDTwRAIABBfHEhD0EAIQkDQCAHIAFBAnQiBmogAyAGaigCADYCACAHIAZBBHIiEmogAyASaigCADYCACAHIAZBCHIiEmogAyASaigCADYCACAHIAZBDHIiBmogAyAGaigCADYCACABQQRqIQEgCUEEaiIJIA9HDQALCyAAQQNxIgBFDQEDQCAHIAFBAnQiCWogAyAJaigCADYCACABQQFqIQEgAkEBaiICIABHDQALDAELIANFDQELIAQtABBBACADGwRAQciFAkHIhQIoAgBBAWo2AgAgA0H80wEoAgARAAALIAQoAgQhAAsgBEEBOgAQIAQgBzYCDCAEIA02AggLIAQoAgwgAEECdGogDjYCACAEIAQoAgRBAWo2AgQLAkACQCAMIA5BFGxqIgcoAgQiAEEATA0AIAcoAgwhAkEAIQEDQCAQIAIgAUECdGooAgBHBEAgAUEBaiIBIABHDQEMAgsLIAAgAUcNAQsCQCAAIAcoAghHDQAgACAAQQF0QQEgABsiBk4NAAJAIAZFBEBBACEEDAELQcSFAkHEhQIoAgBBAWo2AgAgBkECdEEQQfjTASgCABECACEEIAcoAgQhAAsgBygCDCEDAkACQCAAQQBKBEBBACEOQQAhASAAQQFrQQNPBEAgAEF8cSENQQAhAgNAIAQgAUECdCIJaiADIAlqKAIANgIAIAQgCUEEciIPaiADIA9qKAIANgIAIAQgCUEIciIPaiADIA9qKAIANgIAIAQgCUEMciIJaiADIAlqKAIANgIAIAFBBGohASACQQRqIgIgDUcNAAsLIABBA3EiAEUNAQNAIAQgAUECdCICaiACIANqKAIANgIAIAFBAWohASAOQQFqIg4gAEcNAAsMAQsgA0UNAQsgBy0AEEEAIAMbBEBByIUCQciFAigCAEEBajYCACADQfzT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AgwgAiABOAIIIAIoAgwgAioCCDgCUAs8AQF/IwBBEGsiASQAIAEgADYCDCMAQRBrIgAgASgCDDYCDCAAKAIMIgAgACgCBEEBazYCBCABQRBqJAALLwEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgwgAigCCBCwAyACQRBqJAAL8gEBAn8jAEEQayIDJAAgAyAANgIMIAMgATYCCEHw5QEtAABFBEBBkOUBELEDQfDlAUEBOgAACyADKAIIIQEjAEEQayIAIAMoAgw2AgwgACABNgIIIAAoAgwoAgwgACgCCEHgAGxqIQEgACQAIABBkOUBNgIMIAAgATYCCCAAKAIMIgEgACgCCCICKQIANwIAIAEgAigCGDYCGCABIAIpAhA3AhAgASACKQIINwIIIAFBHGogACgCCEEcahDPAiABIAAoAggiAikCTDcCTCABIAIoAlw2AlwgASACKQJUNwJUIABBEGokACADQRBqJABBkOUBCzUBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIgEpAgA3AkwgACABKQIINwJUCxkBAX8jAEEQayIBIAA2AgwgASgCDEHMAGoLMgEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgxBHGogAigCCBDPAiACQRBqJAALNQEBfyMAQRBrIgIgADYCDCACIAE2AgggAigCDCIAIAIoAggiASkCADcCBCAAIAEpAgg3AgwLVQEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgghASMAQRBrIgAgAigCDDYCDCAAIAE2AgggACgCDCgCDCAAKAIIQegAbGohACACQRBqJAAgAAskAQF/IwBBEGsiAiAANgIMIAIgATgCCCACKAIMIAIqAgg4AlgLGAEBfyMAQRBrIgEgADYCDCABKAIMKgJYCzUBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIgEpAgA3AkggACABKQIINwJQC1QBAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCACKAIIIQEjAEEQayIAIAIoAgw2AgwgACABNgIIIAAoAgwoAgwgACgCCEEsbGohACACQRBqJAAgAAs3AQF/IwBBEGsiAyAANgIMIAMgATYCCCADIAI2AgQgAygCDEEIaiADKAIIQQJ0aiADKAIE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IAEgADYCDCABKAIMIgAgACgCACgCMBEBAEEBcSEAIAFBEGokACAAC1MBAX8jAEEQayICJAAgAiAANgIMIAIgAToACyACLQALQQFxIQEjAEEQayIAIAIoAgw2AgwgACABOgALIAAoAgwgAC0AC0EBcToAqgEgAkEQaiQACyMBAX8jAEEQayIBJAAgASAANgIMIAFBEGokACABKAIMKAIICyMBAX8jAEEQayIBJAAgASAANgIMIAFBEGokACABKAIMKgIkCzwBAX8jAEEQayICJAAgAiAANgIMIAIgATgCCCACKAIMIgAgAioCCCIBOAIkIAAgARAaOAIoIAJBEGokAAsjAQF/IwBBEGsiASQAIAEgADYCDCABQRBqJAAgASgCDCoCLAsvAQF/IwBBEGsiAiQAIAIgADYCDCACIAE4AgggAigCDCACKgIIOAIsIAJBEGokAAstAQF/IwBBEGsiASQAIAEgADYCDCABKAIMIgAgACgCACgCLBEAACABQRBqJAALNAEBfyMAQRBrIgEkACABIAA2AgwgASgCDCIAIAAoAgAoAigRAQBBAXEhACABQRBqJAAgAAsvAQF/IwBBEGsiAiQAIAIgADYCDCACIAE4AgggAigCDCACKgIIOAIgIAJBEGokAAsvAQF/IwBBEGsiAiQAIAIgADYCDCACIAE4AgggAigCDCACKgIIOAIcIAJBEGokAAsvAQF/IwBBEGsiAiQAIAIgADYCDCACIAE4AgggAigCDCACKgIIOAIYIAJBEGokAAtFAQF/IwBBEGsiAyQAIAMgADYCDCADIAE2AgggAyACOAIEIAMoAgwiACADKAIIIAMqAgQgACgCACgCJBENACADQRBqJAALOQEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIAAoAgAoAiARAwAgAkEQaiQACzkBAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCACKAIMIgAgAigCCCAAKAIAKAIcEQMAIAJBEGokAAtFAQF/IwBBEGsiAyQAIAMgADYCDCADIAE2AgggAyACOAIEIAMoAgwiACADKAIIIAMqAgQgACgCACgCFBENACADQRBqJAALdQEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgghASMAQRBrIgAgAigCDDYCDCAAIAE2AgggACgCDCEBIAAoAghBAEgEQCAAQQA2AggLIAAoAghBAkoEQCAAQQI2AggLIAEgACgCCDYCsAEgAkEQaiQAC1ABAX8jAEEQayIEJAAgBCAANgIMIAQgATYCCCAEIAI4AgQgBCADNgIAQbgBEAoiACAEKAIMIAQoAgggBCoCBCAEKAIAENcEIARBEGokACAAC0YBAX8jAEEQayIDJAAgAyAANgIMIAMgATYCCCADIAI4AgRBuAEQCiIAIAMoAgwgAygCCCADKgIEQQEQ1wQgA0EQaiQAIAALJQEBfyMAQRBrIgIgADYCDCACIAE4AgggAigCDCACKgIIOAKYAgsZAQF/IwBBEGsiASAANgIMIAEoAgwqApgCCyUBAX8jAEEQayICIAA2AgwgAiABOAIIIAIoAgwgAioCCDgCkAILGQEBfyMAQRBrIgEgADYCDCABKAIMKgKQAgslAQF/IwBBEGsiAiAANgIMIAIgATgCCCACKAIMIAIqAgg4AowCCxkBAX8jAEEQayIBIAA2AgwgASgCDCoCjAILJQEBfyMAQRBrIgIgADYCDCACIAE4AgggAigCDCACKgIIOAKAAgsZAQF/IwBBEGsiASAANgIMIAEoAgwqAoACCyUBAX8jAEEQayICIAA2AgwgAiABOAIIIAIoAgwgAioCCDgC8AELGQEBfyMAQRBrIgEgADYCDCABKAIMKgLwAQslAQF/IwBBEGsiAiAANgIMIAIgATgCCCACKAIMIAIqAgg4AuwBCxkBAX8jAEEQayIBIAA2AgwgASgCDCoC7AELNwEBfyMAQRBrIgIgADYCDCACIAE2AgggAigCDCIAIAIoAggiASkCADcCvAEgACABKQIINwLEAQsZAQF/IwBBEGsiASAANgIMIAEoAgxBvAFqCzcBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIgEpAgA3AqwBIAAgASkCCDcCtAELGQEBfyMAQRBrIgEgADYCDCABKAIMQawBagsyAQF/IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCDEHcAGogAigCCBBEIAJBEGokAAs3AQF/IwBBEGsiAiAANgIMIAIgATYCCCACKAIMIgAgAigCCCIBKQIANwKcASAAIAEpAgg3AqQBCxkBAX8jAEEQayIBIAA2AgwgASgCDEGcAWoLMgEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgwgAigCCEHcABALGiACQRBqJAALKAEBfyMAQRBrIgIgADYCDCACIAE6AAsgAigCDCACLQALQQFxOgCEAgscAQF/IwBBEGsiASAANgIMIAEoAgwtAIQCQQFxCyUBAX8jAEEQayICIAA2AgwgAiABOAIIIAIoAgwgAioCCDgClAILGQEBfyMAQRBrIgEgADYCDCABKAIMKgKUAgslAQF/IwBBEGsiAiAANgIMIAIgATgCCCACKAIMIAIqAgg4AtABCxkBAX8jAEEQayIBIAA2AgwgASgCDCoC0AELJQEBfyMAQRBrIgIgADYCDCACIAE4AgggAigCDCACKgIIOAL4AQsZAQF/IwBBEGsiASAANgIMIAEoAgwqAvgBCyUBAX8jAEEQayICIAA2AgwgAiABOAIIIAIoAgwgAioCCDgC6AELJQEBfyMAQRBrIgIgADYCDCACIAE4AgggAigCDCACKgIIOALgAQslAQF/IwBBEGsiAiAANgIMIAIgATgCCCACKAIMIAIqAgg4AtwBCxkBAX8jAEEQayIBIAA2AgwgASgCDCoC3AELJQEBfyMAQRBrIgIgADYCDCACIAE4AgggAigCDCACKgIIOALUAQsZAQF/IwBBEGsiASAANgIMIAEoAgwqAtQBCyUBAX8jAEEQayICIAA2AgwgAiABOAIIIAIoAgwgAioCCDgCzAELGQEBfyMAQRBrIgEgADYCDCABKAIMKgLMAQslAQF/IwBBEGsiAiAANgIMIAIgATgCCCACKAIMIAIqAgg4AvQBCxkBAX8jAEEQayIBIAA2AgwgASgCDCoC9AELJQEBfyMAQRBrIgIgADYCDCACIAE4AgggAigCDCACKgIIOAL8AQsZAQF/IwBBEGsiASAANgIMIAEoAgwqAvwBCyUBAX8jAEEQayICIAA2AgwgAiABOAIIIAIoAgwgAioCCDgC5AELJQEBfyMAQRBrIgIgADYCDCACIAE4AgggAigCDCACKgIIOALYAQsZAQF/IwBBEGsiASAANgIMIAEoAgwqAtgBC+ACAgF/B30jAEEQayIDJAAgAyAANgIMIAMgATYCCCADIAI2AgQgAygCCCEBAkAgAygCDCIALQBUBEAgACoCCCIEIAAqAjyUIAAqAgAiBSAAKgI0lCAAKgIEIgggACoCOJSS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IAUgADYCHCAFIAE2AhggBSACNgIUIAUgAzYCECAFIAQ6AA9B7AoQCiIAIAUoAhwgBSgCGCAFKAIUIAUoAhAgBS0AD0EBcRDPBCAAQZ0KakEANgAAIABBCTYCBCAAQZSZATYCACAAQaEKakEAOwAAIABBpApqQgA3AgAgAEGsCmpCADcCACAAQbQKakIANwIAIABBvApqQgA3AgAgAEHECmpCADcCACAAQcwKakIANwIAIABB5ApqQoCAgPyDgIDAPzcCACAAQdwKakKAgID8g4CAwD83AgAgAEKAgID8g4CAwD83AtQKIAVBIGokACAAC+UBAQF/IwBBEGsiAyQAIAMgADYCDCADIAE2AgggAyACOgAHQewKEAoiACADKAIMIAMoAgggAy0AB0EBcRDOBCAAQZ0KakEANgAAIABBCTYCBCAAQZSZATYCACAAQaEKakEAOwAAIABBpApqQgA3AgAgAEGsCmpCADcCACAAQbQKakIANwIAIABBvApqQgA3AgAgAEHECmpCADcCACAAQcwKakIANwIAIABB5ApqQoCAgPyDgIDAPzcCACAAQdwKakKAgID8g4CAwD83AgAgAEKAgID8g4CAwD83AtQKIANBEGokACAACzcBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIgEpAgA3AtwCIAAgASgCCDYC5AILNwEBfyMAQRBrIgEkACABIAA2AgwjAEEQayIAIAEoAgw2AgwgACgCDEG8AmohACABQRBqJAAgAAs3AQF/IwBBEGsiASQAIAEgADYCDCMAQRBrIgAgASgCDDYCDCAAKAIMQawCaiEAIAFBEGokACAAC18BAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCACKAIIIQEjAEEQayIAIAIoAgw2AgwgACABNgIIIAAoAgwiASAAKAIIIgApAgA3ArwCIAEgACkCCDcCxAIgAkEQaiQAC18BAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCACKAIIIQEjAEEQayIAIAIoAgw2AgwgACABNgIIIAAoAgwiASAAKAIIIgApAgA3AqwCIAEgACkCCDcCtAIgAkEQaiQAC7QBAQF/IwBBEGsiBCQAIAQgADYCDCAEIAE2AgggBCACNgIEIAQgAzYCAEHoAhAKIQAgBCgCBCEBIAQoAgAhAiAAQQMgBCgCDCAEKAIIEEYgAEHQmgE2AgAgACABKQIANwKsAiAAIAEpAgg3ArQCIAAgAikCADcCvAIgACACKQIINwLEAiAAQQA2AuQCIABCmrPm9IOAgMA/NwLcAiAAQQA6ANgCIABBADYCzAIgBEEQaiQAIAALwAICAn8PfSMAQRBrIgIkACACIAA2AgwgAiABNgIIQegCEAohASACKAIIIQMgAUEDIAIoAgwiABDRAiABQdCaATYCACABIAMpAgA3AqwCIAEgAykCCDcCtAIgACoCNCEHIAAqAgghCCAAKgIMIQkgACoCOCEKIAAqAhQhCyAAKgIYIQwgACoCHCENIAAqAjwhDiAAKgIkIQ8gACoCKCEQIAMqAgghBCAAKgIsIREgACoCBCESIAMqAgAhBSADKgIEIQYgAUEANgLkAiABQpqz5vSDgIDAPzcC3AIgAUEAOgDYAiABQgA3AsgCIAEgDiAEIBGUIAUgD5QgBiAQlJKSkjgCxAIgASAKIAQgDZQgBSALlCAGIAyUkpKSOALAAiABIAcgBCAJlCAFIBKUIAYgCJSSkpI4ArwCIAJBEGokACABCzsBAn9BDBANIQEjAEEQayIAIAE2AgwgACgCDCIAQ5qZmT44AgAgAEMAAIA/OAIEIABDAAAAADgCCCABC6YBAQJ/IwBBEGsiASQAIAEgADYCDCMAQSBrIgAkACAAIAEoAgw2AhwgACgCHCECIABDAAAAADgCGCAAQwAAAAA4AhQgAEMAAAAAOAIQIAJBnANqIABBGGogAEEUaiAAQRBqEAYgAEMAAAAAOAIMIABDAAAAADgCCCAAQwAAAAA4AgQgAkGsA2ogAEEMaiAAQQhqIABBBGoQBiAAQSBqJAAgAUEQaiQACy8BAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCACKAIMIAIoAggQ5gEgAkEQaiQACzcBAX8jAEEQayIBJAAgASAANgIMIwBBEGsiACABKAIMNgIMIAAoAgxB/AJqIQAgAUEQaiQAIAALIwEBfyMAQRBrIgEkACABIAA2AgwgASgCDBCvBCABQRBqJAALUAEBfyMAQRBrIgMkACADIAA2AgwgAyABNgIIIAMgAjYCBCADKAIMIgAoAsABIgEgAEEEaiADKAIIIAMoAgQgASgCACgCCBEEACADQRBqJAALdQEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIwBBEGsiACQAIAAgAigCCDYCCCMAQRBrIgEgACgCCDYCDAJAIAEoAgwoAuwBQQJxBEAgACAAKAIINgIMDAELIABBADYCDAsgAEEQaiQAIAJBEGokACAAKAIMC24BAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCACKAIIIQEjAEEQayIAIAIoAgw2AgwgACABNgIIIAAoAgwiASABKAKEAkEBajYChAIgASAAKAIIIgApAgA3AqAEIAEgACkCCDcCqAQgAkEQaiQACzcBAX8jAEEQayIBJAAgASAANgIMIwBBEGsiACABKAIMNgIMIAAoAgxBoARqIQAgAUEQaiQAIAALegECfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgghASMAQRBrIgAkACAAIAIoAgw2AgwgACABNgIIIAAoAgwiASAAKAIINgLgAyABKALgAwRAIAAoAggiAyABQQRqIAMoAgAoAggRAwALIABBEGokACACQRBqJAALNwEBfyMAQRBrIgEkACABIAA2AgwjAEEQayIAIAEoAgw2AgwgACgCDCgC4AMhACABQRBqJAAgAAtuAQF/IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCCCEBIwBBEGsiACACKAIMNgIMIAAgATYCCCAAKAIMIgEgASgChAJBAWo2AoQCIAEgACgCCCIAKQIANwLIAiABIAApAgg3AtACIAJBEGokAAtuAQF/IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCCCEBIwBBEGsiACACKAIMNgIMIAAgATYCCCAAKAIMIgEgASgChAJBAWo2AoQCIAEgACgCCCIAKQIANwK4AiABIAApAgg3AsACIAJBEGokAAs3AQF/IwBBEGsiASQAIAEgADYCDCMAQRBrIgAgASgCDDYCDCAAKAIMQcgCaiEAIAFBEGokACAACzcBAX8jAEEQayIBJAAgASAANgIMIwBBEGsiACABKAIMNgIMIAAoAgxBuAJqIQAgAUEQaiQAIAAL9QICD30BfyMAQRBrIhAkACAQIAA2AgwgECgCDCIAQQA2ArQCIABBADYCpAIgAEEANgKUAiAAIAAqAiwiASABIAAqApQDIguUIgKUIAAqAiQiAyADIAAqAowDIgyUIgSUIAAqAigiBSAFIAAqApADIg2UIgaUkpI4ArACIAAgACoCHCIHIAKUIAAqAhQiCCAElCAAKgIYIgkgBpSSkjgCrAIgACAAKgIMIgogApQgACoCBCICIASUIAAqAggiBCAGlJKSOAKoAiAAIAEgCyAHlCIGlCADIAwgCJQiDpQgBSANIAmUIg+UkpI4AqACIAAgByAGlCAIIA6UIAkgD5SSkjgCnAIgACAKIAaUIAIgDpQgBCAPlJKSOAKYAiAAIAEgCiALlCIBlCADIAIgDJQiA5QgBSAEIA2UIgWUkpI4ApACIAAgByABlCAIIAOUIAUgCZSSkjgCjAIgACAKIAGUIAIgA5QgBCAFlJKSOAKIAiAQQRBqJAALLwEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgwgAigCCBDSAyACQRBqJAALOgEBfyMAQRBrIgMkACADIAA2AgwgAyABNgIIIAMgAjYCBCADKAIMIAMoAgggAygCBBBDIANBEGokAAsvAQF/IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCDCACKAIIENMDIAJBEGokAAuNAQEDfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgghASMAQTBrIgAkACAAIAIoAgw2AiwgACABNgIoIwBBEGsiAyAAKAIsIgFBBGo2AgwgAEEIaiIEIAMoAgwgACgCKBAPIABBGGoiAyAEIAFB3AJqEFMgAUGcA2ogAxA4GiAAQTBqJAAgAkEQaiQACy8BAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCACKAIMIAIoAggQ1AMgAkEQaiQAC5gBAQJ/IwBBEGsiAyQAIAMgADYCDCADIAE2AgggAyACNgIEIAMoAgghASADKAIEIQIjAEEwayIAJAAgACADKAIMNgIsIAAgATYCKCAAIAI2AiQgACgCLCIBIAAoAigQ1AMgACgCJCECIAAgACgCKCABQdwCahBTIABBEGoiBCACIAAQXSABIAQQ1QMgAEEwaiQAIANBEGokAAuNAQEDfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgghASMAQTBrIgAkACAAIAIoAgw2AiwgACABNgIoIwBBEGsiAyAAKAIsIgFBBGo2AgwgAEEIaiIEIAMoAgwgACgCKBAPIABBGGoiAyAEIAFBoARqEFMgAUGsA2ogAxA4GiAAQTBqJAAgAkEQaiQACy8BAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCACKAIMIAIoAggQ1QMgAkEQaiQAC5MBAQJ/IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCCCEBIwBBIGsiACQAIAAgAigCDDYCHCAAIAE2AhggACgCHCIBIAAoAhgiAykCADcC3AIgASADKQIINwLkAiAAQQhqIAFB3AJqIAFB2AJqEBsgASAAKQIINwKwBCABIAApAhA3ArgEIABBIGokACACQRBqJAALGQEBfyMAQRBrIgEgADYCDCABKAIMQdwCags3AQF/IwBBEGsiASQAIAEgADYCDCMAQRBrIgAgASgCDDYCDCAAKAIMQdwCaiEAIAFBEGokACAACzsBAX8jAEEQayIDJAAgAyAANgIMIAMgATgCCCADIAI2AgQgAygCDCADKgIIIAMoAgQQ6AEgA0EQaiQAC3IBAX8jAEEQayIDJAAgAyAANgIMIAMgATgCCCADIAI4AgQgAyoCCCEBIAMoAgwiAEMAAAAAIAMqAgQiAkMAAIA/liACQwAAAABdGzgCwAMgAEMAAAAAIAFDAACAP5YgAUMAAAAAXRs4ArwDIANBEGokAAs5AgF/AX0jAEEQayIBJAAgASAANgIMIwBBEGsiACABKAIMNgIMIAAoAgwqAsADIQIgAUEQaiQAIAILOQIBfwF9IwBBEGsiASQAIAEgADYCDCMAQRBrIgAgASgCDDYCDCAAKAIMKgK8AyECIAFBEGokACACC28BAn8jAEEQayIDJAAgAyAANgIMIAMgATgCCCADIAI4AgQgAyoCCCEBIAMqAgQhAiMAQRBrIgAgAygCDDYCDCAAIAE4AgggACACOAIEIAAoAgwiBCAAKgIIOALYAyAEIAAqAgQ4AtwDIANBEGokAAsvAQF/IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCDCACKAIIEK0EIAJBEGokAAtYAQJ/IwBBEGsiASQAIAEgADYCDEHoBBAKIQAgASgCDCECIAAQtgEgAEEBOgD0AyAAQYSiATYCACAAQQA2AvADIABCADcC6AMgACACELAEIAFBEGokACAACyUBAX8jAEEQayICIAA2AgwgAiABOAIIIAIoAgwgAioCCDgCiAELGQEBfyMAQRBrIgEgADYCDCABKAIMKgKIAQslAQF/IwBBEGsiAiAANgIMIAIgATgCCCACKAIMIAIqAgg4AoQBCxkBAX8jAEEQayIBIAA2AgwgASgCDCoChAELJQEBfyMAQRBrIgIgADYCDCACIAE4AgggAigCDCACKgIIOAKAAQsZAQF/IwBBEGsiASAANgIMIAEoAgwqAoABCyQBAX8jAEEQayICIAA2AgwgAiABOAIIIAIoAgwgAioCCDgCfAsYAQF/IwBBEGsiASAANgIMIAEoAgwqAnwLJwEBfyMAQRBrIgIgADYCDCACIAE6AAsgAigCDCACLQALQQFxOgB4CxsBAX8jAEEQayIBIAA2AgwgASgCDC0AeEEBcQskAQF/IwBBEGsiAiAANgIMIAIgATgCCCACKAIMIAIqAgg4AnQLGAEBfyMAQRBrIgEgADYCDCABKAIMKgJ0CyQBAX8jAEEQayICIAA2AgwgAiABOAIIIAIoAgwgAioCCDgCcAsYAQF/IwBBEGsiASAANgIMIAEoAgwqAnALJAEBfyMAQRBrIgIgADYCDCACIAE4AgggAigCDCACKgIIOAJsCxgBAX8jAEEQayIBIAA2AgwgASgCDCoCbAskAQF/IwBBEGsiAiAANgIMIAIgATgCCCACKAIMIAIqAgg4AmgLGAEBfyMAQRBrIgEgADYCDCABKAIMKgJoCyQBAX8jAEEQayICIAA2AgwgAiABOAIIIAIoAgwgAioCCDgCZAsYAQF/IwBBEGsiASAANgIMIAEoAgwqAmQLJAEBfyMAQRBrIgIgADYCDCACIAE4AgggAigCDCACKgIIOAJgCxgBAX8jAEEQayIBIAA2AgwgASgCDCoCYAtQAQF/IwBBEGsiBCQAIAQgADgCDCAEIAE2AgggBCACNgIEIAQgAzYCAEGMARANIgEgBCoCDCAEKAIIIAQoAgQgBCgCABDWAyAEQRBqJAAgAQuKAQEDfyMAQTBrIgMkACADIAA4AiwgAyABNgIoIAMgAjYCJEGMARANIQEgAyoCLCEAIAMoAighAiADKAIkIQQgA0MAAAAAOAIMIANDAAAAADgCCCADQwAAAAA4AgQgA0EQaiIFIANBDGogA0EIaiADQQRqEAYgASAAIAIgBCAFENYDIANBMGokACABCyQBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwgAigCCDsBBgsYAQF/IwBBEGsiASAANgIMIAEoAgwuAQYLJAEBfyMAQRBrIgIgADYCDCACIAE2AgggAigCDCACKAIIOwEECxgBAX8jAEEQayIBIAA2AgwgASgCDC4BBAsSAQF/QcQBEA0iAEEAEIQDIAALZAEBfyMAQSBrIgUkACAFIAA2AhwgBSABNgIYIAUgAjYCFCAFIAM2AhAgBSAEOgAPQfQAEAoiACAFKAIcIAUoAhggBSgCFEH//wNxIAUoAhAgBS0AD0EBcRDAASAFQSBqJAAgAAtXAQF/IwBBEGsiBCQAIAQgADYCDCAEIAE2AgggBCACNgIEIAQgAzYCAEH0ABAKIgAgBCgCDCAEKAIIIAQoAgRB//8DcSAEKAIAQQAQwAEgBEEQaiQAIAALTQEBfyMAQRBrIgMkACADIAA2AgwgAyABNgIIIAMgAjYCBEH0ABAKIgAgAygCDCADKAIIIAMoAgRB//8DcUEAQQAQwAEgA0EQaiQAIAALQAEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIQfQAEAoiACACKAIMIAIoAghBgIABQQBBABDAASACQRBqJAAgAAs0AgF/AX0jAEEQayIBJAAgASAANgIMIAEoAgwiACAAKAIAKAIkEQEAsiECIAFBEGokACACC4QCAQV/IwBBEGsiAyQAIAMgADYCDEGMKRANIQAgAygCDCEBIABBAjYCBCAAIAE2AogpIABB5AE2AjwgAEEBOgAYIABB1DI2AgAgAEEANgIUIABBhNoANgIcIABCADcCDCAAIAEgASgCACgCDBEBADYCQCAAIAEgASgCACgCCBEBADYCRANAQQAhAQNAIAAgAkGQAWxqQcgAaiIEIAFBAnRqIAAoAogpIgUgAiABIAUoAgAoAhARBwA2AgAgBCABQQFyIgVBAnRqIAAoAogpIgQgAiAFIAQoAgAoAhARBwA2AgAgAUECaiIBQSRHDQALIAJBAWoiAkEkRw0ACyADQRBqJAAgAAtVAQF/IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCCCEBIwBBEGsiACACKAIMNgIMIAAgATYCCCAAKAIMQQRqIAAoAghBuAFsaiEAIAJBEGokACAACzcBAX8jAEEQayIBJAAgASAANgIMIwBBEGsiACABKAIMNgIMIAAoAgwoAuwFIQAgAUEQaiQAIAALNwEBfyMAQRBrIgEkACABIAA2AgwjAEEQayIAIAEoAgw2AgwgACgCDCgC6AUhACABQRBqJAAgAAs3AQF/IwBBEGsiASQAIAEgADYCDCMAQRBrIgAgASgCDDYCDCAAKAIMKALkBSEAIAFBEGokACAAC+gBAQF/QYQGEAoiAEGBCDYCACAAQgA3AnwgAEEAOgB4IABBADYCdCAAQgA3AoQBIABCADcCjAEgAEIANwKUASAAQgA3ArQCIABBADoAsAIgAEEANgKsAiAAQgA3ArwCIABCADcCxAIgAEIANwLMAiAAQgA3AuwDIABBADoA6AMgAEEANgLkAyAAQgA3AvQDIABCADcC/AMgAEIANwKEBCAAQQA6AKAFIABBADYCnAUgAEIANwKkBSAAQgA3AqwFIABCADcCtAUgAEIANwK8BSAAQQA2AuwFIABBADYCgAYgAEIANwLkBSAACw8BAX9BGBANIgAQzgIgAAvlBwEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgghAEGM8QEtAABFBEBBjPEBQQE6AABBhPEBQYyJATYCAEGI8QFBADoAAAsgAEGQHGpBhPEBNgJIIABBlBxqQYTxATYCSCAAQZgcakGE8QE2AkggAEGcHGpBhPEBNgJIIABBoBxqQYTxATYCSCAAQaQcakGE8QE2AkggAEGoHGpBhPEBNgJIIABBrBxqQYTxATYCSCAAQbAcakGE8QE2AkggAEG0HGpBhPEBNgJIIABBuBxqQYTxATYCSCAAQbwcakGE8QE2AkggAEHAHGpBhPEBNgJIIABBxBxqQYTxATYCSCAAQcgcakGE8QE2AkggAEHMHGpBhPEBNgJIIABB0BxqQYTxATYCSCAAQdQcakGE8QE2AkggAEHYHGpBhPEBNgJIIABB3BxqQYTxATYCSCAAQeAcakGE8QE2AkggAEHkHGpBhPEBNgJIIABB6BxqQYTxATYCSCAAQewcakGE8QE2AkggAEHwHGpBhPEBNgJIIABB9BxqIgFBhPEBNgJIIABB+BxqQYTxATYCSCAAQfwcakGE8QE2AkggAEGAHWpBhPEBNgJIIABBhB1qQYTxATYCSCAAQYgdakGE8QE2AkggAEGMHWpBhPEBNgJIIABBkB1qQYTxATYCSCAAQZQdakGE8QE2AkggAEGYHWpBhPEBNgJIIABBnB1qQYTxATYCSCAAQYTxATYCrAEgAEGE8QE2ArwCIABBhPEBNgLMAyAAQYTxATYC3AQgAEGE8QE2AuwFIABBhPEBNgL8BiAAQcQHakGE8QE2AkggAEHUCGpBhPEBNgJIIABB5AlqQYTxATYCSCAAQfQKakGE8QE2AkggAEGEDGpBhPEBNgJIIABBlA1qQYTxATYCSCAAQaQOakGE8QE2AkggAEG0D2pBhPEBNgJIIABBxBBqQYTxATYCSCAAQdQRakGE8QE2AkggAEHkEmpBhPEBNgJIIABB9BNqQYTxATYCSCAAQYQVakGE8QE2AkggAEGUFmpBhPEBNgJIIABBpBdqQYTxATYCSCAAQbQYakGE8QE2AkggAEHEGWpBhPEBNgJIIABB1BpqQYTxATYCSCAAQeQbakGE8QE2AkggAUGE8QE2AkggAEGEHmpBhPEBNgJIIABBlB9qQYTxATYCSCAAQaQgakGE8QE2AkggAEG0IWpBhPEBNgJIIABBxCJqQYTxATYCSCAAQdQjakGE8QE2AkggAEHkJGpBhPEBNgJIIABB9CVqQYTxATYCSCAAQYQnakGE8QE2AkggAEGUKGpBhPEBNgJIIAJBEGokAAtkAQF/IwBBEGsiAyQAIAMgADYCDCADIAE2AgggAyACNgIEQSgQDSEAIAMoAgwhASAAQbDDADYCACAAIAEoAgA2AgQgAEHMwwA2AgAgAEGkhgE2AgAgAEIANwIIIANBEGokACAAC18BA38jAEEQayICJAAgAiAANgIMIAIgATYCCEEIEA0hASACKAIMIQMgAigCCCEEIwBBEGsiACABNgIMIAAgAzYCCCAAIAQ2AgQgACgCDCAAKAIINgIAIAJBEGokACABCysBAn9BCBANIQEjAEEQayIAIAE2AgwgACgCDCIAQQA2AgAgAEEANgIEIAELMQEBfyMAQRBrIgEkACABIAA2AgwgASgCDCIAIAAoAgAoAjQRAQAhACABQRBqJAAgAAuDAQECfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgghASMAQRBrIgAkACAAIAIoAgw2AgwgACABNgIIIAAoAgghAyMAQRBrIgEgACgCDEGUAWo2AgwgASADNgIIIAEoAgwoAgwgASgCCEECdGooAgAhASAAQRBqJAAgAkEQaiQAIAELVAECfyMAQRBrIgEkACABIAA2AgwjAEEQayIAJAAgACABKAIMNgIMIwBBEGsiAiAAKAIMQZQBajYCDCACKAIMKAIEIQIgAEEQaiQAIAFBEGokACACCzcBAX8jAEEQayIBJAAgASAANgIMIwBBEGsiACABKAIMNgIMIAAoAgwoApABIQAgAUEQaiQAIAAL9QEBBX8jAEEQayIEJAAgBCAANgIMQagBEAohBSAEKAIMIQAjAEEQayIBJAAgASAFNgIMIAEgADYCCCABKAIMIgIQrQIgAkHgjAE2AgAgAkGUAWoQVSACIAEoAgg2ApABIAEoAgghAyMAQRBrIgAkACAAIAI2AgwgACADNgIIIAAoAgwhAiAAQQA2AgQDQCAAKAIEIAAoAggiAyADKAIAKAIcEQEASARAQdQBEAoiAyAAKAIIIAAoAgQQ1wMgACADNgIAIAJBlAFqIAAQrAIgACAAKAIEQQFqNgIEDAELCyAAQRBqJAAgAUEQaiQAIARBEGokACAFCzcBAX8jAEEQayIBJAAgASAANgIMIwBBEGsiACABKAIMNgIMIAAoAgwoAqwBIQAgAUEQaiQAIAALdAEBfyMAQRBrIgMkACADIAA2AgwgAyABNgIIIAMgAjYCBCADKAIIIQEgAygCBCECIwBBEGsiACQAIAAgAygCDDYCDCAAIAE2AgggACACNgIEIAAoAgxBkAFqIAAoAgggACgCBBBUIABBEGokACADQRBqJAALVAECfyMAQRBrIgEkACABIAA2AgwjAEEQayIAJAAgACABKAIMNgIMIwBBEGsiAiAAKAIMQZABajYCDCACKAIMKAIoIQIgAEEQaiQAIAFBEGokACACCzgBAX8jAEEQayICJAAgAiAANgIMIAIgATYCCEHUARAKIgAgAigCDCACKAIIENcDIAJBEGokACAACyQBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwgAigCCDYCQAsYAQF/IwBBEGsiASAANgIMIAEoAgwoAkALJAEBfyMAQRBrIgIgADYCDCACIAE2AgggAigCDCACKAIINgI8CyQBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwgAigCCDYCOAsYAQF/IwBBEGsiASAANgIMIAEoAgwoAjgLJAEBfyMAQRBrIgIgADYCDCACIAE2AgggAigCDCACKAIINgIwCxgBAX8jAEEQayIBIAA2AgwgASgCDCgCMAskAQF/IwBBEGsiAiAANgIMIAIgATYCCCACKAIMIAIoAgg2AiwLGAEBfyMAQRBrIgEgADYCDCABKAIMKAIsCyQBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwgAigCCDYCKAsZAQF/IwBBEGsiASAANgIMIAEoAgwqAugBCyQBAX8jAEEQayICIAA2AgwgAiABNgIIIAIoAgwgAigCCDYCHAsYAQF/IwBBEGsiASAANgIMIAEoAgwoAhwLOwEBfyMAQRBrIgMkACADIAA2AgwgAyABNgIIIAMgAjYCBCADKAIMIAMoAgggAygCBBDbAyADQRBqJAALOgEBfyMAQRBrIgMkACADIAA2AgwgAyABNgIIIAMgAjYCBCADKAIMIAMoAgggAygCBBBUIANBEGokAAtTAQF/IwBBIGsiBSQAIAUgADYCHCAFIAE2AhggBSACNgIUIAUgAzYCECAFIAQ2AgwgBSgCHCAFKAIYIAVBFGogBUEQaiAFQQxqEKsCIAVBIGokAAsYAQF/IwBBEGsiASAANgIMIAEoAgwoAigLNgEBfyMAQRBrIgEkACABIAA2AgwjAEEQayIAIAEoAgw2AgwgACgCDCgCKCEAIAFBEGokACAAC4QBAQN/IwBBEGsiASQAIAEgADYCDCMAQRBrIgIkACACIAEoAgw2AgwCQCACKAIMIgAoAiBFDQAgACgCIEEBSgRAIAAgACgCIEEBazYCIAwBCyAAKAIIIgMgACgCHCADKAIAKAIYEQMAIABBADYCJCAAQQA2AiALIAJBEGokACABQRBqJAALnQEBA38jAEEQayIBJAAgASAANgIMIwBBEGsiAiQAIAIgASgCDDYCDAJAIAIoAgwiACgCIEEASgRAIAAgACgCIEEBajYCIAwBCyAAKAIIIgMgAEEkaiAAQShqIABBLGogAEEwaiAAQTRqIABBOGogAEE8aiAAQUBrIAAoAhwgAygCACgCEBEYACAAQQE2AiALIAJBEGokACABQRBqJAAL9AEBBH8jAEEQayIDJAAgAyAANgIMQcQAEA0iBCEAIAMoAgwhAiMAQRBrIgEkACABIAA2AgwgASACNgIIIAEoAgwiAEEANgIAIwBBEGsiAiAANgIMIAIoAgxB/CY2AgAgAEGcJzYCACMAQRBrIABBDGo2AgwgACABKAIIKAIINgIIIAAgASgCCCgCHDYCHCAAIAEoAggqAgQ4AgQgACABKAIIIgIpAgw3AgwgACACKQIUNwIUIABBADYCICAAQQA2AiQgAEEANgIoIABBADYCMCAAQQA2AjQgAEEANgI4IABBADYCPCABQRBqJAAgA0EQaiQAIAQLEAEBf0HEABANIgAQ3AMgAAtpAQF/IwBB0ABrIgIkACACIAA2AkwgAiABNgJIQfjkAS0AAEUEQEG45AEQWEH45AFBAToAAAsgAkEIaiIBIAIoAkwiACACKAJIIAAoAgAoAoQBEQUAQbjkASABEEQgAkHQAGokAEG45AELXQEBfyMAQSBrIgUkACAFIAA2AhwgBSABNgIYIAUgAjYCFCAFIAM2AhAgBSAENgIMIAUoAhwiACAFKAIYIAUoAhQgBSgCECAFKAIMIAAoAgAoAngRCQAgBUEgaiQAC+AFAQh/IwBBEGsiBiQAIAYgADYCDCAGIAE2AgggBiACNgIEIAYoAgghACAGKAIEIQEjAEEQayIHJAAgByAGKAIMNgIMIAcgADYCCCAHIAE2AgQgBygCCCEAIwBBEGsiCCQAIAggBygCDCIKQZgBajYCDCAIIAA2AggjAEEQayIAIAgoAgwiBTYCDCAIIAAoAgwoAgQ2AgQgCCgCBAJ/IwBBEGsiACAFNgIMIAAoAgwoAggLRgRAIwBBEGsiACAFNgIMIAAoAgwoAgQhASAAIAU2AgwgACABNgIIIAAoAggiAUEBdEEBIAEbIQEgACQAIAAgBTYCDCAAIAE2AggjAEEQayIBIAAoAgwiAjYCDCABKAIMKAIIIAAoAghIBEAgACgCCCEDIwBBEGsiASQAIAEgAjYCCCABIAM2AgQgASgCCCEEAkAgASgCBARAIAEoAgQhCSMAQRBrIgMkACADIAQ2AgwgAyAJNgIIIANBADYCBCADKAIIQQZ0IQRBxIUCQcSFAigCAEEBajYCACAEQRBB+NMBKAIAEQIAIQQgA0EQaiQAIAEgBDYCDAwBCyABQQA2AgwLIAFBEGokACAAIAEoAgw2AgQjACIJQRBrIgEgAjYCDCABKAIMKAIEIQMgACgCBCEEIAlBIGsiASQAIAEgAjYCHCABQQA2AhggASADNgIUIAEgBDYCECABKAIcIQMgASABKAIYNgIMA0AgASgCDCABKAIUSARAIAEoAgxBBnQiBCABKAIQaiAEIAMoAgxqEGMgASABKAIMQQFqNgIMDAELCyABQSBqJAAjAEEQayIBIAI2AgwgAiABKAIMKAIEEE0gAhA6IAJBAToAECACIAAoAgQ2AgwgAiAAKAIINgIICyAAQRBqJAALIAUoAgwgBSgCBEEGdGogCCgCCBBjIAUgBSgCBEEBajYCBCAIQRBqJAAgCkGsAWogB0EEahCsAiAHQRBqJAAgBkEQaiQACxkBAX8jAEEQayIBIAA2AgwgASgCDCoC4AELLwEBfyMAQRBrIgEkACABIAA6AA9BwAEQCiIAIAEtAA9BAXEQ3gMgAUEQaiQAIAALEgEBf0HAARAKIgBBARDeAyAAC/oBAQF/IwBBIGsiBSQAIAUgADYCHCAFIAE2AhggBSACNgIUIAUgAzYCECAFIAQ2AgwgBSgCGCEBIAUoAhQhAiAFKAIQIQMgBSgCDCEEIwBBIGsiACQAIAAgBSgCHDYCHCAAIAE2AhggACACNgIUIAAgAzYCECAAIAQ2AgwgACgCHCIBIAAoAhgiAikCADcCYCABIAIpAgg3AmggASAAKAIUIgIpAgA3AnAgASACKQIINwJ4IAEgACgCECICKQIANwKAASABIAIpAgg3AogBIAEgACgCDCICKQIANwKQASABIAIpAgg3ApgBIAEQWyAAQSBqJAAgBUEgaiQACz8BA39BoAEQCiICIQAjAEEQayIBJAAgASAANgIMIAEoAgwiABD+ASAAQYgjNgIAIABBBDYCXCABQRBqJAAgAgvnAQEGfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgghASMAQUBqIgAkACAAIAIoAgw2AjwgACABNgI4IABBGGoiBCAAKAI8IgFByABqIAFBOGoiBRAfIABBCGoiAyAFQSBqIAUQHyAAQShqIgEgBCADEF0gARDBASAAKAI4IQQjAEEQayIDIAE2AgwgAygCDCEDIwBBEGsiBiABNgIMIAYoAgxBBGohBiMAQRBrIgcgATYCDCAHKAIMQQhqIQcgACAFIAEQJzgCBCAEIAMgBiAHIABBBGoQfCAAQUBrJAAgAkEQaiQAC8MBAQJ/IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCCCEBIwBBQGoiACQAIAAgAigCDDYCPCAAIAE2AjggAEEoaiAAKAI4IAAoAjwiAUE4ahBFIAEgACkCKDcCOCABIAApAjA3AkAgAEEYaiAAKAI4IAFBOGoiA0EQahBFIAEgACkCGDcCSCABIAApAiA3AlAgAEEIaiAAKAI4IANBIGoQRSABIAApAgg3AlggASAAKQIQNwJgIABBQGskACACQRBqJAAL0QIBBX8jAEEQayIEJAAgBCAANgIMIAQgATYCCCAEIAI2AgRB6AAQCiEGIAQoAgwhACAEKAIIIQEgBCgCBCEDIwBBEGsiAiQAIAIgBjYCDCACIAA2AgggAiABNgIEIAIgAzYCACACKAIIIQEgAigCBCEDIAIoAgAhBSMAQSBrIgAkACAAIAIoAgwiBzYCGCAAIAE2AhQgACADNgIQIAAgBTYCDCAAIAAoAhgiATYCHCABEEoaIAFBgBE2AgAgAUE4aiIDQTBqIQUDQCMAQRBrIAM2AgwgBSADQRBqIgNHDQALIAFBATYCBCABIAAoAhQiAykCADcCOCABIAMpAgg3AkAgASAAKAIQIgMpAgA3AkggASADKQIINwJQIAEgACgCDCIDKQIANwJYIAEgAykCCDcCYCAAQSBqJAAgB0G4DzYCACACQRBqJAAgBEEQaiQAIAYLEAEBf0HIABANIgAQ3wMgAAuyAwECfyMAQRBrIgQkACAEIAA2AgwgBCABNgIIIAQgAjgCBCAEKAIIIQEgBCoCBCECIwBBEGsiACQAIAAgBCgCDDYCDCAAIAE2AgggACACOAIEIAAoAgwhASMAQRBrIgMgACgCCDYCDCADKAIMKgIAIAAqAgSTIQIjAEEQayIDIAE2AgwgAygCDCACOAIAIwBBEGsiAyAAKAIINgIMIAMoAgwqAgQgACoCBJMhAiMAQRBrIgMgATYCDCADKAIMIAI4AgQjAEEQayIDIAAoAgg2AgwgAygCDCoCCCAAKgIEkyECIwBBEGsiAyABNgIMIAMoAgwgAjgCCCMAQRBrIgMgACgCCEEQajYCDCADKAIMKgIAIAAqAgSSIQIjAEEQayIDIAFBEGoiATYCDCADKAIMIAI4AgAjAEEQayIDIAAoAghBEGo2AgwgAygCDCoCBCAAKgIEkiECIwBBEGsiAyABNgIMIAMoAgwgAjgCBCMAQRBrIgMgACgCCEEQajYCDCADKAIMKgIIIAAqAgSSIQIjAEEQayIDIAE2AgwgAygCDCACOAIIIABBEGokACAEQRBqJAALsgIBA38jAEEQayIEJAAgBCAANgIMIAQgATgCCCAEKgIIIQEjAEEQayIAJAAgACAEKAIMNgIMIAAgATgCCCAAKgIIIQEjAEEQayICIAAoAgwiAzYCDCACKAIMIgIgAioCACABkzgCACAAKgIIIQEjAEEQayICIAM2AgwgAigCDCICIAIqAgQgAZM4AgQgACoCCCEBIwBBEGsiAiADNgIMIAIoAgwiAiACKgIIIAGTOAIIIAAqAgghASMAQRBrIgIgA0EQaiIDNgIMIAIoAgwiAiACKgIAIAGSOAIAIAAqAgghASMAQRBrIgIgAzYCDCACKAIMIgIgAioCBCABkjgCBCAAKgIIIQEjAEEQayICIAM2AgwgAigCDCIDIAMqAgggAZI4AgggAEEQaiQAIARBEGokAAsjAQF/IwBBEGsiASQAIAEgADYCDCABKAIMEOADIAFBEGokAAtPAQF/IwBBEGsiBCQAIAQgADYCDCAEIAE2AgggBCACNgIEIAQgAzgCAEEgEA0iACAEKAIMIAQoAgggBCgCBCAEKgIAEOEDIARBEGokACAAC4EFAgJ/BH0jAEEwayIJJAAgCSAANgIsIAkgATYCKCAJIAI2AiQgCSADOAIgIAkgBDgCHCAJIAU4AhggCSAGNgIUIAkgBzYCECAJIAg6AA9B/AAQCiEAIAkoAiwhASAJKAIoIQIgCSgCJCEHIAkqAiAhAyAJKgIcIQsgCSoCGCEEIAkoAhQhBiAJKAIQIQggCS0AD0EBcSEKIABCIzcCBCAAQQA2AgwgAEGM6AA2AgAgAEGo9gA2AgAgAEKAgID8g4CAwD83AmwgACAGNgJoIABBADsAZSAAIAo6AGQgACAINgJgIAAgBzYCXCAAIAM4AlggACAEOAJMIAAgCzgCSCAAIAI2AkQgACABNgJAIABBGDYCBCAAQoCAgPwDNwJ0IAAgAkEBa7IiAzgCVCAAIAFBAWuyIgw4AlACQAJ9AkACQAJAAkAgBg4DAQIDAAsgACoCKCEFIAAqAhghDiAAKgIkIQMgACoCFCENIAAqAiAhBCAAKgIQIQsMBAsgACAEOAIgIAAgCzgCECAAQQA2AiwgACADOAIoIAAgDDgCJCAAQQA2AhwgAEIANwIUIAMhBSAMIQMMAwsgACAMOAIgIABBADYCECAAQQA2AiwgACADOAIoIAAgBDgCJCAAQgA3AhggACALOAIUIAMhBSAEIQMgCyENQwAAAAAMAQsgACAMOAIgIABCADcCECAAQQA2AiwgACAEOAIoIAAgAzgCJCAAQQA2AhwgACALOAIYIAQhBSALCyEOIAwhBEMAAAAAIQsLIABBADYCPCAAIA4gBZJDAAAAP5Q4AjggACANIAOSQwAAAD+UOAI0IAAgCyAEkkMAAAA/lDgCMCAJQTBqJAAgAAsZAQF/IwBBEGsiASAANgIMIAEoAgwqAuQBC0oBAX8jAEEQayIDJAAgAyAANgIMIAMgAToACyADIAI6AApBzAAQCiIAIAMoAgwgAy0AC0EBcSADLQAKQQFxEJMFIANBEGokACAACz0BAX8jAEEQayICJAAgAiAANgIMIAIgAToAC0HMABAKIgAgAigCDCACLQALQQFxQQEQkwUgAkEQaiQAIAAL0AECAn8EfSMAQRBrIgIkACACIAA2AgwgAiABOAIIQdQAEAohACACKAIMIQMgAioCCCEGIABCIzcCBCAAQQA2AgwgAEGM6AA2AgAgAEGE/wA2AgAgAyoCCCEBIAMqAgAhBCADKgIEIQUgAyoCDCEHIABCADcCRCAAIAY4AkAgACAHOAI8IABCADcCTCAAQRw2AgQgACABQwAAgD8gASABlCAEIASUIAUgBZSSkpGVIgGUOAI4IAAgBSABlDgCNCAAIAQgAZQ4AjAgAkEQaiQAIAALMQEBf0EgEAoiAEIjNwIEIABBADYCDCAAQYzoADYCACAAQRs2AgQgAEHA9QA2AgAgAAs2AQF/IwBBEGsiASQAIAEgADYCDCMAQRBrIgAgASgCDDYCDCAAKAIMQRRqIQAgAUEQaiQAIAALLwEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgwgAigCCBD9ASACQRBqJAALQgEBfyMAQRBrIgMkACADIAA2AgwgAyABNgIIIAMgAjoAByADKAIMIAMoAgggAy0AB0EBcRD8ASEAIANBEGokACAAC1YBAX8jAEEgayIFJAAgBSAANgIcIAUgATYCGCAFIAI2AhQgBSADNgIQIAUgBDoADyAFKAIcIAUoAhggBSgCFCAFKAIQIAUtAA9BAXEQ8wQgBUEgaiQAC0kBAX8jAEEQayIEJAAgBCAANgIMIAQgATYCCCAEIAI2AgQgBCADNgIAIAQoAgwgBCgCCCAEKAIEIAQoAgBBABDzBCAEQRBqJAALPgEBfyMAQRBrIgIkACACIAA6AA8gAiABOgAOQawBEAoiACACLQAPQQFxIAItAA5BAXEQ5AIgAkEQaiQAIAALMQEBfyMAQRBrIgEkACABIAA6AA9BrAEQCiIAIAEtAA9BAXFBARDkAiABQRBqJAAgAAsUAQF/QawBEAoiAEEBQQEQ5AIgAAtUAQF/IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCCCEBIwBBEGsiACACKAIMNgIMIAAgATYCCCAAKAIMKAIMIAAoAghBBXRqIQAgAkEQaiQAIAALSgEBfyMAQRBrIgQkACAEIAA2AgwgBCABNgIIIAQgAjYCBCAEIAM6AAMgBCgCDCAEKAIIIAQoAgQgBC0AA0EBcRCOBSAEQRBqJAALPQEBfyMAQRBrIgMkACADIAA2AgwgAyABNgIIIAMgAjYCBCADKAIMIAMoAgggAygCBEEBEI4FIANBEGokAAuDAQECfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgghASMAQRBrIgAkACAAIAIoAgw2AgwgACABNgIIIAAoAgghAyMAQRBrIgEgACgCDEEMajYCDCABIAM2AgggASgCDCgCDCABKAIIQdAAbGooAkAhASAAQRBqJAAgAkEQaiQAIAELUwECfyMAQRBrIgEkACABIAA2AgwjAEEQayIAJAAgACABKAIMNgIMIwBBEGsiAiAAKAIMQQxqNgIMIAIoAgwoAgQhAiAAQRBqJAAgAUEQaiQAIAILLwEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgwgAigCCBCNBSACQRBqJAALgAcDB38BfQF+IwBBEGsiBiQAIAYgADYCDCAGIAE2AgggBiACNgIEIAYoAgghAiAGKAIEIQMjAEGQAWsiACQAIAYoAgwiASABKAJEQQFqNgJEIABBADYCjAEgACACKQIINwNIIAAgAikCADcDQCAAIAIpAhg3A1ggACACKQIQNwNQIAAgAikCKDcDaCAAIAIpAiA3A2AgACACKQI4NwN4IAIpAjAhCyAAIAM2AoABIAAgCzcDcCAAIAMoAgQ2AoQBIAAgAyADKAIAKAIwEQYAOAKIASADIAIgAEEwaiAAQSBqIAMoAgAoAggRBAAgACoCMCIKIAEqAiBdBEAgASAKOAIgCyAAKgIgIgogASoCMF4EQCABIAo4AjALIAAqAjQiCiABKgIkXQRAIAEgCjgCJAsgACoCJCIKIAEqAjReBEAgASAKOAI0CyAAKgI4IgogASoCKF0EQCABIAo4AigLIAAqAigiCiABKgI4XgRAIAEgCjgCOAsgASgCQCICBEAgACAAKQM4NwMIIAAgACkDKDcDGCAAIAApAyA3AxAgACAAKQMwNwMAIAAgAiAAIAEoAhAQTDYCjAELIABBQGshAgJAIAEoAhAiBSABKAIURw0AIAUgBUEBdEEBIAUbIglODQAgCQRAQcSFAkHEhQIoAgBBAWo2AgAgCUHQAGxBEEH40wEoAgARAgAhByABKAIQIQULIAVBAEoEQANAIAcgCEHQAGwiBGoiAyABKAIYIARqIgQpAgA3AgAgAyAEKQIINwIIIAMgBCkCGDcCGCADIAQpAhA3AhAgAyAEKQIoNwIoIAMgBCkCIDcCICADIAQpAjg3AjggAyAEKQIwNwIwIAMgBCkCQDcCQCADIAQpAkg3AkggCEEBaiIIIAVHDQALCwJAIAEoAhgiA0UNACABLQAcRQ0AIAMEQEHIhQJByIUCKAIAQQFqNgIAIANB/NMBKAIAEQAACwsgASAHNgIYIAFBAToAHCABIAk2AhQgASgCECEFCyABKAIYIAVB0ABsaiIDIAIpAgA3AgAgAyACKQIINwIIIAMgAikCGDcCGCADIAIpAhA3AhAgAyACKQIoNwIoIAMgAikCIDcCICADIAIpAjg3AjggAyACKQIwNwIwIAMgAikCSDcCSCADIAIpAkA3AkAgASABKAIQQQFqNgIQIABBkAFqJAAgBkEQaiQACy8BAX8jAEEQayIBJAAgASAAOgAPQdwAEAoiACABLQAPQQFxEI8FIAFBEGokACAACxIBAX9B3AAQCiIAQQEQjwUgAAuBAwECfyMAQRBrIgIkACACIAA2AgwgAigCDCIBBEACQCABKAIgIgBFDQAgAS0AJEUNACAABEBByIUCQciFAigCAEEBajYCACAAQfzTASgCABEAAAsLIAFBADYCICABQQE6ACQgAUIANwIYAkACQAJAIAEoAgwiAEEAIAEtABAbRQRAIAFCADcCBCABQQE6ABAMAQsgAARAQciFAkHIhQIoAgBBAWo2AgAgAEH80wEoAgARAAALIAFBAToAECABQQA2AgwgAUIANwIEIAEoAiAiAEUNACABLQAkDQELIAFBADYCICABQQE6ACQgAUIANwIYDAELIAAEQEHIhQJByIUCKAIAQQFqNgIAIABB/NMBKAIAEQAACyABQQE6ACQgAUEANgIgIAFCADcCGCABKAIMIgBFDQAgAS0AEEUNACAABEBByIUCQciFAigCAEEBajYCACAAQfzTASgCABEAAAsLIAFBADYCDCABQQE6ABAgAUIANwIEIAEQgwELIAJBEGokAAtgAQJ/IwBBEGsiAiQAIAIgADYCDCMAQRBrIgAkACAAIAIoAgw2AgwjAEEQayIBIAAoAgw2AgwgAUEANgIIIAEoAgwoAgwgASgCCEEEdGohASAAQRBqJAAgAkEQaiQAIAELIwEBfyMAQRBrIgEkACABIAA2AgwgAUEQaiQAIAEoAgwoAgQL9AwBDn8jAEEQayIMJAAgDCAANgIMIAwgATgCCEEAIQAjAEHgCGsiAiQAQSohByAMKAIMIgMoAiwiBCAEKAIAKAJUEQEAIgRBAEoEQANAIAMoAiwiBSAAIAJBgAFqIAUoAgAoAlgRBQAQ+AQgB0EEdCIFQajpAWogAikDiAE3AgAgBUGg6QFqIAIpA4ABNwIAIAdBAWohByAAQQFqIgAgBEcNAAsLQQAhAANAIAMoAiwhBBD4BCACIAQgAEEEdCIFQaDpAWogBCgCACgCQBEFACACQYABaiAFaiIEIAIpAwg3AgggBCACKQMANwIAIABBAWoiACAHRw0ACyACQoCggICAgAQ3AnQgAkKQgICA8M3EwTo3AmwgAiAHNgJkIAJBATYCYCACIAJBgAFqNgJoIAJBAToAXCACQQA2AlggAkIANwNQIAJBADYCRCACQQE6AEggAkIANwI8IAJBADYCFCACQQE6ABggAkEBOgA0IAJCADcCDCACQQA2AjAgAkIANwMoIAJCADcCHCACQQA2AgQgAkEBOgAAIAJBOGogAkHgAGogAhCQBCIOQQFHBEAgAigCBCIEIQAgBCADKAIEIgZKBEAgBCADKAIISgRAAkAgBEUEQEEAIQcMAQtBxIUCQcSFAigCAEEBajYCACAEQQR0QRBB+NMBKAIAEQIAIQcgAygCBCEGCwJAIAZBAEwNAEEAIQAgBkEBRwRAIAZBfnEhCQNAIAcgAEEEdCIFaiIIIAMoAgwgBWoiCykCADcCACAIIAspAgg3AgggByAFQRByIgVqIgggAygCDCAFaiIFKQIANwIAIAggBSkCCDcCCCAAQQJqIQAgCkECaiIKIAlHDQALCyAGQQFxRQ0AIAcgAEEEdCIAaiIFIAMoAgwgAGoiACkCADcCACAFIAApAgg3AggLAkAgAygCDCIARQ0AIAMtABBFDQAgAARAQciFAkHIhQIoAgBBAWo2AgAgAEH80wEoAgARAAALCyADIAc2AgwgA0EBOgAQIAMgBDYCCAsgAigCBCEACyADIAQ2AgQgAEEASgRAQQAhAANAIABBBHQiBCADKAIMaiIFIAIoAhQgBGoiBCkCADcCACAFIAQpAgg3AgggAEEBaiIAIAIoAgRIDQALCyADIAIoAiAiBDYCKCAEIgAgAygCGCILSgRAAkAgBCADKAIcTARAIAMoAiAhBgwBCwJ/IARFBEBBACEGIAsMAQtBxIUCQcSFAigCAEEBajYCACAEQQJ0QRBB+NMBKAIAEQIAIQYgAygCGAshCSADKAIgIQUCQCAJQQBKBEBBACEHQQAhACAJQQFrQQNPBEAgCUF8cSEPQQAhCgNAIAYgAEECdCIIaiAFIAhqKAIANgIAIAYgCEEEciINaiAFIA1qKAIANgIAIAYgCEEIciINaiAFIA1qKAIANgIAIAYgCEEMciIIaiAFIAhqKAIANgIAIABBBGohACAKQQRqIgogD0cNAAsLIAlBA3EiCkUNAQNAIAYgAEECdCIJaiAFIAlqKAIANgIAIABBAWohACAHQQFqIgcgCkcNAAsMAQsgBQ0AIAMgBjYCICADIAQ2AhwgA0EBOgAkDAELIAMtACRBACAFGwRAQciFAkHIhQIoAgBBAWo2AgAgBUH80wEoAgARAAALIAMgBjYCICADQQE6ACQgAyAENgIcCyAGIAtBAnRqQQAgBCALa0ECdBAJGiADKAIoIQALIAMgBDYCGCAAQQBKBEAgAygCICEEQQAhACACKAIwIQUDQCAEIABBAnQiBmogBSAGaigCADYCACAAQQFqIgAgAygCKEgNAAsLIAIQjwQLAkAgAigCMCIARQ0AIAItADRFDQAgAARAQciFAkHIhQIoAgBBAWo2AgAgAEH80wEoAgARAAALCyACQQA2AjAgAkEBOgA0IAJCADcDKAJAIAIoAhQiAEUNACACLQAYRQ0AIAAEQEHIhQJByIUCKAIAQQFqNgIAIABB/NMBKAIAEQAACwsCQCACKAJYIgBFDQAgAi0AXEUNACAABEBByIUCQciFAigCAEEBajYCACAAQfzTASgCABEAAAsLIAJBADYCWCACQQE6AFwgAkIANwNQAkAgAigCRCIARQ0AIAItAEhFDQAgAARAQciFAkHIhQIoAgBBAWo2AgAgAEH80wEoAgARAAALCyACQeAIaiQAIAxBEGokACAOQQFHC2IBAn8jAEEQayIBJAAgASAANgIMQTAQCiEAIAEoAgwhAiAAQQE6ABAgACACNgIsIABBADYCDCAAQgA3AgQgAEEANgIoIABBAToAJCAAQQA2AiAgAEIANwIYIAFBEGokACAACyIBAX8jAEEQayIBJAAgASAANgIMIAEoAgwQWyABQRBqJAALQAEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgwiACACKAIIIAAoAgAoAlwRAgBBAXEhACACQRBqJAAgAAsxAQF/IwBBEGsiASQAIAEgADYCDCABKAIMIgAgACgCACgCYBEBACEAIAFBEGokACAACz4BAX8jAEEQayIDJAAgAyAANgIMIAMgATYCCCADIAI6AAcgAygCDCADKAIIIAMtAAdBAXEQjAUgA0EQaiQACzEBAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCACKAIMIAIoAghBARCMBSACQRBqJAALOAEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIQfAAEAoiACACKAIMIAIoAggQgwIgAkEQaiQAIAALLgEBfyMAQRBrIgEkACABIAA2AgxB8AAQCiIAIAEoAgxBABCDAiABQRBqJAAgAAsUAQF/QfAAEAoiAEEAQQAQgwIgAAvhAwEFfyMAQRBrIgMkACADIAA2AgwgAyABNgIIIAMoAgghACMAQRBrIgQkACAEIAMoAgxBGGo2AgwgBCAANgIIIAQoAgghACMAQTBrIgEkACABIAQoAgw2AiwgASAANgIoIAEoAiwhBiMAQRBrIgAgASgCKDYCDCABIAAoAgwoAgQ2AiQgASgCJCECIAFCADcCACABQQA2AiAgAUIANwIYIAFCADcCECABQgA3AgggARCcAiMAQSBrIgAkACAAIAY2AhwgACACNgIYIAAgATYCFCMAQRBrIgUgACgCHCICNgIMIAAgBSgCDCgCBDYCEAJAIAAoAhggACgCEEgEQCAAIAAo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NgIMDAELCwwBCyAAKAIYAn8jAEEQayIFIAI2AgwgBSgCDCgCBAtKBEAgAiAAKAIYEKADCyAAIAAoAhA2AggDQCAAKAIIIAAoAhhIBEAgAigCDCAAKAIIQQJ0aiAAKAIUKgIAOAIAIAAgACgCCEEBajYCCAwBCwsLIAIgACgCGDYCBCAAQSBqJAAgASgCCCABKAIEIAYoAgwQnQMgAUEQaiQAIARBEGokACADQRBqJAALGQEBfyMAQRBrIgEgADYCDCABKAIMQfAAagszAQF/IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCDEHcAGogAigCCBCvAiACQRBqJAALMwEBfyMAQRBrIgIkACACIAA2AgwgAiABNgIIIAIoAgxByABqIAIoAggQrwIgAkEQaiQACzEBAX8jAEEQayICJAAgAiAANgIMIAIgATYCCCACKAIMQRRqIAIoAggQeSACQRBqJAALwQEBA38jAEEQayIDJAAgAyAANgIMIAMgATYCCEGEARANIQQgAygCDCEBIAMoAgghACMAQRBrIgIkACACIAQ2AgwgAiABNgIIIAIgADYCBCACKAIMIgEQ8QMgAUGkDDYCACABQRRqEFUgASACKAIIIgApAgA3AiggASAAKQIINwIwIAEgAigCBCIAKQIANwI4IAEgACkCCDcCQCABQcgAahBVIAFB3ABqEFUgAUHwAGoQVSACQRBqJAAgA0EQaiQAIAQLWQIBfwF9IwBBEGsiAiQAIAIgADYCDCACIAE2AgggAigCCCEBIwBBEGsiACACKAIMNgIMIAAgATYCCCAAKAIMKAIMIAAoAghBAnRqKgIAIQMgAkEQaiQAIAMLRAECfyMAQRBrIgEkACABIAA2AgwgASgCDCIAAn8jAEEQayICIAA2AgwgAigCDCgCBAsQTSAAEDogABDOASABQRBqJAALvQEBA38jAEEQayICJAAgAiAANgIMIAIgATYCCEHUABANIQQgAigCDCEBIAIoAgghAyMAQRBrIgAkACAAIAQ2AgwgACABNgIIIAAgAzYCBCAAKAIMIgEQ8QMgAUGICzYCACABIAAoAggiAykCADcCFCABIAMpAgg3AhwgASAAKAIEIgMpAgA3AiQgASADKQIINwIsIwBBEGsgAUE0ajYCDCMAQRBrIAFBxABqNgIMIABBEGokACACQRBqJAAg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AEEQayIAJAAgACABNgIMIwBBEGsiAiAAKAIMIgM2AgwgAigCDEGgCTYCACADQYgINgIAIABBEGokACABCzkBAX9BnAIQCiIAELYBIABBAToAmAIgAEGo2AA2AgAgAEEANgKUAiAAQgA3AowCIABBBDYC7AEgAAsbACAAIAEoAgggBRArBEAgASACIAMgBBC7AgsLOAAgACABKAIIIAUQKwRAIAEgAiADIAQQuwIPCyAAKAIIIgAgASACIAMgBCAFIAAoAgAoAhQREAALlgIBBn8gACABKAIIIAUQKwRAIAEgAiADIAQQuwIPCyABLQA1IQcgACgCDCEGIAFBADoANSABLQA0IQggAUEAOgA0IABBEGoiCSABIAIgAyAEIAUQugIgByABLQA1IgpyIQcgCCABLQA0IgtyIQgCQCAGQQJIDQAgCSAGQQN0aiEJIABBGGohBgNAIAEtADYNAQJAIAsEQCABKAIYQQFGDQMgAC0ACEECcQ0BDAMLIApFDQAgAC0ACEEBcUUNAgsgAUEAOwE0IAYgASACIAMgBCAFELoCIAEtADUiCiAHciEHIAEtADQiCyAIciEIIAZBCGoiBiAJSQ0ACwsgASAHQf8BcUEARzoANSABIAhB/wFxQQBHOgA0C6QBACAAIAEoAgggBBArBEACQCABKAIEIAJHDQAgASgCHEEBRg0AIAEgAzYCHAsPCwJAIAAgASgCACAEECtFDQAgAiABKAIQRyABKAIUIAJHcUUEQCADQQFHDQEgAUEBNgIgDwsgASACNgIUIAEgAzYCICABIAEoAihBAWo2AigCQCABKAIkQQFHDQAgASgCGEECRw0AIAFBAToANgsgAUEENgIsCwuFAgAgACABKAIIIAQQKwRAAkAgASgCBCACRw0AIAEoAhxBAUYNACABIAM2AhwLDwsCQCAAIAEoAgAgBBArBEAgAiABKAIQRyABKAIUIAJHcUUEQCADQQFHDQIgAUEBNgIgDwsgASADNgIgAkAgASgCLEEERg0AIAFBADsBNCAAKAIIIgAgASACIAJBASAEIAAoAgAoAhQREAAgAS0ANQRAIAFBAzYCLCABLQA0RQ0BDAMLIAFBBDYCLAsgASACNgIUIAEgASgCKEEBajYCKCABKAIkQQFHDQEgASgCGEECRw0BIAFBAToANg8LIAAoAggiACABIAIgAyAEIAAoAgAoAhgRCQALC6sEAQN/IAAgASgCCCAEECsEQAJAIAEoAgQgAkcNACABKAIcQQFGDQAgASADNgIcCw8LAkAgACABKAIAIAQQKwRAIAIgASgCEEcgASgCFCACR3FFBEAgA0EBRw0CIAFBATYCIA8LIAEgAzYCICABKAIsQQRHBEAgAEEQaiIFIAAoAgxBA3RqIQdBACEDIAECfwJAA0ACQCAFIAdPDQAgAUEAOwE0IAUgASACIAJBASAEELoCIAEtADYNAAJAIAEtADVFDQAgAS0ANARAQQEhAyABKAIYQQFGDQRBASEGIAAtAAhBAnENAQwEC0EBIQYgAC0ACEEBcUUNAwsgBUEIaiEFDAELC0EEIAZFDQEaC0EDCzYCLCADQQFxDQILIAEgAjYCFCABIAEoAihBAWo2AiggASgCJEEBRw0BIAEoAhhBAkcNASABQQE6ADYPCyAAKAIMIQUgAEEQaiIGIAEgAiADIAQQ3AEgBUECSA0AIAYgBUEDdGohBiAAQRhqIQUgACgCCCIAQQJxRSABKAIkQQFHcUUEQANAIAEtADYNAiAFIAEgAiADIAQQ3AEgBUEIaiIFIAZJDQAMAgsACyAAQQFxRQRAA0AgAS0ANg0CIAEoAiRBAUYNAiAFIAEgAiADIAQQ3AEgBUEIaiIFIAZJDQAMAgsACwNAIAEtADYNASABKAIkQQFGIAEoAhhBAUZxDQEgBSABIAIgAyAEENwBIAVBCGoiBSAGSQ0ACwsLbwECfyAAIAEoAghBABArBEAgASACIAMQvAIPCyAAKAIMIQQgAEEQaiIFIAEgAiADEIQEAkAgBEECSA0AIAUgBEEDdGohBCAAQRhqIQADQCAAIAEgAiADEIQEIAEtADYNASAAQQhqIgAgBEkNAAsLCzIAIAAgASgCCEEAECsEQCABIAIgAxC8Ag8LIAAoAggiACABIAIgAyAAKAIAKAIcEQQACxkAIAAgASgCCEEAECsEQCABIAIgAxC8AgsLugMBBX8jAEFAaiIEJAACf0EBIAAgAUEAECsNABpBACABRQ0AGiMAQUBqIgMkACABKAIAIgVBBGsoAgAhBiAFQQhrKAIAIQcgA0EANgIUIANBtNEBNgIQIAMgATYCDCADQeTRATYCCEEAIQUgA0EYakEAQScQCRogASAHaiEBAkAgBkHk0QFBABArBEAgA0EBNgI4IAYgA0EIaiABIAFBAUEAIAYoAgAoAhQREAAgAUEAIAMoAiBBAUYbIQUMAQsgBiADQQhqIAFBAUEAIAYoAgAoAhgRCQACQAJAIAMoAiwOAgABAgsgAygCHEEAIAMoAihBAUYbQQAgAygCJEEBRhtBACADKAIwQQFGGyEFDAELIAMoAiBBAUcEQCADKAIwDQEgAygCJEEBRw0BIAMoAihBAUcNAQsgAygCGCEFCyADQUBrJABBACAFIgFFDQAaIARBCGoiA0EEckEAQTQQCRogBEEBNgI4IARBfzYCFCAEIAA2AhAgBCABNgIIIAEgAyACKAIAQQEgASgCACgCHBEEACAEKAIgIgBBAUYEQCACIAQoAhg2AgALIABBAUYLIQAgBEFAayQAIAALBQAQAgALCgBB0IUCEL8CGgsSAEHMhQIoAgAiAARAIAAQDAsLcAECfyMAQSBrIgEkACABIAA2AhxB+OIBLQAARQRAIwBBEGtB6OIBNgIMQfjiAUEBOgAACyABQQhqIgAgASgCHCICIAIoAgAoAkwRAwBB6OIBIAApAgA3AgBB8OIBIAApAgg3AgAgAUEgaiQAQejiAQsHACAAEL0CCzUBAX8gACABakEDakGA1AEoAgARAQAiAARAIAAgAWpBA2pBACABa3EiAkEEayAANgIACyACCxkAIAAEQCAAQQRrKAIAQYTUASgCABEAAAsLCQAgACABNgIICwkAIAAgATYCBAvjOgIMfx19IAAoAhgiBEEASgRAA0ACQAJAIAAoAiAgDUECdGooAgAiAygC2AFBAmsOBAEAAAEAC0EAIQQjAEGQAWsiByQAAkAgAy0AnAdFDQAgA0EAOgCcByADKALcBSIFQQBKBEAgAygC5AUhBgNAIAYgBEE0bGoiAiACKAIIIggqAhAgAigCDCIJKgIQkyIOIA6UIAgqAgggCSoCCJMiDiAOlCAIKgIMIAkqAgyTIg4gDpSSkpEiDjgCECACIA4gDpQ4AhwgBEEBaiIEIAVHDQALQQAhBANAIAYgBEE0bGoiAiACKAIIKgJYIAIoAgwqAliSIAIoAgQqAgSVOAIYIARBAWoiBCAFRw0ACwsgAxDHAiADQdwHahC7ASADLQCEA0EQcUUNACADEKEECyADIAMqAvACIAGUIg44AsQDIAMgDkMAAEBAlDgCzAMgA0MAAIA/IA6VOALIAyADIAMoAsABIgQgBCgCACgCMBEGACIOOALQAyADIA5DAACAPpQ4AtQDIAMoAsgFIgVBAEoEQCADKgLEAyIOIAMoAqwFIgQqAjCUIQ8gDiAEKgIslCEQIAQqAiggDpQhDiADKALQBSEGQQAhBANAIAYgBEHoAGxqIgIqAlhDAAAAAF4EQCACIA4gAioCKJI4AiggAiAQIAIqAiySOAIsIAIgDyACKgIwkjgCMAsgBEEBaiIEIAVHDQALC0EAIQRDAAAAACEOQZYVEBEgAygCyAUhBSADKgK4AiEPAn0gAyoCtAIiEkMAAAAAWwRAQwAAAAAgD0MAAAAAXkUNARoLIBJDAACAPyAFQQBMBH1DAAAAAAUgAygC8AUiCUEASgRAIAMoAtAFIgIqAgghECACKgIQIREgAioCDCEWIAMoAvgFIQoDQCAOIAogBEEsbGoiAigCCCIGKgIQIBGTIAIoAgwiCCoCCCAQkyIOIAIoAhAiAioCDCAWkyIVlCACKgIIIBCTIhMgCCoCDCAWkyIUlJOUIAYqAgggEJMgFCACKgIQIBGTIhSUIBUgCCoCECARkyIVlJOUIAYqAgwgFpMgFSATlCAUIA6Uk5SSkpIhDiAEQQFqIgQgCUcNAAsLIA5DAADAQJULIhCLlZQhDiAPIAMqAtwDIBCTlAshEAJAIAVBAEwNACADKgKwAkMAAAAAXiADKgKsAkMAAAAAXnIhBiADQbwJaiEIIBJDAAAAAFwEQEEAIQIDQAJAIAMoAtAFIAJB6ABsaiIEKgJYQwAAAABeRQ0AIAYEQCADIAggAhDlAQsgBCAEKgJIIhYgDiAEKgJcIhKUIhGUIAQqAjiSIhU4AjggBCARIAQqAkwiE5QgBCoCPJIiFDgCPCAEQUBrIgkgESAEKgJQIhmUIAkqAgCSIhc4AgAgD0MAAAAAXkUNACAEIBYgECASlCIRlCAVkjgCOCAEIBEgE5QgFJI4AjwgCSARIBmUIBeSOAIACyACQQFqIgIgBUcNAAsMAQsgD0MAAAAAXgRAQQAhAgNAIAMoAtAFIAJB6ABsaiIEKgJYQwAAAABeBEAgBgRAIAMgCCACEOUBCyAEIAQqAkggECAEKgJclCIOlCAEKgI4kjgCOCAEIA4gBCoCTJQgBCoCPJI4AjwgBEFAayIJIA4gBCoCUJQgCSoCAJI4AgALIAJBAWoiAiAFRw0ACwwBCyAGRQ0AQQAhBANAIAMoAtAFIARB6ABsaioCWEMAAAAAXgRAIAMgCCAEEOUBCyAEQQFqIgQgBUcNAAsLIAMoAvAFIgtBAEoEQCADQbwJaiEJQQAhBANAAkAgAyoCsAIiHEMAAAAAXiADKgKsAiIdQwAAAABeckUNACADKAKgAiIMQQRIDQAgAygC+AUiCiAEQSxsaiIIKAIIIgYqAjAiEyAIKAIMIgIqAjCSIAgoAhAiBSoCMJJDq6qqPpQgCSoCCJMiESARlCAGKgIoIhQgAioCKJIgBSoCKJJDq6qqPpQgCSoCAJMiFiAWlCAGKgIsIhkgAioCLJIgBSoCLJJDq6qqPpQgCSoCBJMiFSAVlJKSIhtDAAAANF5FDQAgAyoCxAMhEiADKAKsBSoCACEeIBFDAACAPyAbkSIflSIPlCEOIBUgD5QhECAWIA+UIQ8gCCoCFCEXIAgqAhwhGCAIKgIYIRoCQAJAIAxBBGsOAwEAAQILIBhDAACAv0MAAIA/IBggEZQgFyAWlCAVIBqUkpJDAAAAAF0bIhGUIhggDpQgFyARlCIXIA+UIBAgGiARlCIalJKSIhUgHUMAAAA/lCAelCAblCAKIARBLGxqKgIkQwAAAD+UIhuUlCIRIA6MlCEdIBEgEIyUISAgESAPjJQhIUMAAAAAIRFDAAAAACEWAn1DAAAAACAVQwAAAABeRQ0AGkMAAAAAIBVD2ht8P11FDQAaIBogDpQgECAYlJMiESAQlCAPIBggD5QgDiAXlJMiGJSTQwAAgD8gFSAVlJORIBxDAAAAP5QgHpQgH5QgG5SUIhWUQ6uqqj6UIRYgFyAQlCAPIBqUkyIXIA+UIA4gEZSTIBWUQ6uqqj6UIREgGCAOlCAQIBeUkyAVlEOrqqo+lAshFSAdQ6uqqj6UIQ8gIEOrqqo+lCEOICFDq6qqPpQhECAGKgJYIhdDAAAAAF4EQAJAIA8gF5QgEpQiGCAYlCAQIBeUIBKUIhggGJQgDiAXlCASlCISIBKUkpIiEkMAAAAAXkUNACASIBMgE5QgFCAUlCAZIBmUkpIiE2BFDQAgDyATkSASkZVDzcxMP5QiEpQhDyAOIBKUIQ4gECASlCEQCyAGIBUgECAGKgI4kpI4AjggBkFAayIIIBYgDyAIKgIAkpI4AgAgBiARIA4gBioCPJKSOAI8CyACKgJYIhJDAAAAAF4EQAJAIA8gEpQgAyoCxAMiE5QiFCAUlCAQIBKUIBOUIhQgFJQgDiASlCATlCISIBKUkpIiEkMAAAAAXkUNACASIAIqAjAiEyATlCACKgIoIhMgE5QgAioCLCITIBOUkpIiE2BFDQAgDyATkSASkZVDzcxMP5QiEpQhDyAOIBKUIQ4gECASlCEQCyACIBUgECACKgI4kpI4AjggAkFAayIGIBYgDyAGKgIAkpI4AgAgAiARIA4gAioCPJKSOAI8CyAFKgJYIhJDAAAAAF5FDQECQCAPIBKUIAMqAsQDIhOUIhQgFJQgECASlCATlCIUIBSUIA4gEpQgE5QiEiASlJKSIhJDAAAAAF5FDQAgEiAFKgIwIhMgE5QgBSoCKCITIBOUIAUqAiwiEyATlJKSIhNgRQ0AIA8gE5EgEpGVQ83MTD+UIhKUIQ8gDiASlCEOIBAgEpQhEAsgBSAVIBAgBSoCOJKSOAI4IAVBQGsiAiAWIA8gAioCAJKSOAIAIAUgESAOIAUqAjySkjgCPAwBCyARIBhDAACAv0MAAIA/IBggEZQgFyAWlCAVIBqUkpJDAAAAAF0bIhGUIhiUIBYgFyARlCIXlCAVIBogEZQiFZSSkiIRQwAAAABeRQ0AIA4gHSAeIBsgESAKIARBLGxqKgIkjJSUlCIOlCIRlCAYIBwgDpQiFpRDAAAAAJKSQ6uqqj6UIg5DAACAPyAOIA6UIA8gEZQgFyAWlEMAAAAAkpJDq6qqPpQiDyAPlCAQIBGUIBUgFpRDAAAAAJKSQ6uqqj6UIhAgEJSSkpGVIhWUIREgECAVlCEWIA8gFZQhFQJAIA4gEiAGKgJYlCIXlCIYIBiUIA8gF5QiGCAYlCAQIBeUIhggGJSSkiATIBOUIBQgFJQgGSAZlJKSXgRAIAYgBioCOEMAAIA/IBeVIhcgFSATIBGUIBQgFZQgFiAZlJKSIhOUlJM4AjggBiAGKgI8IBcgFiATlJSTOAI8IAZBQGsiBiAGKgIAIBcgESATlJSTOAIADAELIAYgDyAGKgI4kjgCOCAGIBAgBioCPJI4AjwgBkFAayIGIA4gBioCAJI4AgALAkAgDiASIAIqAliUIhOUIhQgFJQgDyATlCIUIBSUIBAgE5QiFCAUlJKSIAIqAjAiFCAUlCACKgIoIhkgGZQgAioCLCIXIBeUkpJeRQRAIAIgDyACKgI4kjgCOCACIBAgAioCPJI4AjwgAkFAayICIA4gAioCAJI4AgAMAQsgAiACKgI4QwAAgD8gE5UiEyAVIBQgEZQgGSAVlCAWIBeUkpIiFJSUkzgCOCACIAIqAjwgEyAWIBSUlJM4AjwgAkFAayICIAIqAgAgEyARIBSUlJM4AgALIA4gEiAFKgJYlCISlCITIBOUIA8gEpQiEyATlCAQIBKUIhMgE5SSkiAFKgIwIhMgE5QgBSoCKCIUIBSUIAUqAiwiGSAZlJKSXkUEQCAFIA8gBSoCOJI4AjggBSAQIAUqAjySOAI8IAVBQGsiAiAOIAIqAgCSOAIADAELIAUgBSoCOEMAAIA/IBKVIg4gFSATIBGUIBQgFZQgFiAZlJKSIg+UlJM4AjggBSAFKgI8IA4gFiAPlJSTOAI8IAVBQGsiAiACKgIAIA4gESAPlJSTOAIACyAEQQFqIgQgC0cNAAsLEBAgAygCyAUiBUEASgRAQQAhBANAIAMoAtAFIARB6ABsaiICIAIpAgg3AhggAiACKQIQNwIgIAIgAygCrAUqAgwgAyoCxAMiEJUiDowiDyAOIAIqAjggAioCWCIRlCAQlCIWIA4gFl0bIhYgDyAWXhsgAioCKJIiFjgCKCACIA8gDiAQIBEgAioCPJSUIhIgDiASXRsiEiAPIBJeGyACKgIskiISOAIsIAIgDyAOIBAgESACQUBrIgYqAgCUlCIQIA4gEF0bIg4gDiAPXRsgAioCMJIiDzgCMCACIBYgAyoCxAMiDpQgAioCCJI4AgggAiASIA6UIAIqAgySOAIMIAIgDyAOlCACKgIQkjgCECAGQgA3AgAgAkIANwI4IARBAWoiBCAFRw0ACwsgAxCiBAJAIAMoAqAHIgQEQCADKALAASICIAIoAgAoAjARBgAhDiAEKgIAIQ8gBCoCBCEQIAQqAgghESADQQA2AogHIAMgESAOkzgChAcgAyAQIA6TOAKAByADIA8gDpM4AvwGIAQqAhQhDyAEKgIYIRAgBCoCECERIANBADYCmAcgAyAOIBCSOAKUByADIA4gD5I4ApAHIANBjAdqIgQgDiARkjgCACADKAK8ASICRQ0BIAMoAqwFIgUoAiAiBiACIANB/AZqIAQgBSgCJCAGKAIAKAIQEQkADAELIANCADcC/AYgA0IANwKUByADQgA3AowHIANCADcChAcLIAMoAsgFIgVBAEoEQCADQaAHaiEGQQAhBANAIAMoAtAFIARB6ABsaiICKgIMIQ8gAioCECEQIAIqAgghESADKgLQAyEOIAdBADYCjAEgByAOIBGSOAKAASAHQQA2AnwgByARIA6TOAJwIAcgDiAQkjgCiAEgByAOIA+SOAKEASAHIBAgDpM4AnggByAPIA6TOAJ0IAIoAmAhCCACKgIoIQ8gAioCLCEQIAIqAjAhESADKgLMAyEOIAdBADYCFCAHIA4gEZQ4AhAgByAOIBCUOAIMIAcgDyAOlDgCCCAGIAggB0HwAGogB0EIaiADKgLUAxC4ARogBEEBaiIEIAVHDQALCyADQdwHaiEJAkAgAygC3AdFDQAgAygC8AVBAEwNAEEAIQUDQCADKAL4BSAFQSxsaiIIKAIQIgQqAighGyAIKAIIIgIqAighHiAIKAIMIgYqAighHCAEKgIsIR0gAioCLCEfIAYqAiwhICAEKgIwISEgAioCMCEjIAYqAjAhJCAEKgIMIQ8gAioCDCEQIAYqAgwhESAEKgIQIRYgAioCECESIAYqAhAhFSAEKgIIIRMgAioCCCEUIAYqAgghGSADKgLQAyEOIAcgBCoCFCIXIAYqAhQiGCACKgIUIhogGCAaXhsiIiAXICJeGzgCjAEgByAOIBMgGSAUIBQgGV0bIiIgEyAiXhuSOAKAASAHIBcgGCAaIBggGl0bIhggFyAYXRs4AnwgByATIBkgFCAUIBleGyIUIBMgFF0bIA6TOAJwIAcgDiAWIBUgEiASIBVdGyITIBMgFl0bkjgCiAEgByAOIA8gESAQIBAgEV0bIhMgDyATXhuSOAKEASAHIBYgFSASIBIgFV4bIhIgEiAWXhsgDpM4AnggByAPIBEgECAQIBFeGyIQIA8gEF0bIA6TOAJ0IAgoAighBCADKgLMAyEOIAdBADYCFCAHIA4gISAjICSSkkOrqqo+lJQ4AhAgByAOIB0gHyAgkpJDq6qqPpSUOAIMIAcgDiAbIB4gHJKSQ6uqqj6UlDgCCCAJIAQgB0HwAGogB0EIaiADKgLUAxC4ARogBUEBaiIFIAMoAvAFSA0ACwtDAAAAACEPQQAhAkMAAAAAIRJDAAAAACEOQwAAAAAhEEMAAAAAIRUjAEGQAWsiBCQAAkAgAy0A2QNFDQAgAygCyAUiBkEATCIIRQRAIAMoAoAEIQogAygC0AUhCwNAIBAgCyACQegAbGoiBSoCCCAKIAJBAnRqKgIAIhGUkiEQIA8gESAFKgIQlJIhDyAOIBEgBSoCDJSSIQ4gAkEBaiICIAZHDQALCyADQQA2ApQEIAMgDzgCkAQgAyAOOAKMBCADIBA4AogEIARCADcChAEgBEIANwJ0IARBADYCjAEgBEIANwJ8IARCADcCbCAEQYCAgKYDNgKIASAEQYCAgKQDNgJ0IARCADcCZCAEQYCAgKADNgJgIAhFBEAgAygC7AMhCiADKALQBSELIAMoAoAEIQwgBCoCeCERQwAAADQhFkMAAIA0IRNDAADANCEUIAQqAnAhGSAEKgJoIRcgBCoCZCEYQQAhBQNAIAsgBUHoAGxqIggqAhAhHiAIKgIMIRwgCiAFQQR0aiICKgIAIR0gAioCBCEfIAQgCCoCCCAQkyAMIAVBAnRqKgIAIhqUIhsgAioCCJQgF5IiFzgCaCAEIBsgH5QgGJIiGDgCZCAEIBsgHZQgFpIiFjgCYCACKgIAIR0gAioCBCEfIAQgGiAcIA6TlCIbIAIqAgiUIBGSIhE4AnggBCAbIB+UIBOSIhM4AnQgBCAbIB2UIBmSIhk4AnAgAioCACEbIAIqAgQhHCAEIBogHiAPk5QiGiACKgIIlCAUkiIUOAKIASAEIBogHJQgEpIiEjgChAEgBCAaIBuUIBWSIhU4AoABIAVBAWoiBSAGRw0ACwtBnIQCLQAARQRAQbS1ASoCACEOQZiEAkG4tQEoAgA2AgBBlIQCIA44AgBBnIQCQQE6AAALIARB4ABqIARBMGogBBCLBCADIAQpAzg3AqAEIAMgBCkDMDcCmAQgAyAEKQNINwKwBCADIAQpA0A3AqgEIAMgBCkDUDcCuAQgAyAEKQNYNwLABCADKgKABSEOIAMqAvgEIQ8gAyoC/AQhECADKgKQBSERIAMqAogFIRYgAyoCjAUhEiADKgKgBSEVIAMqApgFIRMgAyoCnAUhFCAEKgJYIRkgBCoCVCEXIAQqAjghGCAEKgJ4IRogBCoCSCEbIAQqAkQhHiAEKgKAASEcIAQqAmAhHSAEKgJwIR8gBCoChAEhICAEKgJkISEgBCoCdCEjIAQqAogBISQgBCoCUCEiIAQqAmghJyAEKgIwISggBCoCNCEpIAQqAkAhKiADQQA2AvQEIANBADYC5AQgA0EANgLUBCADICQgGSAVlCAiIBOUIBcgFJSSkiIllCAnIBggFZQgKCATlCApIBSUkpIiJpQgGiAbIBWUICogE5QgHiAUlJKSIhSUkpIiFTgC8AQgAyAgICWUICEgJpQgFCAjlJKSIhM4AuwEIAMgHCAllCAdICaUIB8gFJSSkiIUOALoBCADICQgGSARlCAiIBaUIBcgEpSSkiIllCAnIBggEZQgKCAWlCApIBKUkpIiJpQgGiAbIBGUICogFpQgHiASlJKSIhKUkpIiETgC4AQgAyAgICWUICEgJpQgEiAjlJKSIhY4AtwEIAMgHCAllCAdICaUIBIgH5SSkiISOALYBCADICQgGSAOlCAiIA+UIBcgEJSSkiIZlCAnIBggDpQgKCAPlCApIBCUkpIiF5QgGiAbIA6UICogD5QgHiAQlJKSIg6UkpIiDzgC0AQgAyAgIBmUICEgF5QgDiAjlJKSIhA4AswEIAMgHCAZlCAdIBeUIA4gH5SSkiIZOALIBCADKgLsAiIOQwAAgD9eRQ0AIAMgFUMAAIA/IA5DAACAPyAPIBIgE5QgFCAWlJOUIBkgFiAVlCATIBGUk5QgECARIBSUIBUgEpSTlJKSlSIVIA4gFV0bIBVDAACAP10bIg6UOALwBCADIBMgDpQ4AuwEIAMgFCAOlDgC6AQgAyARIA6UOALgBCADIBYgDpQ4AtwEIAMgEiAOlDgC2AQgAyAPIA6UOALQBCADIBAgDpQ4AswEIAMgGSAOlDgCyAQLIARBkAFqJAACQCADLQDZA0UNACADKgLAAkMAAAAAXkUNACADKALIBSIGQQBMDQAgAyoCwAQhFiADKgK8BCESIAMqArgEIRUgAyoCsAQhEyADKgKsBCEUIAMqAqgEIRkgAyoCoAQhFyADKgKcBCEYIAMqApgEIRpBACEEA0AgAygC0AUgBEHoAGxqIgIqAlhDAAAAAF4EQCADKALsAyAEQQR0aiIFKgIIIQ4gBSoCACEPIAUqAgQhECADKgKIBCEbIAMqAowEIR4gAyoCwAIhESADKgKQBCEcIAJBADYCFCACIAIqAhAiHSARIBwgFiAOlCAVIA+UIBIgEJSSkpIgHZOUkjgCECACIAIqAgwiHCARIB4gEyAOlCAZIA+UIBQgEJSSkpIgHJOUkjgCDCACIAIqAggiHiARIBsgFyAOlCAaIA+UIBggEJSSkpIgHpOUkjgCCAsgBEEBaiIEIAZHDQALCyAHQQhqQQBB6AAQCRogAygCrAYiBEEASARAIAMoArAGQQBIBEACQCADKAK0BiICRQ0AIAMtALgGRQ0AIAIEQEHIhQJByIUCKAIAQQFqNgIAIAJB/NMBKAIAEQAACwsgA0EBOgC4BiADQgA3ArAGCwNAIAMoArQGIARB6ABsaiICQgA3AgAgAkEANgIYIAJCADcCECACQgA3AgggAiAHKQIsNwIkIAIgBykCJDcCHCACIAcpAjw3AjQgAiAHKQI0NwIsIAIgBykCTDcCRCACIAcpAkQ3AjwgAiAHKQJUNwJMIAIgBykCXDcCVCACIAcpAmQ3AlwgAiAHKAJsNgJkIAQgBEEBaiIETQ0ACwsgA0EANgKsBgJAIAMoAsAGIgJBAE4NACADKALEBkEASARAAkAgAygCyAYiBEUNACADLQDMBkUNACAEBEBByIUCQciFAigCAEEBajYCACAEQfzTASgCABEAAAsLIANBAToAzAYgA0IANwLEBgtBACEFQQAgAiIEa0EDcSIIBEADQCADKALIBiAEQThsaiIGQgA3AgAgBkIANwIwIAZCADcCKCAGQgA3AiAgBkIANwIYIAZCADcCECAGQgA3AgggBEEBaiEEIAVBAWoiBSAIRw0ACwsgAkF8Sw0AA0AgBEE4bCIFIAMoAsgGaiICQgA3AgAgAkIANwIwIAJCADcCKCACQgA3AiAgAkIANwIYIAJCADcCECACQgA3AgggBSADKALIBmoiAkIANwJoIAJCADcCYCACQgA3AlggAkIANwJQIAJCADcCSCACQUBrQgA3AgAgAkIANwI4IAUgAygCyAZqIgJCADcCoAEgAkIANwKYASACQgA3ApABIAJCADcCiAEgAkIANwKAASACQgA3AnggAkIANwJwIAUgAygCyAZqIgJCADcC2AEgAkIANwLQASACQgA3AsgBIAJCADcCwAEgAkIANwK4ASACQgA3ArABIAJCADcCqAEgBEEEaiIEDQALCyADQQA2AsAGIANBoAdqQQEQhgEgCUEBEIYBIANBmAhqQQEQhgEgB0GQAWokACAAKAIYIQQLIA1BAWoiDSAESA0ACwsLrAUCBH0DfyMAQaABayIAJAACQAJAAkAgASgChANBD3FBAWsOAgABAgsgAEHopgE2AgAgAigCDCIHKgI4IQQgByoCNCEFIAIoAggiCCgC7AEhCSAHKgIwIQYgASgCwAEiByAHKAIAKAIwEQYAIQMgAigCBCIHIAIoAgwgAEGQAWogAEGAAWogBygCACgCCBEEACAAIAApA5gBNwNoIAAgACkDgAE3A3AgACAAKQOIATcDeCAAIAAqAmggA5M4AmggACADIAAqAnCSOAJwIAAgACkDkAE3A2AgACAAKgJgIAOTOAJgIAAgACoCZCADkzgCZCAAIAMgACoCdJI4AnQgACADIAAqAniSOAJ4IAAgAzgCFCAAIAMgBCAEkyIDIAOUIAYgBpMiAyADlCAFIAWTIgMgA5SSkpGSOAIQIAAgCCAJQR50QR91cTYCDCAAIAI2AgggACABNgIEIAFBoAdqIAEoAqAHIABB4ABqIAAQXgwBCyAAQQA2AhQgAEGAgID8AzYCBCAAQbynATYCACAAIAE2AhggACACNgIcIAAgASoCyAM4AgggACACKAIEIgcgBygCACgCMBEGACABKALAASIHIAcoAgAoAjARBgCSIgM4AgwgACABKgK8AiIEIAIoAggqAuABIgUgBCAFXRs4AhAgAigCBCIHIAIoAgwgAEGQAWogAEGAAWogBygCACgCCBEEACAAIAApA5gBNwNoIAAgACkDgAE3A3AgACAAKQOIATcDeCAAIAAqAmggA5M4AmggACADIAAqAnCSOAJwIAAgAyAAKgJ0kjgCdCAAIAApA5ABNwNgIAAgACoCYCADkzgCYCAAIAAqAmQgA5M4AmQgACADIAAqAniSOAJ4IAFBmAhqIAEoApgIIABB4ABqIAAQXgsgAEGgAWokAAsJACABIAIQnAQLlgQDCH8BfgF9AkAgAiACKAIAKAIQEQEADQAgASgCyAUhBCACIAIoAgAoAiQRAQAhBwJAIAIgAigCACgCCBEBAEUNACACIAIoAgAoAhQRAQAhACACIAIoAgAoAhgRAQAhBSAEQQBMDQAgByAAQQJ0aiEAIAEoAtAFIQYgBEEBRwRAIARBfnEhCiAFQQJ0IQUDQCAGIANB6ABsaiIIKQIIIQsgACAIKgIQOAIIIAAgCzcCACAGIANBAXJB6ABsaiIIKgIQIQwgACAFaiIAIAgpAgg3AgAgACAMOAIIIAAgBWohACADQQJqIQMgCUECaiIJIApHDQALCyAEQQFxRQ0AIAYgA0HoAGxqIgMpAgghCyAAIAMqAhA4AgggACALNwIACyACIAIoAgAoAgwRAQBFDQAgAiACKAIAKAIcEQEAIQAgAiACKAIAKAIgEQEAIQIgBEEATA0AIAcgAEECdGohACABKALQBSEBQQAhAyAEQQFHBEAgBEF+cSEHIAJBAnQhAkEAIQYDQCABIANB6ABsaiIFKQJIIQsgACAFKgJQOAIIIAAgCzcCACABIANBAXJB6ABsaiIFKgJQIQwgACACaiIAIAUpAkg3AgAgACAMOAIIIAAgAmohACADQQJqIQMgBkECaiIGIAdHDQALCyAEQQFxRQ0AIAEgA0HoAGxqIgEpAkghCyAAIAEqAlA4AgggACALNwIACwucDwILfwh9IAAoAhgiB0EASgRAA0ACQAJAIAAoAiAgDEECdGooAgAiAygC2AFBAmsOBAEAAAEAC0EAIQUjAEFAaiIJJAAgA0EAEJ8EIAMoAtwFIgdBAEoEQANAIAMoAuQFIAVBNGxqIgYoAggiBCoCHCERIAYoAgwiAioCHCEOIAQqAiAhECACKgIgIQ8gBCoCGCENIAIqAhghASAGQQA2AjAgBiABIA2TIhI4AiQgBiAPIBCTIg04AiwgBiAOIBGTIgE4AiggBkMAAIA/IAYqAhggDSANlCASIBKUIAEgAZSSkpSVOAIgIAVBAWoiBSAHRw0ACwsgAygCmAYiB0EASgRAQQAhCANAIAMoAqAGIAhB4ABsaiIEKAIUIgIqAgwhESACKgIIIQ4gAioCBCEQIAIqAhwhDyACKgIUIQ0gAioCGCEBIAkgAioCLCAEKgIMIhOUIAIqAiQgBCoCBCIUlCAEKgIIIhIgAioCKJSSkjgCOCAJQQA2AjwgCSAPIBOUIA0gFJQgEiABlJKSOAI0IAkgESATlCAQIBSUIA4gEpSSkjgCMCAJIAMqAsQDIAQoAgAqAlggAioC2AIgAkGIAmogCUEwahCeBCAEIAkpAwg3AiQgBCAJKQMANwIcIAQgCSkCGDcCNCAEIAkpAhA3AiwgBCAJKQIoNwJEIAQgCSkCIDcCPCAEIAkpAzg3AlQgBCAJKQMwNwJMIAQgAyoCxAMgBCgCACoCWJQ4AlwgBCgCFEEAEDkgCEEBaiIIIAdHDQALCwJAIAMoAvQCIgtBAEwNACADKAKMAyIFQQBKBEBBACEIA0BBACEGIAVBAEoEQANAIANDAACAP0EAQakHIAMoApQDIAZBAnRqKAIAGxEIACAGQQFqIgYgAygCjAMiBUgNAAsgAygC9AIhCwsgCEEBaiIIIAtIDQALCyADKALIBSIHQQBMDQBBACEFA0AgAyoCxAMhASADKALQBSAFQegAbGoiAkEANgIUIAIgASACKgIolCACKgIYkjgCCCACIAEgAioCMJQgAioCIJI4AhAgAiABIAIqAiyUIAIqAhySOAIMIAVBAWoiBSAHRw0ACwsCQCADKAL4AiIGQQBMDQAgAygCoAMhBUEAIQgDQCAFQQBKBEAgCLIgBrKVIQFBACEGA0AgA0MAAIA/IAEgAygCqAMgBkECdGooAgBBAnRB8KoBaigCABEUACAGQQFqIgYgAygCoAMiBUgNAAsgAygC+AIhBgsgCEEBaiIIIAZIDQALIAMoAsgFIgdBAEwNACADKgLIA0MAAIA/IAMqAqgCk5QhAUEAIQUDQCADKALQBSAFQegAbGoiAkIANwI0IAJCADcCPCACQQA2AkQgAiABIAIqAgggAioCGJOUOAIoIAIgASACKgIQIAIqAiCTlDgCMCACIAEgAioCDCACKgIck5Q4AiwgBUEBaiIFIAdHDQALCwJAIAMoAvwCIgtBAEwNACADKgLIAyENIAMqAqQCIQECQCADKALIBSIEQQBKBEBBACEGIARBAUcEQCAEQX5xIQdBACEIA0AgAygC0AUgBkHoAGxqIgIgAikCCDcCGCACIAIpAhA3AiAgAygC0AUgBkEBckHoAGxqIgIgAikCCDcCGCACIAIpAhA3AiAgBkECaiEGIAhBAmoiCCAHRw0ACwsgBEEBcQRAIAMoAtAFIAZB6ABsaiIHIAcpAgg3AhggByAHKQIQNwIgCyADKAL8AiILQQBMDQELQQAhCCADKAK0AyIFQQBMDQADQEEAIQYgBUEASgRAA0AgA0MAAIA/QwAAAAAgAygCvAMgBkECdGooAgBBAnRB8KoBaigCABEUACAGQQFqIgYgAygCtAMiBUgNAAsgAygC/AIhCwsgCEEBaiIIIAtIDQALCyADKALIBSICQQBMDQAgASANlCEBIAMoAtAFIQdBACEFA0AgByAFQegAbGoiBCABIAQqAgggBCoCGJOUIAQqAiiSOAIoIAQgASAEKgIMIAQqAhyTlCAEKgIskjgCLCAEIAEgBCoCECAEKgIgk5QgBCoCMJI4AjAgBUEBaiIFIAJHDQALC0EAIQggA0HYCGooAgAiBkEASgRAIANB4AhqKAIAIQQDQAJAIAQgCEECdGooAgAiCioC4AJDAAAAAF5FDQAgCigCGCICQQBMDQAgCigCICEHQQAhCwNAAkAgByALQQJ0aigCACIFKgJYQwAAAABeRQ0AIAoqAswCIg4gBSoCHCAKKgLoAZMiEJQgBSoCGCAKKgLkAZMiDyAKKgLQAiIBlJMgCioCxAKSIhEgEZQgCioCvAIgASAFKgIgIAoqAuwBkyINlCAQIAoqAtQCIgGUk5IiECAQlCAKKgLAAiABIA+UIA0gDpSTkiINIA2UkpIgBSoCMCIBIAGUIAUqAigiDiAOlCAFKgIsIg8gD5SSkl9FDQAgBSABIBEgAZMgCioC4AIiAZSSOAIwIAUgDyABIA0gD5OUkjgCLCAFIA4gASAQIA6TlJI4AigLIAtBAWoiCyACRw0ACwsgCEEBaiIIIAZHDQALCyADQQEQnwQgCUFAayQAIAAoAhghBwsgDEEBaiIMIAdIDQALCwtQAQN/IAAoAhgiAUEASgRAA0ACQAJAIAAoAiAgAkECdGooAgAiAygC2AFBAmsOBAEAAAEACyADEMgCIAAoAhghAQsgAkEBaiICIAFIDQALCwtLAQF/IwBBEGsiBCQAIAQgADYCDCAEIAE2AgggBCACNgIEIAQgAzYCAEHEAhAKIgAgBCgCDCAEKAIIIAQoAgQQvAQgBEEQaiQAIAAL4AUBCX8CQCABIgIoAgQiBCAAKAIYIgFMDQAgBCAAKAIcSgRAAkAgBAR/QcSFAkHEhQIoAgBBAWo2AgAgBEECdEEQQfjTASgCABECACEFIAAoAhgFIAELIgNBAEwNACADQQFrQQNPBEAgA0F8cSEIA0AgBSAGQQJ0IgdqIAAoAiAgB2ooAgA2AgAgBSAHQQRyIglqIAAoAiAgCWooAgA2AgAgBSAHQQhyIglqIAAoAiAgCWooAgA2AgAgBSAHQQxyIgdqIAAoAiAgB2ooAgA2AgAgBkEEaiEGIApBBGoiCiAIRw0ACwsgA0EDcSIDRQ0AA0AgBSAGQQJ0IgdqIAAoAiAgB2ooAgA2AgAgBkEBaiEGIAtBAWoiCyADRw0ACwsCQCAAKAIgIgNFDQAgAC0AJEUNACADBEBByIUCQciFAigCAEEBajYCACADQfzTASgCABEAAAsLIAAgBTYCICAAQQE6ACQgACAENgIcCyAEIAFBf3NqIQMgBCABa0EDcSIFBEBBACEGA0AgACgCICABQQJ0akEANgIAIAFBAWohASAGQQFqIgYgBUcNAAsLIANBA0kNAANAIAFBAnQiAyAAKAIgakEANgIAIAMgACgCIGpBADYCBCADIAAoAiBqQQA2AgggAyAAKAIgakEANgIMIAFBBGoiASAERw0ACwsgACAENgIYAkAgBEEATA0AIAAoAiAhAUEAIQVBACEAIARBAWtBA08EQCAEQXxxIQdBACEGA0AgASAAQQJ0IgNqIAIoAgwgA2ooAgA2AgAgASADQQRyIghqIAIoAgwgCGooAgA2AgAgASADQQhyIghqIAIoAgwgCGooAgA2AgAgASADQQxyIgNqIAIoAgwgA2ooAgA2AgAgAEEEaiEAIAZBBGoiBiAHRw0ACwsgBEEDcSIDRQ0AA0AgASAAQQJ0IgRqIAIoAgwgBGooAgA2AgAgAEEBaiEAIAVBAWoiBSADRw0ACwsLSAEBfyAAQbC0ATYCAAJAIAAoAiAiAUUNACAALQAkRQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACwsgABAMC1sBAX8gAEGwtAE2AgACQCAAKAIgIgFFDQAgAC0AJEUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCICAAQQE6ACQgAEIANwIYIAALIQAgASgCCCIAKAKcAiIBIAAgAigCCCABKAIAKAIoEQUAC9UMAw1/Fn0BfgJAIAAoAtgBIgIqAgQiIEMAAAAAWw0AIAIgASgCACIBKAK8ASACKAIAKAIIEQIARQ0AIABBxABqIQggAEGEAWohCSABQQRqIQQgACgC2AEhCiMAQUBqIgAkAAJAIAEoAsABIgMoAgRBIEYEQCABRQ0BIAEoAuwBQQhHDQEgCEEwaiEEIAlBMGohAwJAIAEoAvAFRQ0AIAEoAtwHDQAgARChBAsgAEGAgID8AzYCPCAAIAE2AjAgAEKAgICAcDcCNCMAQdAAayICJAAgBCoCACEPIAMqAgAhESAEKgIEIRAgAyoCBCESIAQqAgghEyADKgIIIRQgAkEANgJMIAIgFCATkyITOAJIIAIgEiAQkyIQOAJEIAIgESAPkyIPOAJAAkAgASgC3AciBUUEQCABKALwBSIHQQBMDQFBACEDA0AgBCACQUBrIAEoAvgFIANBLGxqIgUoAghBCGogBSgCDEEIaiAFKAIQQQhqIAAqAjwQoAQiD0MAAAAAXgRAIABBAzYCNCAAIAM2AjggACAPOAI8IAZBAWohBgsgA0EBaiIDIAdHDQALDAELIAAqAjwhESACQeyjATYCACACIAQpAgg3AgwgBCkCACElIAJBADYCMCACIBM4AiwgAiAQOAIoIAIgJTcCBCACIA84AiQgAiADKQIINwIcIAIgAykCADcCFCACQgA3AzggAiAROAI0IAUgBCADIAIQsgUgAigCOCIDRQ0AIAAgAioCNDgCPCAAQQM2AjQgACADIAEoAvgFa0EsbTYCOEEBIQYLIAEoAoQGQQBKBEAgASgCjAYhDkEAIQUgAioCSCEdIAIqAkQhHiACKgJAIR8DQEEAIQMDQAJAIB0gDiAFQegAbGpBCGoiByADQQxsIgtBlKQBaigCAEECdGooAgAiDCoCCCIaIAcgC0GQpAFqKAIAQQJ0aigCACINKgIIIhOTIg8gByALQZikAWooAgBBAnRqKAIAIgcqAgwiISANKgIMIhSTIhCUIAcqAggiIiATkyISIAwqAgwiFiAUkyIXlJMiEZQgHyAXIAcqAhAiIyANKgIQIheTIhiUIBAgDCoCECIbIBeTIhWUkyIQlCAeIBUgEpQgGCAPlJMiEpSSkiIPi0MAAAA0XQ0AIAQqAggiGCARlCAEKgIAIhUgEJQgEiAEKgIEIiSUkpIgFyARlCATIBCUIBQgEpSSkpOMIA+VIg9DAACgNV5FDQAgDyAAKgI8XUUNACARIBMgFSAfIA+UkiIZkyITIBYgJCAeIA+UkiIVkyIWlCAaIBmTIhogFCAVkyIUlJOUIBAgFCAbIBggHSAPlJIiG5MiGJQgFiAXIBuTIheUk5QgEiAXIBqUIBggE5STlJKSQwAAoLVeRQ0AIBEgGiAhIBWTIhWUICIgGZMiGSAWlJOUIBAgFiAjIBuTIhaUIBUgGJSTlCASIBggGZQgFiAalJOUkpJDAACgtV5FDQAgESAZIBSUIBMgFZSTlCAQIBUgF5QgFCAWlJOUIBIgFiATlCAXIBmUk5SSkkMAAKC1XkUNACAPQwAAAABeRQ0AIAZBAWohBiAAQQQ2AjQgACAFNgI4IAAgDzgCPAsgA0EBaiIDQQRHDQALIAVBAWoiBSABKAKEBkgNAAsLIAJB0ABqJAAgBkUNASAAKgI8IhQgCioCBF9FDQEgAEEANgIoIAAgACgCOCICNgIsIAkqAjQgCCoCNJMhDyAJKgIwIAgqAjCTIREgCSoCOCAIKgI4kyEQAkAgACgCNEEDRwRAQwAAgD8gECAQlCARIBGUIA8gD5SSkpGVIhMgEIyUIRIgEyAPjJQhDyATIBGMlCEQDAELIAEoAvgFIAJBLGxqIgIqAhwiEiAQlCACKgIUIhAgEZQgDyACKgIYIg+UkpJDAAAAAF5FBEAgAioCICEcDAELIBKMIRIgD4whDyAQjCEQCyAAIBw4AhwgACASOAIYIAAgDzgCFCAAIBQ4AiAgACAQOAIQIAAgATYCCCAAIABBKGo2AgwgCiAAQQhqQQEgCigCACgCDBEMABoMAQsjAEEgayICJAAgAkJ/NwMYIAIgBDYCFCACIAE2AhAgAiADNgIMIAJBADYCCCAIIAkgAkEIaiAKEIkCIAJBIGokAAsgAEFAayQACyAgQwAAAABcCwQAQQQL8gMBA38gASABKAIAKAIgEQAAIAFB6ABBASABKAIAKAIQEQcAIgMoAghBAEHoABAJIgIgACoC+AE4AlggAiAAKgL8ATgCXCACIAAqAoACOAJgIAIgACoChAI4AmQgAiAAKgJcOAIAIAIgACoCYDgCBCACIAAqAmQ4AgggAiAAKgJoOAIMIAIgACoCbDgCECACIAAqAnQ4AhQgAiAAKgJ4OAIYIAIgACoCfDgCHCACIAAqAoABOAIgIAIgACoChAE4AiQgAiAAKgKMATgCKCACIAAqApABOAIsIAIgACoClAE4AjAgAiAAKgKYATgCNCACIAAqAqgBOAI4IAIgACoCrAE4AjwgAiAAKAJwNgJAIAIgACgCnAE2AkQgAiAAKAKgATYCSCACIAAoAqQBNgJMIAIgACgCiAE2AlAgASADQZEcQcSusaIEIAIgASgCACgCFBEJACAAKAIIIgNBAEoEQANAIAAoAhAgBEECdGooAgAiAi0A7AFBCHEEQCABIAEgAiACKAIAKAIQEQEAQQEgASgCACgCEBEHACIDIAIgAygCCCABIAIoAgAoAhQRBwBB04SRygUgAiABKAIAKAIUEQkAIAAoAgghAwsgBEEBaiIEIANIDQALCyAAIAEQsQQgACABEPkCIAEgASgCACgCJBEAAAvMBAMBfwZ9AX4jAEGAAmsiBCQAQbMSEBEgBEGsswE2AiAgBCABKQIINwJMIAQgASkCADcCRCAEIAIpAgg3AlwgAikCACELIARCADcDaCAEQgA3A3AgBEIANwJ8IARBgICA/AM2AnggBEIANwKEASAEQoCAgPwDNwKMASAEIAs3AlQgBCADNgL4ASAEQYCAgPwDNgJkIAQgADYC9AEgBCABKQIANwKUASAEIAEpAgg3ApwBIARCADcDqAEgBEIANwOwASAEQYCAgPwDNgK4ASAEQgA3ArwBIARCADcCxAEgBEKAgID8AzcCzAEgBEGAgID8AzYCpAEgBCACKQIINwLcASAEIAIpAgA3AtQBIARDyvJJcUMAAIA/IAIqAgggASoCCJMiBUMAAIA/IAUgBZQgAioCACABKgIAkyIFIAWUIAIqAgQgASoCBJMiBiAGlJKSkZUiB5QiCJUgCEMAAAAAWxsiCTgCLCAEQ8rySXFDAACAPyAGIAeUIgaVIAZDAAAAAFsbIgo4AiggBCAJQwAAAABdNgI8IAQgCkMAAAAAXTYCOCAEQ8rySXFDAACAPyAFIAeUIgWVIAVDAAAAAFsbIgc4AiQgBCAHQwAAAABdNgI0IAQgCCAEKgJcIAQqAkyTlCAFIAQqAlQgBCoCRJOUIAYgBCoCWCAEKgJIk5SSkjgCQCAAKAJEIQAgBEIANwMYIARCADcDECAEQgA3AwggBEIANwMAIAAgASACIARBIGogBEEQaiAEIAAoAgAoAhgREAAQECAEQYACaiQAC9xbAw9/GH0DfiAAELsEAkAgACAAKAIAKAIUEQEARQ0AIAAoAsgCQQBMDQADQCAAKALQAiAPQQJ0aigCACEIAkAgACAAKAIAKAIUEQEARQ0AIAAgACgCACgCFBEBACICIAIoAgAoAjARAQBBAXFFDQAgACgCSCEEIwBBQGoiAyQAAkAgCC0A2QNFDQAgAyAIKQKQBDcDGCADIAgpAogENwMQIAgqAsAEIRYgCCoCuAQhESAIKgK8BCEQIAgqAqAEIRsgCCoCmAQhGiAIKgKcBCEUIAgqAvAEISIgCCoC0AQhIyAIKgLgBCEcIAgqAuwEISQgCCoCzAQhJSAIKgLcBCEmIAgqAugEIRggCCoCsAQhJyAIKgLIBCEZIAgqAqgEIRcgCCoC2AQhFSAIKgKsBCETIANBADYCPCADIAMqAhggIiAWlCAjIBGUIBwgEJSSkiIfQwAAAACUIhIgGCAWlCAZIBGUIBUgEJSSkiIgICQgFpQgJSARlCAmIBCUkpIiIUMAAAAAlCIWkpIiEEMAAIA/IBAgEJQgIiAblCAjIBqUIBQgHJSSkiIdQwAAAACUIhEgGCAblCAZIBqUIBUgFJSSkiIeICQgG5QgJSAalCAUICaUkpIiG0MAAAAAlCIUkpIiGiAalCAiICeUICMgF5QgHCATlJKSIhxDAAAAAJQiECAYICeUIBkgF5QgFSATlJKSIhggJCAnlCAlIBeUICYgE5SSkiIZQwAAAACUIhOSkiIXIBeUkpKRlSIVlEMAACBBlJI4AjggAyADKgIUIBcgFZRDAAAgQZSSOAI0IAMgAyoCECAaIBWUQwAAIEGUkjgCMCADQgA3AyggA0KAgID8AzcDICAEIANBEGoiBSADQTBqIgYgA0EgaiICIAQoAgAoAggRBAAgA0EANgI8IAMgEiAgQwAAAACUIhIgIZKSIhVDAACAPyAVIBWUIBEgHkMAAAAAlCIRIBuSkiIaIBqUIBAgGEMAAAAAlCIQIBmSkiIXIBeUkpKRlSIVlEMAACBBlCADKgIYkjgCOCADIBcgFZRDAAAgQZQgAyoCFJI4AjQgAyAaIBWUQwAAIEGUIAMqAhCSOAIwIANCADcDKCADQoCAgICAgIDAPzcDICAEIAUgBiACIAQoAgAoAggRBAAgA0EANgI8IAMgHyASIBaSkiISQwAAgD8gEiASlCARIBSSIB2SIhIgEpQgHCAQIBOSkiIRIBGUkpKRlSIQlEMAACBBlCADKgIYkjgCOCADIBEgEJRDAAAgQZQgAyoCFJI4AjQgAyASIBCUQwAAIEGUIAMqAhCSOAIwIANCgICA/AM3AyggA0IANwMgIAQgBSAGIAIgBCgCACgCCBEEACAIKALkA0EATA0AQQAhBQNAIAgoAuwDIAVBBHRqIgIqAgghFiACKgIAIRQgAioCBCETIAMqAhAhEiADKgIUIREgAyoCGCEQIANCgICA/AM3AwggA0KAgID8AzcDACADQQA2AjwgAyAQIB8gFpQgICAUlCAhIBOUkpKSIhc4AjggAyARIBwgFpQgGCAUlCAZIBOUkpKSIhU4AjQgAyASIB0gFpQgHiAUlCAbIBOUkpKSIhJDzczMvZI4AjAgA0EANgIsIAMgF0MAAAAAkiIQOAIoIAMgFUMAAAAAkiIROAIkIAMgEkPNzMw9kjgCICAEIANBMGoiBiADQSBqIgIgAyAEKAIAKAIIEQQAIANBADYCPCADIBc4AjggAyAVQ83MzL2SOAI0IAMgEjgCMCADQQA2AiwgAyAQOAIoIAMgFUPNzMw9kjgCJCADIBJDAAAAAJIiEDgCICAEIAYgAiADIAQoAgAoAggRBAAgA0EANgI8IAMgF0PNzMy9kjgCOCADIBU4AjQgAyASOAIwIANBADYCLCADIBdDzczMPZI4AiggAyAROAIkIAMgEDgCICAEIAYgAiADIAQoAgAoAggRBAAgBUEBaiIFIAgoAuQDSA0ACwsgA0FAayQAIAAoAkghByAAKALYAiELQQAhAkEAIQ4jAEGwAWsiASQAIAFCADcDmAEgAUIANwOQASABQoCAgPwDNwOIASABQoCAgPyDgIDAPzcDgAEgAUIANwN4IAFCgICA/AM3A3ACQCALQYACcQRAQYCGAkKNDjcDACAIQdgIaigCACIJQQBMDQEDQCAOQQJ0IgQgCCgC4AhqKAIALQD5AgRAQQAhA0GAhgJBgIYCKQMAQq3+1eTUhf2o2AB+QgF8Iio3AwBBgIYCQYCGAikDAEKt/tXk1IX9qNgAfkIBfCIpNwMAQYCGAkGAhgIpAwBCrf7V5NSF/ajYAH5CAXwiKDcDACABQQA2AqwBIAEgKEIhiKeyQwAAADCUIhBDAACAPyAQIBCUICpCIYinskMAAAAwlCISIBKUIClCIYinskMAAAAwlCIRIBGUkpKRlSIQlEMAAEA/lDgCqAEgASARIBCUQwAAQD+UOAKkASABIBIgEJRDAABAP5Q4AqABQQAhDQJAIAgoAuAIIARqKAIAKAIYIgxBAEwNAEEAIQlBxIUCQcSFAigCAEEBajYCACAMQQR0QRBB+NMBKAIAEQIAIQ0gDEEBRwRAIAxBfnEhBUEAIQoDQCANIAlBBHRqIgYgCCgC4AggBGooAgAoAiAgCUECdGooAgAiAikCCDcCACAGIAIpAhA3AgggDSAJQQFyIgJBBHRqIgYgCCgC4AggBGooAgAoAiAgAkECdGooAgAiAikCCDcCACAGIAIpAhA3AgggCUECaiEJIApBAmoiCiAFRw0ACwsgDEEBcUUNACANIAlBBHRqIgYgCCgC4AggBGooAgAoAiAgCUECdGooAgAiAikCCDcCACAGIAIpAhA3AggLIAFBADYCPCABQQE6AEAgAUEBOgBUIAFCADcCNCABQQA2AlAgAUEBOgBoIAFCADcDSCABQQA2AmQgAUIANwJcIAFBMGogDSAMEMACIAEoAlwiCkEASgRAA0AgASgCUCABKAJkIANBAnRqKAIAQQxsaiIMIAwoAgRBDGxqIgIgAigCAEEMbGoiCSAMRwRAIAIoAgghBSAMKAIIIQIDQCAHIAEoAjwiBCAFQQR0aiAEIAJBBHRqIAQgCSgCCCIGQQR0aiABQaABakMAAIA/IAcoAgAoAhwREgAgAiEFIAYhAiAJIAkoAgRBDGxqIgYgBigCAEEMbGoiCSAMRw0ACyABKAJcIQoLIANBAWoiAyAKSA0ACwsCQCABKAJkIgJFDQAgAS0AaEUNACACBEBByIUCQciFAigCAEEBajYCACACQfzTASgCABEAAAsLIAFBADYCZCABQQE6AGggAUIANwJcAkAgASgCUCICRQ0AIAEtAFRFDQAgAgRAQciFAkHIhQIoAgBBAWo2AgAgAkH80wEoAgARAAALCyABQQA2AlAgAUEBOgBUIAFCADcDSAJAIAEoAjwiAkUNACABLQBARQ0AIAIEQEHIhQJByIUCKAIAQQFqNgIAIAJB/NMBKAIAEQAACwsgDQRAQciFAkHIhQIoAgBBAWo2AgAgDUH80wEoAgARAAALIAgoAtgIIQkLIA5BAWoiDiAJSA0ACwwBCwJAIAtBAXFFDQAgCCgCyAUiCkEATA0AA0AgCCgC0AUgAkHoAGxqIgMoAgQtABBBAXEEQCADKgIIIRAgASADKQIMNwI0IAFBADYCPCABIBBDzczMvZI4AjAgAyoCCCESIAMqAgwhESADKgIQIRAgAUEANgKsASABIBBDAAAAAJI4AqgBIAEgEUMAAAAAkjgCpAEgASASQ83MzD2SOAKgASABQgA3AyggAUKAgID8AzcDICAHIAFBMGoiBCABQaABaiIFIAFBIGoiBiAHKAIAKAIIEQQAIAMqAgwhEiADKgIIIREgAyoCECEQIAFBADYCPCABIBA4AjggASAROAIwIAEgEkPNzMy9kjgCNCADKgIIIRIgAyoCDCERIAMqAhAhECABQQA2AqwBIAEgEEMAAAAAkjgCqAEgASARQ83MzD2SOAKkASABIBJDAAAAAJI4AqABIAFCADcDKCABQoCAgICAgIDAPzcDICAHIAQgBSAGIAcoAgAoAggRBAAgAyoCECEQIAMpAgghKCABQQA2AjwgASAoNwMwIAEgEEPNzMy9kjgCOCADKgIIIRIgAyoCDCERIAMqAhAhECABQQA2AqwBIAEgEEPNzMw9kjgCqAEgASARQwAAAACSOAKkASABIBJDAAAAAJI4AqABIAFCgICA/AM3AyggAUIANwMgIAcgBCAFIAYgBygCACgCCBEEACAIKALIBSEKCyACQQFqIgIgCkgNAAsLAkAgC0ECcUUNACAIKALcBSIKQQBMDQBBACEJA0AgCCgC5AUgCUE0bGoiAigCBC0AEEEBcQRAIAcgAigCCEEIaiACKAIMQQhqIAFBkAFqIAcoAgAoAggRBAAgCCgC3AUhCgsgCUEBaiIJIApIDQALCwJAIAtBEHFFDQAgCCgCyAUiCkEATA0AQQAhAgNAIAgoAtAFIAJB6ABsaiIEKAIELQAQQQFxBEAgBCoCSCEVIAQqAkwhFCAEKgJQIRMgBCoCCCESIAQqAgwhESAEKgIQIRAgAUEANgI8IAEgECATQwAAAD+UIhaSOAI4IAEgESAUQwAAAD+UIhSSOAI0IAEgEiAVQwAAAD+UIhOSOAIwIAcgBEEIaiIFIAFBMGoiBiABQYABaiAHKAIAKAIIEQQAIAQqAgghEiAEKgIMIREgBCoCECEQIAFBADYCPCABIBAgFpM4AjggASARIBSTOAI0IAEgEiATkzgCMCABQQA2AqwBIAEgASoCiAFDAAAAP5Q4AqgBIAEgASoChAFDAAAAP5Q4AqQBIAEgASoCgAFDAAAAP5Q4AqABIAcgBSAGIAFBoAFqIAcoAgAoAggRBAAgCCgCyAUhCgsgAkEBaiICIApIDQALCwJAIAtBIHFFDQBBwIUCLQAARQRAQZSFAkIANwIAQZCFAkGAgID8AzYCAEGchQJCADcCAEGohQJCADcDAEGkhQJBgICA/AM2AgBBsIUCQgA3AwBBuIUCQoCAgPwDNwMAQcCFAkEBOgAACyAIKAKsBkEATA0AQQAhAgNAIAgoArQGIAJB6ABsaiIDKgIUIRAgAyoCDCEXIAMoAhgiBioCECEWIAMqAgghFCAGKgIMIRMgAyoCBCESIAYqAgghESABQQA2AjwgASARIBIgECAWIBeUIBEgEpQgEyAUlJKSkiIQlJMiGjgCMCABIBMgFCAQlJMiFTgCNCABIBYgFyAQlJMiFjgCOCADKgIEIhwgAyoCCCIYXSIGRUECIAMqAgwiGSAcIBggBhteG0EEdCIGQZSFAmoqAgAhEyAGQZCFAmoqAgAhEiAGQZiFAmoqAgAhESABQQA2AqwBIAEgFiAcIBOUIBIgGJSTIhBDAACAPyAQIBCUIBggEZQgEyAZlJMiEyATlCAZIBKUIBEgHJSTIhEgEZSSkpGVIhCUIhdDAAAAP5QiEpM4AqgBIAEgFSARIBCUIhRDAAAAP5QiEZM4AqQBIAEgGiATIBCUIhNDAAAAP5QiEJM4AqABIAFBADYCLCABIBYgEpI4AiggASAVIBGSOAIkIAEgGiAQkjgCICAHIAFBoAFqIgQgAUEgaiIFIAFB8ABqIgYgBygCACgCCBEEACABQQA2AqwBIAEgASoCOCIWIBMgGJQgHCAUlJMiEEMAAIA/IBAgEJQgFCAZlCAYIBeUkyIVIBWUIBcgHJQgGSATlJMiESARlJKSkZUiEJRDAAAAP5QiFJM4AqgBIAEgASoCNCITIBEgEJRDAAAAP5QiEpM4AqQBIAEgASoCMCIRIBUgEJRDAAAAP5QiEJM4AqABIAFBADYCLCABIBQgFpI4AiggASASIBOSOAIkIAEgECARkjgCICAHIAQgBSAGIAcoAgAoAggRBAAgAyoCBCESIAMqAgghESADKgIMIRAgAUEANgKsASABIBBDAAAAP5RDAABAQJQgASoCOJI4AqgBIAEgEUMAAAA/lEMAAEBAlCABKgI0kjgCpAEgASASQwAAAD+UQwAAQECUIAEqAjCSOAKgASABQgA3AyggAUKAgID8g4CAwD83AyAgByABQTBqIAQgBSAHKAIAKAIIEQQAIAJBAWoiAiAIKAKsBkgNAAsLAkAgC0EEcUUNACABQgA3AzggAUKAgICAsObMmT83AzAgCCgC8AUiCkEATA0AQQAhCQNAIAgoAvgFIAlBLGxqIgIoAgQtABBBAXEEQCACKAIQIgUqAgwhGiACKAIIIgYqAgwhFyACKAIMIgIqAgwhFSAFKgIQIRYgBioCECEUIAIqAhAhEyAFKgIIIRIgBioCCCERIAIqAgghECABQQA2AqwBIAEgEiARIBCSkkOrqqo+lCIYIBEgGJNDzcxMP5SSOAKgASABIBYgFCATkpJDq6qqPpQiGSAUIBmTQ83MTD+UkjgCqAEgASAaIBcgFZKSQ6uqqj6UIhEgFyARk0PNzEw/lJI4AqQBIAFBADYCLCABIBkgEyAZk0PNzEw/lJI4AiggASARIBUgEZNDzcxMP5SSOAIkIAEgGCAQIBiTQ83MTD+UkjgCICABQQA2AhwgASAZIBYgGZNDzcxMP5SSOAIYIAEgESAaIBGTQ83MTD+UkjgCFCABIBggEiAYk0PNzEw/lJI4AhAgByABQaABaiABQSBqIAFBEGogAUEwakMAAIA/IAcoAgAoAhwREgAgCCgC8AUhCgsgCUEBaiIJIApIDQALCyALQQhxRQ0AIAFCs+bM+QM3AzggAUKas+b0o7PmzD43AzAgCCgChAYiCkEATA0AQQAhCQNAIAgoAowGIAlB6ABsaiICKAIELQAQQQFxBEAgAigCFCIEKgIMISEgAigCECIFKgIMIR0gAigCCCIGKgIMIRcgAigCDCICKgIMIRUgBCoCECEeIAUqAhAhFiAGKgIQIRQgAioCECETIAQqAgghGyAFKgIIIRIgBioCCCERIAIqAgghECABQQA2AqwBIAEgGyASIBEgEJKSkkMAAIA+lCIfIBEgH5NDzcxMP5SSIhw4AqABIAEgHiAWIBQgE5KSkkMAAIA+lCIgIBQgIJNDzcxMP5SSIhg4AqgBIAEgISAdIBcgFZKSkkMAAIA+lCIRIBcgEZNDzcxMP5SSIhk4AqQBIAFBADYCLCABICAgEyAgk0PNzEw/lJIiGjgCKCABIBEgFSARk0PNzEw/lJIiFzgCJCABIB8gECAfk0PNzEw/lJIiFTgCICABQQA2AhwgASAgIBYgIJNDzcxMP5SSIhY4AhggASARIB0gEZNDzcxMP5SSIhQ4AhQgASAfIBIgH5NDzcxMP5SSIhM4AhAgByABQaABaiIEIAFBIGoiBSABQRBqIgYgAUEwaiICQwAAgD8gBygCACgCHBESACABQQA2AqwBIAEgGDgCqAEgASAZOAKkASABIBw4AqABIAFBADYCLCABIBo4AiggASAXOAIkIAEgFTgCICABQQA2AhwgASAgIB4gIJNDzcxMP5SSIhI4AhggASARICEgEZNDzcxMP5SSIhE4AhQgASAfIBsgH5NDzcxMP5SSIhA4AhAgByAEIAUgBiACQwAAgD8gBygCACgCHBESACABQQA2AqwBIAEgGjgCqAEgASAXOAKkASABIBU4AqABIAFBADYCLCABIBY4AiggASAUOAIkIAEgEzgCICABQQA2AhwgASASOAIYIAEgETgCFCABIBA4AhAgByAEIAUgBiACQwAAgD8gBygCACgCHBESACABQQA2AqwBIAEgFjgCqAEgASAUOAKkASABIBM4AqABIAFBADYCLCABIBg4AiggASAZOAIkIAEgHDgCICABQQA2AhwgASASOAIYIAEgETgCFCABIBA4AhAgByAEIAUgBiACQwAAgD8gBygCACgCHBESACAIKAKEBiEKCyAJQQFqIgkgCkgNAAsLAkAgC0HAAHFFDQAgCCgCmAZBAEoEQEEAIQoDQCAIKAKgBiAKQeAAbGoiBSgCFCICKgI0IRwgAioCDCEYIAIqAgghGSACKgIEIRogAioCOCEXIAIqAhwhFSACKgIUIRYgAioCGCEUIAIqAjwhEyAFKgIMIR0gAioCLCESIAUqAgQhHiACKgIkIREgBSoCCCEbIAIqAighECABQQA2AiwgASATIB0gEpQgHiARlCAbIBCUkpKSOAIoIAEgFyAdIBWUIB4gFpQgGyAUlJKSkjgCJCABIBwgHSAYlCAeIBqUIBsgGZSSkpI4AiAgBSgCACEDIAFCADcDGCABQoCAgPwDNwMQIAMqAgghEiADKgIMIREgAyoCECEQIAFBADYCPCABIBA4AjggASAROAI0IAEgEkMAAIC+kjgCMCABQQA2AqwBIAEgEEMAAAAAkjgCqAEgASARQwAAAACSOAKkASABIBJDAACAPpI4AqABIAcgAUEwaiIEIAFBoAFqIgYgAUEQaiICIAcoAgAoAggRBAAgAyoCDCESIAMqAgghESADKgIQIRAgAUEANgI8IAEgEDgCOCABIBE4AjAgASASQwAAgL6SOAI0IAFBADYCrAEgASAQQwAAAACSOAKoASABIBJDAACAPpI4AqQBIAEgEUMAAAAAkjgCoAEgByAEIAYgAiAHKAIAKAIIEQQAIAMqAhAhEiADKgIIIREg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IAIbIAYbQTBqIAFBEGogAUEwaiIGIAcoAgAoAggRBAAgAUIANwMIIAFCgICA/IOAgMA/NwMAIAFBADYCPCABIAEqAigiEjgCOCABIAEqAiQiETgCNCABIAEqAiAiEEMAAIC+kjgCMCABQQA2AqwBIAEgEkMAAAAAkjgCqAEgASARQwAAAACSOAKkASABIBBDAACAPpI4AqABIAcgBiABQaABaiICIAEgBygCACgCCBEEACABQQA2AjwgASABKgIoIhI4AjggASABKgIkIhFDAACAvpI4AjQgASABKgIgIhA4AjAgAUEANgKsASABIBJDAAAAAJI4AqgBIAEgEUMAAIA+kjgCpAEgASAQQwAAAACSOAKgASAHIAYgAiABIAcoAgAoAggRBAAgAUEANgI8IAEgASoCKCISQwAAgL6SOAI4IAEgASoCJCIROAI0IAEgASoCICIQOAIwIAFBADYCrAEgASASQwAAgD6SOAKoASABIBFDAAAAAJI4AqQBIAEgEEMAAAAAkjgCoAEgByAGIAIgASAHKAIAKAIIEQQAIAFCgICA/AM3AwggAUKAgICAgICAwD83AwAgAUEANgI8IAEgASoCGCISOAI4IAEgASoCFCIROAI0IAEgASoCECIQQwAAgL6SOAIwIAFBADYCrAEgASASQwAAAACSOAKoASABIBFDAAAAAJI4AqQBIAEgEEMAAIA+kjgCoAEgByAGIAIgASAHKAIAKAIIEQQAIAFBADYCPCABIAEqAhgiEjgCOCABIAEqAhQiEUMAAIC+kjgCNCABIAEqAhAiEDgCMCABQQA2AqwBIAEgEkMAAAAAkjgCqAEgASARQwAAgD6SOAKkASABIBBDAAAAAJI4AqABIAcgBiACIAEgBygCACgCCBEEACABQQA2AjwgASABKgIYIhJDAACAvpI4AjggASABKgIUIhE4AjQgASABKgIQIhA4AjAgAUEANgKsASABIBJDAACAPpI4AqgBIAEgEUMAAAAAkjgCpAEgASAQQwAAAACSOAKgASAHIAYgAiABIAcoAgAoAggRBAAMAQtBkIQCLQAAIgVBAXFFBEBB0IMCEC8iAikCADcCAEHYgwIgAikCCDcCAEHggwIgAikCEDcCAEHogwIgAikCGDcCAEHwgwIgAikCIDcCAEH4gwIgAikCKDcCACACKQI4ISkgAikCMCEoQZCEAkEBOgAAQYiEAiApNwIAQYCEAiAoNwIAQQEhBQsgASAEKAIMIgZBBGogBCgCBCICQTxqQdCDAiACGyAGGyICKQI4NwM4IAEgAikCMDcDMCAFQQFxRQRAQdCDAhAvIgIpAgA3AgBB2IMCIAIpAgg3AgBB4IMCIAIpAhA3AgBB6IMCIAIpAhg3AgBB8IMCIAIpAiA3AgBB+IMCIAIpAig3AgAgAikCOCEpIAIpAjAhKEGQhAJBAToAAEGIhAIgKTcCAEGAhAIgKDcCAEEBIQULIAEgBCgCGCIGQQRqIAQoAhAiAkE8akHQgwIgAhsgBhsiAikCODcDqAEgASACKQIwNwOgASAFQQFxRQRAQdCDAhAvIgIpAgA3AgBB2IMCIAIpAgg3AgBB4IMCIAIpAhA3AgBB6IMCIAIpAhg3AgBB8IMCIAIpAiA3AgBB+IMCIAIpAig3AgAgAikCOCEpIAIpAjAhKEGQhAJBAToAAEGIhAIgKTcCAEGAhAIgKDcCAEEBIQULIAQoAgwiBkEEaiAEKAIEIgJBPGpB0IMCIAIbIAYbIgIqAgggBCoCJCISlCACKgIAIAQqAhwiEZQgAioCBCAEKgIgIhCUkpIhGyACKgIoIBKUIAIqAiAgEZQgECACKgIklJKSIRQgAioCGCASlCACKgIQIBGUIBAgAioCFJSSkiETIAVBAXFFBEBB0IMCEC8iAikCADcCAEHYgwIgAikCCDcCAEHggwIgAikCEDcCAEHogwIgAikCGDcCAEHwgwIgAikCIDcCAEH4gwIgAikCKDcCACACKQI4ISkgAikCMCEoQZCEAkEBOgAAQYiEAiApNwIAQYCEAiAoNwIACyAEKAIYIgZBBGogBCgCECICQTxqQdCDAiACGyAGGyICKgIIIRwgAioCACEYIAIqAgQhGSACKgIYIRogAioCFCEXIAIqAhAhFSACKgIoIRIgAioCJCERIAIqAiAhECAEKgI0ISEgBCoCMCEdIAQqAiwhHiABQQA2AiwgASAUQwAAIEGUIhYgASoCOJI4AiggASATQwAAIEGUIhQgASoCNJI4AiQgASAbQwAAIEGUIhMgASoCMJI4AiAgAUIANwMYIAFCgICA/IOAgMA/NwMQIAcgAUEwaiICIAFBIGoiBSABQRBqIgYgBygCACgCCBEEACABQQA2AiwgASASICGUIBAgHpQgHSARlJKSQwAAIEGUIhIgASoCOJI4AiggASAaICGUIBUgHpQgHSAXlJKSQwAAIEGUIhEgASoCNJI4AiQgASAcICGUIBggHpQgGSAdlJKSQwAAIEGUIhAgASoCMJI4AiAgAUIANwMYIAFCgICA/IOAgMA/NwMQIAcgAiAFIAYgBygCACgCCBEEACABQQA2AiwgASAWIAEqAqgBkjgCKCABIBQgASoCpAGSOAIkIAEgEyABKgKgAZI4AiAgAUKAgID8AzcDGCABQoCAgICAgIDAPzcDECAHIAFBoAFqIgIgBSAGIAcoAgAoAggRBAAgAUEANgIsIAEgEiABKgKoAZI4AiggASARIAEqAqQBkjgCJCABIBAgASoCoAGSOAIgIAFCgICA/AM3AxggAUKAgICAgICAwD83AxAgByACIAUgBiAHKAIAKAIIEQQACyAKQQFqIgogCCgC1AZIDQALCyABQbABaiQACwJAIAAoAkgiAkUNACACIAIoAgAoAjARAQBBAnFFDQAgAC0A3AIEQCAAKAJIIQYjAEEgayIFJAAgCCgCoAchAiAFQoCAgPwDNwMYIAVCgICA/AM3AxAgBUKAgID8AzcDCCAFQoCAgPyDgIDAPzcDACAGIAJBACAFQRBqIAVBAEF/EFcgBUEgaiQACyAALQDdAgRAIAAoAkghBiMAQSBrIgUkACAIKALcByECIAVCADcDGCAFQoCAgICAgIDAPzcDECAFQgA3AwggBUKAgID8AzcDACAGIAJBACAFQRBqIAVBAEF/EFcgBUEgaiQACyAALQDeAkUNACAAKAJIIQYjAEEgayIFJAAgCCgCmAghAiAFQoCAgPwDNwMYIAVCgICAgICAgMA/NwMQIAVCADcDCCAFQoCAgPwDNwMAIAYgAkEAIAVBEGogBUEAQX8QVyAFQSBqJAALIA9BAWoiDyAAKALIAkgNAAsLCxgBAX8jAEEQayIBIAA2AgwgASgCDEEwaguWAQEEfwJAIAFFDQAgASgC7AFBCEcNAAJAIAAoAsgCIgNBAEwNACAAKALQAiEEA0AgASAEIAJBAnRqIgUoAgBHBEAgAkEBaiICIANHDQEMAgsLIAIgA04NACAFIAQgA0EBayICQQJ0IgNqKAIANgIAIAAoAtACIANqIAE2AgAgACACNgLIAgsgACABELUBDwsgACABELgEC7YIAQx/IAAoAsQDIgQgAEHEAmoiCEEAIAQoAgAoAhARBQAgACgCxAMiBCAEKAIAKAIMEQEAGiAAIAEQugRBqhMQESAAKALIAgRAQQAhBAJAIAgoAgQiCUEATA0AIAgoAgwhAiAJQQFrQQNPBEAgCUF8cSELA0AgBSACIANBAnQiB2ooAgAoAoADIgogBSAKShsiBSACIAdBBHJqKAIAKAKAAyIKIAUgCkobIgUgAiAHQQhyaigCACgCgAMiCiAFIApKGyIFIAIgB0EMcmooAgAoAoADIgcgBSAHShshBSADQQRqIQMgBkEEaiIGIAtHDQALCyAJQQNxIgYEQANAIAUgAiADQQJ0aigCACgCgAMiByAFIAdKGyEFIANBAWohAyAEQQFqIgQgBkcNAAsLIAlBAEwNAEEAIQQDQCAIKAIMIARBAnRqKAIAIgMoAtQGQQBKBEBBACECA0AgAygC3AYgAkECdGooAgAiBiADKgLEAyAFIAYoAgAoAggRDwAgAkEBaiICIAMoAtQGSA0ACwsgBEEBaiIEIAlHDQALIAVBAEoEQCAJQQBMDQFBACEGA0BBACEEA0ACQCAIKAIMIARBAnRqKAIAIgMoAtQGIgdBAEwNAEEAIQIgB0EBRwRAIAdBfnEhCkEAIQsDQCACQQJ0IgwgAygC3AZqKAIAIg0gAyoCxANDAACAPyANKAIAKAIMERQAIAMoAtwGIAxBBHJqKAIAIgwgAyoCxANDAACAPyAMKAIAKAIMERQAIAJBAmohAiALQQJqIgsgCkcNAAsLIAdBAXFFDQAgAygC3AYgAkECdGooAgAiAiADKgLEA0MAAIA/IAIoAgAoAgwRFAALIARBAWoiBCAJRw0ACyAGQQFqIgYgBUcNAAsLIAlBAEwNAEEAIQUDQCAIKAIMIAVBAnRqKAIAIgYoAtQGQQBKBEBBACEEA0AgBEECdCIDIAYoAtwGaigCACICIAYqAsQDIAIoAgAoAhARCAACQCAGKALcBiADaigCACICLQCYAUUEQCAGKALUBiECDAELIAIEQEHIhQJByIUCKAIAQQFqNgIAIAJB/NMBKAIAEQAACyAEQQFrIQQgBigC1AYiAkEATA0AIAYoAtwGIgcgA2ooAgAhC0EAIQMDQCALIAcgA0ECdGoiCigCAEcEQCADQQFqIgMgAkcNAQwCCwsgAiADTA0AIAogByACQQFrIgJBAnQiA2ooAgA2AgAgBigC3AYgA2ogCzYCACAGIAI2AtQGCyAEQQFqIgQgAkgNAAsLIAVBAWoiBSAJRw0ACwsLIAAoAsQDIgggCCoCDCABlCAIKAIAKAIcEQgAEBAgACgCyAJBAEoEQEEAIQgDQCAAKALQAiAIQQJ0aigCACIEIAQQnAQgCEEBaiIIIAAoAsgCSA0ACwsgACgCxAMiACAAKAIAKAIgEQAACyUAIAAgARCzBEGGEhARIAAoAsQDIgAgASAAKAIAKAIYEQgAEBALKQAgABCUBCIABEBByIUCQciFAigCAEEBajYCACAAQfzTASgCABEAAAsLggEBAX8gASACIAAtABAiABshAwJAAkAgAiABIAAbKAIIIgAoAowCIgFBAEwNACADKAIIIQQgACgClAIhBUEAIQIDQCAEIAUgAkECdGooAgBHBEAgAkEBaiICIAFHDQEMAgsLIAEgAkcNAQsgACgCnAIiASAAIAMgASgCACgCJBEFAAsLJgAgASgCACIAQZwBIAAoAgAoAjgRAgAiACABIAIgA0EBEJkEIAALJgAgASgCACIAQZwBIAAoAgAoAjgRAgAiACABIAIgA0EAEJkEIAALRAAgASgCACICQRQgAigCACgCOBECACECIAAtAAQhACACQbDDADYCACACIAEoAgA2AgQgAiAAOgAQIAJBgLEBNgIAIAILNAAgASgCACIAQRggACgCACgCOBECACIAQbDDADYCACAAIAEoAgA2AgQgAEHoswE2AgAgAAt9AQF/AkAgAUEgRyIDDQAgAkEgRw0AIAAoAlwPCwJAAkACQCADRQRAIAJBE0oNASAAKAJgDwsgAUETSg0BIAJBIEcNASAAKAJkDwsgAkEVa0EISw0BIAAoAmgPCyABQRVrQQhLDQAgAkEgRw0AIAAoAmwPCyAAIAEgAhCiBQu5AgEBfyAAQditATYCACAAKAJcIgEgASgCACgCABEBABogACgCXCIBBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsgACgCYCIBIAEoAgAoAgARAQAaIAAoAmAiAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALIAAoAmQiASABKAIAKAIAEQEAGiAAKAJkIgEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACyAAKAJoIgEgASgCACgCABEBABogACgCaCIBBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsgACgCbCIBIAEoAgAoAgARAQAaIAAoAmwiAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALIAAQiAIaIAAQDAu3AgEBfyAAQditATYCACAAKAJcIgEgASgCACgCABEBABogACgCXCIBBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsgACgCYCIBIAEoAgAoAgARAQAaIAAoAmAiAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALIAAoAmQiASABKAIAKAIAEQEAGiAAKAJkIgEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACyAAKAJoIgEgASgCACgCABEBABogACgCaCIBBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsgACgCbCIBIAEoAgAoAgARAQAaIAAoAmwiAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALIAAQiAIaIAALugoBN30jAEHwAWsiBCQAQwAAgD8hBwJAIAIgASAALQAIIgAbIgMqAnwgAyoCPCIKkyIGIAaUIAMqAnQgAyoCNCIVkyIGIAaUIAMqAnggAyoCOCIWkyIGIAaUkpIgAyoC/AEiBiAGlF0NACABIAIgABsiACgCwAEiASgCBEEVa0EISw0AIAAqAhwiCCADKgJcIgeUISogAyoCTCIGIAAqAgwiBZQhKyADKgJsIRcgCCADKgJYIh2UISwgAyoCSCIeIAWUIS0gAyoCaCEYIAMqAmQhGSAIIAMqAlQiH5QhLiADKgJEIiAgBZQhLyAAKgIYIgsgB5QhMCAGIAAqAggiDJQhMSAAKgIkIQkgACoCFCINIAeUITIgBiAAKgIEIg6UITMgCCADKgIcIiGUITQgAyoCDCIiIAWUITUgAyoCLCEaIAggAyoCGCIjlCE2IAMqAggiJCAFlCE3IAMqAighGyADKgIkIRwgCCADKgIUIiWUITggAyoCBCImIAWUITkgBSAAKgI0jCIHlCAIIAAqAjgiD5STIAAqAiwiECAAKgI8IhOUkyEnIAMqAnwiEiAQlCADKgJ0IiggBZQgCCADKgJ4IimUkpIh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BSAAIAEoAgAoAhQRCQALxwUAIAAgASACEP0CGiABIAAqAogCOAKAAiABIAAqAowCOAKEAiABIAAqApACOAKIAiABIAAqApQCOAKMAiABIAAqApgCOAKQAiABIAAqApwCOAKUAiABIAAqAqACOAKYAiABIAAqAqQCOAKcAiABIAAqAqgCOAKgAiABIAAqAqwCOAKkAiABIAAqArACOAKoAiABIAAqArQCOAKsAiABIAAqArgCOAKwAiABIAAqArwCOAK0AiABIAAqAsACOAK4AiABIAAqAsQCOAK8AiABIAAqAsgCOALAAiABIAAqAswCOALEAiABIAAqAtACOALIAiABIAAqAtQCOALMAiABIAAqAtgCOALAAyABIAAqAqAEOALQAiABIAAqAqQEOALUAiABIAAqAqgEOALYAiABIAAqAqwEOALcAiABIAAqAtwCOALgAiABIAAqAuACOALkAiABIAAqAuQCOALoAiABIAAqAugCOALsAiABIAAqAuwCOALwAiABIAAqAvACOAL0AiABIAAqAvQCOAL4AiABIAAqAvgCOAL8AiABIAAqAvwCOAKAAyABIAAqAoADOAKEAyABIAAqAoQDOAKIAyABIAAqAogDOAKMAyABIAAqAowDOAKQAyABIAAqApADOAKUAyABIAAqApQDOAKYAyABIAAqApgDOAKcAyABIAAqApwDOAKgAyABIAAqAqADOAKkAyABIAAqAqQDOAKoAyABIAAqAqgDOAKsAyABIAAqAqwDOAKwAyABIAAqArADOAK0AyABIAAqArQDOAK4AyABIAAqArgDOAK8AyABIAAqArwDOALEAyABIAAqAsADOALIAyABIAAtAMQDNgLkAyABIAAqAsgDOALMAyABIAAqAswDOALQAyABIAAqAtADOALUAyABIAAqAtQDOALYAyABIAAqAtgDOALcAyABIAAqAtwDOALgA0HyGgsFAEHoAwuEAQEEfwJ/QQEgAS0A7AFBAnFFDQAaQQEgAUUNABoCQCAAKALoAyIDQQBMBEBBACEADAELIAAoAvADIQVBASEAA0AgBSACQQJ0aigCACIELQAUBEAgBCgCHCABRg0CIAQoAiAgAUYNAgsgAkEBaiICIANIIQAgAiADRw0ACwsgAEULQQFxCywBAX8jAEEQayIBJAAgASAANgIMQdwAEA0iACABKAIM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AgAgA0H80wEoAgARAAALCyACQQE6ADwgAkIANwI0C0EAIQpBACAFIgNrQQNxIgsEQANAIAIoAjggA0ECdGpBADYCACADQQFqIQMgCkEBaiIKIAtHDQALCyAFQXxLDQADQCADQQJ0IgUgAigCOGpBADYCACAFIAIoAjhqQQA2AgQgBSACKAI4akEANgIIIAUgAigCOGpBADYCDCADQQRqIgMNAAsLIAAgDiAGGyEOIAJBADYCMCAEIAlKDQALCxAQIBdBEGokACAMKALEARC0BCAMKALIASIAIAEgDCgCSCAAKAIAKAIQEQUAEBAgFkEQaiQACy4BA38jAEEgayIAJABB3AAQDSEBIABBCGoiAhDOAiABIAIQ9wIgAEEgaiQAIAELdAEEfwJAIAAoApgCIgNBAEwNACAAKAKgAiEEA0AgASAEIAJBAnRqIgUoAgBHBEAgAkEBaiICIANHDQEMAgsLIAIgA04NACAFIAQgA0EBayICQQJ0IgNqKAIANgIAIAAoAqACIANqIAE2AgAgACACNgKYAgsLngMBCX8CQCAAKAKYAiICIAAoApwCRw0AIAIgAkEBdEEBIAIbIgZODQAgBgRAQcSFAkHEhQIoAgBBAWo2AgAgBkECdEEQQfjTASgCABECACEFIAAoApgCIQILAkAgAkEATA0AIAJBAWtBA08EQCACQXxxIQcDQCAFIANBAnQiBGogACgCoAIgBGooAgA2AgAgBSAEQQRyIghqIAAoAqACIAhqKAIANgIAIAUgBEEIciIIaiAAKAKgAiAIaigCADYCACAFIARBDHIiBGogACgCoAIgBGooAgA2AgAgA0EEaiEDIAlBBGoiCSAHRw0ACwsgAkEDcSIERQ0AA0AgBSADQQJ0IgdqIAAoAqACIAdqKAIANgIAIANBAWohAyAKQQFqIgogBEcNAAsLAkAgACgCoAIiA0UNACAALQCkAkUNACADBEBByIUCQciFAigCAEEBajYCACADQfzTASgCABEAAAsgACgCmAIhAgsgACAFNgKgAiAAQQE6AKQCIAAgBjYCnAILIAAoAqACIAJBAnRqIAE2AgAgACACQQFqNgKYAguIAQEEfwJAIAAoAtQBIgNBAEwNACAAKALcASEEA0AgASAEIAJBAnRqIgUoAgBHBEAgAkEBaiICIANHDQEMAgsLIAIgA04NACAFIAQg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FGxqIAwgGioCWJQ4AgAgGkHgAGokAAsOACABQoaAgIDgADcCAAvPAwAgACABIAIQahogASAAKgKsAjgCNCABIAAqArACOAI4IAEgACoCtAI4AjwgASAAKgK4AjgCQCABIAAqArwCOAJEIAEgACoCwAI4AkggASAAKgLEAjgCTCABIAAqAsgCOAJQIAEgACoCzAI4AlQgASAAKgLQAjgCWCABIAAqAtQCOAJcIAEgACoC2AI4AmAgASAAKgLcAjgCZCABIAAqAuACOAJoIAEgACoC5AI4AmwgASAAKgLoAjgCcCABIAAqAuwCOAJ0IAEgACoC8AI4AnggASAAKgL0AjgCfCABIAAqAvgCOAKAASABIAAqAvwCOAKEASABIAAqAoADOAKIASABIAAqAoQDOAKMASABIAAqAogDOAKQASABIAAqAowDOAKUASABIAAqApADOAKYASABIAAqApQDOAKcASABIAAqApgDOAKgASABIAAqApwDOAKkASABIAAqAqADOAKoASABIAAqAqQDOAKsASABIAAqAqgDOAKwASABIAAqArwDOAK0ASABIAAqAsADOAK4ASABIAAqAsQDOAK8ASABIAAqAqwDOALAASABIAAqArADOALEASABIAAqArQDOALIASABIAAqArgDOALMAUG9GQsFAEHUAQsDAAELvwEAIAAgASkCADcCrAIgACABKQIINwK0AiAAIAEpAhg3AsQCIAAgASkCEDcCvAIgACABKQIoNwLUAiAAIAEpAiA3AswCIAAgASkCODcC5AIgACABKQIwNwLcAiAAIAIpAgg3AvQCIAAgAikCADcC7AIgACACKQIQNwL8AiAAIAIpAhg3AoQDIAAgAikCIDcCjAMgACACKQIoNwKUAyAAIAIpAjg3AqQDIAAgAikCMDcCnAMgACAAKAIAKAIIEQAAC1wBAX0CQAJAAkAgAUEBaw4EAAABAQILIAJBAk0EQCAAKgLYBA8LIAJBA2tBAksNASAAKgKwAw8LIAJBAk0EQCAAKgLUBA8LIAJBA2tBAksNACAAKgLcBCEDCyADC3cAAkACQAJAIAFBAWsOBAAAAQECCyADQQJNBEAgACACOALYBCAAIAAoAtAEQQJyNgLQBA8LIAAgAjgCsAMPCyADQQJNBEAgACACOALUBCAAIAAoAtAEQQFyNgLQBA8LIAAgAjgC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KgI4IQwgBSoCOCENIAQqAjAhDiAFKgIwIQ8gAEEANgJMIAAgDyAOkzgCQCAAIA0gDJM4AkggACALIAqTOAJEAkAgAiAEIAMgBSAAQUBrIABBCGpBARDbAiIBRQRAIAIgBCADIAUgAEFAayAAQQhqEOMERQ0BCyAHIAApAgw3AgAgByAAKQIUNwIIIAggACkCJDcCCCAIIAApAhw3AgAgBiAAKQI0NwIIIAYgACkCLDcCAAsgAEHQAGokACABC0MAIAMgACoCJF0EQCAAQQE6ACggACABKQIANwIEIAAgASkCCDcCDCAAIAIpAgA3AhQgACACKQIINwIcIAAgAzgCJAsLlAEBA38CQCAAKAKYASIBRQ0AIAEhAiABQQFxBEAgACgCoAEgAUEBayICQQJ0aigCACIDIAMoAgAoAkgRAAALIAFBAUYNAANAIAAoAqABIAJBAnRqQQRrKAIAIgEgASgCACgCSBEAACAAKAKgASACQQJrIgJBAnRqKAIAIgEgASgCACgCSBEAACACDQALCyAAQQE6ADALhAMCBn8HfSAAQv////v3//+//wA3AhAgAEH///97NgIoIABBIGoiBEL////7////v383AgAgAEH////7BzYCGCAAKAKYASIDBEAgAEEQaiEFIAAoAqABIQZD//9/fyEJQ///f/8hCkP//3//IQtD//9//yEHQ///f38hDEP//39/IQgDQCAGIANBAWsiA0ECdCICaigCACIBLQAwBEAgASABKAIAKAJEEQAAIAFBADoAMCAAKgIoIQogACoCJCELIAAqAiAhByAAKgIYIQkgACoCFCEMIAAqAhAhCCAAKAKgASIGIAJqKAIAIQELIAAgASoCECINIAggCCANXhsiCDgCECAAIAFBEGoiAiAFIAwgASoCFF4bKgIEIgw4AhQgACACIAUgCSABKgIYXhsqAggiCTgCGCAAIAFBIGoiAioCACINIAcgByANXRsiBzgCICAAIAIgBCALIAEqAiRdGyoCBCILOAIkIAAgAiAEIAogASoCKF0bKgIIIgo4AiggAw0ACwsLoQEBA38gACABOAIMAkAgACgCmAEiAkUNACACIQMgAkEBcQRAIAAoAqABIAJBAWsiA0ECdGooAgAiBCABIAQoAgAoAiwRCAALIAJBAUYNAANAIAAoAqABIANBAnRqQQRrKAIAIgIgASACKAIAKAIsEQgAIAAoAqABIANBAmsiA0ECdGooAgAiAiABIAIoAgAoAiwRCAAgAw0ACwsgAEEBOgAwCwUAQfsXC64BAQN/IAAgASkCADcCNCAAIAEpAgg3AjwCQCAAKAKYASICRQ0AIAIhAyACQQFxBEAgACgCoAEgAkEBayIDQQJ0aigCACIEIAEgBCgCACgCGBEDAAsgAkEBRg0AA0AgACgCoAEgA0ECdGpBBGsoAgAiAiABIAIoAgAoAhgRAwAgACgCoAEgA0ECayIDQQJ0aigCACICIAEgAigCACgCGBEDACADDQALCyAAQQE6ADALKQAgABDoBCIABEBByIUCQciFAigCAEEBajYCACAAQfzTASgCABEAAAsLRwEBfyAAKAKMASIAKAIgIgEEQCAAIAFBAk4EfyABQQFrBSAAKAIIIgEgACgCHCABKAIAKAIYEQMAIABBADYCJEEACzYCIAsLaAEBfyAAKAKMASIAKAIgIgFBAEoEQCAAIAFBAWo2AiAPCyAAKAIIIgEgAEEkaiAAQShqIABBLGogAEEwaiAAQTRqIABBOGogAEE8aiAAQUBrIAAoAhwgASgCACgCEBEYACAAQQE2AiALDwAgAEGQAWogASACENsDCwgAIAAoAswBCwgAIAAqApQBCxcAIAAgATgClAEgACAAKAIAKAJIEQAACwUAQfISCwgAIABBnAFqCyUAIAAgASkCADcCnAEgACABKQIINwKkASAAIAAoAgAoAkgRAAALegEBfyAAQbQkNgIAAkAgACgCVCIBRQ0AIAAtAFhFDQAgAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALCyAAQQA2AlQgAEEBOgBYIABCADcCTCAABEBByIUCQciFAigCAEEBajYCACAAQfzTASgCABEAAAsLWgEBfyAAQbQkNgIAAkAgACgCVCIBRQ0AIAAtAFhFDQAgAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALCyAAQQA2AlQgAEEBOgBYIABCADcCTCAAC2sAIAAoAqQBIAFBBnRqIgEgAikCADcCACABIAIpAgg3AgggASACKQIYNwIYIAEgAikCEDcCECABIAIpAig3AiggASACKQIgNwIgIAEgAikCMDcCMCABIAIpAjg3AjggACAAKAIAKAJIEQAAC14AIAAg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AiAMIBC2lDgCACAEIAYgBygCBGxqIgUrAwAhECAFKwMIIREgBSsDECESIAJBADYCHCACIAogEraUOAIYIAIgCyARtpQ4AhQgAiAMIBC2lDgCECAEIAYgBygCCGxqIgQrAwAhECAEKwMIIREgBCsDECESIAJBADYCLCACIAogEraUOAIoIAIgCyARtpQ4AiQgAiAMIBC2lDgCICABIAIgCCADIAEoAgAoAggRBAAgA0EBaiIDIAIoAjBIDQALDAILQQAhAyACKAIwQQBMDQEDQCACKAJMIgQgAigCOCIGIAIoAkggAigCRCADbGoiBy8BAGxqIgUrAwAhECAFKwMIIREgBSsDECESIAJBADYCDCACIAogEraUOAIIIAIgCyARtpQ4AgQgAiAMIBC2lDgCACAEIAYgBy8BAmxqIgUrAwAhECAFKwMIIREgBSsDECESIAJBADYCHCACIAogEraUOAIYIAIgCyARtpQ4AhQgAiAMIBC2lDgCECAEIAYgBy8BBGxqIgQrAwAhECAEKwMIIREgBCsDECESIAJBADYCLCACIAogEraUOAIoIAIgCyARtpQ4AiQgAiAMIBC2lDgCICABIAIgCCADIAEoAgAoAggRBAAgA0EBaiIDIAIoAjBIDQALDAELQQAhAyACKAIwQQBMDQADQCACKAJMIgQgAigCOCIGIAIoAkggAigCRCADbGoiBy0AAGxqIgUrAwAhECAFKwMIIREgBSsDECESIAJBADYCDCACIAogEraUOAIIIAIgCyARtpQ4AgQgAiAMIBC2lDgCACAEIAYgBy0AAWxqIgUrAwAhECAFKwMIIREgBSsDECESIAJBADYCHCACIAogEraUOAIYIAIgCyARtpQ4AhQgAiAMIBC2lDgCECAEIAYgBy0AAmxqIgQrAwAhECAEKwMIIREgBCsDECESIAJBADYCLCACIAogEraUOAIoIAIgCyARtpQ4AiQgAiAMIBC2lDgCICABIAIgCCADIAEoAgAoAggRBAAgA0EBaiIDIAIoAjBIDQALCyAAIAggACgCACgCGBEDACAIQQFqIgggCUcNAAsLIAJB0ABqJAALFwBBBCAAKAJcIgBBA0ZBAXQgAEEERhsLHgAgAiAAIAFBBHRqIgApAmg3AgggAiAAKQJgNwIAC/0CAAJAIAMCfwJAAkACQCAAKAJcQQJrDgMAAQIE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cSEiDAELIB0gAUEEdGoiAioCCCElIAIqAgQhICACKgIAIR8gACgCNCgCECEFIA8oAgwhBEPK8klxISJBACECA0AgBSAEIAJBAnRqKAIAQQR0aiIKKgIIICWUIAoqAgAgH5QgCioCBCAglJKSIh4gIiAeICJdGyEiIAJBAWoiAiAQRw0ACwsgDyAijDgCICABQQFqIgEgFEcNAAsgFEUNAEEAIQRBACEQQQAhBgNAAkAgBCAGRw0AIARBAXRBASAEGyIGIARNBEAgBCEGDAELQcSFAkHEhQIoAgBBAWo2AgAgBkECdEEQQfjTASgCABECACEBAkACQCAEBEBBACEOQQAhAiAEQQFrQQNPBEAgBEH8////B3EhCkEAIRIDQCABIAJBAnQiB2ogByAQaigCADYCACABIAdBBHIiBWogBSAQaigCADYCACABIAdBCHIiBWogBSAQaigCADYCACABIAdBDHIiBWogBSAQaigCADYCACACQQRqIQIgEkEEaiISIApHDQALCyAEQQNxIgpFDQEDQCABIAJBAnQiBWogBSAQaigCADYCACACQQFqIQIgDkEBaiIOIApHDQALDAELIBANAEEBIQYMAQsgEARAQciFAkHIhQIoAgBBAWo2AgAgEEH80wEoAgARAAALCyABIRALIBAgBEECdGogBDYCACAEQQFqIgQgFEcNAAsgFCEKA0AgECAKQQFrIgRBAnRqKAIAIQJBxIUCQcSFAigCAEEBajYCAEEEQRBB+NMBKAIAEQIAIgEgAjYCAAJAAkAgCkECSARAIAQhCkEBIRMMAQsgFiACQSRsaiICKgIUISAgAioCHCEfIAIqAhghHiAKQQJrIQJBASETIAQhCkEBIQYDQCAfIBYgECACIgRBAnRqKAIAIgtBJGxqIgIqAhyUICAgAioCFJQgHiACKgIYlJKSQ3e+fz9eBEACQCAGIBNHBEAgASEFDAELIBNBAXRBASATGyIGIBNMBEAgASEFIBMhBgwBCyAGBH9BxIUCQcSFAigCAEEBajYCACAGQQJ0QRBB+NMBKAIAEQIABUEACyEFAkAgE0EASgRAQQAhDkEAIQIgE0EBa0EDTwRAIBNBfHEhCUEAIQgDQCAFIAJBAnQiDGogASAMaigCADYCACAFIAxBBHIiB2ogASAHaigCADYCACAFIAxBCHIiB2ogASAHaigC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D5Q4AgQgBSAMIBCUOAIACyACIAhqIAs4AgwgB0EBaiIHIANGDQIgACgCYCEGDAALAAtBACEFQQAhBCAIQQdPBEAgA0F4cSEBQQAhBgNAIAIgBEEEdCIAakHrlvjqfTYCDCACIABBEHJqQeuW+Op9NgIMIAIgAEEgcmpB65b46n02AgwgAiAAQTByakHrlvjqfTYCDCACIABBwAByakHrlvjqfTYCDCACIABB0AByakHrlvjqfTYCDCACIABB4AByakHrlvjqfTYCDCACIABB8AByakHrlvjqfTYCDCAEQQhqIQQgBkEIaiIGIAFHDQALCyADQQdxIgBFDQADQCACIARBBHRqQeuW+Op9NgIMIARBAWohBCAFQQFqIgUgAEcNAAsLC+8BAgh9A38gASgCYCINQQBKBEAgAioCACABKgIMIgaUIQQgAioCCCABKgIUIgeUIQUgAioCBCABKgIQIgiUIQkgASgCaCEMQQAhAUF/IQJD//9//yEDA0AgDCABQQR0aiILKgIIIAWUIAsqAgAgBJQgCSALKgIElJKSIgogAyADIApdIgsbIQMgASACIAsbIQIgAUEBaiIBIA1HDQALIAwgAkEEdGoiASoCACEDIAEqAgQhBCABKgIIIQUgAEEANgIMIAAgByAFlDgCCCAAIAggBJQ4AgQgACAGIAOUOAIADwsgAEIANwIAIABCADcCCAsaACAAIAEpAgA3AgwgACABKQIINwIUIAAQWwsUACAAQgA3AgggAEKAgID8AzcCAAsFAEH2IAsUACAAQoCAgPwDNwIIIABCADcCAAsFAEHTIAtyACAAIAEgAhA0GiABIAAqAhw4AhwgASAAKgIgOAIgIAEgACoCJDgCJCABIAAqAig4AiggASAAKgIMOAIMIAEgACoCEDgCECABIAAqAhQ4AhQgASAAKgIYOAIYIAEgACoCLDgCLCABIAAoAkQ2AjRB0B4LGAAgAEIANwIIIABCgICAgICAgMA/NwIACwUAQcoYC70CAgF/B30jAEHgAGsiAyQAIANCADcCLCADQgA3AzggA0GAgID8AzYCNCADQUBrQgA3AwAgA0IANwJMIANBgICA/AM2AkggA0IANwJUIANBADYCXCADQgA3AiQgA0GAgID8AzYCICAAIANBIGogA0EQaiADIAAoAgAoAggRBAAgAyoCGCEHIAMqAggh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AgAgCSAFKQIINwIIIANBAmohAyAIQQJqIgggCkcNAAsLIARBAXFFDQAgBiADQQR0IgNqIgQgACgCiAEgA2oiAykCADcCACAEIAMpAgg3AggLAkAgACgCiAEiA0UNACAALQCMAUUNACADBEBByIUCQciFAigCAEEBajYCACADQfzTASgCABEAAAsLIAAgBjYCiAEgAEEBOgCMASAAIAc2AoQBCyAHIAJBf3NqIQQgByACa0EDcSIGBEBBACEDA0AgACgCiAEgAkEEdGoiCEIANwIAIAhCADcCCCACQQFqIQIgA0EBaiIDIAZHDQALCyAEQQNJDQADQCACQQR0IgMgACgCiAFqIgRCADcCACAEQgA3AgggAyAAKAKIAWoiBEIANwIYIARCADcCECADIAAoAogBaiIEQgA3AiggBEIANwIgIAMgACgCiAFqIgNCADcCOCADQgA3AjAgAkEEaiICIAdHDQALCyAAIAc2AoABIAdBAEoEQCAAKAKIASEGIAEoAnQhAkEAIQQDQCAGIARBBHRqIgMgAigCDDYCDCADIAIvAQY7AQYgAyACLwEIOwEIIAMgAi8BCjsBCiADIAIvAQA7AQAgAyACLwECOwECIAMgAi8BBDsBBCACQRBqIQIgBEEBaiIEIAdHDQALCyAAIAEoAng2ApABAkAgACgCmAEiAiABKAJ8IgdODQAgACgCnAEgB04NAAJAIAdFBEBBACEIDAELQcSFAkHEhQIoAgBBAWo2AgAgB0EFdEEQQfjTASgCABECACEIIAAoApgBIQILAkAgAkEATA0AQQAhBiACQQFHBEAgAkF+cSEJQQAhBANAIAggBkEFdCIKaiIDIAAoAqABIApqIgUpAgA3AgAgAyAFKQIYNwIYIAMgBSkCEDcCECADIAUpAgg3AgggCCAKQSByIgVqIgMgACgCoAEgBWoiBSkCADcCACADIAUpAgg3AgggAyAFKQIQNwIQIAMgBSkCGDcCGCAGQQJqIQYgBEECaiIEIAlHDQALCyACQQFxRQ0AIAggBkEFdCICaiIDIAAoAqABIAJqIgIpAgA3AgAgAyACKQIYNwIYIAMgAikCEDcCECADIAIpAgg3AggLAkAgACgCoAEiA0UNACAALQCkAUUNACADBEBByIUCQciFAigCAEEBajYCACADQfzTASgCABEAAAsLIAAgCDYCoAEgAEEBOgCkASAAIAc2ApwBCyAAIAc2ApgBIAdBAEoEQCAAKAKgASEDIAEoAoABIQJBACEAA0AgAyAAQQV0aiIBIAIvAQ47AQYgASACLwEQOwEIIAEgAi8BEjsBCiABIAIvAQg7AQAgASACLwEKOwECIAEgAi8BDDsBBCABIAIoAgA2AgwgASACKAIENgIQIAJBFGohAiAAQQFqIgAgB0cNAAsLC74TAQp/IAAgASoCEDgCFCAAIAEqAhQ4AhggACABKgIYOAIcIAAgASoCHDgCICAAIAEqAgA4AgQgACABKgIEOAIIIAAgASoCCDgCDCAAIAEqAgw4AhAgACABKgIgOAIkIAAgASoCJDgCKCAAIAEqAig4AiwgACABKgIsOAIwIAAgASgCMDYCOCAAIAEoAjRBAEc6ADwCQCABKAI4IgcgACgCWCIDTA0AIAcgACgCXEoEQAJAIAcEf0HEhQJBxIUCKAIAQQFqNgIAIAdBBnRBEEH40wEoAgARAgAhBCAAKAJYBSADCyICQQBMDQAgAkEBRwRAIAJBfnEhCQNAIAQgBkEGdCIKaiIIIAAoAmAgCmoiBSkCADcCACAIIAUpAjg3AjggCCAFKQIwNwIwIAggBSkCKDcCKCAIIAUpAiA3AiAgCCAFKQIYNwIYIAggBSkCEDcCECAIIAUpAgg3AgggBCAKQcAAciIFaiIIIAAoAmAgBWoiBSkCADcCACAIIAUpAgg3AgggCCAFKQIQNwIQIAggBSkCGDcCGCAIIAUpAiA3AiAgCCAFKQIoNwIoIAggBSkCMDcCMCAIIAUpAjg3AjggBkECaiEGIAtBAmoiCyAJRw0ACwsgAkEBcUUNACAEIAZBBnQiBmoiAiAAKAJgIAZqIgYpAgA3AgAgAiAGKQI4NwI4IAIgBikCMDcCMCACIAYpAig3AiggAiAGKQIgNwIgIAIgBikCGDcCGCACIAYpAhA3AhAgAiAGKQIINwIICwJAIAAoAmAiAkUNACAALQBkRQ0AIAIEQEHIhQJByIUCKAIAQQFqNgIAIAJB/NMBKAIAEQAACwsgACAENgJgIABBAToAZCAAIAc2AlwLIAcgA0F/c2ohBiAHIANrQQNxIggEQEEAIQQDQCAAKAJgIANBBnRqIgJCADcCACACQgA3AjggAkIANwIwIAJCADcCKCACQgA3AiAgAkIANwIYIAJCADcCECACQgA3AgggA0EBaiEDIARBAWoiBCAIRw0ACwsgBkEDSQ0AA0AgA0EGdCIEIAAoAmBqIgJCADcCACACQgA3AjggAkIANwIwIAJCADcCKCACQgA3AiAgAkIANwIYIAJCADcCECACQgA3AgggBCAAKAJgaiICQgA3AnggAkIANwJwIAJCADcCaCACQgA3AmAgAkIANwJYIAJCADcCUCACQgA3AkggAkFAa0IANwIAIAQgACgCYGoiAkIANwK4ASACQgA3ArABIAJCADcCqAEgAkIANwKgASACQgA3ApgBIAJCADcCkAEgAkIANwKIASACQgA3AoABIAQgACgCYGoiAkIANwL4ASACQgA3AvABIAJCADcC6AEgAkIANwLgASACQgA3AtgBIAJCADcC0AEgAkIANwLIASACQgA3AsABIANBBGoiAyAHRw0ACwsgACAHNgJYIAdBAEoEQCAAKAJgIQYgASgCQCECQQAhBANAIAYgBEEGdGoiAyACKgIQOAIQIAMgAioCFDgCFCADIAIqAhg4AhggAyACKgIcOAIcIAMgAioCADgCACADIAIqAgQ4AgQgAyACKgIIOAIIIAMgAioCDDgCDCADIAIoAiA2AiAgAyACKAIkNgIkIAMgAigCKDYCKCACQTBqIQIgBEEBaiIEIAdHDQALCwJAIAEoAjwiByAAKAKAASICTA0AIAcgACgChAFKBEACQAJ/IAdFBEBBACEGIAIMAQtBxIUCQcSFAigCAEEBajYCACAHQQR0QRBB+NMBKAIAEQIAIQYgACgCgAELIgRBAEwNAEEAIQMgBEEBRwRAIARBfnEhCkEAIQgDQCAGIANBBHQiBWoiCSAAKAKIASAFaiILKQIANwIAIAkgCykCCDcCCCAGIAVBEHIiBWoiCSAAKAKIASAFaiIFKQIANwIAIAkgBSkCCDcCCCADQQJqIQMgCEECaiIIIApHDQALCyAEQQFxRQ0AIAYgA0EEdCIDaiIEIAAoAogBIANqIgMpAgA3AgAgBCADKQIINwIICwJAIAAoAogBIgNFDQAgAC0AjAFFDQAgAwRAQciFAkHIhQIoAgBBAWo2AgAgA0H80wEoAgARAAALCyAAIAY2AogBIABBAToAjAEgACAHNgKEAQsgByACQX9zaiEEIAcgAmtBA3EiBgRAQQAhAwNAIAAoAogBIAJBBHRq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AiADQQJ0aiAJNgIAIAAgA0EBajYCjAIgACgCnAIiACAKIAEgACgCACgCCBEHABoLC80BAQF/IABB1NgANgIAIAAoApwCIgEgASgCACgCABEBABogACgCnAIiAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALIABBqNgANgIAAkAgACgClAIiAUUNACAALQCYAkUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYClAIgAEEBOgCYAiAAQgA3AowCIABB/DM2AgAgAARAQciFAkHIhQIoAgBBAWo2AgAgAEH80wEoAgARAAALC60BAQF/IABB1NgANgIAIAAoApwCIgEgASgCACgCABEBABogACgCnAIiAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALIABBqNgANgIAAkAgACgClAIiAUUNACAALQCYAkUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYClAIgAEEBOgCYAiAAQgA3AowCIABB/DM2AgAgAAtvAQJ/AkAgACgCjAIiAkEATA0AIAEoAgAhBCAAKAKUAiEDQQAhAQNAIAQgAyABQQJ0aiIFKAIARwRAIAFBAWoiASACRw0BDAILCyABIAJODQAgBSADIAJBAWsiAUECdGooAgA2AgAgACABNgKMAgsL9QMBCH8gASgCACEIAkACQCAAKAKMAiICQQBMDQAgACgClAIhA0EAIQEDQCAIIAMgAUECdGooAgBHBEAgAUEBaiIBIAJHDQEMAgsLIAEgAkcNAQsCQCACIAAoApACRw0AIAIgAkEBdEEBIAIbIgVODQACQCAFRQRAQQAhAwwBC0HEhQJBxIUCKAIAQQFqNgIAIAVBAnRBEEH40wEoAgARAgAhAyAAKAKMAiECCwJAIAJBAEwNAEEAIQEgAkEBa0EDTwRAIAJBfHEhBgNAIAMgAUECdCIEaiAAKAKUAiAEaigCADYCACADIARBBHIiB2ogACgClAIgB2ooAgA2AgAgAyAEQQhyIgdqIAAoApQCIAdqKAIANgIAIAMgBEEMciIEaiAAKAKUAiAEaigCADYCACABQQRqIQEgCUEEaiIJIAZHDQALCyACQQNxIgRFDQADQCADIAFBAnQiBmogACgClAIgBmooAgA2AgAgAUEBaiEBIApBAWoiCiAERw0ACwsCQCAAKAKUAiIBRQ0AIAAtAJgCRQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACyAAKAKMAiECCyAAIAM2ApQCIABBAToAmAIgACAFNgKQAgsgACgClAIgAkECdGogCDYCACAAIAJBAWo2AowCCwuIAQEBfyAAQajYADYCAAJAIAAoApQCIgFFDQAgAC0AmAJFDQAgAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALCyAAQQA2ApQCIABBAToAmAIgAEIANwKMAiAAQfwzNgIAIAAEQEHIhQJByIUCKAIAQQFqNgIAIABB/NMBKAIAEQAACwtoAQF/IABBqNgANgIAAkAgACgClAIiAUUNACAALQCYAkUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYClAIgAEEBOgCYAiAAQgA3AowCIABB/DM2AgAgAAvJAQEDfyABKAIAIgRBHCAEKAIAKAI4EQIAIQQgAC0ABCEFIAAoAgghBiAAKAIMIQAgBEGwwwA2AgAgBCABKAIANgIEIAQgADYCGCAEIAY2AhQgBCAFOgAQIARBADYCDCAEQQA6AAggBEHQzwA2AgAgBCgCBCIAIAMgAiAFGyIBKAIIIAIgAyAFGyICKAIIIAAoAgAoAhgRBwAEQCAEKAIEIgAgASgCCCACKAIIIAAoAgAoAgwRBwAhACAEQQE6AAggBCAANgIMCyAEC5YBACABKAIAIgBBECAAKAIAKAI4EQIAIgBBsMMANgIAIAAgASgCADYCBCAAQczDADYCACAAQQA2AgwgAEEAOgAIIABBiM8ANgIAIAAoAgQiASACKAIIIAMoAgggASgCACgCGBEHAARAIAAoAgQiASACKAIIIAMoAgggASgCACgCDBEHACEBIABBAToACCAAIAE2AgwLIAALlgEBAn8gASgCACIEQRQgBCgCACgCOBECACEEIAEoAgQhBSAALQAEIQAgBEGwwwA2AgAgBCABKAIANgIEIARBzMMANgIAIAQgADoAECAEIAU2AgwgBEEAOgAIIARBjNsANgIAIAVFBEAgBCgCBCIAIAIoAgggAygCCCAAKAIAKAIMEQcAIQAgBEEBOgAIIAQgADYCDAsgBAt3ACABKAIAIgBBECAAKAIAKAI4EQIAIgBBsMMANgIAIAAgASgCADYCBCAAQczDADYCACAAQQA2AgwgAEEAOgAIIABBwNoANgIAIAAoAgQiASACKAIIIAMoAgggASgCACgCDBEHACEBIABBAToACCAAIAE2AgwgAAs0ACABKAIAIgBBCCAAKAIAKAI4EQIAIgBBsMMANgIAIAAgASgCADYCBCAAQezXADYCACAACyUAIAEoAgAiAEEsIAAoAgAoAjgRAgAiACABIAIgA0EBEKgFIAALnwQBB38gASgCACIAQTAgACgCACgCOBECACIFQbDDADYCACAFIAEoAgA2AgQgBUHMwwA2AgAgBUEBOgAcIAVBgM0ANgIAIAVBADYCGCAFQgA3AhAgASgCBCEAIAVBADoAJCAFIAA2AiBBxIUCQcSFAigCAEEBajYCAEHEAEEQQfjTASgCABECACIAQQA6ABggAEEBOgAUIABBxNkANgIAIABBADYCECAAQQE6ACwgAEIANwIIIABBADYCKCAAQUBrQQE6AAAgAEIANwIgIABBADYCPCAAQgA3AjRBxIUCQcSFAigCAEEBajYCAEEYQRBB+NMBKAIAEQIAIQECQCAAKAIIIgdBAEwNACAHQQFHBEAgB0F+cSEKA0AgASAEQQxsIgZqIgggACgCECAGaiIGKQIANwIAIAggBigCCDYCCCABIARBAXJBDGwiBmoiCCAAKAIQIAZqIgYpAgA3AgAgCCAGKAIINgIIIARBAmohBCAJQQJqIgkgCkcNAAsLIAdBAXFFDQAgASAEQQxsIgRqIgcgACgCECAEaiIEKQIANwIAIAcgBCgCCDYCCAsCQCAAKAIQIgRFDQAgAC0AFEUNACAEBEBByIUCQciFAigCAEEBajYCACAEQfzTASgCABEAAAsLIAAgATYCECAAQQE6ABQgAEECNgIMIAAQ9gIgBSAANgIIIAUgAigCBCgCRDYCKCAFIAMoAgQoAkQ2AiwgBQslACABKAIAIgBBLCAAKAIAKAI4EQIAIgAgASACIANBABCoBSAACyYAIAEoAgAiAEHQACAAKAIAKAI4EQIAIgAgASACIANBARCqBSAACyYAIAEoAgAiAEHQACAAKAIAKAI4EQIAIgAgASACIANBABCqBSAACwkAIAAQiAIQDAu0GgIHfzF9IwBBMGsiAyQAAkAgACgC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ADoAsAIgA0EANgKsAiADQgA3AuwDIANBADoA6AMgA0EANgLkAyADQgA3AoQBIANCADcCjAEgA0IANwKUASADQgA3ArwCIANCADcCxAIgA0IANwLMAiADQgA3AvQDIANCADcC/AMgA0IANwKEBCADQQA6AKAFIANBADYCnAUgA0IANwKkBSADQgA3AqwFIANCADcCtAUgA0IANwK8BSADIAE2AuQFIAMgAjYC6AUgA0EANgLsBSADIA44AvAFIAMgDSAMIAwgDV4bOAL0BSADIAAoAgwiBDYCgAYCQCAEIAAoAhBHDQAgBCAEQQF0QQEgBBsiB04NAAJAIAdFBEBBACECDAELQcSFAkHEhQIoAgBBAWo2AgAgB0ECdEEQQfjTASgCABECACECIAAoAgwhBAsCQCAEQQBMDQBBACEBIARBAWtBA08EQCAEQXxxIQgDQCACIAFBAnQiBWogACgCFCAFaigCADYCACACIAVBBHIiCWogACgCFCAJaigCADYCACACIAVBCHIiCWogACgCFCAJaigCADYCACACIAVBDHIiBWogACgCFCAFaigCADYCACABQQRqIQEgCkEEaiIKIAhHDQALCyAEQQNxIgVFDQADQCACIAFBAnQiCGogACgCFCAIaigCADYCACABQQFqIQEgC0EBaiILIAVHDQALCwJAIAAoAhQiAUUNACAALQAYRQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACyAAKAIMIQQLIAAgAjYCFCAAQQE6ABggACAHNgIQCyAAKAIUIARBAnRqIAM2AgAgACAEQQFqNgIMCyAGQRBqJAAgAwtcAQF/IABB1DI2AgACQCAAKAIUIgFFDQAgAC0AGEUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCFCAAQQE6ABggAEIANwIMIAAQDAtaAQF/IABB1DI2AgACQCAAKAIUIgFFDQAgAC0AGEUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCFCAAQQE6ABggAEIANwIMIAALxwICBH8BfSMAQdAAayIDJAACQCABIAAoAgAoAgAiBCAAKAIEKAIAIgUgASgCACgCGBEHAEUNACAEKALAASEGIANCfzcDSCADIARBBGo2AkQgAyAENgJAIAMgBjYCPCADQQA2AjggBSgCwAEhBiADQn83AzAgAyAFQQRqNgIsIAMgBTYCKCADIAY2AiQgA0EANgIgIAAoAghFBEAgACABIANBOGogA0EgakEAIAEoAgAoAggRCgAiATYCCCABRQ0BCyADIANBIGo2AgwgAyADQThqNgIIIANBADYCBCADQYTaADYCACADIQEgACgCCCEAIAIoAghBAUYEQCAAIANBOGogA0EgaiACIAEgACgCACgCCBEJAAwBCyAAIAQgBSACIAEgACgCACgCDBEXACIHIAIqAgxdRQ0AIAIgBzgCDAsgA0HQAGokAAsYACAAKAIEIgAgASgCAEYgASgCBCAARnILOQEBfyAAKAIEIgIgASgCAEcgASgCBCACR3FFBEAgACgCCCICIAEgACgCDCACKAIAKAIgEQUAC0EACwkAIAAgATYCGAvuBQEKf0GI5wFBiOcBKAIAQQFqNgIAAkACQCAAKAIYIgMEQCADIAEgAiADKAIAKAIIEQcADQEMAgsgAi8BBiABLwEEcUUNASABLwEGIAIvAQRxRQ0BCwJAIAAiAygCLCABIAIgASgCDCACKAIMSiIAGyIIKAIMIgVBEHQgAiABIAAbIgkoAgwiB3IiACAAQQ90QX9zaiIAQQp1IABzQQlsIgBBBnUgAHMiACAAQQt0QX9zaiIAQRB1IABzIgwgAygCDCIBQQFrcSIKQQJ0aigCACIAQX9HBEAgA0FAaygCACEGIAMoAhAhBANAIAcgBCAAQQR0IgtqIgIoAgAoAgxGIAQgC2ooAgQoAgwgBUZxDQIgBiAAQQJ0aigCACIAQX9HDQALCyADKAIIIgUhAgJAIAUgASIARw0AIAEhAiAAIABBAXRBASAAGyIETg0AAn8gBEUEQEEAIQIgAQwBC0HEhQJBxIUCKAIAQQFqNgIAIARBBHRBEEH40wEoAgARAgAhAiADKAIICyILQQBKBEBBACEAA0AgAiAAQQR0IgZqIgcgAygCECAGaiIGKAIANgIAIAcgBigCBDYCBCAHIAYoAgg2AgggByAGKAIMNgIMIABBAWoiACALRw0ACwsCQCADKAIQIgBFDQAgAy0AFEUNACAABEBByIUCQciFAigCAEEBajYCACAAQfzTASgCABEAAAsLIAMgAjYCECADQQE6ABQgAyAENgIMIAMoAgghAiAEIQALIAMgAkEBajYCCCADKAIQIQQgAygCSCICBEAgAiAJIAggAigCACgCCBEHABogAygCDCEACyAEIAVBBHRqIQIgACABSgRAIAMQuQUgAygCDEEBayAMcSEKCyACIAkgCCAJKAIMIAgoAgxIIgAbNgIAIAQgBUEEdGoiAUIANwIIIAEgCCAJIAAbNgIEIANBQGsoAgAgBUECdGogAygCLCAKQQJ0aiIAKAIANgIAIAAgBTYCAAsgAiEECyAEC6IGAQl/IwBBIGsiAyQAIANBADYCFCADQgA3AgwgA0EBOgAYAkAgACgCCEEATA0AA0AgACgCECEKAkAgAiAERw0AIARBAXRBASAEGyIHIARMBEAgBCECDAELQQAhBUEAIQYgBwRAQcSFAkHEhQIoAgBBAWo2AgAgB0EEdEEQQfjTASgCABECACEGCyAEQQBKBEADQCAGIAVBBHQiCGoiAiADKAIUIAhqIggoAgA2AgAgAiAIKAIENgIEIAIgCCgCCDYCCCACIAgoAgw2AgwgBUEBaiIFIARHDQALCwJAIAMoAhQiAkUNACADLQAYRQ0AIAIEQEHIhQJByIUCKAIAQQFqNgIAIAJB/NMBKAIAEQAACwsgAyAGNgIUIANBAToAGCADIAc2AhAgAygCDCECCyADKAIUIAJBBHRqIgIgCiAJQQR0aiIEKAIANgIAIAIgBCgCBDYCBCACIAQoAgg2AgggAiAEKAIMNgIMIAMgAygCDCIFQQFqIgI2AgwgCUEBaiIJIAAoAghIBEAgAygCECEEDAELC0EAIQQgBUEASA0AIAVBAWoiBkEBcSEIIAMoAhQhByAFBEAgBkF+cSEGQQAhBQNAIAAgByAEQQR0IglqIgooAgAgCigCBCABIAAoAgAoAgwRCgAaIAAgByAJQRByaiIJKAIAIAkoAgQgASAAKAIAKAIMEQoAGiAEQQJqIQQgBUECaiIFIAZHDQALCyAIRQ0AIAAgByAEQQR0aiIEKAIAIAQoAgQgASAAKAIAKAIMEQoAGgsgACgCOEEASgRAIABBQGsoAgAhAUEAIQIDQCABIAJBAnRqQX82AgAgAkEBaiICIAAoAjhIDQALIAMoAgwhAgsgAkECTgR/IANBCGogA0EAIAJBAWsQcCADKAIMBSACC0EASgRAQQAhAgNAIAAgAygCFCACQQR0aiIBKAIAIAEoAgQgACgCACgCCBEHABogAkEBaiICIAMoAgxIDQALCwJAIAMoAhQiAEUNACADLQAYRQ0AIAAEQEHIhQJByIUCKAIAQQFqNgIAIABB/NMBKAIAEQAACwsgA0EgaiQAC3ABAn8gACgCCEEASgRAA0ACQCABIAAoAhAgA0EEdGoiBCABKAIAKAIIEQIABEAgACAEKAIAIAQoAgQgAiAAKAIAKAIMEQoAGkGA5wFBgOcBKAIAQQFrNgIADAELIANBAWohAwsgAyAAKAIISA0ACwsLxQUBCH9BhOcBQYTnASgCAEEBajYCAAJAIAAoAiwgACgCDEEBayABIAIgASgCDCACKAIMSiIEGyIHKAIMIgVBEHQgAiABIAQbIggoAgwiBnIiASABQQ90QX9zaiIBQQp1IAFzQQlsIgFBBnUgAXMiASABQQt0QX9zaiIBQRB1IAFzcSIJQQJ0aigCACIBQX9GDQAgAEFAaygCACELIAAoAhAhBANAIAYgBCABQQR0aiICKAIAKAIMRiACKAIEKAIMIAVGcUUEQCALIAFBAnRqKAIAIgFBf0cNAQwCCwsgACACIAMgACgCACgCIBEFACAEIAFBBHRqKAIMIQoCQAJAIAAoAiwgCUECdGoiBSgCACIBIAIgACgCEGtBBHUiBEYNACAAKAJAIQYDQCAGIAEiAkECdGooAgAiASAERw0ACyACQX9GDQAgACgCQCIBIAJBAnRqIAEgBEECdGooAgA2AgAMAQsgBSAAKAJAIARBAnRqKAIANgIACyAAKAIIQQFrIQUgACgCSCIBBEAgASAIIAcgAyABKAIAKAIMEQoAGgsgBCAFRwRAAkACQCAAKAIsIAAoAgxBAWsgACgCECIHIAVBBHRqIgMoAgQoAgxBEHQgAygCACgCDHIiASABQQ90QX9zaiIBQQp1IAFzQQlsIgFBBnUgAXMiASABQQt0QX9zaiIBQRB1IAFzcSIIQQJ0aiIGKAIAIgEgBUYNACAAKAJAIQkDQCAJIAEiAkECdGooAgAiASAFRw0ACyACQX9GDQAgACgCQCIBIAJBAnRqIAEgBUECdGooAgA2AgAMAQsgBiAAKAJAIAVBAnRqKAIANgIACyAHIARBBHRqIgEgAykCADcCACABIAMpAgg3AgggACgCQCAEQQJ0aiAAKAIsIAhBAnRqIgEoAgA2AgAgASAENgIACyAAIAAoAghBAWs2AggLIAoL7QEBBH9BjOcBQYznASgCAEEBajYCAAJAAkAgACgCDEEBayABIAIgASgCDCACKAIMSiIDGygCDCIEQRB0IAIgASADGygCDCIDciIBIAFBD3RBf3NqIgFBCnUgAXNBCWwiAUEGdSABcyIBIAFBC3RBf3NqIgFBEHUgAXNxIgEgACgCJE4NACAAKAIsIAFBAnRqKAIAIgFBf0YNACAAQUBrKAIAIQUgACgCECEAA0AgAyAAIAFBBHQiBmoiAigCACgCDEYgACAGaigCBCgCDCAERnENAiAFIAFBAnRqKAIAIgFBf0cNAAsLQQAhAgsgAgs3AQF/IwBBEGsiAyQAIAMgATYCDCADQZgxNgIIIAAgA0EIaiACIAAoAgAoAjARBQAgA0EQaiQAC0IBAX8jAEEQayIDJAAgAyACNgIMIAMgADYCCCADIAE2AgQgA0HsLzYCACAAIAMgAiAAKAIAKAIwEQUAIANBEGokAAs7AAJAIAJFDQAgASgCCCIARQ0AIAAgACgCACgCABEBABogAiABKAIIIAIoAgAoAjwRAwAgAUEANgIICwviAQEBfyAAQfQuNgIAAkAgAEFAaygCACIBRQ0AIAAtAERFDQAgAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALCyAAQQA2AkAgAEEBOgBEIABCADcCOAJAIAAoAiwiAUUNACAALQAwRQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACwsgAEEANgIsIABBAToAMCAAQgA3AiQCQCAAKAIQIgFFDQAgAC0AFEUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIAAQDAv1AQEBfyAAQfQuNgIAAkAgAEFAaygCACIBRQ0AIAAtAERFDQAgAQRAQciFAkHIhQIoAgBBAWo2AgAgAUH80wEoAgARAAALCyAAQQA2AkAgAEEBOgBEIABCADcCOAJAIAAoAiwiAUUNACAALQAwRQ0AIAEEQEHIhQJByIUCKAIAQQFqNgIAIAFB/NMBKAIAEQAACwsgAEEANgIsIABBAToAMCAAQgA3AiQCQCAAKAIQIgFFDQAgAC0AFEUNACABBEBByIUCQciFAigCAEEBajYCACABQfzTASgCABEAAAsLIABBADYCECAAQQE6ABQgAEIANwIIIAALEQAgACABIAAoAgAoAgwRAwALGQAgACABIAAoAggoAjAgACgCACgCCBEFAAtBAQF/IAEgAkcEQCAAKAIEKAKIASIDIAEoAiQgAigCJCADKAIAKAIIEQcAGiAAKAIEIgAgACgCoAFBAWo2AqABCwt3ACAAKAIQQQAgACgCTGtGBEAgAEEEahC7ASAAQUBrELsBIABBgAI7AMEBIABBADYCpAEgAEEANgKQASAAQoqAgIAQNwKcASAAQgE3ApQBIABCADcCfCAAQQA2AoQBIABCADcCqAEgAEIANwKwASAAQgA3ArgBCwvVAgIBfwh9IABBQGsoAgAhAwJAIAAoAgQiAARAIAAqAgAhBSADBEAgACoCGCIEIAMqAhgiBiAEIAZeGyEGIAAqAhQiBCADKgIUIgcgBCAHXhshByAAKgIIIgQgAyoCCCIIIAQgCF0bIQggACoCBCIEIAMqAgQiCSAEIAldGyEJIAAqAhAiBCADKgIQIgogBCAKXhshCiAFIAMqAgAiBCAEIAVeGyEFDAILIAAqAhwhCyAAKgIYIQYgACoCFCEHIAAqAhAhCiAAKgIMIQQgACoCCCEIIAAqAgQhCQwBCyADRQRADAELIAMqAhwhCyADKgIYIQYgAyoCFCEHIAMqAhAhCiADKgIMIQQgAyoCCCEIIAMqAgQhCSADKgIAIQULIAEgBDgCDCABIAg4AgggASAJOAIEIAEgBTgCACACIAs4AgwgAiAGOAIIIAIgBzgCBCACIAo4AgALC+zLAQYAQYQIC7hVjAQAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAMTFEZWJ1Z0RyYXdlcgAxMmJ0SURlYnVnRHJhdwAAAAD4aAAAcgQAACBpAABkBAAAhAQAAAAAAACEBAAAGAAAABkAAAAaAAAABAAAAAUAAAAGAAAABwAAAAgAAAAaAAAAGgAAABoAAAAaAAAAGgAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAABpaWlpAGlpaWRpaQBpaQBpaWkAaWkAaQAAAAAAXAUAABsAAAAcAAAAHQAAAB4AAAAyMGJ0RGVmYXVsdE1vdGlvblN0YXRlADEzYnRNb3Rpb25TdGF0ZQAA+GgAAEMFAAAgaQAALAUAAFQFAAAAAAAAVAUAAB8AAAAgAAAAGgAAABoAAAAAAAAA+AUAACEAAAAiAAAAIwAAACQAAABOMTZidENvbGxpc2lvbldvcmxkMjRDbG9zZXN0UmF5UmVzdWx0Q2FsbGJhY2tFAE4xNmJ0Q29sbGlzaW9uV29ybGQxN1JheVJlc3VsdENhbGxiYWNrRQAA+GgAAMcFAAAgaQAAmAUAAPAFAAAAAAAA8AUAACUAAAAmAAAAIwAAABoAAAAAAAAAZAYAACcAAAAoAAAAIwAAACkAAABOMTZidENvbGxpc2lvbldvcmxkMjRBbGxIaXRzUmF5UmVzdWx0Q2FsbGJhY2tFAAAgaQAANAYAAPAFAAAAAAAA3AYAACoAAAArAAAALAAAAC0AAAAyOUNvbmNyZXRlQ29udGFjdFJlc3VsdENhbGxiYWNrAE4xNmJ0Q29sbGlzaW9uV29ybGQyMUNvbnRhY3RSZXN1bHRDYWxsYmFja0UA+GgAAKgGAAAgaQAAiAYAANQGAAAAAAAA1AYAAC4AAAAvAAAALAAAABoAAABpaWlpaWlpaQAAAAAAAAAAjAcAADAAAAAxAAAAMgAAADMAAABOMTZidENvbGxpc2lvbldvcmxkMjdDbG9zZXN0Q29udmV4UmVzdWx0Q2FsbGJhY2tFAE4xNmJ0Q29sbGlzaW9uV29ybGQyMENvbnZleFJlc3VsdENhbGxiYWNrRQAAAAD4aAAAVgcAACBpAAAkBwAAhAcAAAAAAACEBwAANAAAADUAAAAyAAAAGgAAAAAAAABsCAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAAAxN2J0VHJpYW5nbGVTaGFwZUV4ADE1YnRUcmlhbmdsZVNoYXBlAAAAIGkAAEwIAAC8PgAAIGkAADgIAABgCAAAAAAAAGAIAABWAAAAVwAAAFgAAAA5AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAAQAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAEoAAABLAAAATAAAAE0AAABOAAAATwAAAFAAAABRAAAAUgAAAFMAAABUAAAAVQAAAEVtcHR5AHByZWRpY3RVbmNvbnN0cmFpbnRNb3Rpb25Tb2Z0Qm9keQBCb3gAQ29udmV4AHJheVRlc3QAcHJlZGljdGl2ZSBjb252ZXhTd2VlcFRlc3QAaXNsYW5kVW5pb25GaW5kQW5kUXVpY2tTb3J0AEdJbXBhY3RNZXNoU2hhcGVQYXJ0AFJvb3QAaW50AGZsb2F0AGJ0UG9zaXRpb25BbmRSYWRpdXMAc29sdmVTb2Z0Q29uc3RyYWludHMAc29sdmVDb25zdHJhaW50cwBjcmVhdGVQcmVkaWN0aXZlQ29udGFjdHMAZGlzcGF0Y2hBbGxDb2xsaXNpb25QYWlycwBjYWxjdWxhdGVPdmVybGFwcGluZ1BhaXJzAEFwcGx5Q2x1c3RlcnMAVXBkYXRlQ2x1c3RlcnMAdXBkYXRlQWN0aW9ucwBzb2x2ZUdyb3VwQ2FjaGVGcmllbmRseUl0ZXJhdGlvbnMAaW50ZWdyYXRlVHJhbnNmb3JtcwBzeW5jaHJvbml6ZU1vdGlvblN0YXRlcwBTb2Z0Qm9keSBhcHBseUZvcmNlcwBwcm9jZXNzSXNsYW5kcwBjYWxjdWxhdGVTaW11bGF0aW9uSXNsYW5kcwByZWxlYXNlIHByZWRpY3RpdmUgY29udGFjdCBtYW5pZm9sZHMAdXBkYXRlQWFiYnMAc29sdmVHcm91cENhY2hlRnJpZW5kbHlTZXR1cABzb2x2ZUdyb3VwAGFwcGx5IHNwZWN1bGF0aXZlIGNvbnRhY3QgcmVzdGl0dXRpb24AcHJlZGljdFVuY29uc3RyYWludE1vdGlvbgBwZXJmb3JtRGlzY3JldGVDb2xsaXNpb25EZXRlY3Rpb24AT3ZlcmZsb3cgaW4gQUFCQiwgb2JqZWN0IHJlbW92ZWQgZnJvbSBzaW11bGF0aW9uAHN0ZXBTaW11bGF0aW9uAGludGVybmFsU2luZ2xlU3RlcFNpbXVsYXRpb24AQ29udmV4VHJpbWVzaABHSW1wYWN0TWVzaABDQ0QgbW90aW9uIGNsYW1waW5nAHVwZGF0ZUFjdGl2YXRpb25TdGF0ZQBNdWx0aVNwaGVyZQBDYXBzdWxlU2hhcGUAQ29uZQBUcmlhbmdsZQBHSW1wYWN0Q29tcG91bmQAY29udmV4U3dlZXBDb21wb3VuZABkZWJ1Z0RyYXdXb3JsZABidEludEluZGV4RGF0YQBidE1lc2hQYXJ0RGF0YQBidFNvZnRCb2R5Sm9pbnREYXRhAGJ0Q29uZVR3aXN0Q29uc3RyYWludERhdGEAYnRTbGlkZXJDb25zdHJhaW50RGF0YQBidEdlbmVyaWM2RG9mU3ByaW5nQ29uc3RyYWludERhdGEAYnRHZW5lcmljNkRvZkNvbnN0cmFpbnREYXRhAGJ0U2hvcnRJbnRJbmRleFRyaXBsZXREYXRhAGJ0Q2hhckluZGV4VHJpcGxldERhdGEAYnRTb2Z0Qm9keUZsb2F0RGF0YQBidFJpZ2lkQm9keUZsb2F0RGF0YQBidFBvaW50MlBvaW50Q29uc3RyYWludEZsb2F0RGF0YQBidEhpbmdlQ29uc3RyYWludEZsb2F0RGF0YQBidFR5cGVkQ29uc3RyYWludEZsb2F0RGF0YQBidENvbGxpc2lvbk9iamVjdEZsb2F0RGF0YQBidFF1YW50aXplZEJ2aEZsb2F0RGF0YQBidER5bmFtaWNzV29ybGRGbG9hdERhdGEAYnRWZWN0b3IzRmxvYXREYXRhAFNvZnRSaWdpZEFuY2hvckRhdGEAU29mdEJvZHlDbHVzdGVyRGF0YQBidEJ2aFN1YnRyZWVJbmZvRGF0YQBTb2Z0Qm9keU1hdGVyaWFsRGF0YQBTb2Z0Qm9keUxpbmtEYXRhAFNvZnRCb2R5UG9zZURhdGEAYnRDeWxpbmRlclNoYXBlRGF0YQBidENvbGxpc2lvblNoYXBlRGF0YQBidENvbnZleEh1bGxTaGFwZURhdGEAYnRDb252ZXhJbnRlcm5hbFNoYXBlRGF0YQBidEdJbXBhY3RNZXNoU2hhcGVEYXRhAGJ0VHJpYW5nbGVNZXNoU2hhcGVEYXRhAGJ0TXVsdGlTcGhlcmVTaGFwZURhdGEAYnRDb25lU2hhcGVEYXRhAGJ0U3RhdGljUGxhbmVTaGFwZURhdGEAYnRDYXBzdWxlU2hhcGVEYXRhAGJ0Q29tcG91bmRTaGFwZURhdGEAYnRWZWN0b3IzRG91YmxlRGF0YQBTb2Z0Qm9keU5vZGVEYXRhAGJ0UXVhbnRpemVkQnZoTm9kZURhdGEAYnRPcHRpbWl6ZWRCdmhOb2RlRGF0YQBidFN0cmlkaW5nTWVzaEludGVyZmFjZURhdGEAU29mdEJvZHlGYWNlRGF0YQBidENvbXBvdW5kU2hhcGVDaGlsZERhdGEAU29mdEJvZHlUZXRyYURhdGEAQ3lsaW5kZXJaAENvbmVaAENhcHN1bGVaAEN5bGluZGVyWQBDeWxpbmRlclgAQ29uZVgAQ2Fwc3VsZVgAU09GVENMVVNURVIAQlZIVFJJQU5HTEVNRVNIAFNQSEVSRQBTVEFUSUNQTEFORQBIRUlHSFRGSUVMRABidEJVX1NpbXBsZXgxdG80AFB1cmUgdmlydHVhbCBmdW5jdGlvbiBjYWxsZWQhAElmIHlvdSBjYW4gcmVwcm9kdWNlIHRoaXMsIHBsZWFzZSBlbWFpbCBidWdzQGNvbnRpbnVvdXNwaHlzaWNzLmNvbQoAVGhhbmtzLgoAUGxlYXNlIGluY2x1ZGUgYWJvdmUgaW5mb3JtYXRpb24sIHlvdXIgUGxhdGZvcm0sIHZlcnNpb24gb2YgT1MuCgAAAAAAAAAAIBIAAFkAAABaAAAAWwAAADkAAAA6AAAAOwAAAFwAAAA9AAAAXQAAAF4AAABAAAAAQQAAAEIAAABDAAAARAAAAEUAAABGAAAAXwAAAEgAAABgAAAASgAAAGEAAABiAAAATQAAAGMAAABkAAAAZQAAAGYAAABnAAAAaAAAAGkAAABqAAAAMjBidFRldHJhaGVkcm9uU2hhcGVFeAAAIGkAAAgSAACIQAAAAAAAAOQSAABrAAAAbAAAAG0AAAA5AAAAOgAAADsAAABuAAAAbwAAABoAAAAaAAAAQAAAAHAAAABxAAAAcgAAAHMAAABFAAAAdAAAAHUAAAB2AAAAdwAAABoAAAAaAAAAGgAAABoAAAAaAAAAGgAAABoAAAAaAAAAeAAAAHkAAAB6AAAAGgAAABoAAAAaAAAAGgAAAHsAAAB8AAAAMjNidEdJbXBhY3RTaGFwZUludGVyZmFjZQAAACBpAADIEgAAZDQAAAAAAABoEwAAfQAAAH4AAAB/AAAAgAAAAIEAAACCAAAATjIyYnRHSW1wYWN0Q29tcG91bmRTaGFwZTI0Q29tcG91bmRQcmltaXRpdmVNYW5h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AQEAAAIBAAADAQAABAEAAAUBAAAGAQAABwEAAAgBAAAJAQAACgEAADE2YnRDb2xsaXNpb25Xb3JsZAAA+GgAAHAaAAAAAAAAyBoAAAsBAAAMAQAADQEAAA4BAAAPAQAATjEyYnRDb252ZXhDYXN0MTBDYXN0UmVzdWx0RQAAAAD4aAAAqBoAAAAAAAB8GwAAEAEAABEBAAASAQAAEwEAAFpOMTZidENvbGxpc2lvbldvcmxkMjFyYXlUZXN0U2luZ2xlSW50ZXJuYWxFUksxMWJ0VHJhbnNmb3JtUzJfUEsyNGJ0Q29sbGlzaW9uT2JqZWN0V3JhcHBlclJOU18xN1JheVJlc3VsdENhbGxiYWNrRUUyOUJyaWRnZVRyaWFuZ2xlUmF5Y2FzdENhbGxiYWNrAAAgaQAA6BoAAPxJAAAAAAAAOBwAABABAAAUAQAAEgEAABUBAABaTjE2YnRDb2xsaXNpb25Xb3JsZDIxcmF5VGVzdFNpbmdsZUludGVybmFsRVJLMTFidFRyYW5zZm9ybVMyX1BLMjRidENvbGxpc2lvbk9iamVjdFdyYXBwZXJSTlNfMTdSYXlSZXN1bHRDYWxsYmFja0VFMjlCcmlkZ2VUcmlhbmdsZVJheWNhc3RDYWxsYmFja18wAAAAACBpAACgGwAA/EkAAAAAAADoHAAAwgAAABYBAADKAAAAFwEAAMYAAADHAAAAyAAAAFpOMTZidENvbGxpc2lvbldvcmxkMjFyYXlUZXN0U2luZ2xlSW50ZXJuYWxFUksxMWJ0VHJhbnNmb3JtUzJfUEsyNGJ0Q29sbGlzaW9uT2JqZWN0V3JhcHBlclJOU18xN1JheVJlc3VsdENhbGxiYWNrRUU5UmF5VGVzdGVyAAAAIGkAAGgcAADIFgAAAAAAAJQdAAAlAAAAGAEAABkBAAAaAQAAWk4xNmJ0Q29sbGlzaW9uV29ybGQyMXJheVRlc3RTaW5nbGVJbnRlcm5hbEVSSzExYnRUcmFuc2Zvcm1TMl9QSzI0YnRDb2xsaXNpb25PYmplY3RXcmFwcGVyUk5TXzE3UmF5UmVzdWx0Q2FsbGJhY2tFRTE1TG9jYWxJbmZvQWRkZXIyAAAAACBpAAAMHQAA8AUAAAAAAABoHgAAEAEAABsBAAAcAQAAHQEAAFpOMTZidENvbGxpc2lvbldvcmxkMjVvYmplY3RRdWVyeVNpbmdsZUludGVybmFsRVBLMTNidENvbnZleFNoYXBlUksxMWJ0VHJhbnNmb3JtUzVfUEsyNGJ0Q29sbGlzaW9uT2JqZWN0V3JhcHBlclJOU18yMENvbnZleFJlc3VsdENhbGxiYWNrRWZFMzJCcmlkZ2VUcmlhbmdsZUNvbnZleGNhc3RDYWxsYmFjawAAIGkAALgdAAAoSgAAAAAAAEAfAAAQAQAAHgEAABwBAAAfAQAAWk4xNmJ0Q29sbGlzaW9uV29ybGQyNW9iamVjdFF1ZXJ5U2luZ2xlSW50ZXJuYWxFUEsxM2J0Q29udmV4U2hhcGVSSzExYnRUcmFuc2Zvcm1TNV9QSzI0YnRDb2xsaXNpb25PYmplY3RXcmFwcGVyUk5TXzIwQ29udmV4UmVzdWx0Q2FsbGJhY2tFZkUzMkJyaWRnZVRyaWFuZ2xlQ29udmV4Y2FzdENhbGxiYWNrXzAAAAAAIGkAAIweAAAoSgAAAAAAAAQgAAA0AAAAIAEAACEBAAAiAQAAWk4xNmJ0Q29sbGlzaW9uV29ybGQyNW9iamVjdFF1ZXJ5U2luZ2xlSW50ZXJuYWxFUEsxM2J0Q29udmV4U2hhcGVSSzExYnRUcmFuc2Zvcm1TNV9QSzI0YnRDb2xsaXNpb25PYmplY3RXcmFwcGVyUk5TXzIwQ29udmV4UmVzdWx0Q2FsbGJhY2tFZkUxNExvY2FsSW5mb0FkZGVyAAAAACBpAABkHwAAhAcAAAAAAACEIAAAIwEAACQBAAAlAQAAMTlidFNpbmdsZVJheUNhbGxiYWNrADIzYnRCcm9hZHBoYXNlUmF5Q2FsbGJhY2sAMjRidEJyb2FkcGhhc2VBYWJiQ2FsbGJhY2sAAPhoAABUIAAAIGkAADogAABwIAAAIGkAACQgAAB4IAAAAAAAALwgAAAjAQAAJgEAACcBAAAyMWJ0U2luZ2xlU3dlZXBDYWxsYmFjawAgaQAApCAAAHggAAAAAAAA+CAAACMBAAAoAQAAKQEAADIzYnRTaW5nbGVDb250YWN0Q2FsbGJhY2sAAAAgaQAA3CAAAHAgAAAAAAAAPCEAACoBAAArAQAALAEAAC0BAAAuAQAAMjNidEJyaWRnZWRNYW5pZm9sZFJlc3VsdAAAACBpAAAgIQAALC0AAAAAAACIIQAALwEAADABAAAxAQAAMgEAAPz///+IIQAAMwEAADQBAAA1AQAAMTdEZWJ1Z0RyYXdjYWxsYmFjawB8aQAAdCEAAAAAAAACAAAAuEAAAAIAAADkQAAAAgQAAAAAAAAYIgAANgEAADcBAAAaAAAAGgAAABoAAAAAAAAAICIAADgBAAA5AQAAGgAAABoAAAAaAAAAMzBidEFjdGl2YXRpbmdDb2xsaXNpb25BbGdvcml0aG0AMjBidENvbGxpc2lvbkFsZ29yaXRobQD4aAAAASIAACBpAADgIQAAGCIAAAAAAACEIgAAOgEAADsBAAA8AQAAAAAAAKwiAAA9AQAAPgEAAD8BAABAAQAAQQEAAE4yM2J0Q29udmV4Q29udmV4QWxnb3JpdGhtMTBDcmVhdGVGdW5jRQAgaQAAXCIAAPAoAAAyM2J0Q29udmV4Q29udmV4QWxnb3JpdGhtAAAAIGkAAJAiAAAgIgAAAAAAAJQjAAAqAQAAQgEAAEMBAABEAQAARQEAAFpOMjNidENvbnZleENvbnZleEFsZ29yaXRobTE2cHJvY2Vzc0NvbGxpc2lvbkVQSzI0YnRDb2xsaXNpb25PYmplY3RXcmFwcGVyUzJfUksxNmJ0RGlzcGF0Y2hlckluZm9QMTZidE1hbmlmb2xkUmVzdWx0RTEzYnREdW1teVJlc3VsdABOMzZidERpc2NyZXRlQ29sbGlzaW9uRGV0ZWN0b3JJbnRlcmZhY2U2UmVzdWx0RQAAAAD4aAAAWSMAACBpAADUIgAAjCMAAAAAAABMJAAAKgEAAEYBAABHAQAASAEAAEkBAABaTjIzYnRDb252ZXhDb252ZXhBbGdvcml0aG0xNnByb2Nlc3NDb2xsaXNpb25FUEsyNGJ0Q29sbGlzaW9uT2JqZWN0V3JhcHBlclMyX1JLMTZidERpc3BhdGNoZXJJbmZvUDE2YnRNYW5pZm9sZFJlc3VsdEUyMWJ0V2l0aG91dE1hcmdpblJlc3VsdAAAAAAgaQAAvCMAAIwjAAAAAAAAkCQAACoBAABKAQAALAEAAC0BAABLAQAAMjRidFBlcnR1cmJlZENvbnRhY3RSZXN1bHQAACBpAAB0JAAALC0AAAAAAADwJAAATAEAAE0BAABOAQAATwEAAFABAAAAAAAAGCUAAFEBAABSAQAAUwEAADMzYnRDb252ZXhDb25jYXZlQ29sbGlzaW9uQWxnb3JpdGhtACBpAADMJAAAICIAADI0YnRDb252ZXhUcmlhbmdsZUNhbGxiYWNrAAAgaQAA/CQAALhAAAAAAAAA2CUAABABAABUAQAAVQEAAFpOMzNidENvbnZleENvbmNhdmVDb2xsaXNpb25BbGdvcml0aG0yMWNhbGN1bGF0ZVRpbWVPZkltcGFjdEVQMTdidENvbGxpc2lvbk9iamVjdFMxX1JLMTZidERpc3BhdGNoZXJJbmZvUDE2YnRNYW5pZm9sZFJlc3VsdEUzMUxvY2FsVHJpYW5nbGVTcGhlcmVDYXN0Q2FsbGJhY2sAAAAgaQAAOCUAALhAAAAAAAAAICYAAFYBAABXAQAAWAEAAFkBAABaAQAAMjhidENvbXBvdW5kQ29sbGlzaW9uQWxnb3JpdGhtAAAgaQAAACYAACAiAAAAAAAAbCYAAMIAAABbAQAAygAAAFwBAADGAAAAxwAAAMgAAAAyMmJ0Q29tcG91bmRMZWFmQ2FsbGJhY2sAAAAAIGkAAFAmAADIFgAAAAAAALwmAABdAQAAXgEAAF8BAABgAQAAYQEAADM2YnRDb21wb3VuZENvbXBvdW5kQ29sbGlzaW9uQWxnb3JpdGhtAAAgaQAAlCYAACAiAAAAAAAAECcAAMIAAABiAQAAYwEAAGQBAADGAAAAxwAAAMgAAAAzMGJ0Q29tcG91bmRDb21wb3VuZExlYWZDYWxsYmFjawAAAAAgaQAA7CYAAMgWAAAAAAAAdCcAAGUBAABmAQAAZwEAADE2YnRCb3hCb3hEZXRlY3RvcgAzNmJ0RGlzY3JldGVDb2xsaXNpb25EZXRlY3RvckludGVyZmFjZQAAAPhoAABDJwAAIGkAADAnAABsJwAAAAAAALwnAABoAQAAaQEAAGoBAABrAQAAbAEAADI2YnRCb3hCb3hDb2xsaXNpb25BbGdvcml0aG0AAAAAIGkAAJwnAAAgIgAAAAAAAAgoAABtAQAAbgEAAG8BAABwAQAAcQEAADMxYnRDb252ZXhQbGFuZUNvbGxpc2lvbkFsZ29yaXRobQAAACBpAADkJwAAGCIAAAAAAAB8KAAAcgEAAHMBAAB0AQAAdQEAAHYBAAB3AQAAMzFidERlZmF1bHRDb2xsaXNpb25Db25maWd1cmF0aW9uADI0YnRDb2xsaXNpb25Db25maWd1cmF0aW9uAAAAAPhoAABWKAAAIGkAADQoAAB0KAAAAAAAAPgoAAB4AQAAeQEAAHoBAABOMzNidENvbnZleENvbmNhdmVDb2xsaXNpb25BbGdvcml0aG0xMENyZWF0ZUZ1bmNFADMwYnRDb2xsaXNpb25BbGdvcml0aG1DcmVhdGVGdW5jAAD4aAAAzigAACBpAACcKAAA8CgAAAAAAABUKQAAeAEAAHsBAAB8AQAATjMzYnRDb252ZXhDb25jYXZlQ29sbGlzaW9uQWxnb3JpdGhtMTdTd2FwcGVkQ3JlYXRlRnVuY0UAAAAAIGkAABgpAADwKAAAAAAAAKQpAAB4AQAAfQEAAH4BAABOMjhidENvbXBvdW5kQ29sbGlzaW9uQWxnb3JpdGhtMTBDcmVhdGVGdW5jRQAAAAAgaQAAdCkAAPAoAAAAAAAA/CkAAHgBAAB/AQAAgAEAAE4zNmJ0Q29tcG91bmRDb21wb3VuZENvbGxpc2lvbkFsZ29yaXRobTEwQ3JlYXRlRnVuY0UAAAAAIGkAAMQpAADwKAAAAAAAAFAqAAB4AQAAgQEAAIIBAABOMjhidENvbXBvdW5kQ29sbGlzaW9uQWxnb3JpdGhtMTdTd2FwcGVkQ3JlYXRlRnVuY0UAIGkAABwqAADwKAAAAAAAAJQqAAB4AQAAgwEAAIQBAABOMTZidEVtcHR5QWxnb3JpdGhtMTBDcmVhdGVGdW5jRQAAAAAgaQAAcCoAAPAoAAAAAAAA6CoAAHgBAACFAQAAhgEAAE4zMmJ0U3BoZXJlU3BoZXJlQ29sbGlzaW9uQWxnb3JpdGhtMTBDcmVhdGVGdW5jRQAAAAAgaQAAtCoAAPAoAAAAAAAAPCsAAHgBAACHAQAAiAEAAE4zNGJ0U3BoZXJlVHJpYW5nbGVDb2xsaXNpb25BbGdvcml0aG0xMENyZWF0ZUZ1bmNFAAAgaQAACCsAAPAoAAAAAAAAiCsAAHgBAACJAQAAigEAAE4yNmJ0Qm94Qm94Q29sbGlzaW9uQWxnb3JpdGhtMTBDcmVhdGVGdW5jRQAAIGkAAFwrAADwKAAAAAAAANgrAAB4AQAAiwEAAIwBAABOMzFidENvbnZleFBsYW5lQ29sbGlzaW9uQWxnb3JpdGhtMTBDcmVhdGVGdW5jRQAgaQAA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RGVwdGhTb2x2ZXIAMzBidENvbnZleFBlbmV0cmF0aW9uRGVwdGhTb2x2ZXIAAAD4aAAALUgAACBpAAAMSAAAUEgAAAAAAACMSAAAZQEAAAMDAAAEAwAAMTdidEdqa1BhaXJEZXRlY3RvcgAgaQAAeEgAAGwnAAAAAAAA0EgAAAADAAAFAwAABgMAADMzYnRNaW5rb3dza2lQZW5ldHJhdGlvbkRlcHRoU29sdmVyACBpAACsSAAAUEgAAAAAAACkSQAAKgEAAAcDAAAIAwAACQMAAAoDAABaTjMzYnRNaW5rb3dza2lQZW5ldHJhdGlvbkRlcHRoU29sdmVyMTJjYWxjUGVuRGVwdGhFUjIyYnRWb3Jvbm9pU2ltcGxleFNvbHZlclBLMTNidENvbnZleFNoYXBlUzRfUksxMWJ0VHJhbnNmb3JtUzdfUjlidFZlY3RvcjNTOV9TOV9QMTJidElEZWJ1Z0RyYXdFMjBidEludGVybWVkaWF0ZVJlc3VsdAAAIGkAAPhIAACMIwAAAAAAAPxJAAAQAQAACwMAABIBAAAaAAAAAAAAAChKAAAQAQAADAMAABwBAAAaAAAAMjVidFRyaWFuZ2xlUmF5Y2FzdENhbGxiYWNrACBpAADgSQAAuEAAADI4YnRUcmlhbmdsZUNvbnZleGNhc3RDYWxsYmFjawAAIGkAAAhKAAC4QAAAAAAAAGRKAAD1AgAADQMAAA4DAAAyMmJ0U3Vic2ltcGxleENvbnZleENhc3QAAAAAIGkAAEhKAACkRwAAAAAAABxLAAAPAwAAEAMAABEDAAASAwAAEwMAABQDAAAVAwAAFgMAABcDAAAYAwAAGQMAABoDAAAbAwAAHAMAADMwYnRLaW5lbWF0aWNDaGFyYWN0ZXJDb250cm9sbGVyADMwYnRDaGFyYWN0ZXJDb250cm9sbGVySW50ZXJmYWNlADE3YnRBY3Rpb25JbnRlcmZhY2UAAAD4aAAA8koAACBpAADRSgAACEsAACBpAACwSgAAEEsAAAAAAABwSwAANAAAAB0DAAAyAAAAHgMAADQzYnRLaW5lbWF0aWNDbG9zZXN0Tm90TWVDb252ZXhSZXN1bHRDYWxsYmFjawAAACBpAABASwAAjAcAAAAAAADMSwAAHwMAACADAAAhAwAAIgMAACMDAAAkAwAAJQMAACYDAAAn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`; + +// if (typeof exports === 'object' && typeof module === 'object') +// module.exports = Ammo; +// else if (typeof define === 'function' && define['amd']) +// define([], function() { return Ammo; }); +// else if (typeof exports === 'object') +// exports["Ammo"] = Ammo; +export default Ammo diff --git a/packages/ammo/package.json b/packages/ammo/package.json new file mode 100644 index 00000000..634e3838 --- /dev/null +++ b/packages/ammo/package.json @@ -0,0 +1,17 @@ +{ + "name": "@orillusion/ammo", + "version": "0.1.1", + "author": "Orillusion", + "description": "Orillusion WebGPU Engine", + "main": "ammo.js", + "types": "ammo.d.ts", + "files": [ + "ammo.js", + "ammo.d.ts" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/Orillusion/orillusion.git" + } +} diff --git a/packages/draco/draco_decoder_gltf.js b/packages/draco/draco_decoder_gltf.js new file mode 100644 index 00000000..d3be93ac --- /dev/null +++ b/packages/draco/draco_decoder_gltf.js @@ -0,0 +1,36 @@ + +export var DracoDecoderModule = (() => { + var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; + if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename; + return ( +function(DracoDecoderModule) { + DracoDecoderModule = DracoDecoderModule || {}; + +var Module=typeof DracoDecoderModule!="undefined"?DracoDecoderModule:{};var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise(function(resolve,reject){readyPromiseResolve=resolve;readyPromiseReject=reject});var isRuntimeInitialized=false;var isModuleParsed=false;Module["onRuntimeInitialized"]=function(){isRuntimeInitialized=true;if(isModuleParsed){if(typeof Module["onModuleLoaded"]==="function"){Module["onModuleLoaded"](Module)}}};Module["onModuleParsed"]=function(){isModuleParsed=true;if(isRuntimeInitialized){if(typeof Module["onModuleLoaded"]==="function"){Module["onModuleLoaded"](Module)}}};function isVersionSupported(versionString){if(typeof versionString!=="string")return false;const version=versionString.split(".");if(version.length<2||version.length>3)return false;if(version[0]==1&&version[1]>=0&&version[1]<=5)return true;if(version[0]!=0||version[1]>10)return false;return true}Module["isVersionSupported"]=isVersionSupported;var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;function logExceptionOnExit(e){if(e instanceof ExitStatus)return;let toLog=e;err("exiting due to exception: "+toLog)}var fs;var nodePath;var requireNodeFS;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require("path").dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}requireNodeFS=()=>{if(!nodePath){fs=require("fs");nodePath=require("path")}};read_=function shell_read(filename,binary){var ret=tryParseAsDataURI(filename);if(ret){return binary?ret:ret.toString()}requireNodeFS();filename=nodePath["normalize"](filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror)=>{var ret=tryParseAsDataURI(filename);if(ret){onload(ret)}requireNodeFS();filename=nodePath["normalize"](filename);fs.readFile(filename,function(err,data){if(err)onerror(err);else onload(data.buffer)})};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);quit_=(status,toThrow)=>{if(keepRuntimeAlive()){process["exitCode"]=status;throw toThrow}logExceptionOnExit(toThrow);process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=url=>{try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText}catch(err){var data=tryParseAsDataURI(url);if(data){return intArrayToString(data)}throw err}};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}catch(err){var data=tryParseAsDataURI(url);if(data){return data}throw err}}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}var data=tryParseAsDataURI(url);if(data){onload(data.buffer);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=title=>document.title=title}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime=Module["noExitRuntime"]||true;var WebAssembly={Memory:function(opts){this.buffer=new ArrayBuffer(opts["initial"]*65536)},Module:function(binary){},Instance:function(module,info){this.exports=( +// EMSCRIPTEN_START_ASM +function instantiate(la){function c(d){d.set=function(a,b){this[a]=b};d.get=function(a){return this[a]};return d}var e;var f=new Uint8Array(123);for(var a=25;a>=0;--a){f[48+a]=52+a;f[65+a]=a;f[97+a]=26+a}f[43]=62;f[47]=63;function l(m,n,o){var g,h,a=0,i=n,j=o.length,k=n+(j*3>>2)-(o[j-2]=="=")-(o[j-1]=="=");for(;a>4;if(i>2;if(i>2];h=D[c+12>>2];f=D[c+16>>2];a:{if((e|0)>=(h|0)&f>>>0>=G[c+8>>2]|(e|0)>(h|0)){break a}h=E[f+D[c>>2]|0];f=f+1|0;e=f?e:e+1|0;D[c+16>>2]=f;D[c+20>>2]=e;b:{switch(h|0){case 0:m=a;e=b;h=d;a=0;d=0;j=$+-64|0;$=j;D[j+56>>2]=0;D[j+48>>2]=0;D[j+52>>2]=0;D[j+40>>2]=0;D[j+44>>2]=0;D[j+32>>2]=0;D[j+36>>2]=0;D[j+24>>2]=0;D[j+28>>2]=0;D[j+16>>2]=0;D[j+20>>2]=0;D[j+8>>2]=0;D[j+12>>2]=0;c:{if(!Kd(j+8|0,c)){break c}if(!Jd(j+8|0,c)|(D[j+20>>2]?0:m)){break c}ec(c,0,0);if(m){n=e<<2;r=D[j+36>>2];s=D[j+48>>2];t=D[j+24>>2];while(1){l=D[j+56>>2];d:{if(l>>>0>16383){break d}a=D[j+52>>2];while(1){if((a|0)<=0){break d}a=a-1|0;D[j+52>>2]=a;l=E[a+s|0]|l<<8;D[j+56>>2]=l;if(l>>>0<16384){continue}break}}a=l&4095;i=D[(a<<2)+t>>2];b=(i<<3)+r|0;D[j+56>>2]=(J(D[b>>2],l>>>12|0)+a|0)-D[b+4>>2];e:{if((e|0)<=0){break e}a=0;if(!E[c+36|0]|i>>>0>32){break c}if(!i){qa(h+(d<<2)|0,0,n);d=d+e|0;break e}u=i&-2;x=i&1;q=d+e|0;b=D[c+32>>2];g=D[c+28>>2];k=D[c+24>>2];while(1){l=0;a=b;f=0;p=0;if((i|0)!=1){while(1){o=k+(a>>>3|0)|0;f:{if(o>>>0>=g>>>0){o=0;break f}o=E[o|0];b=a+1|0;D[c+32>>2]=b;o=o>>>(a&7)&1;a=b}o=o<>>3|0)|0;if(v>>>0>>0){f=E[v|0];b=a+1|0;D[c+32>>2]=b;f=f>>>(a&7)&1;a=b}v=l|1;l=l+2|0;f=o|f<>>3|0)|0;if(o>>>0>>0){o=E[o|0];b=a+1|0;D[c+32>>2]=b;a=o>>>(a&7)&1}else{a=0}f=a<>2]=f;d=d+1|0;if((q|0)!=(d|0)){continue}break}d=q}w=e+w|0;if(m>>>0>w>>>0){continue}break}}B[c+36|0]=0;l=D[c+20>>2];a=0;b=D[c+32>>2]+7|0;a=b>>>0<7?1:a;e=a<<29|b>>>3;b=e+D[c+16>>2]|0;a=(a>>>3|0)+l|0;D[c+16>>2]=b;D[c+20>>2]=b>>>0>>0?a+1|0:a;a=1}b=D[j+36>>2];if(b){D[j+40>>2]=b;ma(b)}b=D[j+24>>2];if(b){D[j+28>>2]=b;ma(b)}b=D[j+8>>2];if(b){D[j+12>>2]=b;ma(b)}$=j- -64|0;return a;case 1:break b;default:break a}}b=0;e=D[c+20>>2];h=D[c+12>>2];f=D[c+16>>2];g:{if((e|0)>=(h|0)&f>>>0>=G[c+8>>2]|(e|0)>(h|0)){break g}h=E[f+D[c>>2]|0];f=f+1|0;e=f?e:e+1|0;D[c+16>>2]=f;D[c+20>>2]=e;h:{switch(h-1|0){case 8:h=a;q=d;e=$+-64|0;$=e;D[e+56>>2]=0;D[e+48>>2]=0;D[e+52>>2]=0;D[e+40>>2]=0;D[e+44>>2]=0;D[e+32>>2]=0;D[e+36>>2]=0;D[e+24>>2]=0;D[e+28>>2]=0;D[e+16>>2]=0;D[e+20>>2]=0;D[e+8>>2]=0;D[e+12>>2]=0;j=e+8|0;i:{j:{if(!F[c+38>>1]){break j}if(!Wa(1,j+12|0,c)){break j}a=D[c+8>>2];b=D[c+16>>2];d=a-b|0;i=D[j+12>>2];a=D[c+12>>2]-(D[c+20>>2]+(a>>>0>>0)|0)|0;if(d>>>0>>6>>>0&(a|0)<=0|(a|0)<0){break j}b=D[j>>2];a=D[j+4>>2]-b>>2;k:{if(a>>>0>>0){ra(j,i-a|0);i=D[j+12>>2];break k}if(a>>>0<=i>>>0){break k}D[j+4>>2]=b+(i<<2)}f=1;if(!i){break i}g=D[c+16>>2];d=D[c+20>>2];n=D[j>>2];r=D[c+8>>2];k=D[c+12>>2];b=0;while(1){f=0;if((d|0)>=(k|0)&g>>>0>=r>>>0|(d|0)>(k|0)){break i}s=D[c>>2];o=E[s+g|0];a=d;d=g+1|0;a=d?a:a+1|0;g=d;D[c+16>>2]=d;d=a;D[c+20>>2]=a;a=o>>>2|0;f=0;l:{m:{n:{o:{t=o&3;switch(t|0){case 0:break m;case 3:break o;default:break n}}a=a+b|0;f=0;if(a>>>0>=i>>>0){break i}qa(n+(b<<2)|0,0,(o&252)+4|0);b=a;break l}while(1){if((d|0)>=(k|0)&g>>>0>=r>>>0|(d|0)>(k|0)){break j}i=E[g+s|0];g=g+1|0;d=g?d:d+1|0;D[c+16>>2]=g;D[c+20>>2]=d;a=i<<(f<<3|6)|a;f=f+1|0;if((t|0)!=(f|0)){continue}break}}D[n+(b<<2)>>2]=a}b=b+1|0;i=D[j+12>>2];if(b>>>0>>0){continue}break}a=j+16|0;o=D[j>>2];d=D[j+16>>2];b=D[j+20>>2]-d|0;p:{if(b>>>0<=32767){ra(a,8192-(b>>>2|0)|0);break p}if((b|0)==32768){break p}D[j+20>>2]=d+32768}d=j+28|0;b=D[d>>2];f=D[j+32>>2]-b>>3;q:{if(f>>>0>>0){db(d,i-f|0);b=D[d>>2];break q}if(f>>>0>i>>>0){D[j+32>>2]=(i<<3)+b}if(!i){break j}}j=D[a>>2];g=0;d=0;while(1){f=o+(g<<2)|0;k=D[f>>2];n=(g<<3)+b|0;a=d;D[n+4>>2]=a;D[n>>2]=k;k=D[f>>2];d=k+a|0;if(d>>>0>8192){break j}r:{if(a>>>0>=d>>>0){break r}f=0;n=k&7;if(n){while(1){D[j+(a<<2)>>2]=g;a=a+1|0;f=f+1|0;if((n|0)!=(f|0)){continue}break}}if(k-1>>>0<=6){break r}while(1){f=j+(a<<2)|0;D[f>>2]=g;D[f+28>>2]=g;D[f+24>>2]=g;D[f+20>>2]=g;D[f+16>>2]=g;D[f+12>>2]=g;D[f+8>>2]=g;D[f+4>>2]=g;a=a+8|0;if((d|0)!=(a|0)){continue}break}}g=g+1|0;if((i|0)!=(g|0)){continue}break}m=(d|0)==8192}f=m}s:{if(!f|(D[e+20>>2]?0:h)){break s}d=0;f=$-16|0;$=f;t:{if(!Va(1,f+8|0,c)){break t}a=D[c+8>>2];b=D[c+16>>2];j=a-b|0;i=D[f+12>>2];g=D[c+20>>2];a=D[c+12>>2]-(g+(a>>>0>>0)|0)|0;m=D[f+8>>2];if((i|0)==(a|0)&j>>>0>>0|a>>>0>>0){break t}a=g+i|0;j=b+m|0;a=j>>>0>>0?a+1|0:a;D[c+16>>2]=j;D[c+20>>2]=a;a=m;if((a|0)<=0){break t}b=b+D[c>>2]|0;D[e+48>>2]=b;c=a-1|0;m=c+b|0;j=E[m|0];u:{if(j>>>0<=63){D[e+52>>2]=c;a=E[m|0]&63;break u}v:{switch((j>>>6|0)-1|0){case 0:if(a>>>0<2){break t}D[e+52>>2]=a-2;a=(a+b|0)-2|0;a=E[a+1|0]<<8&16128|E[a|0];break u;case 1:if(a>>>0<3){break t}D[e+52>>2]=a-3;a=(a+b|0)-3|0;a=E[a+1|0]<<8|E[a+2|0]<<16&4128768|E[a|0];break u;default:break v}}D[e+52>>2]=a-4;a=(a+b|0)-4|0;a=E[a+2|0]<<16|E[a+3|0]<<24&1056964608|E[a+1|0]<<8|E[a|0]}D[e+56>>2]=a+32768;d=a>>>0<8355840}$=f+16|0;if(!d){break s}if(!h){l=1;break s}a=D[e+56>>2];b=D[e+36>>2];c=D[e+48>>2];d=D[e+24>>2];while(1){w:{if(a>>>0>32767){break w}l=D[e+52>>2];while(1){if((l|0)<=0){break w}l=l-1|0;D[e+52>>2]=l;a=E[c+l|0]|a<<8;D[e+56>>2]=a;if(a>>>0<32768){continue}break}}l=a&8191;m=D[d+(l<<2)>>2];f=b+(m<<3)|0;a=(J(D[f>>2],a>>>13|0)+l|0)-D[f+4>>2]|0;D[e+56>>2]=a;D[q+(p<<2)>>2]=m;l=1;p=p+1|0;if((h|0)!=(p|0)){continue}break}}a=D[e+36>>2];if(a){D[e+40>>2]=a;ma(a)}a=D[e+24>>2];if(a){D[e+28>>2]=a;ma(a)}a=D[e+8>>2];if(a){D[e+12>>2]=a;ma(a)}$=e- -64|0;b=l;break g;case 9:q=a;j=d;h=$+-64|0;$=h;D[h+56>>2]=0;D[h+48>>2]=0;D[h+52>>2]=0;D[h+40>>2]=0;D[h+44>>2]=0;D[h+32>>2]=0;D[h+36>>2]=0;D[h+24>>2]=0;D[h+28>>2]=0;D[h+16>>2]=0;D[h+20>>2]=0;D[h+8>>2]=0;D[h+12>>2]=0;k=h+8|0;x:{y:{if(!F[c+38>>1]){break y}if(!Wa(1,k+12|0,c)){break y}a=D[c+8>>2];b=D[c+16>>2];d=a-b|0;i=D[k+12>>2];a=D[c+12>>2]-(D[c+20>>2]+(a>>>0>>0)|0)|0;if(d>>>0>>6>>>0&(a|0)<=0|(a|0)<0){break y}b=D[k>>2];a=D[k+4>>2]-b>>2;z:{if(a>>>0>>0){ra(k,i-a|0);i=D[k+12>>2];break z}if(a>>>0<=i>>>0){break z}D[k+4>>2]=b+(i<<2)}e=1;if(!i){break x}g=D[c+16>>2];d=D[c+20>>2];r=D[k>>2];s=D[c+8>>2];o=D[c+12>>2];b=0;while(1){e=0;if((d|0)>=(o|0)&g>>>0>=s>>>0|(d|0)>(o|0)){break x}t=D[c>>2];n=E[t+g|0];e=d;a=g+1|0;e=a?e:e+1|0;g=a;D[c+16>>2]=a;d=e;D[c+20>>2]=e;a=n>>>2|0;f=0;A:{B:{C:{D:{e=n&3;switch(e|0){case 0:break B;case 3:break D;default:break C}}a=a+b|0;e=0;if(a>>>0>=i>>>0){break x}qa(r+(b<<2)|0,0,(n&252)+4|0);b=a;break A}while(1){if((d|0)>=(o|0)&g>>>0>=s>>>0|(d|0)>(o|0)){break y}i=E[g+t|0];g=g+1|0;d=g?d:d+1|0;D[c+16>>2]=g;D[c+20>>2]=d;a=i<<(f<<3|6)|a;f=f+1|0;if((e|0)!=(f|0)){continue}break}}D[r+(b<<2)>>2]=a}b=b+1|0;i=D[k+12>>2];if(b>>>0>>0){continue}break}a=k+16|0;o=D[k>>2];d=D[k+16>>2];b=D[k+20>>2]-d|0;E:{if(b>>>0<=131071){ra(a,32768-(b>>>2|0)|0);break E}if((b|0)==131072){break E}D[k+20>>2]=d+131072}d=k+28|0;b=D[d>>2];e=D[k+32>>2]-b>>3;F:{if(e>>>0>>0){db(d,i-e|0);b=D[d>>2];break F}if(e>>>0>i>>>0){D[k+32>>2]=(i<<3)+b}if(!i){break y}}k=D[a>>2];g=0;d=0;while(1){e=o+(g<<2)|0;f=D[e>>2];n=(g<<3)+b|0;a=d;D[n+4>>2]=a;D[n>>2]=f;e=D[e>>2];d=e+a|0;if(d>>>0>32768){break y}G:{if(a>>>0>=d>>>0){break G}f=0;n=e&7;if(n){while(1){D[k+(a<<2)>>2]=g;a=a+1|0;f=f+1|0;if((n|0)!=(f|0)){continue}break}}if(e-1>>>0<=6){break G}while(1){e=k+(a<<2)|0;D[e>>2]=g;D[e+28>>2]=g;D[e+24>>2]=g;D[e+20>>2]=g;D[e+16>>2]=g;D[e+12>>2]=g;D[e+8>>2]=g;D[e+4>>2]=g;a=a+8|0;if((d|0)!=(a|0)){continue}break}}g=g+1|0;if((i|0)!=(g|0)){continue}break}m=(d|0)==32768}e=m}H:{if(!e|(D[h+20>>2]?0:q)){break H}d=0;m=$-16|0;$=m;I:{if(!Va(1,m+8|0,c)){break I}a=D[c+8>>2];b=D[c+16>>2];e=a-b|0;i=D[m+12>>2];f=i;g=D[c+20>>2];k=D[c+12>>2]-(g+(a>>>0>>0)|0)|0;a=D[m+8>>2];if((f|0)==(k|0)&e>>>0>>0|f>>>0>k>>>0){break I}e=g+i|0;f=a+b|0;e=f>>>0>>0?e+1|0:e;D[c+16>>2]=f;D[c+20>>2]=e;if((a|0)<=0){break I}b=b+D[c>>2]|0;D[h+48>>2]=b;c=a-1|0;e=c+b|0;f=E[e|0];J:{if(f>>>0<=63){D[h+52>>2]=c;a=E[e|0]&63;break J}K:{switch((f>>>6|0)-1|0){case 0:if(a>>>0<2){break I}D[h+52>>2]=a-2;a=(a+b|0)-2|0;a=E[a+1|0]<<8&16128|E[a|0];break J;case 1:if(a>>>0<3){break I}D[h+52>>2]=a-3;a=(a+b|0)-3|0;a=E[a+1|0]<<8|E[a+2|0]<<16&4128768|E[a|0];break J;default:break K}}D[h+52>>2]=a-4;a=(a+b|0)-4|0;a=E[a+2|0]<<16|E[a+3|0]<<24&1056964608|E[a+1|0]<<8|E[a|0]}D[h+56>>2]=a+131072;d=a>>>0<33423360}$=m+16|0;if(!d){break H}if(!q){l=1;break H}a=D[h+56>>2];b=D[h+36>>2];c=D[h+48>>2];d=D[h+24>>2];while(1){L:{if(a>>>0>131071){break L}l=D[h+52>>2];while(1){if((l|0)<=0){break L}l=l-1|0;D[h+52>>2]=l;a=E[c+l|0]|a<<8;D[h+56>>2]=a;if(a>>>0<131072){continue}break}}l=a&32767;e=D[d+(l<<2)>>2];m=b+(e<<3)|0;a=(J(D[m>>2],a>>>15|0)+l|0)-D[m+4>>2]|0;D[h+56>>2]=a;D[j+(p<<2)>>2]=e;l=1;p=p+1|0;if((q|0)!=(p|0)){continue}break}}a=D[h+36>>2];if(a){D[h+40>>2]=a;ma(a)}a=D[h+24>>2];if(a){D[h+28>>2]=a;ma(a)}a=D[h+8>>2];if(a){D[h+12>>2]=a;ma(a)}$=h- -64|0;b=l;break g;case 10:q=a;j=d;h=$+-64|0;$=h;D[h+56>>2]=0;D[h+48>>2]=0;D[h+52>>2]=0;D[h+40>>2]=0;D[h+44>>2]=0;D[h+32>>2]=0;D[h+36>>2]=0;D[h+24>>2]=0;D[h+28>>2]=0;D[h+16>>2]=0;D[h+20>>2]=0;D[h+8>>2]=0;D[h+12>>2]=0;k=h+8|0;M:{N:{if(!F[c+38>>1]){break N}if(!Wa(1,k+12|0,c)){break N}a=D[c+8>>2];b=D[c+16>>2];d=a-b|0;i=D[k+12>>2];a=D[c+12>>2]-(D[c+20>>2]+(a>>>0>>0)|0)|0;if(d>>>0>>6>>>0&(a|0)<=0|(a|0)<0){break N}b=D[k>>2];a=D[k+4>>2]-b>>2;O:{if(a>>>0>>0){ra(k,i-a|0);i=D[k+12>>2];break O}if(a>>>0<=i>>>0){break O}D[k+4>>2]=b+(i<<2)}e=1;if(!i){break M}g=D[c+16>>2];d=D[c+20>>2];r=D[k>>2];s=D[c+8>>2];o=D[c+12>>2];b=0;while(1){e=0;if((d|0)>=(o|0)&g>>>0>=s>>>0|(d|0)>(o|0)){break M}t=D[c>>2];n=E[t+g|0];a=d;d=g+1|0;a=d?a:a+1|0;g=d;D[c+16>>2]=d;d=a;D[c+20>>2]=a;a=n>>>2|0;f=0;P:{Q:{R:{S:{u=n&3;switch(u|0){case 0:break Q;case 3:break S;default:break R}}a=a+b|0;e=0;if(a>>>0>=i>>>0){break M}qa(r+(b<<2)|0,0,(n&252)+4|0);b=a;break P}while(1){if((d|0)>=(o|0)&g>>>0>=s>>>0|(d|0)>(o|0)){break N}i=E[g+t|0];e=d;d=g+1|0;e=d?e:e+1|0;g=d;D[c+16>>2]=d;d=e;D[c+20>>2]=e;a=i<<(f<<3|6)|a;f=f+1|0;if((u|0)!=(f|0)){continue}break}}D[r+(b<<2)>>2]=a}b=b+1|0;i=D[k+12>>2];if(b>>>0>>0){continue}break}a=k+16|0;o=D[k>>2];d=D[k+16>>2];b=D[k+20>>2]-d|0;T:{if(b>>>0<=262143){ra(a,65536-(b>>>2|0)|0);break T}if((b|0)==262144){break T}D[k+20>>2]=d+262144}d=k+28|0;b=D[d>>2];e=D[k+32>>2]-b>>3;U:{if(e>>>0>>0){db(d,i-e|0);b=D[d>>2];break U}if(e>>>0>i>>>0){D[k+32>>2]=(i<<3)+b}if(!i){break N}}k=D[a>>2];g=0;d=0;while(1){e=o+(g<<2)|0;f=D[e>>2];n=(g<<3)+b|0;a=d;D[n+4>>2]=a;D[n>>2]=f;e=D[e>>2];d=e+a|0;if(d>>>0>65536){break N}V:{if(a>>>0>=d>>>0){break V}f=0;n=e&7;if(n){while(1){D[k+(a<<2)>>2]=g;a=a+1|0;f=f+1|0;if((n|0)!=(f|0)){continue}break}}if(e-1>>>0<=6){break V}while(1){e=k+(a<<2)|0;D[e>>2]=g;D[e+28>>2]=g;D[e+24>>2]=g;D[e+20>>2]=g;D[e+16>>2]=g;D[e+12>>2]=g;D[e+8>>2]=g;D[e+4>>2]=g;a=a+8|0;if((d|0)!=(a|0)){continue}break}}g=g+1|0;if((i|0)!=(g|0)){continue}break}m=(d|0)==65536}e=m}W:{if(!e|(D[h+20>>2]?0:q)){break W}d=0;m=$-16|0;$=m;X:{if(!Va(1,m+8|0,c)){break X}a=D[c+8>>2];b=D[c+16>>2];f=a-b|0;i=D[m+12>>2];g=D[c+20>>2];a=D[c+12>>2]-(g+(a>>>0>>0)|0)|0;e=D[m+8>>2];if((i|0)==(a|0)&f>>>0>>0|a>>>0>>0){break X}a=g+i|0;f=b+e|0;a=f>>>0>>0?a+1|0:a;D[c+16>>2]=f;D[c+20>>2]=a;a=e;if((a|0)<=0){break X}b=b+D[c>>2]|0;D[h+48>>2]=b;c=a-1|0;e=c+b|0;f=E[e|0];Y:{if(f>>>0<=63){D[h+52>>2]=c;a=E[e|0]&63;break Y}Z:{switch((f>>>6|0)-1|0){case 0:if(a>>>0<2){break X}D[h+52>>2]=a-2;a=(a+b|0)-2|0;a=E[a+1|0]<<8&16128|E[a|0];break Y;case 1:if(a>>>0<3){break X}D[h+52>>2]=a-3;a=(a+b|0)-3|0;a=E[a+1|0]<<8|E[a+2|0]<<16&4128768|E[a|0];break Y;default:break Z}}D[h+52>>2]=a-4;a=(a+b|0)-4|0;a=E[a+2|0]<<16|E[a+3|0]<<24&1056964608|E[a+1|0]<<8|E[a|0]}D[h+56>>2]=a+262144;d=a>>>0<66846720}$=m+16|0;if(!d){break W}if(!q){l=1;break W}a=D[h+56>>2];b=D[h+36>>2];c=D[h+48>>2];d=D[h+24>>2];while(1){_:{if(a>>>0>262143){break _}l=D[h+52>>2];while(1){if((l|0)<=0){break _}l=l-1|0;D[h+52>>2]=l;a=E[c+l|0]|a<<8;D[h+56>>2]=a;if(a>>>0<262144){continue}break}}l=a&65535;e=D[d+(l<<2)>>2];m=b+(e<<3)|0;a=(J(D[m>>2],a>>>16|0)+l|0)-D[m+4>>2]|0;D[h+56>>2]=a;D[j+(p<<2)>>2]=e;l=1;p=p+1|0;if((q|0)!=(p|0)){continue}break}}a=D[h+36>>2];if(a){D[h+40>>2]=a;ma(a)}a=D[h+24>>2];if(a){D[h+28>>2]=a;ma(a)}a=D[h+8>>2];if(a){D[h+12>>2]=a;ma(a)}$=h- -64|0;b=l;break g;case 11:q=a;j=d;h=$+-64|0;$=h;D[h+56>>2]=0;D[h+48>>2]=0;D[h+52>>2]=0;D[h+40>>2]=0;D[h+44>>2]=0;D[h+32>>2]=0;D[h+36>>2]=0;D[h+24>>2]=0;D[h+28>>2]=0;D[h+16>>2]=0;D[h+20>>2]=0;D[h+8>>2]=0;D[h+12>>2]=0;k=h+8|0;$:{aa:{if(!F[c+38>>1]){break aa}if(!Wa(1,k+12|0,c)){break aa}a=D[c+8>>2];b=D[c+16>>2];d=a-b|0;i=D[k+12>>2];a=D[c+12>>2]-(D[c+20>>2]+(a>>>0>>0)|0)|0;if(d>>>0>>6>>>0&(a|0)<=0|(a|0)<0){break aa}b=D[k>>2];a=D[k+4>>2]-b>>2;ba:{if(a>>>0>>0){ra(k,i-a|0);i=D[k+12>>2];break ba}if(a>>>0<=i>>>0){break ba}D[k+4>>2]=b+(i<<2)}e=1;if(!i){break $}g=D[c+16>>2];d=D[c+20>>2];r=D[k>>2];s=D[c+8>>2];o=D[c+12>>2];b=0;while(1){e=0;if((d|0)>=(o|0)&g>>>0>=s>>>0|(d|0)>(o|0)){break $}t=D[c>>2];n=E[t+g|0];e=d;a=g+1|0;e=a?e:e+1|0;g=a;D[c+16>>2]=a;d=e;D[c+20>>2]=e;a=n>>>2|0;f=0;ca:{da:{ea:{fa:{e=n&3;switch(e|0){case 0:break da;case 3:break fa;default:break ea}}a=a+b|0;e=0;if(a>>>0>=i>>>0){break $}qa(r+(b<<2)|0,0,(n&252)+4|0);b=a;break ca}while(1){if((d|0)>=(o|0)&g>>>0>=s>>>0|(d|0)>(o|0)){break aa}i=E[g+t|0];g=g+1|0;d=g?d:d+1|0;D[c+16>>2]=g;D[c+20>>2]=d;a=i<<(f<<3|6)|a;f=f+1|0;if((e|0)!=(f|0)){continue}break}}D[r+(b<<2)>>2]=a}b=b+1|0;i=D[k+12>>2];if(b>>>0>>0){continue}break}a=k+16|0;o=D[k>>2];d=D[k+16>>2];b=D[k+20>>2]-d|0;ga:{if(b>>>0<=1048575){ra(a,262144-(b>>>2|0)|0);break ga}if((b|0)==1048576){break ga}D[k+20>>2]=d- -1048576}d=k+28|0;b=D[d>>2];e=D[k+32>>2]-b>>3;ha:{if(e>>>0>>0){db(d,i-e|0);b=D[d>>2];break ha}if(e>>>0>i>>>0){D[k+32>>2]=(i<<3)+b}if(!i){break aa}}k=D[a>>2];g=0;d=0;while(1){e=o+(g<<2)|0;f=D[e>>2];n=(g<<3)+b|0;a=d;D[n+4>>2]=a;D[n>>2]=f;e=D[e>>2];d=e+a|0;if(d>>>0>262144){break aa}ia:{if(a>>>0>=d>>>0){break ia}f=0;n=e&7;if(n){while(1){D[k+(a<<2)>>2]=g;a=a+1|0;f=f+1|0;if((n|0)!=(f|0)){continue}break}}if(e-1>>>0<=6){break ia}while(1){e=k+(a<<2)|0;D[e>>2]=g;D[e+28>>2]=g;D[e+24>>2]=g;D[e+20>>2]=g;D[e+16>>2]=g;D[e+12>>2]=g;D[e+8>>2]=g;D[e+4>>2]=g;a=a+8|0;if((d|0)!=(a|0)){continue}break}}g=g+1|0;if((i|0)!=(g|0)){continue}break}m=(d|0)==262144}e=m}ja:{if(!e|(D[h+20>>2]?0:q)){break ja}d=0;m=$-16|0;$=m;ka:{if(!Va(1,m+8|0,c)){break ka}a=D[c+8>>2];b=D[c+16>>2];e=a-b|0;i=D[m+12>>2];f=i;g=D[c+20>>2];k=D[c+12>>2]-(g+(a>>>0>>0)|0)|0;a=D[m+8>>2];if((f|0)==(k|0)&e>>>0>>0|f>>>0>k>>>0){break ka}e=g+i|0;f=a+b|0;e=f>>>0>>0?e+1|0:e;D[c+16>>2]=f;D[c+20>>2]=e;if((a|0)<=0){break ka}b=b+D[c>>2]|0;D[h+48>>2]=b;c=a-1|0;e=c+b|0;f=E[e|0];la:{if(f>>>0<=63){D[h+52>>2]=c;a=E[e|0]&63;break la}ma:{switch((f>>>6|0)-1|0){case 0:if(a>>>0<2){break ka}D[h+52>>2]=a-2;a=(a+b|0)-2|0;a=E[a+1|0]<<8&16128|E[a|0];break la;case 1:if(a>>>0<3){break ka}D[h+52>>2]=a-3;a=(a+b|0)-3|0;a=E[a+1|0]<<8|E[a+2|0]<<16&4128768|E[a|0];break la;default:break ma}}D[h+52>>2]=a-4;a=(a+b|0)-4|0;a=E[a+2|0]<<16|E[a+3|0]<<24&1056964608|E[a+1|0]<<8|E[a|0]}D[h+56>>2]=a- -1048576;d=a>>>0<267386880}$=m+16|0;if(!d){break ja}if(!q){l=1;break ja}a=D[h+56>>2];b=D[h+36>>2];c=D[h+48>>2];d=D[h+24>>2];while(1){na:{if(a>>>0>1048575){break na}l=D[h+52>>2];while(1){if((l|0)<=0){break na}l=l-1|0;D[h+52>>2]=l;a=E[c+l|0]|a<<8;D[h+56>>2]=a;if(a>>>0<1048576){continue}break}}l=a&262143;e=D[d+(l<<2)>>2];m=b+(e<<3)|0;a=(J(D[m>>2],a>>>18|0)+l|0)-D[m+4>>2]|0;D[h+56>>2]=a;D[j+(p<<2)>>2]=e;l=1;p=p+1|0;if((q|0)!=(p|0)){continue}break}}a=D[h+36>>2];if(a){D[h+40>>2]=a;ma(a)}a=D[h+24>>2];if(a){D[h+28>>2]=a;ma(a)}a=D[h+8>>2];if(a){D[h+12>>2]=a;ma(a)}$=h- -64|0;b=l;break g;case 12:h=a;q=d;e=$+-64|0;$=e;D[e+56>>2]=0;D[e+48>>2]=0;D[e+52>>2]=0;D[e+40>>2]=0;D[e+44>>2]=0;D[e+32>>2]=0;D[e+36>>2]=0;D[e+24>>2]=0;D[e+28>>2]=0;D[e+16>>2]=0;D[e+20>>2]=0;D[e+8>>2]=0;D[e+12>>2]=0;j=e+8|0;oa:{pa:{if(!F[c+38>>1]){break pa}if(!Wa(1,j+12|0,c)){break pa}a=D[c+8>>2];b=D[c+16>>2];d=a-b|0;i=D[j+12>>2];a=D[c+12>>2]-(D[c+20>>2]+(a>>>0>>0)|0)|0;if(d>>>0>>6>>>0&(a|0)<=0|(a|0)<0){break pa}b=D[j>>2];a=D[j+4>>2]-b>>2;qa:{if(a>>>0>>0){ra(j,i-a|0);i=D[j+12>>2];break qa}if(a>>>0<=i>>>0){break qa}D[j+4>>2]=b+(i<<2)}f=1;if(!i){break oa}g=D[c+16>>2];d=D[c+20>>2];n=D[j>>2];r=D[c+8>>2];k=D[c+12>>2];b=0;while(1){f=0;if((d|0)>=(k|0)&g>>>0>=r>>>0|(d|0)>(k|0)){break oa}s=D[c>>2];o=E[s+g|0];a=d;d=g+1|0;a=d?a:a+1|0;g=d;D[c+16>>2]=d;d=a;D[c+20>>2]=a;a=o>>>2|0;f=0;ra:{sa:{ta:{ua:{t=o&3;switch(t|0){case 0:break sa;case 3:break ua;default:break ta}}a=a+b|0;f=0;if(a>>>0>=i>>>0){break oa}qa(n+(b<<2)|0,0,(o&252)+4|0);b=a;break ra}while(1){if((d|0)>=(k|0)&g>>>0>=r>>>0|(d|0)>(k|0)){break pa}i=E[g+s|0];g=g+1|0;d=g?d:d+1|0;D[c+16>>2]=g;D[c+20>>2]=d;a=i<<(f<<3|6)|a;f=f+1|0;if((t|0)!=(f|0)){continue}break}}D[n+(b<<2)>>2]=a}b=b+1|0;i=D[j+12>>2];if(b>>>0>>0){continue}break}a=j+16|0;o=D[j>>2];d=D[j+16>>2];b=D[j+20>>2]-d|0;va:{if(b>>>0<=2097151){ra(a,524288-(b>>>2|0)|0);break va}if((b|0)==2097152){break va}D[j+20>>2]=d+2097152}d=j+28|0;b=D[d>>2];f=D[j+32>>2]-b>>3;wa:{if(f>>>0>>0){db(d,i-f|0);b=D[d>>2];break wa}if(f>>>0>i>>>0){D[j+32>>2]=(i<<3)+b}if(!i){break pa}}j=D[a>>2];g=0;d=0;while(1){f=o+(g<<2)|0;k=D[f>>2];n=(g<<3)+b|0;a=d;D[n+4>>2]=a;D[n>>2]=k;k=D[f>>2];d=k+a|0;if(d>>>0>524288){break pa}xa:{if(a>>>0>=d>>>0){break xa}f=0;n=k&7;if(n){while(1){D[j+(a<<2)>>2]=g;a=a+1|0;f=f+1|0;if((n|0)!=(f|0)){continue}break}}if(k-1>>>0<=6){break xa}while(1){f=j+(a<<2)|0;D[f>>2]=g;D[f+28>>2]=g;D[f+24>>2]=g;D[f+20>>2]=g;D[f+16>>2]=g;D[f+12>>2]=g;D[f+8>>2]=g;D[f+4>>2]=g;a=a+8|0;if((d|0)!=(a|0)){continue}break}}g=g+1|0;if((i|0)!=(g|0)){continue}break}m=(d|0)==524288}f=m}ya:{if(!f|(D[e+20>>2]?0:h)){break ya}d=0;f=$-16|0;$=f;za:{if(!Va(1,f+8|0,c)){break za}a=D[c+8>>2];b=D[c+16>>2];j=a-b|0;i=D[f+12>>2];g=D[c+20>>2];a=D[c+12>>2]-(g+(a>>>0>>0)|0)|0;m=D[f+8>>2];if((i|0)==(a|0)&j>>>0>>0|a>>>0>>0){break za}a=g+i|0;j=b+m|0;a=j>>>0>>0?a+1|0:a;D[c+16>>2]=j;D[c+20>>2]=a;a=m;if((a|0)<=0){break za}b=b+D[c>>2]|0;D[e+48>>2]=b;c=a-1|0;m=c+b|0;j=E[m|0];Aa:{if(j>>>0<=63){D[e+52>>2]=c;a=E[m|0]&63;break Aa}Ba:{switch((j>>>6|0)-1|0){case 0:if(a>>>0<2){break za}D[e+52>>2]=a-2;a=(a+b|0)-2|0;a=E[a+1|0]<<8&16128|E[a|0];break Aa;case 1:if(a>>>0<3){break za}D[e+52>>2]=a-3;a=(a+b|0)-3|0;a=E[a+1|0]<<8|E[a+2|0]<<16&4128768|E[a|0];break Aa;default:break Ba}}D[e+52>>2]=a-4;a=(a+b|0)-4|0;a=E[a+2|0]<<16|E[a+3|0]<<24&1056964608|E[a+1|0]<<8|E[a|0]}D[e+56>>2]=a+2097152;d=a>>>0<534773760}$=f+16|0;if(!d){break ya}if(!h){l=1;break ya}a=D[e+56>>2];b=D[e+36>>2];c=D[e+48>>2];d=D[e+24>>2];while(1){Ca:{if(a>>>0>2097151){break Ca}l=D[e+52>>2];while(1){if((l|0)<=0){break Ca}l=l-1|0;D[e+52>>2]=l;a=E[c+l|0]|a<<8;D[e+56>>2]=a;if(a>>>0<2097152){continue}break}}l=a&524287;m=D[d+(l<<2)>>2];f=b+(m<<3)|0;a=(J(D[f>>2],a>>>19|0)+l|0)-D[f+4>>2]|0;D[e+56>>2]=a;D[q+(p<<2)>>2]=m;l=1;p=p+1|0;if((h|0)!=(p|0)){continue}break}}a=D[e+36>>2];if(a){D[e+40>>2]=a;ma(a)}a=D[e+24>>2];if(a){D[e+28>>2]=a;ma(a)}a=D[e+8>>2];if(a){D[e+12>>2]=a;ma(a)}$=e- -64|0;b=l;break g;case 17:b=Id(a,c,d);break g;case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:e=$+-64|0;$=e;D[e+56>>2]=0;D[e+48>>2]=0;D[e+52>>2]=0;D[e+40>>2]=0;D[e+44>>2]=0;D[e+32>>2]=0;D[e+36>>2]=0;D[e+24>>2]=0;D[e+28>>2]=0;D[e+16>>2]=0;D[e+20>>2]=0;D[e+8>>2]=0;D[e+12>>2]=0;Da:{if(!Kd(e+8|0,c)|(D[e+20>>2]?0:a)){break Da}if(!Jd(e+8|0,c)){break Da}if(!a){b=1;break Da}c=D[e+56>>2];m=D[e+36>>2];f=D[e+48>>2];h=D[e+24>>2];while(1){Ea:{if(c>>>0>16383){break Ea}b=D[e+52>>2];while(1){if((b|0)<=0){break Ea}b=b-1|0;D[e+52>>2]=b;c=E[b+f|0]|c<<8;D[e+56>>2]=c;if(c>>>0<16384){continue}break}}b=c&4095;q=D[h+(b<<2)>>2];j=m+(q<<3)|0;c=(J(D[j>>2],c>>>12|0)+b|0)-D[j+4>>2]|0;D[e+56>>2]=c;D[(l<<2)+d>>2]=q;b=1;l=l+1|0;if((l|0)!=(a|0)){continue}break}}a=D[e+36>>2];if(a){D[e+40>>2]=a;ma(a)}a=D[e+24>>2];if(a){D[e+28>>2]=a;ma(a)}a=D[e+8>>2];if(a){D[e+12>>2]=a;ma(a)}$=e- -64|0;break g;case 13:case 14:case 15:case 16:break h;default:break g}}b=Id(a,c,d)}l=b}return l}function eh(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,H=0,I=0,K=0,L=0,M=0,N=0;v=$+-64|0;$=v;D[a+132>>2]=0;if(D[a+148>>2]){d=D[a+144>>2];if(d){while(1){g=D[d>>2];ma(d);d=g;if(d){continue}break}}d=0;D[a+144>>2]=0;g=D[a+140>>2];a:{if(!g){break a}if(g-1>>>0>=3){k=g&-4;while(1){b=d<<2;D[b+D[a+136>>2]>>2]=0;D[D[a+136>>2]+(b|4)>>2]=0;D[D[a+136>>2]+(b|8)>>2]=0;D[D[a+136>>2]+(b|12)>>2]=0;d=d+4|0;f=f+4|0;if((k|0)!=(f|0)){continue}break}}g=g&3;if(!g){break a}f=0;while(1){D[D[a+136>>2]+(d<<2)>>2]=0;d=d+1|0;f=f+1|0;if((g|0)!=(f|0)){continue}break}}D[a+148>>2]=0}b:{c:{if(!Ga(1,v+60|0,D[D[a+4>>2]+32>>2])){break c}D[a+156>>2]=D[v+60>>2];if(!Ga(1,v+56|0,D[D[a+4>>2]+32>>2])){break c}b=D[v+56>>2];if(b>>>0>1431655765|G[a+156>>2]>J(b,3)>>>0){break c}d=D[D[a+4>>2]+32>>2];f=D[d+8>>2];k=D[d+12>>2];g=D[d+20>>2];c=f;f=D[d+16>>2];if((k|0)<=(g|0)&c>>>0<=f>>>0|(g|0)>(k|0)){break c}i=E[f+D[d>>2]|0];f=f+1|0;g=f?g:g+1|0;D[d+16>>2]=f;D[d+20>>2]=g;if(!Ga(1,v+52|0,d)){break c}n=D[v+52>>2];if(n>>>0>b>>>0|b>>>0>n+((n>>>0)/3|0)>>>0){break c}if(!Ga(1,v+48|0,D[D[a+4>>2]+32>>2])){break c}f=D[v+48>>2];if(f>>>0>n>>>0){break c}D[a+28>>2]=D[a+24>>2];g=Wb(na(88));d=D[a+8>>2];D[a+8>>2]=g;if(d){cb(d);if(!D[a+8>>2]){break c}}D[a+164>>2]=D[a+160>>2];Ib(a+160|0,b);D[a+176>>2]=D[a+172>>2];Ib(a+172|0,b);D[a- -64>>2]=0;D[a+92>>2]=-1;D[a+84>>2]=-1;D[a+88>>2]=-1;D[a+40>>2]=D[a+36>>2];D[a+52>>2]=D[a+48>>2];D[a+76>>2]=D[a+72>>2];z=a+216|0;Ad(z);zd(z,i);if(!Yc(D[a+8>>2],b,f+D[a+156>>2]|0)){break c}d=D[a+156>>2];B[v+8|0]=1;Ha(a+120|0,d+f|0,v+8|0);if((yd(a,D[D[a+4>>2]+32>>2])|0)==-1){break c}k=a+232|0;g=k;D[g+144>>2]=a;d=D[(ba[D[D[a>>2]+32>>2]](a)|0)+32>>2];b=D[d>>2]+D[d+16>>2]|0;e=D[(ba[D[D[a>>2]+32>>2]](a)|0)+32>>2];d=D[e+8>>2];e=D[e+16>>2];d=d-e|0;M=g,N=F[D[(ba[D[D[a>>2]+32>>2]](a)|0)+32>>2]+38>>1],C[M+38>>1]=N;D[g>>2]=b;D[g+16>>2]=0;D[g+20>>2]=0;D[g+8>>2]=d;D[g+12>>2]=0;M=g,N=ba[D[D[a>>2]+36>>2]](a)|0,D[M+148>>2]=N;D[a+372>>2]=i;D[a+384>>2]=f+D[a+156>>2];K=La(v+8|0);i=K;b=0;e=$-16|0;$=e;d:{if(!Da(g+80|0,g)){break d}if(!vd(k)){break d}d=D[k+4>>2];D[i>>2]=D[k>>2];D[i+4>>2]=d;d=D[k+36>>2];D[i+32>>2]=D[k+32>>2];D[i+36>>2]=d;d=D[k+28>>2];D[i+24>>2]=D[k+24>>2];D[i+28>>2]=d;d=D[k+20>>2];D[i+16>>2]=D[k+16>>2];D[i+20>>2]=d;d=D[k+12>>2];D[i+8>>2]=D[k+8>>2];D[i+12>>2]=d;D[k+176>>2]=2;D[k+180>>2]=7;d=D[k+152>>2];if((d|0)<0){break d}D[e+12>>2]=0;b=2;c=D[k+156>>2];g=D[k+160>>2]-c>>2;e:{if(g>>>0>>0){xa(k+156|0,d-g|0,e+12|0);b=D[k+176>>2];f=D[k+180>>2];break e}f=7;if(d>>>0>=g>>>0){break e}D[k+160>>2]=c+(d<<2)}g=k+184|0;f=(f-b|0)+1|0;d=D[k+188>>2];b=D[k+184>>2];c=(d-b|0)/12|0;f:{if(f>>>0>c>>>0){d=f-c|0;o=D[g+8>>2];b=D[g+4>>2];g:{if(d>>>0<=(o-b|0)/12>>>0){if(d){d=J(d,12)-12|0;d=(d-((d>>>0)%12|0)|0)+12|0;b=qa(b,0,d)+d|0}D[g+4>>2]=b;break g}h:{i:{j:{c=D[g>>2];q=(b-c|0)/12|0;f=q+d|0;if(f>>>0<357913942){o=(o-c|0)/12|0;m=o<<1;o=o>>>0<178956970?f>>>0>>0?m:f:357913941;if(o){if(o>>>0>=357913942){break j}h=na(J(o,12))}f=J(q,12)+h|0;d=J(d,12)-12|0;q=(d-((d>>>0)%12|0)|0)+12|0;d=qa(f,0,q);q=d+q|0;o=J(o,12)+h|0;if((b|0)==(c|0)){break i}while(1){f=f-12|0;b=b-12|0;D[f>>2]=D[b>>2];D[f+4>>2]=D[b+4>>2];D[f+8>>2]=D[b+8>>2];D[b+8>>2]=0;D[b>>2]=0;D[b+4>>2]=0;if((b|0)!=(c|0)){continue}break}D[g+8>>2]=o;d=D[g+4>>2];D[g+4>>2]=q;b=D[g>>2];D[g>>2]=f;if((b|0)==(d|0)){break h}while(1){f=d-12|0;c=D[f>>2];if(c){D[d-8>>2]=c;ma(c)}d=f;if((d|0)!=(b|0)){continue}break}break h}break b}sa();T()}D[g+8>>2]=o;D[g+4>>2]=q;D[g>>2]=d}if(b){ma(b)}}f=D[k+188>>2];break f}if(f>>>0>=c>>>0){f=d;break f}f=b+J(f,12)|0;if((f|0)!=(d|0)){while(1){b=d-12|0;c=D[b>>2];if(c){D[d-8>>2]=c;ma(c)}d=b;if((b|0)!=(f|0)){continue}break}}D[k+188>>2]=f}o=k+196|0;b=D[k+184>>2];d=(f-b|0)/12|0;q=D[k+196>>2];c=D[k+200>>2]-q>>2;k:{if(d>>>0>c>>>0){ra(o,d-c|0);b=D[k+184>>2];f=D[k+188>>2];break k}if(d>>>0>=c>>>0){break k}D[k+200>>2]=q+(d<<2)}if((b|0)==(f|0)){b=1;break d}d=0;while(1){l:{if(!Ga(1,e+8|0,i)){break l}b=D[k+148>>2];c=(D[b+4>>2]-D[b>>2]>>2>>>0)/3|0;b=D[e+8>>2];if(c>>>0>>0){break l}if(b){h=J(d,12);c=h+D[g>>2]|0;f=D[c>>2];q=D[c+4>>2]-f>>2;m:{if(q>>>0>>0){ra(c,b-q|0);f=D[h+D[g>>2]>>2];break m}if(b>>>0>=q>>>0){break m}D[c+4>>2]=(b<<2)+f}jc(b,1,i,f);D[D[o>>2]+(d<<2)>>2]=b}b=1;d=d+1|0;if(d>>>0<(D[k+188>>2]-D[k+184>>2]|0)/12>>>0){continue}break d}break}b=0}$=e+16|0;n:{if(!b){break n}b=0;g=0;f=0;d=0;q=0;k=0;o=0;m=$-96|0;$=m;D[m+72>>2]=0;D[m+64>>2]=0;D[m+68>>2]=0;D[m+48>>2]=0;D[m+52>>2]=0;D[m+40>>2]=0;D[m+44>>2]=0;D[m+56>>2]=1065353216;D[m+32>>2]=0;D[m+24>>2]=0;D[m+28>>2]=0;i=a;A=D[a+124>>2];o:{p:{q:{r:{if((n|0)<=0){break r}x=i+232|0;L=D[i+216>>2]!=D[i+220>>2];s=1;s:{while(1){c=o;o=c+1|0;t:{u:{v:{a=D[i+404>>2];if((a|0)==-1){D[i+400>>2]=7;break v}e=-1;h=D[i+428>>2]+(a<<2)|0;j=D[h>>2];a=j-1|0;D[h>>2]=a;if((j|0)<=0){break q}a=D[D[D[i+416>>2]+J(D[i+404>>2],12)>>2]+(a<<2)>>2];if(a>>>0>4){break q}h=D[(a<<2)+8896>>2];D[i+400>>2]=h;if(!a){if((b|0)==(d|0)){break q}a=-1;j=D[i+8>>2];s=D[j+24>>2];r=b-4|0;e=D[r>>2];h=-1;w:{if((e|0)==-1){break w}l=e+1|0;l=(l>>>0)%3|0?l:e-2|0;h=-1;if((l|0)==-1){break w}h=D[D[j>>2]+(l<<2)>>2]}g=D[s+(h<<2)>>2];if((g|0)!=-1){a=g+1|0;a=(a>>>0)%3|0?a:g-2|0}g=D[j+12>>2];l=J(c,3);c=l+1|0;D[g+(e<<2)>>2]=c;w=c<<2;D[w+g>>2]=e;p=l+2|0;D[g+(a<<2)>>2]=p;t=p<<2;D[t+g>>2]=a;g=-1;c=-1;x:{if((e|0)==-1){break x}y:{if((e>>>0)%3|0){e=e-1|0;break y}e=e+2|0;c=-1;if((e|0)==-1){break x}}c=D[D[j>>2]+(e<<2)>>2]}z:{if((a|0)==-1){break z}e=a+1|0;a=(e>>>0)%3|0?e:a-2|0;if((a|0)==-1){break z}g=D[D[j>>2]+(a<<2)>>2]}e=-1;if((c|0)==(h|0)|(g|0)==(h|0)){break q}a=D[j>>2];D[a+(l<<2)>>2]=h;D[a+w>>2]=g;D[a+t>>2]=c;if((c|0)!=-1){D[s+(c<<2)>>2]=p}a=D[i+120>>2]+(h>>>3&536870908)|0;g=D[a>>2];M=a,N=ji(h)&g,D[M>>2]=N;D[r>>2]=l;g=d;hc(x,l);break t}A:{switch(h-1|0){case 2:case 4:if((b|0)==(d|0)){break q}j=D[i+8>>2];e=D[j+12>>2];h=J(c,3);a=(a|0)==3;p=h+(a?2:1)|0;r=p<<2;w=b-4|0;g=D[w>>2];D[e+r>>2]=g;D[e+(g<<2)>>2]=p;Ua(j+24|0);e=-1;b=D[i+8>>2];l=D[b+24>>2];if((A|0)>2]-l>>2){break q}b=D[b>>2];t=b+r|0;e=D[j+28>>2];j=D[j+24>>2];r=(e-j>>2)-1|0;D[t>>2]=r;if((e|0)!=(j|0)){D[l+(r<<2)>>2]=p}e=a?h:h+2|0;t=b+(a+h<<2)|0;B:{if((g|0)==-1){D[b+(e<<2)>>2]=-1;a=-1;break B}C:{D:{E:{if((g>>>0)%3|0){a=g-1|0;break E}a=g+2|0;if((a|0)==-1){break D}}a=D[b+(a<<2)>>2];D[b+(e<<2)>>2]=a;if((a|0)==-1){break C}D[l+(a<<2)>>2]=e;break C}D[b+(e<<2)>>2]=-1}e=g+1|0;g=(e>>>0)%3|0?e:g-2|0;a=-1;if((g|0)==-1){break B}a=D[b+(g<<2)>>2]}D[t>>2]=a;D[w>>2]=h;g=d;break u;case 6:break v;case 0:break A;default:break q}}if((b|0)==(g|0)){break q}f=b-4|0;j=D[f>>2];D[m+68>>2]=f;l=D[m+44>>2];F:{if(!l){break F}e=D[m+40>>2];p=ii(l)>>>0>1;a=c&l+2147483647;G:{if(!p){break G}a=c;if(a>>>0>>0){break G}a=(c>>>0)%(l>>>0)|0}h=a;a=D[e+(h<<2)>>2];if(!a){break F}e=D[a>>2];if(!e){break F}H:{if(!p){a=l-1|0;while(1){l=D[e+4>>2];I:{if((l|0)!=(c|0)){if((h|0)==(a&l)){break I}break F}if((c|0)==D[e+8>>2]){break H}}e=D[e>>2];if(e){continue}break}break F}while(1){a=D[e+4>>2];J:{if((a|0)!=(c|0)){if(a>>>0>=l>>>0){a=(a>>>0)%(l>>>0)|0}if((a|0)==(h|0)){break J}break F}if((c|0)==D[e+8>>2]){break H}}e=D[e>>2];if(e){continue}break}break F}if((f|0)!=(u|0)){D[f>>2]=D[e+12>>2];D[m+68>>2]=b;f=b;break F}a=u-g|0;f=a>>2;d=f+1|0;if(d>>>0>=1073741824){break b}b=a>>1;b=a>>>0<2147483644?b>>>0>d>>>0?b:d:1073741823;if(b){if(b>>>0>=1073741824){break p}d=na(b<<2)}else{d=0}f=d+(f<<2)|0;D[f>>2]=D[e+12>>2];u=(b<<2)+d|0;f=f+4|0;if((a|0)>0){oa(d,g,a)}D[m+72>>2]=u;D[m+68>>2]=f;D[m+64>>2]=d;if(g){ma(g)}g=d}if((g|0)==(f|0)){break s}w=f-4|0;e=D[w>>2];a=(e|0)==-1;l=D[i+8>>2];if(!a&D[D[l+12>>2]+(e<<2)>>2]!=-1){break s}p=D[l+12>>2];if((j|0)!=-1&D[p+(j<<2)>>2]!=-1){break s}s=J(c,3);r=s+2|0;D[p+(e<<2)>>2]=r;c=r<<2;D[c+p>>2]=e;b=s+1|0;D[p+(j<<2)>>2]=b;t=b<<2;D[t+p>>2]=j;K:{L:{M:{if(!a){if((e>>>0)%3|0){h=e-1|0;break M}h=e+2|0;if((h|0)!=-1){break M}b=D[l>>2];a=-1;break L}a=-1;b=D[l>>2];D[b+(s<<2)>>2]=-1;h=-1;break K}b=D[l>>2];a=D[b+(h<<2)>>2]}D[(s<<2)+b>>2]=a;H=e+1|0;e=(H>>>0)%3|0?H:e-2|0;h=-1;if((e|0)==-1){break K}h=D[(e<<2)+b>>2]}D[b+t>>2]=h;N:{if((j|0)==-1){D[b+c>>2]=-1;h=-1;e=-1;break N}O:{P:{Q:{if((j>>>0)%3|0){e=j-1|0;break Q}e=j+2|0;if((e|0)==-1){break P}}e=D[(e<<2)+b>>2];D[b+c>>2]=e;if((e|0)==-1){break O}D[D[l+24>>2]+(e<<2)>>2]=r;break O}D[b+c>>2]=-1}h=-1;c=j+1|0;c=(c>>>0)%3|0?c:j-2|0;e=-1;if((c|0)==-1){break N}h=D[(c<<2)+b>>2];e=c}c=D[i+388>>2];j=a<<2;r=c+j|0;t=c;c=h<<2;D[r>>2]=D[r>>2]+D[t+c>>2];l=D[l+24>>2];c=l+c|0;if((a|0)!=-1){D[j+l>>2]=D[c>>2]}R:{if((e|0)==-1){break R}while(1){D[(e<<2)+b>>2]=a;j=e+1|0;e=(j>>>0)%3|0?j:e-2|0;if((e|0)==-1){break R}e=D[p+(e<<2)>>2];if((e|0)==-1){break R}j=e+1|0;e=(j>>>0)%3|0?j:e-2|0;if((e|0)!=-1){continue}break}}D[c>>2]=-1;S:{if(L){break S}if((q|0)!=(y|0)){D[q>>2]=h;q=q+4|0;D[m+28>>2]=q;break S}b=y-k|0;c=b>>2;a=c+1|0;if(a>>>0<1073741824){e=b>>1;e=b>>>0<2147483644?a>>>0>>0?e:a:1073741823;if(e){if(e>>>0>=1073741824){break p}a=na(e<<2)}else{a=0}c=a+(c<<2)|0;D[c>>2]=h;y=a+(e<<2)|0;q=c+4|0;if((b|0)>0){oa(a,k,b)}D[m+32>>2]=y;D[m+28>>2]=q;D[m+24>>2]=a;if(k){ma(k)}k=a;break S}break b}D[w>>2]=s;b=f;hc(x,s);break t}h=D[i+8>>2];Ua(h+24|0);e=-1;f=D[i+8>>2];a=J(c,3);j=D[h+28>>2];l=D[h+24>>2];p=j-l|0;h=p>>2;r=h-1|0;D[D[f>>2]+(a<<2)>>2]=r;Ua(f+24|0);w=a+1|0;D[D[f>>2]+(w<<2)>>2]=(D[f+28>>2]-D[f+24>>2]>>2)-1;f=D[i+8>>2];Ua(f+24|0);t=a+2|0;D[D[f>>2]+(t<<2)>>2]=(D[f+28>>2]-D[f+24>>2]>>2)-1;H=D[i+8>>2];f=D[H+24>>2];if((A|0)>2]-f>>2){break q}T:{U:{if((j|0)!=(l|0)){D[f+(r<<2)>>2]=a;e=0;if((p|0)==-4){break U}}D[f+(h<<2)>>2]=w;e=h+1|0;if((e|0)==-1){break T}}D[f+(e<<2)>>2]=t}if((b|0)!=(u|0)){D[b>>2]=a;f=b+4|0;D[m+68>>2]=f;break u}b=u-d|0;e=b>>2;g=e+1|0;if(g>>>0>=1073741824){break b}f=b>>1;f=b>>>0<2147483644?g>>>0>>0?f:g:1073741823;if(f){if(f>>>0>=1073741824){break p}g=na(f<<2)}else{g=0}e=g+(e<<2)|0;D[e>>2]=a;u=(f<<2)+g|0;f=e+4|0;if((b|0)>0){oa(g,d,b)}D[m+72>>2]=u;D[m+68>>2]=f;D[m+64>>2]=g;if(d){ma(d)}d=g}hc(x,D[f-4>>2]);e=D[i+40>>2];V:{if((e|0)==D[i+36>>2]){break V}c=n+(c^-1)|0;h=f-4|0;while(1){a=e-12|0;b=D[a+4>>2];if(b>>>0>c>>>0){break s}if((b|0)!=(c|0)){break V}e=E[e-4|0];b=D[a>>2];D[i+40>>2]=a;if((b|0)<0){break s}a=D[h>>2];D[m+20>>2]=n+(b^-1);b=m+20|0;D[m+88>>2]=b;ud(m,m+40|0,b,m+88|0);t=D[m>>2];W:{if(e&1){b=-1;if((a|0)==-1){break W}b=a+1|0;b=(b>>>0)%3|0?b:a-2|0;break W}b=-1;if((a|0)==-1){break W}b=a-1|0;if((a>>>0)%3|0){break W}b=a+2|0}D[t+12>>2]=b;e=D[i+40>>2];if((e|0)!=D[i+36>>2]){continue}break}}b=f}s=(n|0)>(o|0);if((n|0)!=(o|0)){continue}break}o=n;break r}e=-1;if(s&1){break q}}e=-1;b=D[i+8>>2];if((A|0)>2]-D[b+24>>2]>>2){break q}X:{if((d|0)!=(f|0)){g=i+60|0;A=i+312|0;while(1){f=f-4|0;j=D[f>>2];D[m+68>>2]=f;Y:{if(za(A)){p=D[i+8>>2];l=D[p>>2];if(((D[p+4>>2]-l>>2>>>0)/3|0)<=(o|0)){break X}a=-1;b=-1;n=D[p+24>>2];c=-1;Z:{if((j|0)==-1){break Z}h=j+1|0;h=(h>>>0)%3|0?h:j-2|0;c=-1;if((h|0)==-1){break Z}c=D[l+(h<<2)>>2]}h=c;c=D[n+(h<<2)>>2];_:{if((c|0)==-1){break _}u=c+1|0;c=(u>>>0)%3|0?u:c-2|0;if((c|0)==-1){break _}a=c+1|0;a=(a>>>0)%3|0?a:c-2|0;if((a|0)!=-1){b=D[l+(a<<2)>>2]}a=c}u=-1;s=-1;n=D[n+(b<<2)>>2];c=-1;$:{if((n|0)==-1){break $}x=n+1|0;n=(x>>>0)%3|0?x:n-2|0;c=-1;if((n|0)==-1){break $}c=n+1|0;c=(c>>>0)%3|0?c:n-2|0;if((c|0)!=-1){s=D[l+(c<<2)>>2]}c=n}n=D[p+12>>2];p=J(o,3);x=p<<2;D[n+x>>2]=j;D[n+(j<<2)>>2]=p;j=p+1|0;y=j<<2;D[y+n>>2]=a;D[n+(a<<2)>>2]=j;a=p+2|0;r=a<<2;D[r+n>>2]=c;D[n+(c<<2)>>2]=a;D[l+x>>2]=b;c=l+y|0;D[c>>2]=s;n=l+r|0;D[n>>2]=h;h=j?b:-1;b=D[i+120>>2];l=(h>>>3&536870908)+b|0;s=D[l>>2];M=l,N=ji(h)&s,D[M>>2]=N;u=(j|0)!=-1?D[c>>2]:u;c=b+(u>>>3&536870908)|0;h=D[c>>2];M=c,N=ji(u)&h,D[M>>2]=N;h=-1;h=(a|0)!=-1?D[n>>2]:h;a=b+(h>>>3&536870908)|0;b=D[a>>2];M=a,N=ji(h)&b,D[M>>2]=N;h=D[i+64>>2];a=D[i+68>>2];if((h|0)==a<<5){if((h+1|0)<0){break b}if(h>>>0<=1073741822){a=a<<6;b=h+32&-32;a=a>>>0>b>>>0?a:b}else{a=2147483647}Xa(g,a);h=D[i+64>>2]}o=o+1|0;D[i+64>>2]=h+1;a=D[i+60>>2]+(h>>>3&536870908)|0;D[a>>2]=D[a>>2]|1<>2];if((a|0)!=D[i+80>>2]){D[a>>2]=p;D[i+76>>2]=a+4;break Y}c=D[i+72>>2];b=a-c|0;h=b>>2;a=h+1|0;if(a>>>0>=1073741824){break b}n=b>>1;n=b>>>0<2147483644?a>>>0>>0?n:a:1073741823;if(n){if(n>>>0>=1073741824){break p}a=na(n<<2)}else{a=0}h=a+(h<<2)|0;D[h>>2]=p;if((b|0)>0){oa(a,c,b)}D[i+80>>2]=a+(n<<2);D[i+76>>2]=h+4;D[i+72>>2]=a;if(!c){break Y}ma(c);break Y}b=D[i+64>>2];a=D[i+68>>2];if((b|0)==a<<5){if((b+1|0)<0){break b}if(b>>>0<=1073741822){a=a<<6;b=b+32&-32;a=a>>>0>b>>>0?a:b}else{a=2147483647}Xa(g,a);b=D[i+64>>2]}D[i+64>>2]=b+1;a=D[i+60>>2]+(b>>>3&536870908)|0;c=D[a>>2];M=a,N=ji(b)&c,D[M>>2]=N;a=D[i+76>>2];if((a|0)!=D[i+80>>2]){D[a>>2]=j;D[i+76>>2]=a+4;break Y}c=D[i+72>>2];b=a-c|0;h=b>>2;a=h+1|0;if(a>>>0>=1073741824){break b}n=b>>1;n=b>>>0<2147483644?a>>>0>>0?n:a:1073741823;if(n){if(n>>>0>=1073741824){break p}a=na(n<<2)}else{a=0}h=a+(h<<2)|0;D[h>>2]=j;if((b|0)>0){oa(a,c,b)}D[i+80>>2]=a+(n<<2);D[i+76>>2]=h+4;D[i+72>>2]=a;if(!c){break Y}ma(c)}if((d|0)!=(f|0)){continue}break}b=D[i+8>>2]}if(((D[b+4>>2]-D[b>>2]>>2>>>0)/3|0)!=(o|0)){break q}e=D[b+28>>2]-D[b+24>>2]>>2;if((k|0)==(q|0)){k=q;break q}a=k;while(1){g=D[a>>2];c=D[b+24>>2];f=e-1|0;h=c+(f<<2)|0;if(D[h>>2]==-1){while(1){f=e-2|0;e=e-1|0;h=c+(f<<2)|0;if(D[h>>2]==-1){continue}break}}if(g>>>0<=f>>>0){D[m>>2]=b;h=D[h>>2];B[m+12|0]=1;D[m+8>>2]=h;D[m+4>>2]=h;if((h|0)!=-1){while(1){b=D[D[i+8>>2]>>2]+(h<<2)|0;if(D[b>>2]!=(f|0)){break X}D[b>>2]=g;kc(m);h=D[m+8>>2];if((h|0)!=-1){continue}break}b=D[i+8>>2]}o=D[b+24>>2];c=o+(f<<2)|0;if((g|0)!=-1){D[o+(g<<2)>>2]=D[c>>2]}D[c>>2]=-1;c=1<>2];g=o+(g>>>3&536870908)|0;o=o+(f>>>3&536870908)|0;f=1<>2]&f){c=c|D[g>>2]}else{c=D[g>>2]&(c^-1)}D[g>>2]=c;D[o>>2]=D[o>>2]&(f^-1);e=e-1|0}a=a+4|0;if((q|0)!=(a|0)){continue}break}break q}e=-1}if(k){ma(k)}a=D[m+48>>2];if(a){while(1){g=D[a>>2];ma(a);a=g;if(a){continue}break}}a=D[m+40>>2];D[m+40>>2]=0;if(a){ma(a)}if(d){D[m+68>>2]=d;ma(d)}$=m+96|0;break o}sa();T()}if((e|0)==-1){break n}a=D[K+16>>2];d=a+D[K>>2]|0;g=D[K+8>>2];g=g-a|0;a=D[D[i+4>>2]+32>>2];C[a+38>>1]=F[a+38>>1];D[a>>2]=d;D[a+16>>2]=0;D[a+20>>2]=0;D[a+8>>2]=g;D[a+12>>2]=0;aa:{if(D[i+216>>2]==D[i+220>>2]){break aa}a=D[i+8>>2];if(D[a+4>>2]==D[a>>2]){break aa}d=0;while(1){if(xd(i,d)){d=d+3|0;a=D[i+8>>2];if(d>>>0>2]-D[a>>2]>>2>>>0){continue}break aa}break}break n}if(E[i+308|0]){B[i+308|0]=0;g=D[i+292>>2];a=0;d=D[i+304>>2]+7|0;a=d>>>0<7?1:a;f=a<<29|d>>>3;d=f+D[i+288>>2]|0;a=(a>>>3|0)+g|0;D[i+288>>2]=d;D[i+292>>2]=d>>>0>>0?a+1|0:a}d=D[i+216>>2];if((d|0)!=D[i+220>>2]){while(1){g=J(I,144);Xc((g+d|0)+4|0,D[i+8>>2]);a=D[z>>2];b=a+g|0;d=D[b+132>>2];b=D[b+136>>2];if((d|0)!=(b|0)){while(1){Vc((g+D[z>>2]|0)+4|0,D[d>>2]);d=d+4|0;if((b|0)!=(d|0)){continue}break}a=D[z>>2]}Wc((a+g|0)+4|0);I=I+1|0;d=D[i+216>>2];if(I>>>0<(D[i+220>>2]-d|0)/144>>>0){continue}break}}a=D[i+8>>2];Hb(i+184|0,D[a+28>>2]-D[a+24>>2]>>2);f=D[i+216>>2];if((f|0)!=D[i+220>>2]){d=0;while(1){a=J(d,144)+f|0;g=D[a+60>>2]-D[a+56>>2]>>2;c=a+104|0;a=D[i+8>>2];a=D[a+28>>2]-D[a+24>>2]>>2;Hb(c,(a|0)<(g|0)?g:a);d=d+1|0;f=D[i+216>>2];if(d>>>0<(D[i+220>>2]-f|0)/144>>>0){continue}break}}I=wd(i,e)}}$=v- -64|0;return I|0}pa();T()}function hh(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,H=0,I=0,K=0,L=0,M=0,N=0;t=$+-64|0;$=t;D[a+132>>2]=0;if(D[a+148>>2]){d=D[a+144>>2];if(d){while(1){c=D[d>>2];ma(d);d=c;if(d){continue}break}}d=0;D[a+144>>2]=0;c=D[a+140>>2];a:{if(!c){break a}if(c-1>>>0>=3){f=c&-4;while(1){j=d<<2;D[j+D[a+136>>2]>>2]=0;D[D[a+136>>2]+(j|4)>>2]=0;D[D[a+136>>2]+(j|8)>>2]=0;D[D[a+136>>2]+(j|12)>>2]=0;d=d+4|0;k=k+4|0;if((f|0)!=(k|0)){continue}break}}c=c&3;if(!c){break a}k=0;while(1){D[D[a+136>>2]+(d<<2)>>2]=0;d=d+1|0;k=k+1|0;if((c|0)!=(k|0)){continue}break}}D[a+148>>2]=0}b:{if(!Ga(1,t+60|0,D[D[a+4>>2]+32>>2])){break b}D[a+156>>2]=D[t+60>>2];if(!Ga(1,t+56|0,D[D[a+4>>2]+32>>2])){break b}j=D[t+56>>2];if(j>>>0>1431655765|G[a+156>>2]>J(j,3)>>>0){break b}d=D[D[a+4>>2]+32>>2];k=D[d+8>>2];f=D[d+12>>2];c=D[d+20>>2];b=k;k=D[d+16>>2];if((f|0)<=(c|0)&b>>>0<=k>>>0|(c|0)>(f|0)){break b}f=E[k+D[d>>2]|0];k=k+1|0;c=k?c:c+1|0;D[d+16>>2]=k;D[d+20>>2]=c;if(!Ga(1,t+52|0,d)){break b}n=D[t+52>>2];if(n>>>0>j>>>0|j>>>0>n+((n>>>0)/3|0)>>>0){break b}if(!Ga(1,t+48|0,D[D[a+4>>2]+32>>2])){break b}d=D[t+48>>2];if(d>>>0>n>>>0){break b}D[a+28>>2]=D[a+24>>2];k=Wb(na(88));c=D[a+8>>2];D[a+8>>2]=k;if(c){cb(c);if(!D[a+8>>2]){break b}}D[a+164>>2]=D[a+160>>2];Ib(a+160|0,j);D[a+176>>2]=D[a+172>>2];Ib(a+172|0,j);D[a- -64>>2]=0;D[a+92>>2]=-1;D[a+84>>2]=-1;D[a+88>>2]=-1;D[a+40>>2]=D[a+36>>2];D[a+52>>2]=D[a+48>>2];D[a+76>>2]=D[a+72>>2];y=a+216|0;Ad(y);zd(y,f);if(!Yc(D[a+8>>2],j,d+D[a+156>>2]|0)){break b}c=D[a+156>>2];B[t+8|0]=1;Ha(a+120|0,d+c|0,t+8|0);if((yd(a,D[D[a+4>>2]+32>>2])|0)==-1){break b}d=a+232|0;D[d+144>>2]=a;c=D[(ba[D[D[a>>2]+32>>2]](a)|0)+32>>2];j=D[c>>2]+D[c+16>>2]|0;k=D[(ba[D[D[a>>2]+32>>2]](a)|0)+32>>2];c=D[k+8>>2];k=D[k+16>>2];c=c-k|0;M=d,N=F[D[(ba[D[D[a>>2]+32>>2]](a)|0)+32>>2]+38>>1],C[M+38>>1]=N;D[d>>2]=j;D[d+16>>2]=0;D[d+20>>2]=0;D[d+8>>2]=c;D[d+12>>2]=0;D[a+372>>2]=f;H=La(t+8|0);f=H;j=0;g=$-16|0;$=g;c=D[d+4>>2];D[d+40>>2]=D[d>>2];D[d+44>>2]=c;c=D[d+36>>2];D[d+72>>2]=D[d+32>>2];D[d+76>>2]=c;k=D[d+28>>2];c=d- -64|0;D[c>>2]=D[d+24>>2];D[c+4>>2]=k;c=D[d+20>>2];D[d+56>>2]=D[d+16>>2];D[d+60>>2]=c;c=D[d+12>>2];D[d+48>>2]=D[d+8>>2];D[d+52>>2]=c;c:{d:{if(ec(d+40|0,1,g+8|0)){c=D[d+44>>2];D[d>>2]=D[d+40>>2];D[d+4>>2]=c;c=D[d+76>>2];D[d+32>>2]=D[d+72>>2];D[d+36>>2]=c;c=D[d+68>>2];D[d+24>>2]=D[d+64>>2];D[d+28>>2]=c;k=D[d+60>>2];b=k;c=D[d+56>>2];D[d+16>>2]=c;D[d+20>>2]=b;e=D[d+52>>2];k=D[d+48>>2];D[d+8>>2]=k;D[d+12>>2]=e;h=k-c|0;m=D[g+12>>2];e=e-((c>>>0>k>>>0)+b|0)|0;k=D[g+8>>2];if((m|0)==(e|0)&h>>>0>=k>>>0|e>>>0>m>>>0){break d}}break c}b=b+m|0;c=c+k|0;b=c>>>0>>0?b+1|0:b;D[d+16>>2]=c;D[d+20>>2]=b;if(!Da(d+80|0,d)){break c}if(!vd(d)){break c}c=D[d+4>>2];D[f>>2]=D[d>>2];D[f+4>>2]=c;c=D[d+36>>2];D[f+32>>2]=D[d+32>>2];D[f+36>>2]=c;c=D[d+28>>2];D[f+24>>2]=D[d+24>>2];D[f+28>>2]=c;c=D[d+20>>2];D[f+16>>2]=D[d+16>>2];D[f+20>>2]=c;c=D[d+12>>2];D[f+8>>2]=D[d+8>>2];D[f+12>>2]=c;j=1}$=g+16|0;e:{if(!j){break e}e=0;c=0;d=0;j=0;k=0;m=$-96|0;$=m;D[m+72>>2]=0;D[m+64>>2]=0;D[m+68>>2]=0;D[m+48>>2]=0;D[m+52>>2]=0;D[m+40>>2]=0;D[m+44>>2]=0;D[m+56>>2]=1065353216;D[m+32>>2]=0;D[m+24>>2]=0;D[m+28>>2]=0;f=a;z=D[a+124>>2];f:{g:{h:{i:{j:{k:{l:{if((n|0)<=0){break l}I=D[f+216>>2]!=D[f+220>>2];p=1;while(1){g=v;v=g+1|0;m:{n:{o:{p:{q:{r:{s:{t:{u:{v:{w:{x:{if(!E[f+308|0]){break x}y:{z:{h=D[f+296>>2];b=D[f+304>>2];a=h+(b>>>3|0)|0;i=D[f+300>>2];if(a>>>0>=i>>>0){break z}l=E[a|0];a=b+1|0;D[f+304>>2]=a;if(!(l>>>(b&7)&1)){break z}o=a>>>3|0;l=h+o|0;A:{if(l>>>0>=i>>>0){b=a;a=0;break A}l=E[l|0];b=b+2|0;D[f+304>>2]=b;o=b>>>3|0;a=l>>>(a&7)&1}h=h+o|0;if(h>>>0>>0){h=E[h|0];D[f+304>>2]=b+1;b=h>>>(b&7)<<1&2}else{b=0}b=(a|b)<<1;switch(b-1|0){case 0:case 2:case 4:break t;case 5:break w;case 1:case 3:break y;default:break x}}if((d|0)==(c|0)){break k}i=-1;l=D[f+8>>2];o=D[l+24>>2];r=d-4|0;h=D[r>>2];a=-1;B:{if((h|0)==-1){break B}e=h+1|0;e=(e>>>0)%3|0?e:h-2|0;a=-1;if((e|0)==-1){break B}a=D[D[l>>2]+(e<<2)>>2]}b=D[o+(a<<2)>>2];if((b|0)!=-1){e=b+1|0;i=(e>>>0)%3|0?e:b-2|0}b=D[l+12>>2];g=J(g,3);e=g+1|0;D[b+(h<<2)>>2]=e;s=e<<2;D[s+b>>2]=h;p=g+2|0;D[b+(i<<2)>>2]=p;u=p<<2;D[u+b>>2]=i;e=-1;b=-1;C:{if((h|0)==-1){break C}D:{if((h>>>0)%3|0){h=h-1|0;break D}h=h+2|0;b=-1;if((h|0)==-1){break C}}b=D[D[l>>2]+(h<<2)>>2]}E:{if((i|0)==-1){break E}h=i+1|0;h=(h>>>0)%3|0?h:i-2|0;if((h|0)==-1){break E}e=D[D[l>>2]+(h<<2)>>2]}h=-1;if((a|0)==(b|0)|(a|0)==(e|0)){break j}h=D[l>>2];D[h+(g<<2)>>2]=a;D[h+s>>2]=e;D[h+u>>2]=b;if((b|0)!=-1){D[o+(b<<2)>>2]=p}b=D[f+120>>2]+(a>>>3&536870908)|0;e=D[b>>2];M=b,N=ji(a)&e,D[M>>2]=N;D[r>>2]=g;e=c;break m}if((d|0)==(c|0)){break k}a=D[f+8>>2];e=D[a+12>>2];i=J(g,3);o=(b|1)==5;r=i+(o?2:1)|0;s=r<<2;u=d-4|0;b=D[u>>2];D[e+s>>2]=b;D[e+(b<<2)>>2]=r;Ua(a+24|0);h=-1;e=D[f+8>>2];l=D[e+24>>2];if((z|0)>2]-l>>2){break j}e=D[e>>2];K=e+s|0;h=D[a+28>>2];a=D[a+24>>2];s=(h-a>>2)-1|0;D[K>>2]=s;if((a|0)!=(h|0)){D[l+(s<<2)>>2]=r}h=o?i:i+2|0;o=e+(i+o<<2)|0;F:{if((b|0)==-1){D[e+(h<<2)>>2]=-1;a=-1;break F}G:{H:{I:{if((b>>>0)%3|0){a=b-1|0;break I}a=b+2|0;if((a|0)==-1){break H}}a=D[e+(a<<2)>>2];D[e+(h<<2)>>2]=a;if((a|0)==-1){break G}D[l+(a<<2)>>2]=h;break G}D[e+(h<<2)>>2]=-1}h=b+1|0;b=(h>>>0)%3|0?h:b-2|0;a=-1;if((b|0)==-1){break F}a=D[e+(b<<2)>>2]}D[o>>2]=a;D[u>>2]=i;e=c;break v}if((d|0)==(c|0)){break k}a=d-4|0;i=D[a>>2];D[m+68>>2]=a;l=D[m+44>>2];J:{if(!l){d=a;break J}e=D[m+40>>2];o=ii(l)>>>0>1;b=g&l+2147483647;K:{if(!o){break K}b=g;if(b>>>0>>0){break K}b=(g>>>0)%(l>>>0)|0}h=b;b=D[e+(h<<2)>>2];if(!b){d=a;break J}b=D[b>>2];if(!b){d=a;break J}L:{if(!o){e=l-1|0;while(1){l=D[b+4>>2];M:{if((l|0)!=(g|0)){if((h|0)==(e&l)){break M}d=a;break J}if((g|0)==D[b+8>>2]){break L}}b=D[b>>2];if(b){continue}break}d=a;break J}while(1){e=D[b+4>>2];N:{if((e|0)!=(g|0)){if(e>>>0>=l>>>0){e=(e>>>0)%(l>>>0)|0}if((e|0)==(h|0)){break N}d=a;break J}if((g|0)==D[b+8>>2]){break L}}b=D[b>>2];if(b){continue}break}d=a;break J}if((a|0)!=(q|0)){D[a>>2]=D[b+12>>2];D[m+68>>2]=d;break J}a=q-c|0;e=a>>2;d=e+1|0;if(d>>>0>=1073741824){break s}j=a>>1;d=a>>>0<2147483644?d>>>0>>0?j:d:1073741823;if(d){if(d>>>0>=1073741824){break i}j=na(d<<2)}else{j=0}e=j+(e<<2)|0;D[e>>2]=D[b+12>>2];q=(d<<2)+j|0;d=e+4|0;if((a|0)>0){oa(j,c,a)}D[m+72>>2]=q;D[m+68>>2]=d;D[m+64>>2]=j;if(!c){break J}ma(c)}if((d|0)==(j|0)){break u}r=d-4|0;b=D[r>>2];a=(b|0)==-1;e=D[f+8>>2];if(!a&D[D[e+12>>2]+(b<<2)>>2]!=-1){break u}h=D[e+12>>2];if((i|0)!=-1&D[h+(i<<2)>>2]!=-1){break u}p=J(g,3);o=p+2|0;D[h+(b<<2)>>2]=o;g=o<<2;D[g+h>>2]=b;c=p+1|0;D[h+(i<<2)>>2]=c;s=c<<2;D[s+h>>2]=i;if(a){break r}if((b>>>0)%3|0){a=b-1|0;break p}a=b+2|0;if((a|0)!=-1){break p}c=D[e>>2];a=-1;break o}i=D[f+8>>2];Ua(i+24|0);h=-1;b=D[f+8>>2];a=J(g,3);l=D[i+28>>2];o=D[i+24>>2];r=l-o|0;i=r>>2;s=i-1|0;D[D[b>>2]+(a<<2)>>2]=s;Ua(b+24|0);u=a+1|0;D[D[b>>2]+(u<<2)>>2]=(D[b+28>>2]-D[b+24>>2]>>2)-1;b=D[f+8>>2];Ua(b+24|0);K=a+2|0;D[D[b>>2]+(K<<2)>>2]=(D[b+28>>2]-D[b+24>>2]>>2)-1;L=D[f+8>>2];b=D[L+24>>2];if((z|0)>2]-b>>2){break j}O:{P:{if((l|0)!=(o|0)){D[b+(s<<2)>>2]=a;h=0;if((r|0)==-4){break P}}D[b+(i<<2)>>2]=u;h=i+1|0;if((h|0)==-1){break O}}D[b+(h<<2)>>2]=K}if((d|0)!=(q|0)){D[d>>2]=a;d=d+4|0;D[m+68>>2]=d;break v}c=d-e|0;b=c>>2;d=b+1|0;if(d>>>0>=1073741824){break q}j=c>>1;d=c>>>0<2147483644?d>>>0>>0?j:d:1073741823;if(d){if(d>>>0>=1073741824){break i}j=na(d<<2)}else{j=0}b=j+(b<<2)|0;D[b>>2]=a;q=(d<<2)+j|0;d=b+4|0;if((c|0)>0){oa(j,e,c)}D[m+72>>2]=q;D[m+68>>2]=d;D[m+64>>2]=j;if(e){ma(e)}c=j;e=c}b=D[f+40>>2];if((b|0)==D[f+36>>2]){break m}g=n+(g^-1)|0;h=d-4|0;while(1){a=b-12|0;i=D[a+4>>2];if(i>>>0>g>>>0){break u}if((g|0)!=(i|0)){break m}i=E[b-4|0];b=D[a>>2];D[f+40>>2]=a;if((b|0)<0){break u}a=D[h>>2];D[m+20>>2]=n+(b^-1);b=m+20|0;D[m+88>>2]=b;ud(m,m+40|0,b,m+88|0);l=D[m>>2];Q:{if(i&1){b=-1;if((a|0)==-1){break Q}b=a+1|0;b=(b>>>0)%3|0?b:a-2|0;break Q}b=-1;if((a|0)==-1){break Q}b=a-1|0;if((a>>>0)%3|0){break Q}b=a+2|0}D[l+12>>2]=b;b=D[f+40>>2];if((b|0)!=D[f+36>>2]){continue}break}break m}h=-1;if(p&1){break j}break l}T()}pa();T()}a=-1;c=D[e>>2];D[c+(p<<2)>>2]=-1;l=-1;break n}pa();T()}c=D[e>>2];a=D[c+(a<<2)>>2]}D[(p<<2)+c>>2]=a;u=b+1|0;b=(u>>>0)%3|0?u:b-2|0;l=-1;if((b|0)==-1){break n}l=D[(b<<2)+c>>2]}D[c+s>>2]=l;R:{if((i|0)==-1){D[c+g>>2]=-1;l=-1;b=-1;break R}S:{T:{U:{if((i>>>0)%3|0){b=i-1|0;break U}b=i+2|0;if((b|0)==-1){break T}}b=D[(b<<2)+c>>2];D[c+g>>2]=b;if((b|0)==-1){break S}D[D[e+24>>2]+(b<<2)>>2]=o;break S}D[c+g>>2]=-1}l=-1;g=i+1|0;g=(g>>>0)%3|0?g:i-2|0;b=-1;if((g|0)==-1){break R}l=D[(g<<2)+c>>2];b=g}e=D[e+24>>2];g=e+(l<<2)|0;if((a|0)!=-1){D[e+(a<<2)>>2]=D[g>>2]}V:{if((b|0)==-1){break V}while(1){D[(b<<2)+c>>2]=a;e=b+1|0;b=(e>>>0)%3|0?e:b-2|0;if((b|0)==-1){break V}b=D[h+(b<<2)>>2];if((b|0)==-1){break V}e=b+1|0;b=(e>>>0)%3|0?e:b-2|0;if((b|0)!=-1){continue}break}}D[g>>2]=-1;W:{if(I){break W}if((w|0)!=(x|0)){D[w>>2]=l;w=w+4|0;D[m+28>>2]=w;break W}c=x-k|0;g=c>>2;a=g+1|0;if(a>>>0<1073741824){b=c>>1;b=c>>>0<2147483644?a>>>0>>0?b:a:1073741823;if(b){if(b>>>0>=1073741824){break i}a=na(b<<2)}else{a=0}g=a+(g<<2)|0;D[g>>2]=l;x=a+(b<<2)|0;w=g+4|0;if((c|0)>0){oa(a,k,c)}D[m+32>>2]=x;D[m+28>>2]=w;D[m+24>>2]=a;if(k){ma(k)}k=a;break W}pa();T()}D[r>>2]=p;c=j;e=c}p=(n|0)>(v|0);if((n|0)!=(v|0)){continue}break}v=n}h=-1;i=D[f+8>>2];if((z|0)>2]-D[i+24>>2]>>2){break j}if((d|0)!=(j|0)){a=f+60|0;z=f+312|0;while(1){d=d-4|0;n=D[d>>2];D[m+68>>2]=d;X:{if(za(z)){q=D[f+8>>2];l=D[q>>2];if(((D[q+4>>2]-l>>2>>>0)/3|0)<=(v|0)){break k}c=-1;i=-1;g=D[q+24>>2];b=-1;Y:{if((n|0)==-1){break Y}e=n+1|0;e=(e>>>0)%3|0?e:n-2|0;b=-1;if((e|0)==-1){break Y}b=D[l+(e<<2)>>2]}e=b;b=D[g+(e<<2)>>2];Z:{if((b|0)==-1){break Z}p=b+1|0;b=(p>>>0)%3|0?p:b-2|0;if((b|0)==-1){break Z}c=b+1|0;c=(c>>>0)%3|0?c:b-2|0;if((c|0)!=-1){i=D[l+(c<<2)>>2]}c=b}p=-1;o=-1;g=D[g+(i<<2)>>2];b=-1;_:{if((g|0)==-1){break _}x=g+1|0;g=(x>>>0)%3|0?x:g-2|0;b=-1;if((g|0)==-1){break _}b=g+1|0;b=(b>>>0)%3|0?b:g-2|0;if((b|0)!=-1){o=D[l+(b<<2)>>2]}b=g}g=D[q+12>>2];q=J(v,3);x=q<<2;D[g+x>>2]=n;D[g+(n<<2)>>2]=q;n=q+1|0;r=n<<2;D[r+g>>2]=c;D[g+(c<<2)>>2]=n;c=q+2|0;I=c<<2;D[I+g>>2]=b;D[g+(b<<2)>>2]=c;D[l+x>>2]=i;b=l+r|0;D[b>>2]=o;l=l+I|0;D[l>>2]=e;g=D[f+120>>2];e=n?i:-1;i=g+(e>>>3&536870908)|0;o=D[i>>2];M=i,N=ji(e)&o,D[M>>2]=N;p=(n|0)!=-1?D[b>>2]:p;b=g+(p>>>3&536870908)|0;e=D[b>>2];M=b,N=ji(p)&e,D[M>>2]=N;b=-1;b=(c|0)!=-1?D[l>>2]:b;c=g+(b>>>3&536870908)|0;g=D[c>>2];M=c,N=ji(b)&g,D[M>>2]=N;b=D[f+64>>2];c=D[f+68>>2];if((b|0)==c<<5){if((b+1|0)<0){break h}if(b>>>0<=1073741822){c=c<<6;b=b+32&-32;c=b>>>0>>0?c:b}else{c=2147483647}Xa(a,c);b=D[f+64>>2]}v=v+1|0;D[f+64>>2]=b+1;c=D[f+60>>2]+(b>>>3&536870908)|0;D[c>>2]=D[c>>2]|1<>2];if((c|0)!=D[f+80>>2]){D[c>>2]=q;D[f+76>>2]=c+4;break X}g=D[f+72>>2];b=c-g|0;n=b>>2;c=n+1|0;if(c>>>0>=1073741824){break g}e=b>>1;e=b>>>0<2147483644?c>>>0>>0?e:c:1073741823;if(e){if(e>>>0>=1073741824){break i}c=na(e<<2)}else{c=0}n=c+(n<<2)|0;D[n>>2]=q;if((b|0)>0){oa(c,g,b)}D[f+80>>2]=c+(e<<2);D[f+76>>2]=n+4;D[f+72>>2]=c;if(!g){break X}ma(g);break X}c=D[f+64>>2];b=D[f+68>>2];if((c|0)==b<<5){if((c+1|0)<0){break h}if(c>>>0<=1073741822){b=b<<6;c=c+32&-32;c=b>>>0>c>>>0?b:c}else{c=2147483647}Xa(a,c);c=D[f+64>>2]}D[f+64>>2]=c+1;b=D[f+60>>2]+(c>>>3&536870908)|0;g=D[b>>2];M=b,N=ji(c)&g,D[M>>2]=N;c=D[f+76>>2];if((c|0)!=D[f+80>>2]){D[c>>2]=n;D[f+76>>2]=c+4;break X}g=D[f+72>>2];b=c-g|0;i=b>>2;c=i+1|0;if(c>>>0>=1073741824){break g}e=b>>1;e=b>>>0<2147483644?c>>>0>>0?e:c:1073741823;if(e){if(e>>>0>=1073741824){break i}c=na(e<<2)}else{c=0}i=c+(i<<2)|0;D[i>>2]=n;if((b|0)>0){oa(c,g,b)}D[f+80>>2]=c+(e<<2);D[f+76>>2]=i+4;D[f+72>>2]=c;if(!g){break X}ma(g)}if((d|0)!=(j|0)){continue}break}i=D[f+8>>2]}if(((D[i+4>>2]-D[i>>2]>>2>>>0)/3|0)!=(v|0)){break j}h=D[i+28>>2]-D[i+24>>2]>>2;if((k|0)==(w|0)){k=w;break j}a=k;while(1){c=D[a>>2];g=D[i+24>>2];b=h-1|0;d=g+(b<<2)|0;if(D[d>>2]==-1){while(1){b=h-2|0;h=h-1|0;d=g+(b<<2)|0;if(D[d>>2]==-1){continue}break}}if(b>>>0>=c>>>0){D[m>>2]=i;d=D[d>>2];B[m+12|0]=1;D[m+8>>2]=d;D[m+4>>2]=d;if((d|0)!=-1){while(1){d=D[D[f+8>>2]>>2]+(d<<2)|0;if(D[d>>2]!=(b|0)){break k}D[d>>2]=c;kc(m);d=D[m+8>>2];if((d|0)!=-1){continue}break}i=D[f+8>>2]}g=D[i+24>>2];d=g+(b<<2)|0;if((c|0)!=-1){D[g+(c<<2)>>2]=D[d>>2]}D[d>>2]=-1;d=1<>2];c=g+(c>>>3&536870908)|0;g=g+(b>>>3&536870908)|0;b=1<>2]&b){d=d|D[c>>2]}else{d=D[c>>2]&(d^-1)}D[c>>2]=d;D[g>>2]=D[g>>2]&(b^-1);h=h-1|0}a=a+4|0;if((w|0)!=(a|0)){continue}break}break j}h=-1}if(k){ma(k)}a=D[m+48>>2];if(a){while(1){d=D[a>>2];ma(a);a=d;if(a){continue}break}}a=D[m+40>>2];D[m+40>>2]=0;if(a){ma(a)}if(j){D[m+68>>2]=j;ma(j)}$=m+96|0;a=h;break f}sa();T()}pa();T()}pa();T()}c=a;if((a|0)==-1){break e}a=D[H+16>>2];d=a+D[H>>2]|0;j=D[H+8>>2];j=j-a|0;a=D[D[f+4>>2]+32>>2];C[a+38>>1]=F[a+38>>1];D[a>>2]=d;D[a+16>>2]=0;D[a+20>>2]=0;D[a+8>>2]=j;D[a+12>>2]=0;$:{if(D[f+216>>2]==D[f+220>>2]){break $}a=D[f+8>>2];if(D[a+4>>2]==D[a>>2]){break $}d=0;while(1){if(xd(f,d)){d=d+3|0;a=D[f+8>>2];if(d>>>0>2]-D[a>>2]>>2>>>0){continue}break $}break}break e}if(E[f+308|0]){B[f+308|0]=0;d=D[f+292>>2];a=0;j=D[f+304>>2]+7|0;a=j>>>0<7?1:a;k=a>>>3|0;j=a<<29|j>>>3;a=j+D[f+288>>2]|0;b=d+k|0;D[f+288>>2]=a;D[f+292>>2]=a>>>0>>0?b+1|0:b}d=D[f+216>>2];if((d|0)!=D[f+220>>2]){while(1){j=J(A,144);Xc((j+d|0)+4|0,D[f+8>>2]);a=D[y>>2];k=a+j|0;d=D[k+132>>2];k=D[k+136>>2];if((d|0)!=(k|0)){while(1){Vc((j+D[y>>2]|0)+4|0,D[d>>2]);d=d+4|0;if((k|0)!=(d|0)){continue}break}a=D[y>>2]}Wc((a+j|0)+4|0);A=A+1|0;d=D[f+216>>2];if(A>>>0<(D[f+220>>2]-d|0)/144>>>0){continue}break}}a=D[f+8>>2];Hb(f+184|0,D[a+28>>2]-D[a+24>>2]>>2);k=D[f+216>>2];if((k|0)!=D[f+220>>2]){d=0;while(1){a=J(d,144)+k|0;j=D[a+60>>2]-D[a+56>>2]>>2;b=a+104|0;a=D[f+8>>2];a=D[a+28>>2]-D[a+24>>2]>>2;Hb(b,(a|0)<(j|0)?j:a);d=d+1|0;k=D[f+216>>2];if(d>>>0<(D[f+220>>2]-k|0)/144>>>0){continue}break}}A=wd(f,c)}}$=t- -64|0;return A|0}function of(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;a:{b:{c:{d:{switch(d-1|0){case 0:a=0;m=$-16|0;$=m;j=D[b+80>>2];d=B[c+24|0];e:{if((J(j,d)|0)!=(e|0)){break e}a=D[c+28>>2]!=1;k=E[c+84|0];if(!(a|!k)){oa(f,D[D[c>>2]>>2]+D[c+48>>2]|0,e);a=1;break e}D[m+8>>2]=0;D[m>>2]=0;D[m+4>>2]=0;if(d){if((d|0)<0){break c}h=na(d);D[m>>2]=h;qa(h,0,d)}f:{g:{if(!j){break g}if(!a){if(d){n=d&-4;l=d&3;b=0;o=d-1>>>0<3;d=0;while(1){e=D[D[c>>2]>>2];t=D[c+40>>2];a=D[c+48>>2]+fi(t,D[c+44>>2],E[c+84|0]?d:D[D[c+68>>2]+(d<<2)>>2],0)|0;e=oa(h,e+a|0,t);k=0;a=0;g=0;if(!o){while(1){i=b+f|0;B[i|0]=E[a+e|0];B[i+1|0]=E[e+(a|1)|0];B[i+2|0]=E[e+(a|2)|0];B[i+3|0]=E[e+(a|3)|0];a=a+4|0;b=b+4|0;g=g+4|0;if((n|0)!=(g|0)){continue}break}}if(l){while(1){B[b+f|0]=E[a+e|0];a=a+1|0;b=b+1|0;k=k+1|0;if((l|0)!=(k|0)){continue}break}}a=1;d=d+1|0;if((j|0)!=(d|0)){continue}break}break f}l=D[c>>2];b=D[c+48>>2];o=D[c+68>>2];d=D[c+44>>2];c=D[c+40>>2];t=c;a=0;if((j|0)!=1){q=j&-2;while(1){e=a|1;p=D[l>>2];f=fi(c,d,k?a:D[o+(a<<2)>>2],0)+b|0;f=oa(h,p+f|0,t);p=D[l>>2];if(!k){e=D[o+(e<<2)>>2]}e=fi(c,d,e,0)+b|0;oa(f,e+p|0,t);a=a+2|0;g=g+2|0;if((q|0)!=(g|0)){continue}break}}if(!(j&1)){break g}e=D[l>>2];if(!k){a=D[o+(a<<2)>>2]}a=fi(c,d,a,0)+b|0;oa(h,a+e|0,t);break g}if(!d){a=0;i=1;while(1){if(!Db(c,E[c+84|0]?a:D[D[c+68>>2]+(a<<2)>>2],B[c+24|0],h)){break g}a=a+1|0;i=j>>>0>a>>>0;if((a|0)!=(j|0)){continue}break}break g}l=d&-4;g=d&3;b=0;n=d-1>>>0<3;i=1;d=0;while(1){if(!Db(c,E[c+84|0]?d:D[D[c+68>>2]+(d<<2)>>2],B[c+24|0],h)){break g}i=0;a=0;k=0;if(!n){while(1){e=b+f|0;B[e|0]=E[a+h|0];B[e+1|0]=E[(a|1)+h|0];B[e+2|0]=E[(a|2)+h|0];B[e+3|0]=E[(a|3)+h|0];a=a+4|0;b=b+4|0;k=k+4|0;if((l|0)!=(k|0)){continue}break}}if(g){while(1){B[b+f|0]=E[a+h|0];a=a+1|0;b=b+1|0;i=i+1|0;if((g|0)!=(i|0)){continue}break}}d=d+1|0;i=j>>>0>d>>>0;if((d|0)!=(j|0)){continue}break}a=d>>>0>=j>>>0;break f}a=i^1;if(!h){break e}}ma(h)}break b;case 2:a=0;m=$-16|0;$=m;g=B[c+24|0];d=g<<1;l=D[b+80>>2];h:{if((J(d,l)|0)!=(e|0)){break h}b=D[c+28>>2]!=3;n=E[c+84|0];if(!(b|!n)){oa(f,D[D[c>>2]>>2]+D[c+48>>2]|0,e);a=1;break h}D[m+8>>2]=0;D[m>>2]=0;D[m+4>>2]=0;if(g){if((g|0)<0){break c}h=na(d);D[m>>2]=h;qa(h,0,d)}i:{j:{if(!l){break j}if(!b){o=D[c>>2];e=D[c+48>>2];q=D[c+68>>2];j=D[c+44>>2];k=D[c+40>>2];p=k;if(g){v=g&-4;u=g&3;d=0;w=g-1>>>0<3;b=0;while(1){c=D[o>>2];a=fi(k,j,n?b:D[q+(b<<2)>>2],0)+e|0;g=oa(h,c+a|0,p);i=0;a=0;c=0;if(!w){while(1){r=(d<<1)+f|0;s=a<<1;C[r>>1]=F[s+g>>1];C[r+2>>1]=F[g+(s|2)>>1];C[r+4>>1]=F[g+(s|4)>>1];C[r+6>>1]=F[g+(s|6)>>1];a=a+4|0;d=d+4|0;c=c+4|0;if((v|0)!=(c|0)){continue}break}}if(u){while(1){C[(d<<1)+f>>1]=F[g+(a<<1)>>1];a=a+1|0;d=d+1|0;i=i+1|0;if((u|0)!=(i|0)){continue}break}}a=1;b=b+1|0;if((l|0)!=(b|0)){continue}break}break i}if((l|0)!=1){d=l&-2;g=0;while(1){b=a|1;f=D[o>>2];c=fi(k,j,n?a:D[q+(a<<2)>>2],0)+e|0;c=oa(h,f+c|0,p);f=D[o>>2];if(!n){b=D[q+(b<<2)>>2]}b=fi(k,j,b,0)+e|0;oa(c,b+f|0,p);a=a+2|0;g=g+2|0;if((d|0)!=(g|0)){continue}break}}if(!(l&1)){break j}b=D[o>>2];if(!n){a=D[q+(a<<2)>>2]}a=fi(k,j,a,0)+e|0;oa(h,a+b|0,p);break j}if(!g){i=1;while(1){if(!Bb(c,E[c+84|0]?a:D[D[c+68>>2]+(a<<2)>>2],B[c+24|0],h)){break j}a=a+1|0;i=l>>>0>a>>>0;if((a|0)!=(l|0)){continue}break}break j}n=g&-4;k=g&3;d=0;o=g-1>>>0<3;i=1;b=0;while(1){if(!Bb(c,E[c+84|0]?b:D[D[c+68>>2]+(b<<2)>>2],B[c+24|0],h)){break j}g=0;a=0;i=0;if(!o){while(1){e=(d<<1)+f|0;j=a<<1;C[e>>1]=F[j+h>>1];C[e+2>>1]=F[(j|2)+h>>1];C[e+4>>1]=F[(j|4)+h>>1];C[e+6>>1]=F[(j|6)+h>>1];a=a+4|0;d=d+4|0;i=i+4|0;if((n|0)!=(i|0)){continue}break}}if(k){while(1){C[(d<<1)+f>>1]=F[(a<<1)+h>>1];a=a+1|0;d=d+1|0;g=g+1|0;if((k|0)!=(g|0)){continue}break}}b=b+1|0;i=l>>>0>b>>>0;if((b|0)!=(l|0)){continue}break}a=b>>>0>=l>>>0;break i}a=!i;if(!h){break h}}ma(h)}break b;case 4:a=0;m=$-16|0;$=m;g=B[c+24|0];d=g<<2;l=D[b+80>>2];k:{if((J(d,l)|0)!=(e|0)){break k}b=D[c+28>>2]!=5;n=E[c+84|0];if(!(b|!n)){oa(f,D[D[c>>2]>>2]+D[c+48>>2]|0,e);a=1;break k}D[m+8>>2]=0;D[m>>2]=0;D[m+4>>2]=0;if(g){if((g|0)<0){break c}h=na(d);D[m>>2]=h;qa(h,0,d)}l:{m:{if(!l){break m}if(!b){o=D[c>>2];e=D[c+48>>2];q=D[c+68>>2];j=D[c+44>>2];k=D[c+40>>2];p=k;if(g){v=g&-4;u=g&3;d=0;w=g-1>>>0<3;b=0;while(1){c=D[o>>2];a=fi(k,j,n?b:D[q+(b<<2)>>2],0)+e|0;g=oa(h,c+a|0,p);i=0;a=0;c=0;if(!w){while(1){r=(d<<2)+f|0;s=a<<2;D[r>>2]=D[s+g>>2];D[r+4>>2]=D[g+(s|4)>>2];D[r+8>>2]=D[g+(s|8)>>2];D[r+12>>2]=D[g+(s|12)>>2];a=a+4|0;d=d+4|0;c=c+4|0;if((v|0)!=(c|0)){continue}break}}if(u){while(1){D[(d<<2)+f>>2]=D[g+(a<<2)>>2];a=a+1|0;d=d+1|0;i=i+1|0;if((u|0)!=(i|0)){continue}break}}a=1;b=b+1|0;if((l|0)!=(b|0)){continue}break}break l}if((l|0)!=1){d=l&-2;g=0;while(1){b=a|1;f=D[o>>2];c=fi(k,j,n?a:D[q+(a<<2)>>2],0)+e|0;c=oa(h,f+c|0,p);f=D[o>>2];if(!n){b=D[q+(b<<2)>>2]}b=fi(k,j,b,0)+e|0;oa(c,b+f|0,p);a=a+2|0;g=g+2|0;if((d|0)!=(g|0)){continue}break}}if(!(l&1)){break m}b=D[o>>2];if(!n){a=D[q+(a<<2)>>2]}a=fi(k,j,a,0)+e|0;oa(h,a+b|0,p);break m}if(!g){i=1;while(1){if(!zb(c,E[c+84|0]?a:D[D[c+68>>2]+(a<<2)>>2],B[c+24|0],h)){break m}a=a+1|0;i=l>>>0>a>>>0;if((a|0)!=(l|0)){continue}break}break m}n=g&-4;k=g&3;d=0;o=g-1>>>0<3;i=1;b=0;while(1){if(!zb(c,E[c+84|0]?b:D[D[c+68>>2]+(b<<2)>>2],B[c+24|0],h)){break m}g=0;a=0;i=0;if(!o){while(1){e=(d<<2)+f|0;j=a<<2;D[e>>2]=D[j+h>>2];D[e+4>>2]=D[(j|4)+h>>2];D[e+8>>2]=D[(j|8)+h>>2];D[e+12>>2]=D[(j|12)+h>>2];a=a+4|0;d=d+4|0;i=i+4|0;if((n|0)!=(i|0)){continue}break}}if(k){while(1){D[(d<<2)+f>>2]=D[(a<<2)+h>>2];a=a+1|0;d=d+1|0;g=g+1|0;if((k|0)!=(g|0)){continue}break}}b=b+1|0;i=l>>>0>b>>>0;if((b|0)!=(l|0)){continue}break}a=b>>>0>=l>>>0;break l}a=!i;if(!h){break k}}ma(h)}break b;case 1:a=0;m=$-16|0;$=m;j=D[b+80>>2];d=B[c+24|0];n:{if((J(j,d)|0)!=(e|0)){break n}a=D[c+28>>2]!=2;k=E[c+84|0];if(!(a|!k)){oa(f,D[D[c>>2]>>2]+D[c+48>>2]|0,e);a=1;break n}D[m+8>>2]=0;D[m>>2]=0;D[m+4>>2]=0;if(d){if((d|0)<0){break c}h=na(d);D[m>>2]=h;qa(h,0,d)}o:{p:{if(!j){break p}if(!a){if(d){n=d&-4;l=d&3;b=0;o=d-1>>>0<3;d=0;while(1){e=D[D[c>>2]>>2];t=D[c+40>>2];a=D[c+48>>2]+fi(t,D[c+44>>2],E[c+84|0]?d:D[D[c+68>>2]+(d<<2)>>2],0)|0;e=oa(h,e+a|0,t);k=0;a=0;g=0;if(!o){while(1){i=b+f|0;B[i|0]=E[a+e|0];B[i+1|0]=E[e+(a|1)|0];B[i+2|0]=E[e+(a|2)|0];B[i+3|0]=E[e+(a|3)|0];a=a+4|0;b=b+4|0;g=g+4|0;if((n|0)!=(g|0)){continue}break}}if(l){while(1){B[b+f|0]=E[a+e|0];a=a+1|0;b=b+1|0;k=k+1|0;if((l|0)!=(k|0)){continue}break}}a=1;d=d+1|0;if((j|0)!=(d|0)){continue}break}break o}l=D[c>>2];b=D[c+48>>2];o=D[c+68>>2];d=D[c+44>>2];c=D[c+40>>2];t=c;a=0;if((j|0)!=1){q=j&-2;while(1){e=a|1;p=D[l>>2];f=fi(c,d,k?a:D[o+(a<<2)>>2],0)+b|0;f=oa(h,p+f|0,t);p=D[l>>2];if(!k){e=D[o+(e<<2)>>2]}e=fi(c,d,e,0)+b|0;oa(f,e+p|0,t);a=a+2|0;g=g+2|0;if((q|0)!=(g|0)){continue}break}}if(!(j&1)){break p}e=D[l>>2];if(!k){a=D[o+(a<<2)>>2]}a=fi(c,d,a,0)+b|0;oa(h,a+e|0,t);break p}if(!d){a=0;i=1;while(1){if(!Cb(c,E[c+84|0]?a:D[D[c+68>>2]+(a<<2)>>2],B[c+24|0],h)){break p}a=a+1|0;i=j>>>0>a>>>0;if((a|0)!=(j|0)){continue}break}break p}l=d&-4;g=d&3;b=0;n=d-1>>>0<3;i=1;d=0;while(1){if(!Cb(c,E[c+84|0]?d:D[D[c+68>>2]+(d<<2)>>2],B[c+24|0],h)){break p}i=0;a=0;k=0;if(!n){while(1){e=b+f|0;B[e|0]=E[a+h|0];B[e+1|0]=E[(a|1)+h|0];B[e+2|0]=E[(a|2)+h|0];B[e+3|0]=E[(a|3)+h|0];a=a+4|0;b=b+4|0;k=k+4|0;if((l|0)!=(k|0)){continue}break}}if(g){while(1){B[b+f|0]=E[a+h|0];a=a+1|0;b=b+1|0;i=i+1|0;if((g|0)!=(i|0)){continue}break}}d=d+1|0;i=j>>>0>d>>>0;if((d|0)!=(j|0)){continue}break}a=d>>>0>=j>>>0;break o}a=i^1;if(!h){break n}}ma(h)}break b;case 3:a=0;m=$-16|0;$=m;g=B[c+24|0];d=g<<1;l=D[b+80>>2];q:{if((J(d,l)|0)!=(e|0)){break q}b=D[c+28>>2]!=4;n=E[c+84|0];if(!(b|!n)){oa(f,D[D[c>>2]>>2]+D[c+48>>2]|0,e);a=1;break q}D[m+8>>2]=0;D[m>>2]=0;D[m+4>>2]=0;if(g){if((g|0)<0){break c}h=na(d);D[m>>2]=h;qa(h,0,d)}r:{s:{if(!l){break s}if(!b){o=D[c>>2];e=D[c+48>>2];q=D[c+68>>2];j=D[c+44>>2];k=D[c+40>>2];p=k;if(g){v=g&-4;u=g&3;d=0;w=g-1>>>0<3;b=0;while(1){c=D[o>>2];a=fi(k,j,n?b:D[q+(b<<2)>>2],0)+e|0;g=oa(h,c+a|0,p);i=0;a=0;c=0;if(!w){while(1){r=(d<<1)+f|0;s=a<<1;C[r>>1]=F[s+g>>1];C[r+2>>1]=F[g+(s|2)>>1];C[r+4>>1]=F[g+(s|4)>>1];C[r+6>>1]=F[g+(s|6)>>1];a=a+4|0;d=d+4|0;c=c+4|0;if((v|0)!=(c|0)){continue}break}}if(u){while(1){C[(d<<1)+f>>1]=F[g+(a<<1)>>1];a=a+1|0;d=d+1|0;i=i+1|0;if((u|0)!=(i|0)){continue}break}}a=1;b=b+1|0;if((l|0)!=(b|0)){continue}break}break r}if((l|0)!=1){d=l&-2;g=0;while(1){b=a|1;f=D[o>>2];c=fi(k,j,n?a:D[q+(a<<2)>>2],0)+e|0;c=oa(h,f+c|0,p);f=D[o>>2];if(!n){b=D[q+(b<<2)>>2]}b=fi(k,j,b,0)+e|0;oa(c,b+f|0,p);a=a+2|0;g=g+2|0;if((d|0)!=(g|0)){continue}break}}if(!(l&1)){break s}b=D[o>>2];if(!n){a=D[q+(a<<2)>>2]}a=fi(k,j,a,0)+e|0;oa(h,a+b|0,p);break s}if(!g){i=1;while(1){if(!Ab(c,E[c+84|0]?a:D[D[c+68>>2]+(a<<2)>>2],B[c+24|0],h)){break s}a=a+1|0;i=l>>>0>a>>>0;if((a|0)!=(l|0)){continue}break}break s}n=g&-4;k=g&3;d=0;o=g-1>>>0<3;i=1;b=0;while(1){if(!Ab(c,E[c+84|0]?b:D[D[c+68>>2]+(b<<2)>>2],B[c+24|0],h)){break s}g=0;a=0;i=0;if(!o){while(1){e=(d<<1)+f|0;j=a<<1;C[e>>1]=F[j+h>>1];C[e+2>>1]=F[(j|2)+h>>1];C[e+4>>1]=F[(j|4)+h>>1];C[e+6>>1]=F[(j|6)+h>>1];a=a+4|0;d=d+4|0;i=i+4|0;if((n|0)!=(i|0)){continue}break}}if(k){while(1){C[(d<<1)+f>>1]=F[(a<<1)+h>>1];a=a+1|0;d=d+1|0;g=g+1|0;if((k|0)!=(g|0)){continue}break}}b=b+1|0;i=l>>>0>b>>>0;if((b|0)!=(l|0)){continue}break}a=b>>>0>=l>>>0;break r}a=!i;if(!h){break q}}ma(h)}break b;case 5:a=0;m=$-16|0;$=m;g=B[c+24|0];d=g<<2;l=D[b+80>>2];t:{if((J(d,l)|0)!=(e|0)){break t}b=D[c+28>>2]!=6;n=E[c+84|0];if(!(b|!n)){oa(f,D[D[c>>2]>>2]+D[c+48>>2]|0,e);a=1;break t}D[m+8>>2]=0;D[m>>2]=0;D[m+4>>2]=0;if(g){if((g|0)<0){break c}h=na(d);D[m>>2]=h;qa(h,0,d)}u:{v:{if(!l){break v}if(!b){o=D[c>>2];e=D[c+48>>2];q=D[c+68>>2];j=D[c+44>>2];k=D[c+40>>2];p=k;if(g){v=g&-4;u=g&3;d=0;w=g-1>>>0<3;b=0;while(1){c=D[o>>2];a=fi(k,j,n?b:D[q+(b<<2)>>2],0)+e|0;g=oa(h,c+a|0,p);i=0;a=0;c=0;if(!w){while(1){r=(d<<2)+f|0;s=a<<2;D[r>>2]=D[s+g>>2];D[r+4>>2]=D[g+(s|4)>>2];D[r+8>>2]=D[g+(s|8)>>2];D[r+12>>2]=D[g+(s|12)>>2];a=a+4|0;d=d+4|0;c=c+4|0;if((v|0)!=(c|0)){continue}break}}if(u){while(1){D[(d<<2)+f>>2]=D[g+(a<<2)>>2];a=a+1|0;d=d+1|0;i=i+1|0;if((u|0)!=(i|0)){continue}break}}a=1;b=b+1|0;if((l|0)!=(b|0)){continue}break}break u}if((l|0)!=1){d=l&-2;g=0;while(1){b=a|1;f=D[o>>2];c=fi(k,j,n?a:D[q+(a<<2)>>2],0)+e|0;c=oa(h,f+c|0,p);f=D[o>>2];if(!n){b=D[q+(b<<2)>>2]}b=fi(k,j,b,0)+e|0;oa(c,b+f|0,p);a=a+2|0;g=g+2|0;if((d|0)!=(g|0)){continue}break}}if(!(l&1)){break v}b=D[o>>2];if(!n){a=D[q+(a<<2)>>2]}a=fi(k,j,a,0)+e|0;oa(h,a+b|0,p);break v}if(!g){i=1;while(1){if(!yb(c,E[c+84|0]?a:D[D[c+68>>2]+(a<<2)>>2],B[c+24|0],h)){break v}a=a+1|0;i=l>>>0>a>>>0;if((a|0)!=(l|0)){continue}break}break v}n=g&-4;k=g&3;d=0;o=g-1>>>0<3;i=1;b=0;while(1){if(!yb(c,E[c+84|0]?b:D[D[c+68>>2]+(b<<2)>>2],B[c+24|0],h)){break v}g=0;a=0;i=0;if(!o){while(1){e=(d<<2)+f|0;j=a<<2;D[e>>2]=D[j+h>>2];D[e+4>>2]=D[(j|4)+h>>2];D[e+8>>2]=D[(j|8)+h>>2];D[e+12>>2]=D[(j|12)+h>>2];a=a+4|0;d=d+4|0;i=i+4|0;if((n|0)!=(i|0)){continue}break}}if(k){while(1){D[(d<<2)+f>>2]=D[(a<<2)+h>>2];a=a+1|0;d=d+1|0;g=g+1|0;if((k|0)!=(g|0)){continue}break}}b=b+1|0;i=l>>>0>b>>>0;if((b|0)!=(l|0)){continue}break}a=b>>>0>=l>>>0;break u}a=!i;if(!h){break t}}ma(h)}break b;case 8:break d;default:break a}}a=0;l=$-16|0;$=l;i=B[c+24|0];d=i<<2;g=D[b+80>>2];w:{if((J(d,g)|0)!=(e|0)){break w}e=D[c+28>>2];D[l+8>>2]=0;D[l>>2]=0;D[l+4>>2]=0;b=0;x:{y:{z:{A:{if(!i){break A}if((i|0)<0){break z}b=na(d);D[l>>2]=b;j=(i<<2)+b|0;D[l+8>>2]=j;a=b;d=d-4|0;m=(d>>>2|0)+1&7;if(m){while(1){D[a>>2]=-1073741824;a=a+4|0;h=h+1|0;if((m|0)!=(h|0)){continue}break}}if(d>>>0<28){break A}while(1){D[a+24>>2]=-1073741824;D[a+28>>2]=-1073741824;D[a+16>>2]=-1073741824;D[a+20>>2]=-1073741824;D[a+8>>2]=-1073741824;D[a+12>>2]=-1073741824;D[a>>2]=-1073741824;D[a+4>>2]=-1073741824;a=a+32|0;if((j|0)!=(a|0)){continue}break}}if(!g){break y}if((e|0)==9){a=0;n=D[c>>2];d=D[c+48>>2];t=D[c+68>>2];q=E[c+84|0];e=D[c+44>>2];j=D[c+40>>2];p=j;if((i|0)<=0){if((g|0)!=1){i=g&-2;c=0;while(1){f=a|1;m=D[n>>2];h=fi(j,e,q?a:D[t+(a<<2)>>2],0)+d|0;h=oa(b,m+h|0,p);m=D[n>>2];if(!q){f=D[t+(f<<2)>>2]}f=fi(j,e,f,0)+d|0;oa(h,f+m|0,p);a=a+2|0;c=c+2|0;if((i|0)!=(c|0)){continue}break}}if(!(g&1)){break y}c=D[n>>2];if(!q){a=D[t+(a<<2)>>2]}a=fi(j,e,a,0)+d|0;oa(b,a+c|0,p);break y}v=i&-4;s=i&3;h=0;w=i-1>>>0<3;i=0;while(1){c=D[n>>2];a=fi(j,e,q?i:D[t+(i<<2)>>2],0)+d|0;c=oa(b,c+a|0,p);m=0;a=0;u=0;if(!w){while(1){k=(h<<2)+f|0;r=a<<2;H[k>>2]=H[r+c>>2];H[k+4>>2]=H[c+(r|4)>>2];H[k+8>>2]=H[c+(r|8)>>2];H[k+12>>2]=H[c+(r|12)>>2];a=a+4|0;h=h+4|0;u=u+4|0;if((v|0)!=(u|0)){continue}break}}if(s){while(1){H[(h<<2)+f>>2]=H[c+(a<<2)>>2];a=a+1|0;h=h+1|0;m=m+1|0;if((s|0)!=(m|0)){continue}break}}a=1;i=i+1|0;if((g|0)!=(i|0)){continue}break}break x}k=1;if((i|0)<=0){a=0;while(1){if(!nb(c,E[c+84|0]?a:D[D[c+68>>2]+(a<<2)>>2],B[c+24|0],b)){break y}a=a+1|0;k=g>>>0>a>>>0;if((a|0)!=(g|0)){continue}break}break y}n=i&-4;j=i&3;h=0;o=i-1>>>0<3;i=0;while(1){if(!nb(c,E[c+84|0]?i:D[D[c+68>>2]+(i<<2)>>2],B[c+24|0],b)){break y}k=0;a=0;m=0;if(!o){while(1){d=(h<<2)+f|0;e=a<<2;H[d>>2]=H[e+b>>2];H[d+4>>2]=H[(e|4)+b>>2];H[d+8>>2]=H[(e|8)+b>>2];H[d+12>>2]=H[(e|12)+b>>2];a=a+4|0;h=h+4|0;m=m+4|0;if((n|0)!=(m|0)){continue}break}}if(j){while(1){H[(h<<2)+f>>2]=H[(a<<2)+b>>2];a=a+1|0;h=h+1|0;k=k+1|0;if((j|0)!=(k|0)){continue}break}}i=i+1|0;k=g>>>0>i>>>0;if((g|0)!=(i|0)){continue}break}a=g>>>0<=i>>>0;break x}pa();T()}a=k^1;if(!b){break w}}ma(b)}$=l+16|0;h=a&1;break a}pa();T()}$=m+16|0;h=a&1}return h|0}function yf(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,C=0,F=0,G=0,H=0,I=0,K=0,L=0,M=0;z=c;c=0;n=$-96|0;$=n;k=n+16|0;qa(k,0,76);D[n+92>>2]=-1;D[n+8>>2]=0;D[n>>2]=0;D[n+4>>2]=0;q=$-16|0;$=q;D[k+68>>2]=0;D[k+72>>2]=0;D[k>>2]=b;s=$-16|0;$=s;v=b;a=D[b+20>>2];a:{if((D[b+24>>2]-a|0)<=0){break a}a=D[a>>2];if((a|0)==-1){break a}c=D[D[v+8>>2]+(a<<2)>>2]}b:{c:{d:{if(!c){a=0;break d}a=D[v+100>>2];d=D[v+96>>2];D[s+8>>2]=0;D[s>>2]=0;D[s+4>>2]=0;e=a-d|0;b=(e|0)/12|0;e:{if((a|0)==(d|0)){break e}if(b>>>0>=357913942){break c}f=na(e);D[s>>2]=f;D[s+8>>2]=f+J(b,12);a=0;g=f;e=e-12|0;f=(e-((e>>>0)%12|0)|0)+12|0;e=qa(g,0,f);D[s+4>>2]=e+f;if(E[c+84|0]){c=b>>>0>1?b:1;g=c&1;if(b>>>0>=2){i=c&-2;c=0;while(1){f=J(a,12);b=f+d|0;h=D[b+4>>2];o=D[b>>2];f=e+f|0;D[f+8>>2]=D[b+8>>2];D[f>>2]=o;D[f+4>>2]=h;f=J(a|1,12);b=f+d|0;h=D[b+4>>2];o=D[b>>2];f=e+f|0;D[f+8>>2]=D[b+8>>2];D[f>>2]=o;D[f+4>>2]=h;a=a+2|0;c=c+2|0;if((i|0)!=(c|0)){continue}break}}if(!g){break e}b=J(a,12);a=b+d|0;c=D[a+4>>2];d=D[a>>2];b=b+e|0;D[b+8>>2]=D[a+8>>2];D[b>>2]=d;D[b+4>>2]=c;break e}g=b>>>0>1?b:1;a=D[c+68>>2];c=0;while(1){f=J(c,12);b=f+d|0;i=D[a+(D[b>>2]<<2)>>2];h=D[a+(D[b+4>>2]<<2)>>2];f=e+f|0;D[f+8>>2]=D[a+(D[b+8>>2]<<2)>>2];D[f+4>>2]=h;D[f>>2]=i;c=c+1|0;if((g|0)!=(c|0)){continue}break}}c=0;F=$-16|0;$=F;h=na(88);Wb(h);A=$-16|0;$=A;D[h+80>>2]=0;D[h+84>>2]=0;a=D[h+76>>2];D[h+76>>2]=0;if(a){ma(a)}D[h+68>>2]=0;D[h+72>>2]=0;b=h- -64|0;a=D[b>>2];D[b>>2]=0;if(a){ma(a)}d=D[s+4>>2];g=D[s>>2];b=(d-g|0)/12|0;a=J(b,3);f=D[h>>2];e=D[h+4>>2]-f>>2;f:{if(a>>>0>e>>>0){ra(h,a-e|0);d=D[s+4>>2];g=D[s>>2];b=(d-g|0)/12|0;break f}if(a>>>0>=e>>>0){break f}D[h+4>>2]=f+(a<<2)}g:{if((d|0)==(g|0)){break g}d=b>>>0>1?b:1;f=d&1;a=D[h>>2];if(b>>>0>=2){i=d&-2;b=0;while(1){d=J(c,12);o=d+a|0;e=d+g|0;D[o>>2]=D[e>>2];D[a+(d|4)>>2]=D[e+4>>2];D[o+8>>2]=D[e+8>>2];e=J(c|1,12);d=e+a|0;e=e+g|0;D[d>>2]=D[e>>2];D[d+4>>2]=D[e+4>>2];D[d+8>>2]=D[e+8>>2];c=c+2|0;b=b+2|0;if((i|0)!=(b|0)){continue}break}}if(!f){break g}b=J(c,12);a=b+a|0;b=b+g|0;D[a>>2]=D[b>>2];D[a+4>>2]=D[b+4>>2];D[a+8>>2]=D[b+8>>2]}D[A+12>>2]=-1;a=0;e=0;d=0;i=$-32|0;$=i;h:{i:{w=A+12|0;j:{if(!w){break j}b=D[h+4>>2];o=D[h>>2];c=b-o|0;j=c>>2;g=D[h+12>>2];f=D[h+16>>2]-g>>2;k:{if(j>>>0>f>>>0){xa(h+12|0,j-f|0,10228);b=D[h+4>>2];o=D[h>>2];c=b-o|0;j=c>>2;break k}if(f>>>0<=j>>>0){break k}D[h+16>>2]=g+(j<<2)}D[i+24>>2]=0;D[i+16>>2]=0;D[i+20>>2]=0;f=(b|0)==(o|0);if(!f){if((c|0)<0){break i}e=na(c);D[i+20>>2]=e;D[i+16>>2]=e;D[i+24>>2]=(j<<2)+e}l:{m:{n:{o:{p:{if(c){while(1){g=D[(a<<2)+o>>2];c=D[i+20>>2]-e>>2;q:{if(g>>>0>>0){break q}D[i>>2]=0;f=g+1|0;if(f>>>0>c>>>0){xa(i+16|0,f-c|0,i);o=D[h>>2];b=D[h+4>>2];e=D[i+16>>2];break q}if(c>>>0<=f>>>0){break q}D[i+20>>2]=(f<<2)+e}c=(g<<2)+e|0;D[c>>2]=D[c>>2]+1;a=a+1|0;c=b-o|0;j=c>>2;if(a>>>0>>0){continue}break}break p}c=0;if(!f){break o}break n}if((b|0)==(o|0)){c=0;break n}if(c>>>0>=2147483645){break m}}c=na(c<<1);qa(c,255,j<<3)}D[i+8>>2]=0;D[i>>2]=0;D[i+4>>2]=0;b=D[i+20>>2];a=b-e|0;t=a>>2;r:{s:{if((b|0)==(e|0)){break s}if((a|0)<0){break r}m=na(a);D[i>>2]=m;D[i+8>>2]=(t<<2)+m;b=qa(m,0,a);D[i+4>>2]=b+a;f=t>>>0>1?t:1;g=f&3;a=0;if(f-1>>>0>=3){r=f&-4;while(1){f=d<<2;D[f+b>>2]=a;x=f|4;a=D[e+f>>2]+a|0;D[x+b>>2]=a;u=f|8;a=a+D[e+x>>2]|0;D[u+b>>2]=a;f=f|12;a=a+D[e+u>>2]|0;D[f+b>>2]=a;a=a+D[e+f>>2]|0;d=d+4|0;p=p+4|0;if((r|0)!=(p|0)){continue}break}}if(!g){break s}while(1){f=d<<2;D[f+b>>2]=a;d=d+1|0;a=D[e+f>>2]+a|0;l=l+1|0;if((g|0)!=(l|0)){continue}break}}if(!j){break l}x=D[h+12>>2];f=0;while(1){G=f<<2;a=G+o|0;l=-1;g=f+1|0;b=(g>>>0)%3|0?g:f-2|0;if((b|0)!=-1){l=D[(b<<2)+o>>2]}b=D[a>>2];t:{u:{if(!((f>>>0)%3|0)){p=-1;a=f+2|0;if((a|0)!=-1){p=D[(a<<2)+o>>2]}if(!((b|0)==(l|0)|(b|0)==(p|0))&(l|0)!=(p|0)){break u}D[h+40>>2]=D[h+40>>2]+1;f=f+3|0;break t}p=D[a-4>>2]}a=p<<2;u=D[a+e>>2];v:{w:{if((u|0)<=0){break w}a=D[a+m>>2];d=0;while(1){r=(a<<3)+c|0;y=D[r>>2];if((y|0)==-1){break w}x:{if((l|0)!=(y|0)){break x}r=D[r+4>>2];if((r|0)!=-1){y=D[(r<<2)+o>>2]}else{y=-1}if((y|0)==(b|0)){break x}while(1){y:{b=a;d=d+1|0;if((u|0)<=(d|0)){break y}a=b+1|0;H=(a<<3)+c|0;y=D[H>>2];I=(b<<3)+c|0;D[I+4>>2]=D[H+4>>2];D[I>>2]=y;if((y|0)!=-1){continue}}break}D[(b<<3)+c>>2]=-1;if((r|0)==-1){break w}D[x+G>>2]=r;D[x+(r<<2)>>2]=f;break v}a=a+1|0;d=d+1|0;if((u|0)!=(d|0)){continue}break}}a=l<<2;l=D[a+e>>2];if((l|0)<=0){break v}a=D[a+m>>2];d=0;while(1){b=(a<<3)+c|0;if(D[b>>2]==-1){D[b>>2]=p;D[b+4>>2]=f;break v}a=a+1|0;d=d+1|0;if((l|0)!=(d|0)){continue}break}}f=g}if(j>>>0>f>>>0){continue}break}break l}break i}pa();T()}D[w>>2]=t;if(m){ma(m)}if(c){ma(c)}a=D[i+16>>2];if(!a){break j}D[i+20>>2]=a;ma(a)}$=i+32|0;x=(w|0)!=0;if(x){l=$-32|0;$=l;m=D[h>>2];a=D[h+4>>2];D[l+24>>2]=0;D[l+16>>2]=0;D[l+20>>2]=0;z:{if((a|0)==(m|0)){break z}d=a-m|0;if((d|0)<0){break i}b=d>>2;e=b-1>>>5|0;f=e+1|0;c=na(f<<2);D[l+24>>2]=f;D[l+16>>2]=c;D[l+20>>2]=b;D[c+((d>>>0<132?0:e)<<2)>>2]=0;d=c;c=b>>>5<<2;d=qa(d,0,c);if((b|0)==(b&-32)){break z}c=c+d|0;D[c>>2]=D[c>>2]&(-1>>>32-(b&31)^-1)}D[l+8>>2]=0;D[l>>2]=0;while(1){A:{r=0;o=0;if((a|0)==(m|0)){break A}while(1){b=D[l+16>>2];B:{if(D[b+(o>>>3&536870908)>>2]>>>o&1){break B}e=D[l>>2];D[l+4>>2]=e;c=D[h+12>>2];a=o;while(1){C:{d=a+1|0;i=a;a=(d>>>0)%3|0?d:a-2|0;if((a|0)==-1){break C}a=D[c+(a<<2)>>2];if((a|0)==-1){break C}d=a+1|0;a=(d>>>0)%3|0?d:a-2|0;if((o|0)==(a|0)|(a|0)==-1){break C}if(!(D[b+(a>>>3&536870908)>>2]>>>a&1)){continue}}break}d=i;D:{E:{F:{while(1){a=D[l+16>>2]+(d>>>3&536870908)|0;D[a>>2]=D[a>>2]|1<>>0)%3|0?a:d-2|0;m=D[h>>2];u=(d>>>0)%3|0;b=(u?-1:2)+d|0;j=D[l>>2];G:{if((j|0)==(e|0)){break G}w=D[(g<<2)+m>>2];p=D[h+12>>2];a=j;if((b|0)!=-1){c=p+(b<<2)|0;while(1){H:{if((w|0)!=D[a>>2]){break H}f=D[a+4>>2];t=D[c>>2];if((f|0)==(t|0)){break H}e=-1;c=b;a=-1;if((f|0)==-1){break D}break E}a=a+8|0;if((e|0)!=(a|0)){continue}break}break G}while(1){if((w|0)==D[a>>2]){t=-1;c=-1;f=D[a+4>>2];if((f|0)!=-1){break E}}a=a+8|0;if((e|0)!=(a|0)){continue}break}}f=D[(b<<2)+m>>2];I:{if(D[l+8>>2]!=(e|0)){D[e>>2]=f;D[e+4>>2]=g;e=e+8|0;D[l+4>>2]=e;break I}b=e-j|0;e=b>>3;a=e+1|0;if(a>>>0>=536870912){break i}c=b>>2;c=b>>>0<2147483640?a>>>0>>0?c:a:536870911;if(c){if(c>>>0>=536870912){break F}a=na(c<<3)}else{a=0}e=a+(e<<3)|0;D[e>>2]=f;D[e+4>>2]=g;e=e+8|0;if((b|0)>0){oa(a,j,b)}D[l+8>>2]=a+(c<<3);D[l+4>>2]=e;D[l>>2]=a;if(!j){break I}ma(j)}J:{K:{if(u){a=d-1|0;break K}a=d+2|0;if((a|0)==-1){break J}}a=D[D[h+12>>2]+(a<<2)>>2];if((a|0)==-1){break J}d=a+((a>>>0)%3|0?-1:2)|0;if((i|0)==(d|0)){break J}if((d|0)!=-1){continue}}break}m=D[h>>2];break B}sa();T()}b=c;e=f;a=D[p+(e<<2)>>2]}if((t|0)!=-1){D[p+(t<<2)>>2]=-1}if((a|0)!=-1){D[D[h+12>>2]+(a<<2)>>2]=-1}a=D[h+12>>2];D[a+(b<<2)>>2]=-1;D[a+(e<<2)>>2]=-1;r=1}o=o+1|0;a=D[h+4>>2];if(o>>>0>2>>>0){continue}break}if(r){continue}}break}a=D[l>>2];if(a){ma(a)}a=D[l+16>>2];if(a){ma(a)}$=l+32|0;c=0;f=0;l=0;i=$-32|0;$=i;a=D[A+12>>2];D[h+36>>2]=a;o=h+24|0;d=D[h+24>>2];b=D[h+28>>2]-d>>2;L:{M:{if(b>>>0>>0){xa(o,a-b|0,10228);D[i+24>>2]=0;D[i+16>>2]=0;D[i+20>>2]=0;break M}if(a>>>0>>0){D[h+28>>2]=d+(a<<2)}D[i+24>>2]=0;D[i+16>>2]=0;D[i+20>>2]=0;if(!a){break L}}if((a|0)<0){break i}b=a-1>>>5|0;d=b+1|0;c=na(d<<2);D[i+24>>2]=d;D[i+16>>2]=c;D[i+20>>2]=a;D[((a>>>0<33?0:b)<<2)+c>>2]=0;b=a>>>5<<2;d=qa(c,0,b);if((a&-32)==(a|0)){break L}b=b+d|0;D[b>>2]=D[b>>2]&(-1>>>32-(a&31)^-1)}j=D[h>>2];e=D[h+4>>2];D[i+8>>2]=0;D[i>>2]=0;D[i+4>>2]=0;d=e-j|0;N:{if((e|0)==(j|0)){break N}if((d|0)<0){break i}b=d>>2;g=b-1>>>5|0;m=g+1|0;f=na(m<<2);D[i+8>>2]=m;D[i>>2]=f;D[i+4>>2]=b;D[((d>>>0<132?0:g)<<2)+f>>2]=0;g=b>>>5<<2;m=qa(f,0,g);if((b|0)==(b&-32)){break N}g=g+m|0;D[g>>2]=D[g>>2]&(-1>>>32-(b&31)^-1)}if(d>>>0>=12){O:{P:{while(1){p=J(l,3);d=(p<<2)+j|0;b=D[d>>2];g=-1;m=p+1|0;if((m|0)!=-1){g=D[(m<<2)+j>>2]}Q:{if((b|0)==(g|0)){break Q}m=b;b=D[d+8>>2];if((m|0)==(b|0)){break Q}m=0;if((b|0)==(g|0)){break Q}while(1){b=m+p|0;if(!(D[(b>>>3&536870908)+f>>2]>>>b&1)){d=D[(b<<2)+j>>2];g=1<>>5|0;t=g&D[(j<<2)+c>>2];if(t){c=D[h+28>>2];R:{if((c|0)!=D[h+32>>2]){D[c>>2]=-1;D[h+28>>2]=c+4;break R}f=D[o>>2];e=c-f|0;j=e>>2;c=j+1|0;if(c>>>0>=1073741824){break i}g=e>>1;g=e>>>0<2147483644?c>>>0>>0?g:c:1073741823;if(g){if(g>>>0>=1073741824){break P}c=na(g<<2)}else{c=0}j=c+(j<<2)|0;D[j>>2]=-1;if((e|0)>0){oa(c,f,e)}D[h+32>>2]=c+(g<<2);D[h+28>>2]=j+4;D[h+24>>2]=c;if(!f){break R}ma(f)}c=D[h+52>>2];S:{if((c|0)!=D[h+56>>2]){D[c>>2]=d;D[h+52>>2]=c+4;break S}f=D[h+48>>2];e=c-f|0;j=e>>2;c=j+1|0;if(c>>>0>=1073741824){break i}g=e>>1;g=e>>>0<2147483644?c>>>0>>0?g:c:1073741823;if(g){if(g>>>0>=1073741824){break P}c=na(g<<2)}else{c=0}j=c+(j<<2)|0;D[j>>2]=d;if((e|0)>0){oa(c,f,e)}D[h+56>>2]=c+(g<<2);D[h+52>>2]=j+4;D[h+48>>2]=c;if(!f){break S}ma(f)}g=D[i+20>>2];c=D[i+24>>2];if((g|0)==c<<5){if((g+1|0)<0){break i}d=i+16|0;if(g>>>0<=1073741822){c=c<<6;e=g+32&-32;c=c>>>0>e>>>0?c:e}else{c=2147483647}Xa(d,c);g=D[i+20>>2]}D[i+20>>2]=g+1;c=D[i+16>>2]+(g>>>3&536870908)|0;d=D[c>>2];L=c,M=ji(g)&d,D[L>>2]=M;g=1<>>5|0;d=a;a=a+1|0}e=a;c=D[i+16>>2];a=c+(j<<2)|0;D[a>>2]=D[a>>2]|g;w=D[h+24>>2]+(d<<2)|0;r=D[h+12>>2];j=D[h>>2];f=D[i>>2];a=b;T:{U:{V:{while(1){if((a|0)==-1){break V}g=(a>>>3&536870908)+f|0;D[g>>2]=D[g>>2]|1<>2]=a;if(t){D[(a<<2)+j>>2]=d}u=a+1|0;a=(u>>>0)%3|0?u:a-2|0;g=-1;W:{if((a|0)==-1){break W}a=D[r+(a<<2)>>2];g=-1;if((a|0)==-1){break W}g=a+1|0;g=(g>>>0)%3|0?g:a-2|0}a=g;if((b|0)!=(a|0)){continue}break}if((b|0)!=-1){break T}a=1;break U}if((b>>>0)%3|0){a=b-1|0;break U}a=b+2|0;if((a|0)==-1){break T}}a=D[r+(a<<2)>>2];if((a|0)==-1){break T}X:{if((a>>>0)%3|0){a=a-1|0;break X}a=a+2|0;if((a|0)==-1){break T}}b=D[h+12>>2];j=D[h>>2];f=D[i>>2];while(1){g=(a>>>3&536870908)+f|0;D[g>>2]=D[g>>2]|1<>2]=d}Y:{if((a>>>0)%3|0){a=a-1|0;break Y}a=a+2|0;if((a|0)==-1){break T}}a=D[b+(a<<2)>>2];if((a|0)==-1){break T}a=a+((a>>>0)%3|0?-1:2)|0;if((a|0)!=-1){continue}break}}a=e}m=m+1|0;if((m|0)!=3){continue}break}j=D[h>>2];e=D[h+4>>2]}l=l+1|0;if(l>>>0<(e-j>>2>>>0)/3>>>0){continue}break}break O}sa();T()}c=D[i+16>>2]}a=0;D[h+44>>2]=0;b=D[i+20>>2];if(b){d=b&31;b=(b>>>3&536870908)+c|0;g=c;f=0;while(1){if(!(D[g>>2]>>>a&1)){f=f+1|0;D[h+44>>2]=f}e=(a|0)==31;a=e?0:a+1|0;g=(e<<2)+g|0;if((b|0)!=(g|0)|(a|0)!=(d|0)){continue}break}}a=D[i>>2];if(a){ma(a);c=D[i+16>>2]}if(c){ma(c)}$=i+32|0}$=A+16|0;if(!x){D[F+8>>2]=0;cb(h);h=0}$=F+16|0;a=h;break h}pa();T()}b=D[s>>2];if(!b){break d}D[s+4>>2]=b;ma(b)}$=s+16|0;break b}pa();T()}c=D[k+4>>2];b=a;D[k+4>>2]=a;if(c){cb(c);b=D[k+4>>2]}Z:{if(!b){break Z}a=D[v+100>>2];c=D[v+96>>2];B[q+12|0]=0;Ha(k+56|0,(a-c|0)/12|0,q+12|0);a=D[v+100>>2];c=D[v+96>>2];if((a|0)==(c|0)){break Z}while(1){if(!(D[D[k+56>>2]+(C>>>3&536870908)>>2]>>>C&1)){a=J(C,3);Tb(k,0,a);c=D[k+8>>2];d=D[k+12>>2];Tb(k,1,a+1|0);e=D[k+20>>2];f=D[k+24>>2];Tb(k,2,a+2|0);g=(c|0)==(d|0)?-1:0;a=f-e>>2;c=d-c>>2;d=a>>>0>c>>>0;c=D[k+36>>2]-D[k+32>>2]>>2>>>0>(d?a:c)>>>0?2:d?1:g;_:{if(D[k+68>>2]<=0){break _}D[q+12>>2]=D[k+76>>2];D[q+8>>2]=n;Ta(q+8|0,q+12|0);a=D[((c<<2)+k|0)+44>>2];if((a|0)<0){a=-1}else{d=(a>>>0)/3|0;a=D[(D[D[k>>2]+96>>2]+J(d,12)|0)+(a-J(d,3)<<2)>>2]}D[q+12>>2]=a;D[q+8>>2]=n;Ta(q+8|0,q+12|0);d=D[k+72>>2];D[k+72>>2]=d+2;if(!(d&1)){break _}D[q+12>>2]=a;D[q+8>>2]=n;Ta(q+8|0,q+12|0);D[k+72>>2]=D[k+72>>2]+1}f=0;d=$-16|0;$=d;D[k+68>>2]=D[k+68>>2]+1;a=J(c,12)+k|0;a=D[a+12>>2]-D[a+8>>2]|0;if((a|0)>0){a=a>>>2|0;g=a>>>0>1?a:1;c=D[((c<<2)+k|0)+44>>2];while(1){a=c;e=(a>>>0)/3|0;i=(a|0)==-1;c=i?-1:e;h=D[k+56>>2]+(c>>>3&536870908)|0;D[h>>2]=D[h>>2]|1<>2]=D[k+72>>2]+1;$:{aa:{ba:{ca:{da:{if(!f){D[d+12>>2]=(a|0)<0?-1:D[(D[D[k>>2]+96>>2]+J(e,12)|0)+((a>>>0)%3<<2)>>2];D[d+8>>2]=n;Ta(d+8|0,d+12|0);if(i){break da}c=-1;e=a+1|0;e=(e>>>0)%3|0?e:a-2|0;if((e|0)>=0){i=(e>>>0)/3|0;e=D[(D[D[k>>2]+96>>2]+J(i,12)|0)+(e-J(i,3)<<2)>>2]}else{e=-1}D[d+12>>2]=e;D[d+8>>2]=n;Ta(d+8|0,d+12|0);e=((a>>>0)%3|0?-1:2)+a|0;if((e|0)<0){break ca}c=(e>>>0)/3|0;c=D[(D[D[k>>2]+96>>2]+J(c,12)|0)+(e-J(c,3)<<2)>>2];break ca}c=(a|0)<0?-1:D[(D[D[k>>2]+96>>2]+J(e,12)|0)+((a>>>0)%3<<2)>>2];D[k+76>>2]=c;D[d+12>>2]=c;D[d+8>>2]=n;Ta(d+8|0,d+12|0);if(f&1){c=-1;if((a|0)==-1){break $}if((J(e,3)|0)!=(a|0)){a=a-1|0;break aa}a=a+2|0;break ba}c=-1;if((a|0)==-1){break $}c=a+1|0;a=(c>>>0)%3|0?c:a-2|0;break ba}c=-1;D[d+12>>2]=-1;D[d+8>>2]=n;Ta(d+8|0,d+12|0)}D[k+76>>2]=c;D[d+12>>2]=c;D[d+8>>2]=n;Ta(d+8|0,d+12|0)}c=-1;if((a|0)==-1){break $}}c=D[D[D[k+4>>2]+12>>2]+(a<<2)>>2]}f=f+1|0;if((g|0)!=(f|0)){continue}break}}$=d+16|0;c=D[v+96>>2];a=D[v+100>>2]}C=C+1|0;if(C>>>0<(a-c|0)/12>>>0){continue}break}}$=q+16|0;ea:{if(b){a=D[z>>2];if(a){D[z+4>>2]=a;ma(a)}D[z>>2]=D[n>>2];D[z+4>>2]=D[n+4>>2];D[z+8>>2]=D[n+8>>2];K=D[n+84>>2];break ea}a=D[n>>2];if(!a){break ea}D[n+4>>2]=a;ma(a)}a=D[n+72>>2];if(a){ma(a)}a=D[n+48>>2];if(a){D[n+52>>2]=a;ma(a)}a=D[n+36>>2];if(a){D[n+40>>2]=a;ma(a)}a=D[n+24>>2];if(a){D[n+28>>2]=a;ma(a)}a=D[n+20>>2];D[n+20>>2]=0;if(a){cb(a)}$=n+96|0;return K|0}function Ic(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;l=$-16|0;$=l;a:{b:{c:{d:{e:{f:{g:{h:{i:{j:{k:{if(a>>>0<=244){e=D[2936];h=a>>>0<11?16:a+11&-8;c=h>>>3|0;b=e>>>c|0;if(b&3){c=c+((b^-1)&1)|0;a=c<<3;b=a+11784|0;d=D[a+11792>>2];a=D[d+8>>2];l:{if((b|0)==(a|0)){m=11744,n=ji(c)&e,D[m>>2]=n;break l}D[a+12>>2]=b;D[b+8>>2]=a}a=d+8|0;b=c<<3;D[d+4>>2]=b|3;b=b+d|0;D[b+4>>2]=D[b+4>>2]|1;break a}k=D[2938];if(k>>>0>=h>>>0){break k}if(b){a=2<>>12&16;c=a;b=b>>>a|0;a=b>>>5&8;c=c|a;b=b>>>a|0;a=b>>>2&4;c=c|a;b=b>>>a|0;a=b>>>1&2;c=c|a;b=b>>>a|0;a=b>>>1&1;d=(c|a)+(b>>>a|0)|0;a=d<<3;b=a+11784|0;g=D[a+11792>>2];a=D[g+8>>2];m:{if((b|0)==(a|0)){e=ji(d)&e;D[2936]=e;break m}D[a+12>>2]=b;D[b+8>>2]=a}D[g+4>>2]=h|3;c=g+h|0;a=d<<3;d=a-h|0;D[c+4>>2]=d|1;D[a+g>>2]=d;if(k){b=(k&-8)+11784|0;f=D[2941];a=1<<(k>>>3);n:{if(!(a&e)){D[2936]=a|e;a=b;break n}a=D[b+8>>2]}D[b+8>>2]=f;D[a+12>>2]=f;D[f+12>>2]=b;D[f+8>>2]=a}a=g+8|0;D[2941]=c;D[2938]=d;break a}j=D[2937];if(!j){break k}b=(0-j&j)-1|0;a=b>>>12&16;c=a;b=b>>>a|0;a=b>>>5&8;c=c|a;b=b>>>a|0;a=b>>>2&4;c=c|a;b=b>>>a|0;a=b>>>1&2;c=c|a;b=b>>>a|0;a=b>>>1&1;c=D[((c|a)+(b>>>a|0)<<2)+12048>>2];f=(D[c+4>>2]&-8)-h|0;b=c;while(1){o:{a=D[b+16>>2];if(!a){a=D[b+20>>2];if(!a){break o}}b=(D[a+4>>2]&-8)-h|0;d=b>>>0>>0;f=d?b:f;c=d?a:c;b=a;continue}break}i=D[c+24>>2];d=D[c+12>>2];if((d|0)!=(c|0)){a=D[c+8>>2];D[a+12>>2]=d;D[d+8>>2]=a;break b}b=c+20|0;a=D[b>>2];if(!a){a=D[c+16>>2];if(!a){break j}b=c+16|0}while(1){g=b;d=a;b=a+20|0;a=D[b>>2];if(a){continue}b=d+16|0;a=D[d+16>>2];if(a){continue}break}D[g>>2]=0;break b}h=-1;if(a>>>0>4294967231){break k}a=a+11|0;h=a&-8;j=D[2937];if(!j){break k}f=0-h|0;e=0;p:{if(h>>>0<256){break p}e=31;if(h>>>0>16777215){break p}a=a>>>8|0;g=a+1048320>>>16&8;a=a<>>16&4;a=a<>>16&2;a=(a<>>15|0)-(b|(c|g))|0;e=(a<<1|h>>>a+21&1)+28|0}b=D[(e<<2)+12048>>2];q:{r:{s:{if(!b){a=0;break s}a=0;c=h<<((e|0)==31?0:25-(e>>>1|0)|0);while(1){t:{g=(D[b+4>>2]&-8)-h|0;if(g>>>0>=f>>>0){break t}d=b;f=g;if(f){break t}f=0;a=b;break r}g=D[b+20>>2];b=D[((c>>>29&4)+b|0)+16>>2];a=g?(g|0)==(b|0)?a:g:a;c=c<<1;if(b){continue}break}}if(!(a|d)){d=0;a=2<>>12&16;c=a;b=b>>>a|0;a=b>>>5&8;c=c|a;b=b>>>a|0;a=b>>>2&4;c=c|a;b=b>>>a|0;a=b>>>1&2;c=c|a;b=b>>>a|0;a=b>>>1&1;a=D[((c|a)+(b>>>a|0)<<2)+12048>>2]}if(!a){break q}}while(1){b=(D[a+4>>2]&-8)-h|0;c=b>>>0>>0;f=c?b:f;d=c?a:d;b=D[a+16>>2];if(b){a=b}else{a=D[a+20>>2]}if(a){continue}break}}if(!d|D[2938]-h>>>0<=f>>>0){break k}e=D[d+24>>2];c=D[d+12>>2];if((d|0)!=(c|0)){a=D[d+8>>2];D[a+12>>2]=c;D[c+8>>2]=a;break c}b=d+20|0;a=D[b>>2];if(!a){a=D[d+16>>2];if(!a){break i}b=d+16|0}while(1){g=b;c=a;b=a+20|0;a=D[b>>2];if(a){continue}b=c+16|0;a=D[c+16>>2];if(a){continue}break}D[g>>2]=0;break c}c=D[2938];if(c>>>0>=h>>>0){d=D[2941];b=c-h|0;u:{if(b>>>0>=16){D[2938]=b;a=d+h|0;D[2941]=a;D[a+4>>2]=b|1;D[c+d>>2]=b;D[d+4>>2]=h|3;break u}D[2941]=0;D[2938]=0;D[d+4>>2]=c|3;a=c+d|0;D[a+4>>2]=D[a+4>>2]|1}a=d+8|0;break a}i=D[2939];if(i>>>0>h>>>0){b=i-h|0;D[2939]=b;c=D[2942];a=c+h|0;D[2942]=a;D[a+4>>2]=b|1;D[c+4>>2]=h|3;a=c+8|0;break a}a=0;j=h+47|0;if(D[3054]){c=D[3056]}else{D[3057]=-1;D[3058]=-1;D[3055]=4096;D[3056]=4096;D[3054]=l+12&-16^1431655768;D[3059]=0;D[3047]=0;c=4096}g=j+c|0;f=0-c|0;b=g&f;if(b>>>0<=h>>>0){break a}d=D[3046];if(d){c=D[3044];e=c+b|0;if(d>>>0>>0|c>>>0>=e>>>0){break a}}if(E[12188]&4){break f}v:{w:{d=D[2942];if(d){a=12192;while(1){c=D[a>>2];if(c>>>0<=d>>>0&d>>>0>2]>>>0){break w}a=D[a+8>>2];if(a){continue}break}}c=_a(0);if((c|0)==-1){break g}e=b;d=D[3055];a=d-1|0;if(a&c){e=(b-c|0)+(a+c&0-d)|0}if(e>>>0<=h>>>0|e>>>0>2147483646){break g}d=D[3046];if(d){a=D[3044];f=a+e|0;if(d>>>0>>0|a>>>0>=f>>>0){break g}}a=_a(e);if((c|0)!=(a|0)){break v}break e}e=f&g-i;if(e>>>0>2147483646){break g}c=_a(e);if((c|0)==(D[a>>2]+D[a+4>>2]|0)){break h}a=c}if(!((a|0)==-1|h+48>>>0<=e>>>0)){c=D[3056];c=c+(j-e|0)&0-c;if(c>>>0>2147483646){c=a;break e}if((_a(c)|0)!=-1){e=c+e|0;c=a;break e}_a(0-e|0);break g}c=a;if((a|0)!=-1){break e}break g}d=0;break b}c=0;break c}if((c|0)!=-1){break e}}D[3047]=D[3047]|4}if(b>>>0>2147483646){break d}c=_a(b);a=_a(0);if((c|0)==-1|(a|0)==-1|a>>>0<=c>>>0){break d}e=a-c|0;if(e>>>0<=h+40>>>0){break d}}a=D[3044]+e|0;D[3044]=a;if(a>>>0>G[3045]){D[3045]=a}x:{y:{z:{g=D[2942];if(g){a=12192;while(1){d=D[a>>2];b=D[a+4>>2];if((d+b|0)==(c|0)){break z}a=D[a+8>>2];if(a){continue}break}break y}a=D[2940];if(!(a>>>0<=c>>>0?a:0)){D[2940]=c}a=0;D[3049]=e;D[3048]=c;D[2944]=-1;D[2945]=D[3054];D[3051]=0;while(1){d=a<<3;b=d+11784|0;D[d+11792>>2]=b;D[d+11796>>2]=b;a=a+1|0;if((a|0)!=32){continue}break}d=e-40|0;a=c+8&7?-8-c&7:0;b=d-a|0;D[2939]=b;a=a+c|0;D[2942]=a;D[a+4>>2]=b|1;D[(c+d|0)+4>>2]=40;D[2943]=D[3058];break x}if(E[a+12|0]&8|d>>>0>g>>>0|c>>>0<=g>>>0){break y}D[a+4>>2]=b+e;a=g+8&7?-8-g&7:0;c=a+g|0;D[2942]=c;b=D[2939]+e|0;a=b-a|0;D[2939]=a;D[c+4>>2]=a|1;D[(b+g|0)+4>>2]=40;D[2943]=D[3058];break x}if(G[2940]>c>>>0){D[2940]=c}b=c+e|0;a=12192;A:{B:{C:{D:{E:{F:{while(1){if((b|0)!=D[a>>2]){a=D[a+8>>2];if(a){continue}break F}break}if(!(E[a+12|0]&8)){break E}}a=12192;while(1){b=D[a>>2];if(b>>>0<=g>>>0){f=b+D[a+4>>2]|0;if(f>>>0>g>>>0){break D}}a=D[a+8>>2];continue}}D[a>>2]=c;D[a+4>>2]=D[a+4>>2]+e;j=(c+8&7?-8-c&7:0)+c|0;D[j+4>>2]=h|3;e=b+(b+8&7?-8-b&7:0)|0;i=h+j|0;a=e-i|0;if((e|0)==(g|0)){D[2942]=i;a=D[2939]+a|0;D[2939]=a;D[i+4>>2]=a|1;break B}if(D[2941]==(e|0)){D[2941]=i;a=D[2938]+a|0;D[2938]=a;D[i+4>>2]=a|1;D[a+i>>2]=a;break B}f=D[e+4>>2];if((f&3)==1){g=f&-8;G:{if(f>>>0<=255){d=D[e+8>>2];b=f>>>3|0;c=D[e+12>>2];if((c|0)==(d|0)){m=11744,n=D[2936]&ji(b),D[m>>2]=n;break G}D[d+12>>2]=c;D[c+8>>2]=d;break G}h=D[e+24>>2];c=D[e+12>>2];H:{if((e|0)!=(c|0)){b=D[e+8>>2];D[b+12>>2]=c;D[c+8>>2]=b;break H}I:{f=e+20|0;b=D[f>>2];if(b){break I}f=e+16|0;b=D[f>>2];if(b){break I}c=0;break H}while(1){d=f;c=b;f=b+20|0;b=D[f>>2];if(b){continue}f=c+16|0;b=D[c+16>>2];if(b){continue}break}D[d>>2]=0}if(!h){break G}d=D[e+28>>2];b=(d<<2)+12048|0;J:{if(D[b>>2]==(e|0)){D[b>>2]=c;if(c){break J}m=11748,n=D[2937]&ji(d),D[m>>2]=n;break G}D[h+(D[h+16>>2]==(e|0)?16:20)>>2]=c;if(!c){break G}}D[c+24>>2]=h;b=D[e+16>>2];if(b){D[c+16>>2]=b;D[b+24>>2]=c}b=D[e+20>>2];if(!b){break G}D[c+20>>2]=b;D[b+24>>2]=c}e=e+g|0;f=D[e+4>>2];a=a+g|0}D[e+4>>2]=f&-2;D[i+4>>2]=a|1;D[a+i>>2]=a;if(a>>>0<=255){b=(a&-8)+11784|0;c=D[2936];a=1<<(a>>>3);K:{if(!(c&a)){D[2936]=a|c;a=b;break K}a=D[b+8>>2]}D[b+8>>2]=i;D[a+12>>2]=i;D[i+12>>2]=b;D[i+8>>2]=a;break B}f=31;if(a>>>0<=16777215){b=a>>>8|0;f=b+1048320>>>16&8;b=b<>>16&4;b=b<>>16&2;b=(b<>>15|0)-(c|(d|f))|0;f=(b<<1|a>>>b+21&1)+28|0}D[i+28>>2]=f;D[i+16>>2]=0;D[i+20>>2]=0;b=(f<<2)+12048|0;d=D[2937];c=1<>2]=i;break L}f=a<<((f|0)==31?0:25-(f>>>1|0)|0);c=D[b>>2];while(1){b=c;if((D[b+4>>2]&-8)==(a|0)){break C}c=f>>>29|0;f=f<<1;d=(c&4)+b|0;c=D[d+16>>2];if(c){continue}break}D[d+16>>2]=i}D[i+24>>2]=b;D[i+12>>2]=i;D[i+8>>2]=i;break B}d=e-40|0;a=c+8&7?-8-c&7:0;b=d-a|0;D[2939]=b;a=a+c|0;D[2942]=a;D[a+4>>2]=b|1;D[(c+d|0)+4>>2]=40;D[2943]=D[3058];a=(f+(f-39&7?39-f&7:0)|0)-47|0;d=a>>>0>>0?g:a;D[d+4>>2]=27;a=D[3051];D[d+16>>2]=D[3050];D[d+20>>2]=a;a=D[3049];D[d+8>>2]=D[3048];D[d+12>>2]=a;D[3050]=d+8;D[3049]=e;D[3048]=c;D[3051]=0;a=d+24|0;while(1){D[a+4>>2]=7;b=a+8|0;a=a+4|0;if(b>>>0>>0){continue}break}if((d|0)==(g|0)){break x}D[d+4>>2]=D[d+4>>2]&-2;f=d-g|0;D[g+4>>2]=f|1;D[d>>2]=f;if(f>>>0<=255){b=(f&-8)+11784|0;c=D[2936];a=1<<(f>>>3);M:{if(!(c&a)){D[2936]=a|c;a=b;break M}a=D[b+8>>2]}D[b+8>>2]=g;D[a+12>>2]=g;D[g+12>>2]=b;D[g+8>>2]=a;break x}a=31;if(f>>>0<=16777215){a=f>>>8|0;d=a+1048320>>>16&8;a=a<>>16&4;a=a<>>16&2;a=(a<>>15|0)-(b|(c|d))|0;a=(a<<1|f>>>a+21&1)+28|0}D[g+28>>2]=a;D[g+16>>2]=0;D[g+20>>2]=0;b=(a<<2)+12048|0;d=D[2937];c=1<>2]=g;break N}a=f<<((a|0)==31?0:25-(a>>>1|0)|0);d=D[b>>2];while(1){b=d;if((f|0)==(D[b+4>>2]&-8)){break A}c=a>>>29|0;a=a<<1;c=(c&4)+b|0;d=D[c+16>>2];if(d){continue}break}D[c+16>>2]=g}D[g+24>>2]=b;D[g+12>>2]=g;D[g+8>>2]=g;break x}a=D[b+8>>2];D[a+12>>2]=i;D[b+8>>2]=i;D[i+24>>2]=0;D[i+12>>2]=b;D[i+8>>2]=a}a=j+8|0;break a}a=D[b+8>>2];D[a+12>>2]=g;D[b+8>>2]=g;D[g+24>>2]=0;D[g+12>>2]=b;D[g+8>>2]=a}a=D[2939];if(a>>>0<=h>>>0){break d}b=a-h|0;D[2939]=b;c=D[2942];a=c+h|0;D[2942]=a;D[a+4>>2]=b|1;D[c+4>>2]=h|3;a=c+8|0;break a}D[2935]=48;a=0;break a}O:{if(!e){break O}b=D[d+28>>2];a=(b<<2)+12048|0;P:{if(D[a>>2]==(d|0)){D[a>>2]=c;if(c){break P}j=ji(b)&j;D[2937]=j;break O}D[e+(D[e+16>>2]==(d|0)?16:20)>>2]=c;if(!c){break O}}D[c+24>>2]=e;a=D[d+16>>2];if(a){D[c+16>>2]=a;D[a+24>>2]=c}a=D[d+20>>2];if(!a){break O}D[c+20>>2]=a;D[a+24>>2]=c}Q:{if(f>>>0<=15){a=f+h|0;D[d+4>>2]=a|3;a=a+d|0;D[a+4>>2]=D[a+4>>2]|1;break Q}D[d+4>>2]=h|3;e=d+h|0;D[e+4>>2]=f|1;D[e+f>>2]=f;if(f>>>0<=255){b=(f&-8)+11784|0;c=D[2936];a=1<<(f>>>3);R:{if(!(c&a)){D[2936]=a|c;a=b;break R}a=D[b+8>>2]}D[b+8>>2]=e;D[a+12>>2]=e;D[e+12>>2]=b;D[e+8>>2]=a;break Q}a=31;if(f>>>0<=16777215){a=f>>>8|0;g=a+1048320>>>16&8;a=a<>>16&4;a=a<>>16&2;a=(a<>>15|0)-(b|(c|g))|0;a=(a<<1|f>>>a+21&1)+28|0}D[e+28>>2]=a;D[e+16>>2]=0;D[e+20>>2]=0;b=(a<<2)+12048|0;S:{c=1<>2]=e;break T}a=f<<((a|0)==31?0:25-(a>>>1|0)|0);h=D[b>>2];while(1){b=h;if((D[b+4>>2]&-8)==(f|0)){break S}c=a>>>29|0;a=a<<1;c=(c&4)+b|0;h=D[c+16>>2];if(h){continue}break}D[c+16>>2]=e}D[e+24>>2]=b;D[e+12>>2]=e;D[e+8>>2]=e;break Q}a=D[b+8>>2];D[a+12>>2]=e;D[b+8>>2]=e;D[e+24>>2]=0;D[e+12>>2]=b;D[e+8>>2]=a}a=d+8|0;break a}U:{if(!i){break U}b=D[c+28>>2];a=(b<<2)+12048|0;V:{if(D[a>>2]==(c|0)){D[a>>2]=d;if(d){break V}m=11748,n=ji(b)&j,D[m>>2]=n;break U}D[i+(D[i+16>>2]==(c|0)?16:20)>>2]=d;if(!d){break U}}D[d+24>>2]=i;a=D[c+16>>2];if(a){D[d+16>>2]=a;D[a+24>>2]=d}a=D[c+20>>2];if(!a){break U}D[d+20>>2]=a;D[a+24>>2]=d}W:{if(f>>>0<=15){a=f+h|0;D[c+4>>2]=a|3;a=a+c|0;D[a+4>>2]=D[a+4>>2]|1;break W}D[c+4>>2]=h|3;d=c+h|0;D[d+4>>2]=f|1;D[d+f>>2]=f;if(k){b=(k&-8)+11784|0;g=D[2941];a=1<<(k>>>3);X:{if(!(a&e)){D[2936]=a|e;a=b;break X}a=D[b+8>>2]}D[b+8>>2]=g;D[a+12>>2]=g;D[g+12>>2]=b;D[g+8>>2]=a}D[2941]=d;D[2938]=f}a=c+8|0}$=l+16|0;return a|0}function Md(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;h=$-80|0;$=h;e=D[c+36>>2];D[h+72>>2]=D[c+32>>2];D[h+76>>2]=e;f=D[c+28>>2];e=h- -64|0;D[e>>2]=D[c+24>>2];D[e+4>>2]=f;e=D[c+20>>2];D[h+56>>2]=D[c+16>>2];D[h+60>>2]=e;e=D[c+12>>2];D[h+48>>2]=D[c+8>>2];D[h+52>>2]=e;e=D[c+4>>2];D[h+40>>2]=D[c>>2];D[h+44>>2]=e;gc(a,h+40|0,h+24|0);a:{if(D[a>>2]){break a}l=a+4|0;if(B[a+15|0]<0){ma(D[l>>2])}if(E[h+31|0]!=1){b=na(32);c=E[1446]|E[1447]<<8|(E[1448]<<16|E[1449]<<24);B[b+16|0]=c;B[b+17|0]=c>>>8;B[b+18|0]=c>>>16;B[b+19|0]=c>>>24;c=E[1442]|E[1443]<<8|(E[1444]<<16|E[1445]<<24);d=E[1438]|E[1439]<<8|(E[1440]<<16|E[1441]<<24);B[b+8|0]=d;B[b+9|0]=d>>>8;B[b+10|0]=d>>>16;B[b+11|0]=d>>>24;B[b+12|0]=c;B[b+13|0]=c>>>8;B[b+14|0]=c>>>16;B[b+15|0]=c>>>24;c=E[1434]|E[1435]<<8|(E[1436]<<16|E[1437]<<24);d=E[1430]|E[1431]<<8|(E[1432]<<16|E[1433]<<24);B[b|0]=d;B[b+1|0]=d>>>8;B[b+2|0]=d>>>16;B[b+3|0]=d>>>24;B[b+4|0]=c;B[b+5|0]=c>>>8;B[b+6|0]=c>>>16;B[b+7|0]=c>>>24;B[b+20|0]=0;D[a>>2]=-1;ta(l,b,20);ma(b);break a}i=$-16|0;$=i;b:{c:{switch(E[h+32|0]){case 0:e=Hd(na(48));D[e>>2]=9864;D[h+8>>2]=0;D[h+12>>2]=0;D[h>>2]=0;D[h+4>>2]=0;D[h+16>>2]=e;break b;case 1:e=Hd(na(52));D[e+48>>2]=0;D[e>>2]=8176;D[h+8>>2]=0;D[h+12>>2]=0;D[h>>2]=0;D[h+4>>2]=0;D[h+16>>2]=e;break b;default:break c}}f=na(32);e=E[1520]|E[1521]<<8|(E[1522]<<16|E[1523]<<24);B[f+24|0]=e;B[f+25|0]=e>>>8;B[f+26|0]=e>>>16;B[f+27|0]=e>>>24;e=E[1516]|E[1517]<<8|(E[1518]<<16|E[1519]<<24);g=E[1512]|E[1513]<<8|(E[1514]<<16|E[1515]<<24);B[f+16|0]=g;B[f+17|0]=g>>>8;B[f+18|0]=g>>>16;B[f+19|0]=g>>>24;B[f+20|0]=e;B[f+21|0]=e>>>8;B[f+22|0]=e>>>16;B[f+23|0]=e>>>24;e=E[1508]|E[1509]<<8|(E[1510]<<16|E[1511]<<24);g=E[1504]|E[1505]<<8|(E[1506]<<16|E[1507]<<24);B[f+8|0]=g;B[f+9|0]=g>>>8;B[f+10|0]=g>>>16;B[f+11|0]=g>>>24;B[f+12|0]=e;B[f+13|0]=e>>>8;B[f+14|0]=e>>>16;B[f+15|0]=e>>>24;e=E[1500]|E[1501]<<8|(E[1502]<<16|E[1503]<<24);g=E[1496]|E[1497]<<8|(E[1498]<<16|E[1499]<<24);B[f|0]=g;B[f+1|0]=g>>>8;B[f+2|0]=g>>>16;B[f+3|0]=g>>>24;B[f+4|0]=e;B[f+5|0]=e>>>8;B[f+6|0]=e>>>16;B[f+7|0]=e>>>24;B[f+28|0]=0;D[i>>2]=-1;e=i|4;ta(e,f,28);k=B[i+15|0];D[h>>2]=D[i>>2];g=h+4|0;d:{if((k|0)>=0){k=D[e+4>>2];D[g>>2]=D[e>>2];D[g+4>>2]=k;D[g+8>>2]=D[e+8>>2];D[h+16>>2]=0;break d}ta(g,D[i+4>>2],D[i+8>>2]);e=B[i+15|0];D[h+16>>2]=0;if((e|0)>=0){break d}ma(D[i+4>>2])}ma(f)}$=i+16|0;e=D[h>>2];e:{if(e){D[a>>2]=e;if(B[h+15|0]>=0){a=h|4;b=D[a+4>>2];D[l>>2]=D[a>>2];D[l+4>>2]=b;D[l+8>>2]=D[a+8>>2];break e}ta(l,D[h+4>>2],D[h+8>>2]);break e}e=D[h+16>>2];D[h+16>>2]=0;D[e+44>>2]=d;i=$-32|0;$=i;D[e+32>>2]=c;D[e+40>>2]=b;D[e+4>>2]=d;gc(a,c,i+16|0);f:{if(D[a>>2]){break f}f=a+4|0;if(B[a+15|0]<0){ma(D[f>>2])}b=E[i+23|0];if((ba[D[D[e>>2]+8>>2]](e)|0)!=(b|0)){b=na(64);c=E[1304]|E[1305]<<8;B[b+48|0]=c;B[b+49|0]=c>>>8;c=E[1300]|E[1301]<<8|(E[1302]<<16|E[1303]<<24);d=E[1296]|E[1297]<<8|(E[1298]<<16|E[1299]<<24);B[b+40|0]=d;B[b+41|0]=d>>>8;B[b+42|0]=d>>>16;B[b+43|0]=d>>>24;B[b+44|0]=c;B[b+45|0]=c>>>8;B[b+46|0]=c>>>16;B[b+47|0]=c>>>24;c=E[1292]|E[1293]<<8|(E[1294]<<16|E[1295]<<24);d=E[1288]|E[1289]<<8|(E[1290]<<16|E[1291]<<24);B[b+32|0]=d;B[b+33|0]=d>>>8;B[b+34|0]=d>>>16;B[b+35|0]=d>>>24;B[b+36|0]=c;B[b+37|0]=c>>>8;B[b+38|0]=c>>>16;B[b+39|0]=c>>>24;c=E[1284]|E[1285]<<8|(E[1286]<<16|E[1287]<<24);d=E[1280]|E[1281]<<8|(E[1282]<<16|E[1283]<<24);B[b+24|0]=d;B[b+25|0]=d>>>8;B[b+26|0]=d>>>16;B[b+27|0]=d>>>24;B[b+28|0]=c;B[b+29|0]=c>>>8;B[b+30|0]=c>>>16;B[b+31|0]=c>>>24;c=E[1276]|E[1277]<<8|(E[1278]<<16|E[1279]<<24);d=E[1272]|E[1273]<<8|(E[1274]<<16|E[1275]<<24);B[b+16|0]=d;B[b+17|0]=d>>>8;B[b+18|0]=d>>>16;B[b+19|0]=d>>>24;B[b+20|0]=c;B[b+21|0]=c>>>8;B[b+22|0]=c>>>16;B[b+23|0]=c>>>24;c=E[1268]|E[1269]<<8|(E[1270]<<16|E[1271]<<24);d=E[1264]|E[1265]<<8|(E[1266]<<16|E[1267]<<24);B[b+8|0]=d;B[b+9|0]=d>>>8;B[b+10|0]=d>>>16;B[b+11|0]=d>>>24;B[b+12|0]=c;B[b+13|0]=c>>>8;B[b+14|0]=c>>>16;B[b+15|0]=c>>>24;c=E[1260]|E[1261]<<8|(E[1262]<<16|E[1263]<<24);d=E[1256]|E[1257]<<8|(E[1258]<<16|E[1259]<<24);B[b|0]=d;B[b+1|0]=d>>>8;B[b+2|0]=d>>>16;B[b+3|0]=d>>>24;B[b+4|0]=c;B[b+5|0]=c>>>8;B[b+6|0]=c>>>16;B[b+7|0]=c>>>24;B[b+50|0]=0;D[a>>2]=-1;ta(f,b,50);ma(b);break f}c=E[i+21|0];B[e+36|0]=c;d=E[i+22|0];B[e+37|0]=d;if((c|0)!=2){b=na(32);c=E[1427]|E[1428]<<8;B[b+24|0]=c;B[b+25|0]=c>>>8;c=E[1423]|E[1424]<<8|(E[1425]<<16|E[1426]<<24);d=E[1419]|E[1420]<<8|(E[1421]<<16|E[1422]<<24);B[b+16|0]=d;B[b+17|0]=d>>>8;B[b+18|0]=d>>>16;B[b+19|0]=d>>>24;B[b+20|0]=c;B[b+21|0]=c>>>8;B[b+22|0]=c>>>16;B[b+23|0]=c>>>24;c=E[1415]|E[1416]<<8|(E[1417]<<16|E[1418]<<24);d=E[1411]|E[1412]<<8|(E[1413]<<16|E[1414]<<24);B[b+8|0]=d;B[b+9|0]=d>>>8;B[b+10|0]=d>>>16;B[b+11|0]=d>>>24;B[b+12|0]=c;B[b+13|0]=c>>>8;B[b+14|0]=c>>>16;B[b+15|0]=c>>>24;c=E[1407]|E[1408]<<8|(E[1409]<<16|E[1410]<<24);d=E[1403]|E[1404]<<8|(E[1405]<<16|E[1406]<<24);B[b|0]=d;B[b+1|0]=d>>>8;B[b+2|0]=d>>>16;B[b+3|0]=d>>>24;B[b+4|0]=c;B[b+5|0]=c>>>8;B[b+6|0]=c>>>16;B[b+7|0]=c>>>24;B[b+26|0]=0;D[a>>2]=-5;ta(f,b,26);ma(b);break f}b=b?2:3;if((b|0)!=(d|0)){b=na(32);c=E[1400]|E[1401]<<8;B[b+24|0]=c;B[b+25|0]=c>>>8;c=E[1396]|E[1397]<<8|(E[1398]<<16|E[1399]<<24);d=E[1392]|E[1393]<<8|(E[1394]<<16|E[1395]<<24);B[b+16|0]=d;B[b+17|0]=d>>>8;B[b+18|0]=d>>>16;B[b+19|0]=d>>>24;B[b+20|0]=c;B[b+21|0]=c>>>8;B[b+22|0]=c>>>16;B[b+23|0]=c>>>24;c=E[1388]|E[1389]<<8|(E[1390]<<16|E[1391]<<24);d=E[1384]|E[1385]<<8|(E[1386]<<16|E[1387]<<24);B[b+8|0]=d;B[b+9|0]=d>>>8;B[b+10|0]=d>>>16;B[b+11|0]=d>>>24;B[b+12|0]=c;B[b+13|0]=c>>>8;B[b+14|0]=c>>>16;B[b+15|0]=c>>>24;c=E[1380]|E[1381]<<8|(E[1382]<<16|E[1383]<<24);d=E[1376]|E[1377]<<8|(E[1378]<<16|E[1379]<<24);B[b|0]=d;B[b+1|0]=d>>>8;B[b+2|0]=d>>>16;B[b+3|0]=d>>>24;B[b+4|0]=c;B[b+5|0]=c>>>8;B[b+6|0]=c>>>16;B[b+7|0]=c>>>24;B[b+26|0]=0;D[a>>2]=-5;ta(f,b,26);ma(b);break f}C[D[e+32>>2]+38>>1]=b|512;g:{if(C[i+26>>1]>=0){break g}k=$-16|0;$=k;d=na(36);b=d;D[b+4>>2]=0;D[b+8>>2]=0;D[b+24>>2]=0;D[b+28>>2]=0;b=b+16|0;D[b>>2]=0;D[b+4>>2]=0;D[d>>2]=d+4;D[d+32>>2]=0;D[d+12>>2]=b;D[k>>2]=0;c=D[e+32>>2];m=$-16|0;$=m;b=0;h:{if(!d){break h}D[k>>2]=c;D[m+12>>2]=0;b=0;if(!hb(1,m+12|0,c)){break h}p=D[m+12>>2];if(p){while(1){i:{if(hb(1,m+8|0,D[k>>2])){b=na(28);D[b+4>>2]=0;D[b+8>>2]=0;c=b+16|0;D[c>>2]=0;D[c+4>>2]=0;D[b>>2]=b+4;D[b+12>>2]=c;D[b+24>>2]=D[m+8>>2];if(Tc(k,b)){break i}Fa(b+12|0,D[b+16>>2]);Ea(b,D[b+4>>2]);ma(b)}b=0;break h}g=$-16|0;$=g;D[g+8>>2]=b;j:{if(!b){D[g+8>>2]=0;break j}c=D[d+28>>2];k:{if(c>>>0>2]){D[g+8>>2]=0;D[c>>2]=b;D[d+28>>2]=c+4;break k}c=0;l:{m:{n:{j=D[d+24>>2];o=D[d+28>>2]-j>>2;b=o+1|0;if(b>>>0<1073741824){j=D[d+32>>2]-j|0;n=j>>1;b=j>>>0<2147483644?b>>>0>>0?n:b:1073741823;if(b){if(b>>>0>=1073741824){break n}c=na(b<<2)}n=D[g+8>>2];D[g+8>>2]=0;j=(o<<2)+c|0;D[j>>2]=n;o=(b<<2)+c|0;n=j+4|0;c=D[d+28>>2];b=D[d+24>>2];if((c|0)==(b|0)){break m}while(1){c=c-4|0;r=D[c>>2];D[c>>2]=0;j=j-4|0;D[j>>2]=r;if((b|0)!=(c|0)){continue}break}D[d+32>>2]=o;c=D[d+28>>2];D[d+28>>2]=n;b=D[d+24>>2];D[d+24>>2]=j;if((b|0)==(c|0)){break l}while(1){c=c-4|0;j=D[c>>2];D[c>>2]=0;if(j){Fa(j+12|0,D[j+16>>2]);Ea(j,D[j+4>>2]);ma(j)}if((b|0)!=(c|0)){continue}break}break l}pa();T()}sa();T()}D[d+32>>2]=o;D[d+28>>2]=n;D[d+24>>2]=j}if(b){ma(b)}}b=D[g+8>>2];D[g+8>>2]=0;if(!b){break j}Fa(b+12|0,D[b+16>>2]);Ea(b,D[b+4>>2]);ma(b)}$=g+16|0;q=q+1|0;if((q|0)!=(p|0)){continue}break}}b=Tc(k,d)}$=m+16|0;o:{if(b){c=D[e+4>>2];b=D[c+4>>2];D[c+4>>2]=d;if(b){fc(b)}D[a>>2]=0;D[a+4>>2]=0;D[a+8>>2]=0;D[a+12>>2]=0;break o}b=na(32);c=E[1549]|E[1550]<<8;B[b+24|0]=c;B[b+25|0]=c>>>8;c=E[1545]|E[1546]<<8|(E[1547]<<16|E[1548]<<24);g=E[1541]|E[1542]<<8|(E[1543]<<16|E[1544]<<24);B[b+16|0]=g;B[b+17|0]=g>>>8;B[b+18|0]=g>>>16;B[b+19|0]=g>>>24;B[b+20|0]=c;B[b+21|0]=c>>>8;B[b+22|0]=c>>>16;B[b+23|0]=c>>>24;c=E[1537]|E[1538]<<8|(E[1539]<<16|E[1540]<<24);g=E[1533]|E[1534]<<8|(E[1535]<<16|E[1536]<<24);B[b+8|0]=g;B[b+9|0]=g>>>8;B[b+10|0]=g>>>16;B[b+11|0]=g>>>24;B[b+12|0]=c;B[b+13|0]=c>>>8;B[b+14|0]=c>>>16;B[b+15|0]=c>>>24;c=E[1529]|E[1530]<<8|(E[1531]<<16|E[1532]<<24);g=E[1525]|E[1526]<<8|(E[1527]<<16|E[1528]<<24);B[b|0]=g;B[b+1|0]=g>>>8;B[b+2|0]=g>>>16;B[b+3|0]=g>>>24;B[b+4|0]=c;B[b+5|0]=c>>>8;B[b+6|0]=c>>>16;B[b+7|0]=c>>>24;B[b+26|0]=0;D[a>>2]=-1;ta(a+4|0,b,26);ma(b);D[k+8>>2]=0;fc(d)}$=k+16|0;if(D[a>>2]){break f}if(B[f+11|0]>=0){break g}ma(D[f>>2])}if(!(ba[D[D[e>>2]+12>>2]](e)|0)){b=na(48);B[b+32|0]=E[1374];c=E[1370]|E[1371]<<8|(E[1372]<<16|E[1373]<<24);d=E[1366]|E[1367]<<8|(E[1368]<<16|E[1369]<<24);B[b+24|0]=d;B[b+25|0]=d>>>8;B[b+26|0]=d>>>16;B[b+27|0]=d>>>24;B[b+28|0]=c;B[b+29|0]=c>>>8;B[b+30|0]=c>>>16;B[b+31|0]=c>>>24;c=E[1362]|E[1363]<<8|(E[1364]<<16|E[1365]<<24);d=E[1358]|E[1359]<<8|(E[1360]<<16|E[1361]<<24);B[b+16|0]=d;B[b+17|0]=d>>>8;B[b+18|0]=d>>>16;B[b+19|0]=d>>>24;B[b+20|0]=c;B[b+21|0]=c>>>8;B[b+22|0]=c>>>16;B[b+23|0]=c>>>24;c=E[1354]|E[1355]<<8|(E[1356]<<16|E[1357]<<24);d=E[1350]|E[1351]<<8|(E[1352]<<16|E[1353]<<24);B[b+8|0]=d;B[b+9|0]=d>>>8;B[b+10|0]=d>>>16;B[b+11|0]=d>>>24;B[b+12|0]=c;B[b+13|0]=c>>>8;B[b+14|0]=c>>>16;B[b+15|0]=c>>>24;c=E[1346]|E[1347]<<8|(E[1348]<<16|E[1349]<<24);d=E[1342]|E[1343]<<8|(E[1344]<<16|E[1345]<<24);B[b|0]=d;B[b+1|0]=d>>>8;B[b+2|0]=d>>>16;B[b+3|0]=d>>>24;B[b+4|0]=c;B[b+5|0]=c>>>8;B[b+6|0]=c>>>16;B[b+7|0]=c>>>24;B[b+33|0]=0;D[a>>2]=-1;ta(f,b,33);ma(b);break f}if(!(ba[D[D[e>>2]+20>>2]](e)|0)){b=Fb(i,1552);D[a>>2]=-1;if(B[b+11|0]>=0){c=D[b+4>>2];D[f>>2]=D[b>>2];D[f+4>>2]=c;D[f+8>>2]=D[b+8>>2];break f}ta(f,D[b>>2],D[b+4>>2]);if(B[b+11|0]>=0){break f}ma(D[b>>2]);break f}if(!(ba[D[D[e>>2]+24>>2]](e)|0)){b=Fb(i,1307);D[a>>2]=-1;if(B[b+11|0]>=0){c=D[b+4>>2];D[f>>2]=D[b>>2];D[f+4>>2]=c;D[f+8>>2]=D[b+8>>2];break f}ta(f,D[b>>2],D[b+4>>2]);if(B[b+11|0]>=0){break f}ma(D[b>>2]);break f}D[a>>2]=0;D[a+4>>2]=0;D[a+8>>2]=0;D[a+12>>2]=0}$=i+32|0;if(!D[a>>2]){if(B[l+11|0]<0){ma(D[l>>2])}D[a>>2]=0;D[a+4>>2]=0;D[a+8>>2]=0;D[a+12>>2]=0}ba[D[D[e>>2]+4>>2]](e)}a=D[h+16>>2];D[h+16>>2]=0;if(a){ba[D[D[a>>2]+4>>2]](a)}if(B[h+15|0]>=0){break a}ma(D[h+4>>2])}$=h+80|0}function Tc(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0;m=$-32|0;$=m;o=na(12);D[o+8>>2]=0;D[o+4>>2]=b;D[o>>2]=0;t=o+12|0;b=t;a:{b:{c:{d:{while(1){b=b-12|0;w=D[b+8>>2];j=D[b+4>>2];u=D[b>>2];if(u){q=0;if((w|0)>1e3){break a}D[m+24>>2]=0;D[m+16>>2]=0;D[m+20>>2]=0;f=1;c=D[a>>2];d=D[c+8>>2];h=D[c+12>>2];e=D[c+20>>2];g=d;d=D[c+16>>2];e:{if((h|0)<=(e|0)&g>>>0<=d>>>0|(e|0)>(h|0)){break e}h=E[d+D[c>>2]|0];d=d+1|0;e=d?e:e+1|0;D[c+16>>2]=d;D[c+20>>2]=e;Rb(m+16|0,h);if(h){d=D[a>>2];l=Sb(m+16|0);e=D[d+20>>2];i=D[d+16>>2];c=h;n=i+c|0;g=D[d+12>>2];e=c>>>0>n>>>0?e+1|0:e;if(n>>>0>G[d+8>>2]&(g|0)<=(e|0)|(e|0)>(g|0)){break e}oa(l,i+D[d>>2]|0,h);e=D[d+20>>2];f=c+D[d+16>>2]|0;e=f>>>0>>0?e+1|0:e;D[d+16>>2]=f;D[d+20>>2]=e}j=na(24);c=j;D[c+4>>2]=0;D[c+8>>2]=0;c=c+16|0;D[c>>2]=0;D[c+4>>2]=0;D[j>>2]=j+4;D[j+12>>2]=c;e=$-32|0;$=e;h=u+12|0;c=m+16|0;p=bb(h,c);k=u+16|0;f:{if((p|0)==(k|0)){D[e+16>>2]=c;g:{h:{d=D[h+4>>2];i:{if(!d){f=h+4|0;c=f;break i}f=E[c+11|0];g=f<<24>>24<0;n=g?D[c>>2]:c;g=g?D[c+4>>2]:f;while(1){c=d;d=E[c+27|0];f=d<<24>>24<0;d=f?D[c+20>>2]:d;l=d>>>0>>0;j:{k:{l:{m:{i=l?d:g;n:{if(i){r=c+16|0;f=f?D[r>>2]:r;r=ua(n,f,i);if(!r){if(d>>>0>g>>>0){break n}break m}if((r|0)>=0){break m}break n}if(d>>>0<=g>>>0){break l}}f=c;d=D[c>>2];if(d){continue}break i}d=ua(f,n,i);if(d){break k}}if(l){break j}break h}if((d|0)>=0){break h}}d=D[c+4>>2];if(d){continue}break}f=c+4|0}d=na(32);n=d+16|0;g=D[e+16>>2];o:{if(B[g+11|0]>=0){l=D[g+4>>2];D[n>>2]=D[g>>2];D[n+4>>2]=l;D[n+8>>2]=D[g+8>>2];break o}ta(n,D[g>>2],D[g+4>>2])}D[d+8>>2]=c;D[d>>2]=0;D[d+4>>2]=0;D[d+28>>2]=0;D[f>>2]=d;c=d;g=D[D[h>>2]>>2];if(g){D[h>>2]=g;c=D[f>>2]}pb(D[h+4>>2],c);D[h+8>>2]=D[h+8>>2]+1;c=1;break g}d=c;c=0}B[e+28|0]=c;D[e+24>>2]=d;d=D[e+24>>2];c=D[d+28>>2];D[d+28>>2]=j;if(!c){break f}Fa(c+12|0,D[c+16>>2]);Ea(c,D[c+4>>2]);ma(c);break f}if(!j){break f}Fa(j+12|0,D[j+16>>2]);Ea(j,D[j+4>>2]);ma(j)}$=e+32|0;f=(k|0)!=(p|0)}if(B[m+27|0]<0){ma(D[m+16>>2])}if(f){break a}}q=0;if(!j){break a}D[m+16>>2]=0;if(!hb(1,m+16|0,D[a>>2])){break a}p=0;x=D[m+16>>2];if(x){while(1){c=0;i=$-32|0;$=i;D[i+24>>2]=0;D[i+16>>2]=0;D[i+20>>2]=0;d=D[a>>2];f=D[d+8>>2];p:{q:{h=D[d+12>>2];e=D[d+20>>2];g=D[d+16>>2];r:{if((h|0)<=(e|0)&g>>>0>=f>>>0|(e|0)>(h|0)){break r}h=E[g+D[d>>2]|0];f=d;d=e;e=g+1|0;d=e?d:d+1|0;D[f+16>>2]=e;D[f+20>>2]=d;Rb(i+16|0,h);if(h){f=D[a>>2];l=Sb(i+16|0);e=D[f+20>>2];k=D[f+16>>2];d=h;n=k+d|0;g=D[f+12>>2];e=d>>>0>n>>>0?e+1|0:e;if(n>>>0>G[f+8>>2]&(g|0)<=(e|0)|(e|0)>(g|0)){break r}oa(l,k+D[f>>2]|0,h);e=D[f+20>>2];h=d+D[f+16>>2]|0;e=h>>>0>>0?e+1|0:e;D[f+16>>2]=h;D[f+20>>2]=e}D[i+12>>2]=0;if(!hb(1,i+12|0,D[a>>2])){break r}d=D[i+12>>2];if(!d){break r}D[i+8>>2]=0;D[i>>2]=0;D[i+4>>2]=0;if((d|0)<0){break q}c=na(d);D[i>>2]=c;e=c+d|0;D[i+8>>2]=e;l=qa(c,0,d);D[i+4>>2]=e;e=D[a>>2];r=D[e+8>>2];h=D[e+12>>2];y=h;f=D[e+20>>2];k=D[e+16>>2];g=d+k|0;f=g>>>0>>0?f+1|0:f;s:{z=g;n=f;if(g>>>0>r>>>0&(f|0)>=(h|0)|(f|0)>(h|0)){break s}oa(l,k+D[e>>2]|0,d);c=d;f=c+D[e+16>>2]|0;d=D[e+20>>2];D[e+16>>2]=f;D[e+20>>2]=c>>>0>f>>>0?d+1|0:d;h=$-48|0;$=h;e=bb(j,i+16|0);if((e|0)!=(j+4|0)){c=D[e+4>>2];t:{if(!c){c=e;while(1){d=D[c+8>>2];f=D[d>>2]!=(c|0);c=d;if(f){continue}break}break t}while(1){d=c;c=D[c>>2];if(c){continue}break}}if((e|0)==D[j>>2]){D[j>>2]=d}D[j+8>>2]=D[j+8>>2]-1;f=D[j+4>>2];u:{v:{g=e;d=e;e=D[d>>2];if(e){c=D[g+4>>2];if(!c){break v}while(1){d=c;c=D[c>>2];if(c){continue}break}}e=D[d+4>>2];if(e){break v}e=0;l=1;break u}D[e+8>>2]=D[d+8>>2];l=0}k=D[d+8>>2];c=D[k>>2];w:{if((d|0)==(c|0)){D[k>>2]=e;if((d|0)==(f|0)){c=0;f=e;break w}c=D[k+4>>2];break w}D[k+4>>2]=e}s=!E[d+12|0];if((d|0)!=(g|0)){k=D[g+8>>2];D[d+8>>2]=k;D[k+(((g|0)!=D[D[g+8>>2]>>2])<<2)>>2]=d;k=D[g>>2];D[d>>2]=k;D[k+8>>2]=d;k=D[g+4>>2];D[d+4>>2]=k;if(k){D[k+8>>2]=d}B[d+12|0]=E[g+12|0];f=(f|0)==(g|0)?d:f}x:{if(s|!f){break x}if(l){while(1){e=E[c+12|0];y:{d=D[c+8>>2];if(D[d>>2]!=(c|0)){if(!e){B[c+12|0]=1;B[d+12|0]=0;e=D[d+4>>2];l=D[e>>2];D[d+4>>2]=l;if(l){D[l+8>>2]=d}D[e+8>>2]=D[d+8>>2];l=D[d+8>>2];D[(((d|0)!=D[l>>2])<<2)+l>>2]=e;D[e>>2]=d;D[d+8>>2]=e;d=c;c=D[c>>2];f=(c|0)==(f|0)?d:f;c=D[c+4>>2]}z:{A:{d=D[c>>2];B:{if(!(E[d+12|0]?0:d)){e=D[c+4>>2];if(E[e+12|0]?0:e){break B}B[c+12|0]=0;c=D[c+8>>2];C:{if((f|0)==(c|0)){c=f;break C}if(E[c+12|0]){break y}}B[c+12|0]=1;break x}e=D[c+4>>2];if(!e){break A}}if(E[e+12|0]){break A}d=c;break z}B[d+12|0]=1;B[c+12|0]=0;e=D[d+4>>2];D[c>>2]=e;if(e){D[e+8>>2]=c}D[d+8>>2]=D[c+8>>2];e=D[c+8>>2];D[((D[e>>2]!=(c|0))<<2)+e>>2]=d;D[d+4>>2]=c;D[c+8>>2]=d;e=c}c=D[d+8>>2];B[d+12|0]=E[c+12|0];B[c+12|0]=1;B[e+12|0]=1;d=D[c+4>>2];e=D[d>>2];D[c+4>>2]=e;if(e){D[e+8>>2]=c}D[d+8>>2]=D[c+8>>2];e=D[c+8>>2];D[(((c|0)!=D[e>>2])<<2)+e>>2]=d;D[d>>2]=c;D[c+8>>2]=d;break x}if(!e){B[c+12|0]=1;B[d+12|0]=0;e=D[c+4>>2];D[d>>2]=e;if(e){D[e+8>>2]=d}D[c+8>>2]=D[d+8>>2];e=D[d+8>>2];D[(((d|0)!=D[e>>2])<<2)+e>>2]=c;D[c+4>>2]=d;D[d+8>>2]=c;f=(d|0)==(f|0)?c:f;c=D[d>>2]}e=D[c>>2];D:{if(!(!e|E[e+12|0])){d=c;break D}d=D[c+4>>2];if(!(E[d+12|0]?0:d)){B[c+12|0]=0;c=D[c+8>>2];if((c|0)!=(f|0)?E[c+12|0]:0){break y}B[c+12|0]=1;break x}if(e){if(!E[e+12|0]){d=c;break D}d=D[c+4>>2]}B[d+12|0]=1;B[c+12|0]=0;e=D[d>>2];D[c+4>>2]=e;if(e){D[e+8>>2]=c}D[d+8>>2]=D[c+8>>2];e=D[c+8>>2];D[((D[e>>2]!=(c|0))<<2)+e>>2]=d;D[d>>2]=c;D[c+8>>2]=d;e=c}c=D[d+8>>2];B[d+12|0]=E[c+12|0];B[c+12|0]=1;B[e+12|0]=1;d=D[c>>2];e=D[d+4>>2];D[c>>2]=e;if(e){D[e+8>>2]=c}D[d+8>>2]=D[c+8>>2];e=D[c+8>>2];D[(((c|0)!=D[e>>2])<<2)+e>>2]=d;D[d+4>>2]=c;D[c+8>>2]=d;break x}d=c;c=D[c+8>>2];c=D[(((d|0)==D[c>>2])<<2)+c>>2];continue}}B[e+12|0]=1}c=D[g+28>>2];if(c){D[g+32>>2]=c;ma(c)}if(B[g+27|0]<0){ma(D[g+16>>2])}ma(g)}D[h+8>>2]=0;D[h>>2]=0;D[h+4>>2]=0;c=D[i+4>>2];d=D[i>>2];f=c-d|0;e=0;E:{F:{if((c|0)!=(d|0)){if((f|0)<0){break F}e=na(f);c=qa(e,0,f);g=c+f|0;D[h+8>>2]=g;D[h+4>>2]=g;D[h>>2]=c;c=d}oa(e,c,f);G:{if(B[i+27|0]>=0){D[h+24>>2]=D[i+24>>2];c=D[i+20>>2];D[h+16>>2]=D[i+16>>2];D[h+20>>2]=c;break G}ta(h+16|0,D[i+16>>2],D[i+20>>2])}Rc(h+28|0,h);f=h+16|0;c=f;H:{I:{d=D[j+4>>2];J:{if(!d){e=j+4|0;c=e;break J}e=E[c+11|0];g=e<<24>>24<0;l=g?D[c>>2]:c;g=g?D[c+4>>2]:e;while(1){c=d;d=E[c+27|0];e=d<<24>>24<0;d=e?D[c+20>>2]:d;k=d>>>0>>0;K:{L:{M:{N:{v=k?d:g;O:{if(v){s=c+16|0;e=e?D[s>>2]:s;s=ua(l,e,v);if(!s){if(d>>>0>g>>>0){break O}break N}if((s|0)>=0){break N}break O}if(d>>>0<=g>>>0){break M}}e=c;d=D[c>>2];if(d){continue}break J}d=ua(e,l,v);if(d){break L}}if(k){break K}break I}if((d|0)>=0){break I}}d=D[c+4>>2];if(d){continue}break}e=c+4|0}d=na(40);D[d+24>>2]=D[f+8>>2];g=D[f+4>>2];D[d+16>>2]=D[f>>2];D[d+20>>2]=g;D[f>>2]=0;D[f+4>>2]=0;D[f+8>>2]=0;Rc(d+28|0,f+12|0);D[d+8>>2]=c;D[d>>2]=0;D[d+4>>2]=0;D[e>>2]=d;c=d;f=D[D[j>>2]>>2];if(f){D[j>>2]=f;c=D[e>>2]}pb(D[j+4>>2],c);D[j+8>>2]=D[j+8>>2]+1;c=1;break H}d=c;c=0}B[h+44|0]=c;D[h+40>>2]=d;c=D[h+28>>2];if(c){D[h+32>>2]=c;ma(c)}if(B[h+27|0]<0){ma(D[h+16>>2])}c=D[h>>2];if(c){D[h+4>>2]=c;ma(c)}$=h+48|0;break E}pa();T()}c=D[i>>2];if(c){break s}c=1;break r}D[i+4>>2]=c;ma(c);c=(n|0)<=(y|0)&r>>>0>=z>>>0|(n|0)<(y|0)}if(B[i+27|0]<0){ma(D[i+16>>2])}$=i+32|0;break p}pa();T()}if(!c){break a}p=p+1|0;if((x|0)!=(p|0)){continue}break}}D[m+12>>2]=0;if(!hb(1,m+12|0,D[a>>2])){break b}c=D[a>>2];d=D[c+8>>2];e=D[c+16>>2];f=d-e|0;q=D[m+12>>2];c=D[c+12>>2]-(D[c+20>>2]+(d>>>0>>0)|0)|0;if(f>>>0>>0&(c|0)<=0|(c|0)<0){break b}if(q){p=0;h=((u|0)!=0)+w|0;while(1){P:{if(b>>>0>>0){D[b+8>>2]=h;D[b+4>>2]=0;D[b>>2]=j;b=b+12|0;q=D[m+12>>2];break P}e=b-o|0;c=(e|0)/12|0;b=c+1|0;if(b>>>0>=357913942){break d}d=(t-o|0)/12|0;f=d<<1;f=d>>>0<178956970?b>>>0>>0?f:b:357913941;if(f){if(f>>>0>=357913942){break c}b=na(J(f,12))}else{b=0}d=b+J(c,12)|0;D[d+8>>2]=h;D[d+4>>2]=0;D[d>>2]=j;c=d+J((e|0)/-12|0,12)|0;if((e|0)>0){oa(c,o,e)}t=b+J(f,12)|0;b=d+12|0;if(o){ma(o)}o=c}p=p+1|0;if(p>>>0>>0){continue}break}}if((b|0)!=(o|0)){continue}break}q=1;break a}pa();T()}sa();T()}q=0}if(o){ma(o)}$=m+32|0;return q}function ie(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;h=$-48|0;$=h;a:{if((c|0)!=1){break a}e=D[a+4>>2];i=D[a+12>>2];D[h+40>>2]=0;a=h;D[a+32>>2]=0;D[a+36>>2]=0;D[a+24>>2]=0;D[a+28>>2]=0;D[a+16>>2]=0;D[a+20>>2]=0;D[a+8>>2]=0;D[a+12>>2]=0;c=a+8|0;b:{if((b|0)==-2){break b}k=D[D[D[e+4>>2]+8>>2]+(i<<2)>>2];if((ba[D[D[e>>2]+8>>2]](e)|0)==1){g=$-32|0;$=g;f=D[D[D[e+4>>2]+8>>2]+(i<<2)>>2];c:{d:{e:{if((ba[D[D[e>>2]+8>>2]](e)|0)!=1|b-1>>>0>5){break e}j=ba[D[D[e>>2]+36>>2]](e)|0;a=ba[D[D[e>>2]+44>>2]](e,i)|0;if(!j|!a){break e}d=ba[D[D[e>>2]+40>>2]](e,i)|0;if(d){e=D[e+44>>2];D[g+12>>2]=d;D[g+8>>2]=e;D[g+20>>2]=a;D[g+16>>2]=a+12;d=g+8|0;a=0;f:{g:{switch(b-1|0){case 0:a=na(60);D[a+4>>2]=f;D[a>>2]=2960;b=D[c+4>>2];D[a+8>>2]=D[c>>2];D[a+12>>2]=b;b=D[c+12>>2];D[a+16>>2]=D[c+8>>2];D[a+20>>2]=b;b=D[c+20>>2];D[a+24>>2]=D[c+16>>2];D[a+28>>2]=b;D[a+40>>2]=0;D[a+32>>2]=0;D[a+36>>2]=0;b=D[c+28>>2];e=D[c+24>>2];if((b|0)!=(e|0)){b=b-e|0;if((b|0)<0){break d}f=na(b);D[a+32>>2]=f;D[a+40>>2]=f+(b>>2<<2);l=a,m=oa(f,e,b)+b|0,D[l+36>>2]=m}b=D[d+4>>2];D[a+44>>2]=D[d>>2];D[a+48>>2]=b;b=D[d+12>>2];D[a+52>>2]=D[d+8>>2];D[a+56>>2]=b;D[a>>2]=2252;break f;case 3:a=na(112);D[a+4>>2]=f;D[a>>2]=2960;b=D[c+4>>2];D[a+8>>2]=D[c>>2];D[a+12>>2]=b;b=D[c+12>>2];D[a+16>>2]=D[c+8>>2];D[a+20>>2]=b;b=D[c+20>>2];D[a+24>>2]=D[c+16>>2];D[a+28>>2]=b;D[a+40>>2]=0;D[a+32>>2]=0;D[a+36>>2]=0;b=D[c+28>>2];e=D[c+24>>2];if((b|0)!=(e|0)){b=b-e|0;if((b|0)<0){break d}f=na(b);D[a+32>>2]=f;D[a+40>>2]=f+(b>>2<<2);l=a,m=oa(f,e,b)+b|0,D[l+36>>2]=m}b=D[d+4>>2];D[a+44>>2]=D[d>>2];D[a+48>>2]=b;b=D[d+12>>2];D[a+52>>2]=D[d+8>>2];D[a+56>>2]=b;D[a+60>>2]=0;D[a+64>>2]=0;D[a>>2]=3016;D[a+68>>2]=0;D[a+72>>2]=0;D[a+76>>2]=0;D[a+80>>2]=0;D[a+84>>2]=0;D[a+88>>2]=0;D[a+92>>2]=0;D[a+96>>2]=0;D[a+100>>2]=0;D[a+104>>2]=0;D[a+108>>2]=0;break f;case 4:a=na(104);D[a+4>>2]=f;D[a>>2]=2960;b=D[c+4>>2];D[a+8>>2]=D[c>>2];D[a+12>>2]=b;b=D[c+12>>2];D[a+16>>2]=D[c+8>>2];D[a+20>>2]=b;b=D[c+20>>2];D[a+24>>2]=D[c+16>>2];D[a+28>>2]=b;D[a+40>>2]=0;D[a+32>>2]=0;D[a+36>>2]=0;b=D[c+28>>2];e=D[c+24>>2];if((b|0)!=(e|0)){b=b-e|0;if((b|0)<0){break d}f=na(b);D[a+32>>2]=f;D[a+40>>2]=f+(b>>2<<2);l=a,m=oa(f,e,b)+b|0,D[l+36>>2]=m}b=D[d+4>>2];D[a+44>>2]=D[d>>2];D[a+48>>2]=b;b=D[d+12>>2];D[a+52>>2]=D[d+8>>2];D[a+56>>2]=b;D[a+84>>2]=0;D[a+76>>2]=0;D[a+80>>2]=0;D[a+60>>2]=0;D[a+64>>2]=0;D[a>>2]=3264;b=D[d+4>>2];D[a+88>>2]=D[d>>2];D[a+92>>2]=b;b=D[d+12>>2];D[a+96>>2]=D[d+8>>2];D[a+100>>2]=b;break f;case 5:break g;default:break f}}a=na(128);D[a+4>>2]=f;D[a>>2]=2960;b=D[c+4>>2];D[a+8>>2]=D[c>>2];D[a+12>>2]=b;b=D[c+12>>2];D[a+16>>2]=D[c+8>>2];D[a+20>>2]=b;b=D[c+20>>2];D[a+24>>2]=D[c+16>>2];D[a+28>>2]=b;D[a+40>>2]=0;D[a+32>>2]=0;D[a+36>>2]=0;h:{i:{b=D[c+28>>2];e=D[c+24>>2];if((b|0)!=(e|0)){e=b-e|0;if((e|0)<0){break i}b=na(e);D[a+32>>2]=b;D[a+36>>2]=b;D[a+40>>2]=b+(e>>2<<2);f=D[c+24>>2];e=D[c+28>>2]-f|0;if((e|0)>0){b=oa(b,f,e)+e|0}D[a+36>>2]=b}D[a>>2]=2904;b=D[d+4>>2];D[a+44>>2]=D[d>>2];D[a+48>>2]=b;b=D[d+12>>2];D[a+52>>2]=D[d+8>>2];D[a+56>>2]=b;b=a- -64|0;D[b>>2]=0;D[b+4>>2]=0;D[a+60>>2]=4128;D[a>>2]=3500;b=D[d+4>>2];D[a+72>>2]=D[d>>2];D[a+76>>2]=b;b=D[d+12>>2];D[a+80>>2]=D[d+8>>2];D[a+84>>2]=b;D[a+104>>2]=1065353216;D[a+108>>2]=-1;D[a+96>>2]=-1;D[a+100>>2]=-1;D[a+88>>2]=1;D[a+92>>2]=-1;D[a+60>>2]=3736;D[a+112>>2]=0;D[a+116>>2]=0;B[a+117|0]=0;B[a+118|0]=0;B[a+119|0]=0;B[a+120|0]=0;B[a+121|0]=0;B[a+122|0]=0;B[a+123|0]=0;B[a+124|0]=0;break h}pa();T()}break f}d=a;break e}d=D[e+44>>2];D[g+12>>2]=j;D[g+8>>2]=d;D[g+20>>2]=a;D[g+16>>2]=a+12;d=g+8|0;a=0;j:{k:{switch(b-1|0){case 0:a=na(60);D[a+4>>2]=f;D[a>>2]=2960;b=D[c+4>>2];D[a+8>>2]=D[c>>2];D[a+12>>2]=b;b=D[c+12>>2];D[a+16>>2]=D[c+8>>2];D[a+20>>2]=b;b=D[c+20>>2];D[a+24>>2]=D[c+16>>2];D[a+28>>2]=b;D[a+40>>2]=0;D[a+32>>2]=0;D[a+36>>2]=0;b=D[c+28>>2];e=D[c+24>>2];if((b|0)!=(e|0)){b=b-e|0;if((b|0)<0){break d}f=na(b);D[a+32>>2]=f;D[a+40>>2]=f+(b>>2<<2);l=a,m=oa(f,e,b)+b|0,D[l+36>>2]=m}b=D[d+4>>2];D[a+44>>2]=D[d>>2];D[a+48>>2]=b;b=D[d+12>>2];D[a+52>>2]=D[d+8>>2];D[a+56>>2]=b;D[a>>2]=4156;break j;case 3:a=na(112);D[a+4>>2]=f;D[a>>2]=2960;b=D[c+4>>2];D[a+8>>2]=D[c>>2];D[a+12>>2]=b;b=D[c+12>>2];D[a+16>>2]=D[c+8>>2];D[a+20>>2]=b;b=D[c+20>>2];D[a+24>>2]=D[c+16>>2];D[a+28>>2]=b;D[a+40>>2]=0;D[a+32>>2]=0;D[a+36>>2]=0;b=D[c+28>>2];e=D[c+24>>2];if((b|0)!=(e|0)){b=b-e|0;if((b|0)<0){break d}f=na(b);D[a+32>>2]=f;D[a+40>>2]=f+(b>>2<<2);l=a,m=oa(f,e,b)+b|0,D[l+36>>2]=m}b=D[d+4>>2];D[a+44>>2]=D[d>>2];D[a+48>>2]=b;b=D[d+12>>2];D[a+52>>2]=D[d+8>>2];D[a+56>>2]=b;D[a+60>>2]=0;D[a+64>>2]=0;D[a>>2]=4580;D[a+68>>2]=0;D[a+72>>2]=0;D[a+76>>2]=0;D[a+80>>2]=0;D[a+84>>2]=0;D[a+88>>2]=0;D[a+92>>2]=0;D[a+96>>2]=0;D[a+100>>2]=0;D[a+104>>2]=0;D[a+108>>2]=0;break j;case 4:a=na(104);D[a+4>>2]=f;D[a>>2]=2960;b=D[c+4>>2];D[a+8>>2]=D[c>>2];D[a+12>>2]=b;b=D[c+12>>2];D[a+16>>2]=D[c+8>>2];D[a+20>>2]=b;b=D[c+20>>2];D[a+24>>2]=D[c+16>>2];D[a+28>>2]=b;D[a+40>>2]=0;D[a+32>>2]=0;D[a+36>>2]=0;b=D[c+28>>2];e=D[c+24>>2];if((b|0)!=(e|0)){b=b-e|0;if((b|0)<0){break d}f=na(b);D[a+32>>2]=f;D[a+40>>2]=f+(b>>2<<2);l=a,m=oa(f,e,b)+b|0,D[l+36>>2]=m}b=D[d+4>>2];D[a+44>>2]=D[d>>2];D[a+48>>2]=b;b=D[d+12>>2];D[a+52>>2]=D[d+8>>2];D[a+56>>2]=b;D[a+84>>2]=0;D[a+76>>2]=0;D[a+80>>2]=0;D[a+60>>2]=0;D[a+64>>2]=0;D[a>>2]=4816;b=D[d+4>>2];D[a+88>>2]=D[d>>2];D[a+92>>2]=b;b=D[d+12>>2];D[a+96>>2]=D[d+8>>2];D[a+100>>2]=b;break j;case 5:break k;default:break j}}a=na(128);D[a+4>>2]=f;D[a>>2]=2960;b=D[c+4>>2];D[a+8>>2]=D[c>>2];D[a+12>>2]=b;b=D[c+12>>2];D[a+16>>2]=D[c+8>>2];D[a+20>>2]=b;b=D[c+20>>2];D[a+24>>2]=D[c+16>>2];D[a+28>>2]=b;D[a+40>>2]=0;D[a+32>>2]=0;D[a+36>>2]=0;l:{m:{b=D[c+28>>2];e=D[c+24>>2];if((b|0)!=(e|0)){e=b-e|0;if((e|0)<0){break m}b=na(e);D[a+32>>2]=b;D[a+36>>2]=b;D[a+40>>2]=b+(e>>2<<2);f=D[c+24>>2];e=D[c+28>>2]-f|0;if((e|0)>0){b=oa(b,f,e)+e|0}D[a+36>>2]=b}D[a>>2]=4524;b=D[d+4>>2];D[a+44>>2]=D[d>>2];D[a+48>>2]=b;b=D[d+12>>2];D[a+52>>2]=D[d+8>>2];D[a+56>>2]=b;b=a- -64|0;D[b>>2]=0;D[b+4>>2]=0;D[a+60>>2]=5624;D[a>>2]=5040;b=D[d+4>>2];D[a+72>>2]=D[d>>2];D[a+76>>2]=b;b=D[d+12>>2];D[a+80>>2]=D[d+8>>2];D[a+84>>2]=b;D[a+104>>2]=1065353216;D[a+108>>2]=-1;D[a+96>>2]=-1;D[a+100>>2]=-1;D[a+88>>2]=1;D[a+92>>2]=-1;D[a+60>>2]=5260;D[a+112>>2]=0;D[a+116>>2]=0;B[a+117|0]=0;B[a+118|0]=0;B[a+119|0]=0;B[a+120|0]=0;B[a+121|0]=0;B[a+122|0]=0;B[a+123|0]=0;B[a+124|0]=0;break l}pa();T()}break j}d=a}$=g+32|0;break c}pa();T()}if(d){break b}}d=na(44);D[d+4>>2]=k;D[d>>2]=2960;a=D[c+4>>2];D[d+8>>2]=D[c>>2];D[d+12>>2]=a;a=D[c+12>>2];D[d+16>>2]=D[c+8>>2];D[d+20>>2]=a;a=D[c+20>>2];D[d+24>>2]=D[c+16>>2];D[d+28>>2]=a;D[d+40>>2]=0;D[d+32>>2]=0;D[d+36>>2]=0;n:{a=D[c+28>>2];b=D[c+24>>2];if((a|0)!=(b|0)){a=a-b|0;if((a|0)<0){break n}c=na(a);D[d+32>>2]=c;D[d+40>>2]=c+(a>>2<<2);l=d,m=oa(c,b,a)+a|0,D[l+36>>2]=m}D[d>>2]=5652;break b}pa();T()}a=D[h+32>>2];if(!a){break a}D[h+36>>2]=a;ma(a)}$=h+48|0;return d|0}function nf(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;o=$-16|0;$=o;D[o+12>>2]=b;b=na(32);D[o>>2]=b;D[o+4>>2]=24;D[o+8>>2]=-2147483616;B[b+24|0]=0;d=E[1196]|E[1197]<<8|(E[1198]<<16|E[1199]<<24);c=E[1192]|E[1193]<<8|(E[1194]<<16|E[1195]<<24);B[b+16|0]=c;B[b+17|0]=c>>>8;B[b+18|0]=c>>>16;B[b+19|0]=c>>>24;B[b+20|0]=d;B[b+21|0]=d>>>8;B[b+22|0]=d>>>16;B[b+23|0]=d>>>24;d=E[1188]|E[1189]<<8|(E[1190]<<16|E[1191]<<24);c=E[1184]|E[1185]<<8|(E[1186]<<16|E[1187]<<24);B[b+8|0]=c;B[b+9|0]=c>>>8;B[b+10|0]=c>>>16;B[b+11|0]=c>>>24;B[b+12|0]=d;B[b+13|0]=d>>>8;B[b+14|0]=d>>>16;B[b+15|0]=d>>>24;d=E[1180]|E[1181]<<8|(E[1182]<<16|E[1183]<<24);c=E[1176]|E[1177]<<8|(E[1178]<<16|E[1179]<<24);B[b|0]=c;B[b+1|0]=c>>>8;B[b+2|0]=c>>>16;B[b+3|0]=c>>>24;B[b+4|0]=d;B[b+5|0]=d>>>8;B[b+6|0]=d>>>16;B[b+7|0]=d>>>24;k=$-48|0;$=k;m=a;f=a+16|0;d=D[f>>2];a:{b:{if(!d){break b}b=D[o+12>>2];a=f;while(1){c=(b|0)>D[d+16>>2];a=c?a:d;d=D[(c?d+4|0:d)>>2];if(d){continue}break}if((a|0)==(f|0)){break b}if((b|0)>=D[a+16>>2]){break a}}u=k+24|0;a=u;D[a+4>>2]=0;D[a+8>>2]=0;v=a+4|0;D[a>>2]=v;b=D[o+12>>2];p=k+16|0;a=p;D[a>>2]=0;D[a+4>>2]=0;D[k+8>>2]=b;D[k+12>>2]=a;s=k+8|4;d=D[u>>2];if((v|0)!=(d|0)){while(1){g=d+16|0;q=$-16|0;$=q;b=q+8|0;c:{d:{e:{f:{g:{h:{i:{c=p;e=s+4|0;j:{if((c|0)==(e|0)){break j}a=E[c+27|0];h=a<<24>>24<0;j=E[g+11|0];n=j<<24>>24;i=(n|0)<0;a=h?D[c+20>>2]:a;j=i?D[g+4>>2]:j;l=a>>>0>>0;r=l?a:j;if(r){i=i?D[g>>2]:g;t=c+16|0;h=h?D[t>>2]:t;t=ua(i,h,r);if(!t){if(a>>>0>j>>>0){break j}break i}if((t|0)>=0){break i}break j}if(a>>>0<=j>>>0){break h}}h=D[c>>2];k:{b=c;l:{if((b|0)==D[s>>2]){break l}m:{if(!h){a=c;while(1){b=D[a+8>>2];j=D[b>>2]==(a|0);a=b;if(j){continue}break}break m}a=h;while(1){b=a;a=D[a+4>>2];if(a){continue}break}}j=E[g+11|0];l=j<<24>>24;a=(l|0)<0;i=E[b+27|0];n=i<<24>>24<0;n:{j=a?D[g+4>>2]:j;i=n?D[b+20>>2]:i;r=j>>>0>>0?j:i;if(r){t=b+16|0;a=ua(n?D[t>>2]:t,a?D[g>>2]:g,r);if(a){break n}}if(j>>>0>i>>>0){break l}break k}if((a|0)>=0){break k}}if(!h){D[q+12>>2]=c;b=c;break c}D[q+12>>2]=b;b=b+4|0;break c}a=D[e>>2];if(!a){D[q+12>>2]=e;b=e;break c}h=(l|0)<0?D[g>>2]:g;c=e;while(1){b=a;n=E[a+27|0];e=n<<24>>24<0;a=e?D[a+20>>2]:n;n=a>>>0>>0;o:{p:{q:{r:{i=n?a:j;s:{if(i){l=b+16|0;e=e?D[l>>2]:l;l=ua(h,e,i);if(!l){if(a>>>0>j>>>0){break s}break r}if((l|0)>=0){break r}break s}if(a>>>0<=j>>>0){break q}}c=b;a=D[b>>2];if(a){continue}break e}a=ua(e,h,i);if(a){break p}}if(n){break o}break e}if((a|0)>=0){break e}}c=b+4|0;a=D[b+4>>2];if(a){continue}break}break e}a=ua(h,i,r);if(a){break g}}if(l){break f}break d}if((a|0)>=0){break d}}h=D[c+4>>2];t:{if(!h){a=c;while(1){b=D[a+8>>2];i=D[b>>2]!=(a|0);a=b;if(i){continue}break}break t}a=h;while(1){b=a;a=D[a>>2];if(a){continue}break}}u:{v:{if((b|0)==(e|0)){break v}i=E[b+27|0];a=i<<24>>24<0;w:{i=a?D[b+20>>2]:i;l=j>>>0>i>>>0?i:j;if(l){r=b+16|0;a=ua((n|0)<0?D[g>>2]:g,a?D[r>>2]:r,l);if(a){break w}}if(j>>>0>>0){break v}break u}if((a|0)>=0){break u}}if(!h){D[q+12>>2]=c;b=c+4|0;break c}D[q+12>>2]=b;break c}a=D[e>>2];if(!a){D[q+12>>2]=e;b=e;break c}h=(n|0)<0?D[g>>2]:g;c=e;while(1){b=a;n=E[a+27|0];e=n<<24>>24<0;a=e?D[a+20>>2]:n;n=a>>>0>>0;x:{y:{z:{A:{i=n?a:j;B:{if(i){l=b+16|0;e=e?D[l>>2]:l;l=ua(h,e,i);if(!l){if(a>>>0>j>>>0){break B}break A}if((l|0)>=0){break A}break B}if(a>>>0<=j>>>0){break z}}c=b;a=D[b>>2];if(a){continue}break e}a=ua(e,h,i);if(a){break y}}if(n){break x}break e}if((a|0)>=0){break e}}c=b+4|0;a=D[b+4>>2];if(a){continue}break}}D[q+12>>2]=b;b=c;break c}D[q+12>>2]=c;D[b>>2]=c}c=D[b>>2];if(c){a=0}else{c=na(40);a=c+16|0;C:{if(B[g+11|0]>=0){e=D[g+4>>2];D[a>>2]=D[g>>2];D[a+4>>2]=e;D[a+8>>2]=D[g+8>>2];break C}ta(a,D[g>>2],D[g+4>>2])}a=c+28|0;D:{if(B[g+23|0]>=0){e=D[g+16>>2];D[a>>2]=D[g+12>>2];D[a+4>>2]=e;D[a+8>>2]=D[g+20>>2];break D}ta(a,D[g+12>>2],D[g+16>>2])}D[c+8>>2]=D[q+12>>2];D[c>>2]=0;D[c+4>>2]=0;D[b>>2]=c;a=c;e=D[D[s>>2]>>2];if(e){D[s>>2]=e;a=D[b>>2]}pb(D[s+4>>2],a);D[s+8>>2]=D[s+8>>2]+1;a=1}B[k+44|0]=a;D[k+40>>2]=c;$=q+16|0;a=D[d+4>>2];E:{if(a){while(1){d=a;a=D[a>>2];if(a){continue}break E}}while(1){a=d;d=D[d+8>>2];if((a|0)!=D[d>>2]){continue}break}}if((d|0)!=(v|0)){continue}break}b=D[k+8>>2]}d=f;a=D[d>>2];F:{G:{if(!a){break G}while(1){d=a;a=D[a+16>>2];if((a|0)>(b|0)){f=d;a=D[d>>2];if(a){continue}break G}if((a|0)>=(b|0)){a=d;break F}a=D[d+4>>2];if(a){continue}break}f=d+4|0}a=na(32);D[a+16>>2]=b;D[a+20>>2]=D[k+12>>2];b=a+24|0;c=D[k+16>>2];D[b>>2]=c;e=D[k+20>>2];D[a+28>>2]=e;H:{if(!e){D[a+20>>2]=b;break H}D[c+8>>2]=b;D[k+16>>2]=0;D[k+20>>2]=0;D[k+12>>2]=p}D[a+8>>2]=d;D[a>>2]=0;D[a+4>>2]=0;D[f>>2]=a;d=a;b=D[D[m+12>>2]>>2];if(b){D[m+12>>2]=b;d=D[f>>2]}pb(D[m+16>>2],d);D[m+20>>2]=D[m+20>>2]+1}kb(s,D[k+16>>2]);kb(u,D[u+4>>2])}$=k+48|0;e=$-48|0;$=e;f=$-32|0;$=f;d=f+21|0;h=f+32|0;c=h;I:{if((d|0)==(c|0)){break I}}b=c-d|0;J:{if((b|0)<=9){p=61;if((b|0)<(G[2736]<=1|0)){break J}}B[d|0]=49;c=d+1|0;p=0}D[f+12>>2]=p;D[f+8>>2]=c;p=$-16|0;$=p;b=e+8|0;m=$-16|0;$=m;K:{g=D[f+8>>2];f=g-d|0;if(f>>>0<=4294967279){L:{if(f>>>0<11){B[b+11|0]=f;c=b;break L}if(f>>>0>=11){k=f+16&-16;c=k-1|0;c=(c|0)==11?k:c}else{c=10}k=c+1|0;c=na(k);D[b>>2]=c;D[b+8>>2]=k|-2147483648;D[b+4>>2]=f}while(1){if((d|0)!=(g|0)){B[c|0]=E[d|0];c=c+1|0;d=d+1|0;continue}break}B[m+15|0]=0;B[c|0]=E[m+15|0];$=m+16|0;break K}Ca();T()}$=p+16|0;$=h;D[e+32>>2]=o;M:{N:{c=a+20|0;a=D[c+4>>2];O:{if(!a){b=c+4|0;d=b;break O}b=E[o+11|0];d=b<<24>>24<0;m=d?D[o>>2]:o;f=d?D[o+4>>2]:b;while(1){d=a;h=E[a+27|0];b=h<<24>>24<0;a=b?D[a+20>>2]:h;h=a>>>0>>0;P:{Q:{R:{S:{p=h?a:f;T:{if(p){g=d+16|0;b=b?D[g>>2]:g;g=ua(m,b,p);if(!g){if(a>>>0>f>>>0){break T}break S}if((g|0)>=0){break S}break T}if(a>>>0<=f>>>0){break R}}b=d;a=D[b>>2];if(a){continue}break O}a=ua(b,m,p);if(a){break Q}}if(h){break P}break N}if((a|0)>=0){break N}}a=D[d+4>>2];if(a){continue}break}b=d+4|0}a=na(40);m=a+16|0;f=D[e+32>>2];U:{if(B[f+11|0]>=0){h=D[f+4>>2];D[m>>2]=D[f>>2];D[m+4>>2]=h;D[m+8>>2]=D[f+8>>2];break U}ta(m,D[f>>2],D[f+4>>2])}D[a+8>>2]=d;D[a>>2]=0;D[a+4>>2]=0;D[a+36>>2]=0;D[a+28>>2]=0;D[a+32>>2]=0;D[b>>2]=a;d=a;f=D[D[c>>2]>>2];if(f){D[c>>2]=f;d=D[b>>2]}pb(D[c+4>>2],d);D[c+8>>2]=D[c+8>>2]+1;b=1;break M}a=d;b=0}B[e+44|0]=b;D[e+40>>2]=a;a=D[e+40>>2];if(B[a+39|0]<0){ma(D[a+28>>2])}b=D[e+12>>2];D[a+28>>2]=D[e+8>>2];D[a+32>>2]=b;D[a+36>>2]=D[e+16>>2];$=e+48|0;if(B[o+11|0]<0){ma(D[o>>2])}$=o+16|0}function nb(a,b,c,d){var e=0,f=0,g=0,h=0,i=0;a:{b:{if(!d){break b}c:{d:{switch(D[a+28>>2]-1|0){case 0:i=1;e:{e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)<=0){break e}e=D[a>>2];h=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;f=b;b=h+f|0;g=D[e+4>>2];e=g-h|0;if(!E[a+32|0]){if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=B[b|0];f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break e}b=b+1|0;if(g>>>0>b>>>0){continue}break}break a}if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=K(B[b|0])/K(127);f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break e}b=b+1|0;if(g>>>0>b>>>0){continue}break}break a}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 1:i=1;f:{e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)<=0){break f}e=D[a>>2];h=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;f=b;b=h+f|0;g=D[e+4>>2];e=g-h|0;if(!E[a+32|0]){if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=E[b|0];f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break f}b=b+1|0;if(g>>>0>b>>>0){continue}break}break a}if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=K(E[b|0])/K(255);f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break f}b=b+1|0;if(g>>>0>b>>>0){continue}break}break a}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 2:i=1;g:{e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)<=0){break g}e=D[a>>2];h=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;f=b;b=h+f|0;g=D[e+4>>2];e=g-h|0;if(!E[a+32|0]){if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=C[b>>1];f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break g}b=b+2|0;if(g>>>0>b>>>0){continue}break}break a}if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=K(C[b>>1])/K(32767);f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break g}b=b+2|0;if(g>>>0>b>>>0){continue}break}break a}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 3:i=1;h:{e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)<=0){break h}e=D[a>>2];h=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;f=b;b=h+f|0;g=D[e+4>>2];e=g-h|0;if(!E[a+32|0]){if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=F[b>>1];f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break h}b=b+2|0;if(g>>>0>b>>>0){continue}break}break a}if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=K(F[b>>1])/K(65535);f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break h}b=b+2|0;if(g>>>0>b>>>0){continue}break}break a}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 4:i=1;i:{e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)<=0){break i}e=D[a>>2];h=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;f=b;b=h+f|0;g=D[e+4>>2];e=g-h|0;if(!E[a+32|0]){if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=D[b>>2];f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break i}b=b+4|0;if(g>>>0>b>>>0){continue}break}break a}if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=K(D[b>>2])*K(4.656612873077393e-10);f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break i}b=b+4|0;if(g>>>0>b>>>0){continue}break}break a}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 5:i=1;j:{e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)<=0){break j}e=D[a>>2];h=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;f=b;b=h+f|0;g=D[e+4>>2];e=g-h|0;if(!E[a+32|0]){if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=G[b>>2];f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break j}b=b+4|0;if(g>>>0>b>>>0){continue}break}break a}if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=K(G[b>>2])*K(2.3283064365386963e-10);f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break j}b=b+4|0;if(g>>>0>b>>>0){continue}break}break a}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 6:i=1;k:{e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)<=0){break k}e=D[a>>2];h=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;f=b;b=h+f|0;g=D[e+4>>2];e=g-h|0;if(!E[a+32|0]){if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=+G[b>>2]+ +D[b+4>>2]*4294967296;f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break k}b=b+8|0;if(g>>>0>b>>>0){continue}break}break a}if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=K(+G[b>>2]+ +D[b+4>>2]*4294967296)*K(10842021724855044e-35);f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break k}b=b+8|0;if(g>>>0>b>>>0){continue}break}break a}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 7:i=1;l:{e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)<=0){break l}e=D[a>>2];h=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;f=b;b=h+f|0;g=D[e+4>>2];e=g-h|0;if(!E[a+32|0]){if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=+G[b>>2]+ +G[b+4>>2]*4294967296;f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break l}b=b+8|0;if(g>>>0>b>>>0){continue}break}break a}if((e|0)<=(f|0)){break a}f=0;while(1){H[(f<<2)+d>>2]=K(+G[b>>2]+ +G[b+4>>2]*4294967296)*K(5.421010862427522e-20);f=f+1|0;e=B[a+24|0];if((f|0)>=(((c|0)>(e|0)?e:c)|0)){break l}b=b+8|0;if(g>>>0>b>>>0){continue}break}break a}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 8:i=1;f=B[a+24|0];if((((c|0)>(f|0)?f:c)|0)>0){g=D[a>>2];f=D[g>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;g=D[g+4>>2];while(1){if(b>>>0>=g>>>0){break a}H[(e<<2)+d>>2]=H[b>>2];b=b+4|0;e=e+1|0;f=B[a+24|0];if((e|0)<(((c|0)>(f|0)?f:c)|0)){continue}break}}if((c|0)<=(f|0)){break b}c=c-f|0;a=(f<<2)+d|0;break c;case 9:i=1;f=B[a+24|0];if((((c|0)>(f|0)?f:c)|0)>0){g=D[a>>2];f=D[g>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;g=D[g+4>>2];while(1){if(b>>>0>=g>>>0){break a}H[(e<<2)+d>>2]=I[b>>3];b=b+8|0;e=e+1|0;f=B[a+24|0];if((e|0)<(((c|0)>(f|0)?f:c)|0)){continue}break}}if((c|0)<=(f|0)){break b}c=c-f|0;a=(f<<2)+d|0;break c;case 10:break d;default:break b}}i=1;f=B[a+24|0];if((((c|0)>(f|0)?f:c)|0)>0){g=D[a>>2];f=D[g>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;while(1){if(G[g+4>>2]<=b>>>0){break a}H[(e<<2)+d>>2]=E[b|0]?K(1):K(0);b=b+1|0;e=e+1|0;f=B[a+24|0];if((e|0)<(((c|0)>(f|0)?f:c)|0)){continue}break}}if((c|0)<=(f|0)){break b}c=c-f|0;a=(f<<2)+d|0}qa(a,0,c<<2)}return i}return 0}function $d(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,E=0,F=0,G=0,H=0,I=0,K=0,L=0,M=0,N=0;g=$+-64|0;$=g;D[a+8>>2]=e;x=a+32|0;f=D[x>>2];d=D[a+36>>2]-f>>2;a:{b:{if(d>>>0>>0){ra(x,e-d|0);D[g+56>>2]=0;D[g+60>>2]=0;D[g+48>>2]=0;D[g+52>>2]=0;D[g+40>>2]=0;D[g+44>>2]=0;D[g+32>>2]=0;D[g+36>>2]=0;D[g+24>>2]=0;D[g+28>>2]=0;D[g+16>>2]=0;D[g+20>>2]=0;D[g>>2]=0;break b}if(d>>>0>e>>>0){D[a+36>>2]=f+(e<<2)}D[g+56>>2]=0;D[g+60>>2]=0;D[g+48>>2]=0;D[g+52>>2]=0;D[g+40>>2]=0;D[g+44>>2]=0;D[g+32>>2]=0;D[g+36>>2]=0;D[g+24>>2]=0;D[g+28>>2]=0;D[g+16>>2]=0;D[g+20>>2]=0;D[g>>2]=0;d=0;if(!e){break a}}xa(g+16|0,e,g);h=D[g+28>>2];d=D[g+32>>2]}D[g>>2]=0;d=d-h>>2;c:{if(d>>>0>=e>>>0){if(d>>>0<=e>>>0){break c}D[g+32>>2]=(e<<2)+h;break c}xa(g+16|12,e-d|0,g)}D[g>>2]=0;f=D[g+40>>2];d=D[g+44>>2]-f>>2;d:{if(d>>>0>=e>>>0){if(d>>>0<=e>>>0){break d}D[g+44>>2]=f+(e<<2);break d}xa(g+40|0,e-d|0,g)}D[g>>2]=0;f=D[g+52>>2];d=D[g+56>>2]-f>>2;e:{if(d>>>0>=e>>>0){if(d>>>0<=e>>>0){break e}D[g+56>>2]=f+(e<<2);break e}xa(g+52|0,e-d|0,g)}f:{if(D[a+8>>2]<=0){break f}i=D[g+16>>2];j=D[a+32>>2];h=0;while(1){d=h<<2;f=D[d+i>>2];n=D[a+16>>2];g:{if((f|0)>(n|0)){D[d+j>>2]=n;break g}d=d+j|0;n=D[a+12>>2];if((n|0)>(f|0)){D[d>>2]=n;break g}D[d>>2]=f}h=h+1|0;d=D[a+8>>2];if((h|0)<(d|0)){continue}break}if((d|0)<=0){break f}d=0;while(1){i=d<<2;f=i+c|0;i=D[b+i>>2]+D[j+i>>2]|0;D[f>>2]=i;h:{if((i|0)>D[a+16>>2]){i=i-D[a+20>>2]|0}else{if((i|0)>=D[a+12>>2]){break h}i=i+D[a+20>>2]|0}D[f>>2]=i}d=d+1|0;if((d|0)>2]){continue}break}}G=D[a+52>>2];q=D[a+48>>2];y=na(16);d=y;D[d>>2]=0;D[d+4>>2]=0;D[d+8>>2]=0;D[d+12>>2]=0;D[g+8>>2]=0;D[g>>2]=0;D[g+4>>2]=0;i:{if(e){if(e>>>0>=1073741824){break i}d=e<<2;s=na(d);D[g>>2]=s;D[g+8>>2]=d+s;qa(s,0,d)}d=D[a+56>>2];A=D[d>>2];d=D[d+4>>2]-A|0;j:{if((d|0)<5){break j}u=d>>2;H=(u|0)>2?u:2;I=u>>>0>1?u:1;B=e&-2;C=e&1;K=e&-4;E=e&3;z=e-1|0;L=e<<2;F=1;n=1;while(1){k:{l:{m:{n:{if((n|0)!=(I|0)){o:{p:{f=D[(n<<2)+A>>2];if((f|0)==-1){break p}k=1;d=f+2|0;j=(f>>>0)%3|0;v=j?f-1|0:d;o=1<>>5|0;i=0;M=(j|0)!=0|(d|0)!=-1;N=D[q>>2];d=f;q:{while(1){r:{if(D[(d>>>3&536870908)+N>>2]>>>d&1){break r}j=D[D[D[q+64>>2]+12>>2]+(d<<2)>>2];if((j|0)==-1){break r}m=D[G>>2];h=D[q+28>>2];r=D[m+(D[h+(j<<2)>>2]<<2)>>2];if((r|0)>=(n|0)){break r}l=j+1|0;l=D[m+(D[h+(((l>>>0)%3|0?l:j-2|0)<<2)>>2]<<2)>>2];if((l|0)>=(n|0)){break r}h=D[m+(D[h+(j+((j>>>0)%3|0?-1:2)<<2)>>2]<<2)>>2];if((h|0)>=(n|0)){break r}s:{if(!e){break s}j=D[(g+16|0)+J(i,12)>>2];m=J(e,h);l=J(e,l);r=J(e,r);h=0;w=0;if(z){while(1){D[j+(h<<2)>>2]=(D[(h+m<<2)+c>>2]+D[(h+l<<2)+c>>2]|0)-D[(h+r<<2)+c>>2];p=h|1;D[j+(p<<2)>>2]=(D[(m+p<<2)+c>>2]+D[(l+p<<2)+c>>2]|0)-D[(r+p<<2)+c>>2];h=h+2|0;w=w+2|0;if((B|0)!=(w|0)){continue}break}}if(!C){break s}D[j+(h<<2)>>2]=(D[(h+m<<2)+c>>2]+D[(h+l<<2)+c>>2]|0)-D[(h+r<<2)+c>>2]}j=4;i=i+1|0;if((i|0)==4){break q}}t:{if(k&1){h=d-2|0;j=d+1|0;d=-1;j=(j>>>0)%3|0?j:h;if((j|0)==-1|D[D[q>>2]+(j>>>3&536870908)>>2]>>>j&1){break t}j=D[D[D[q+64>>2]+12>>2]+(j<<2)>>2];if((j|0)==-1){break t}d=j+1|0;d=(d>>>0)%3|0?d:j-2|0;break t}u:{if((d>>>0)%3|0){h=d-1|0;break u}h=d+2|0;d=-1;if((h|0)==-1){break t}}d=-1;if(D[D[q>>2]+(h>>>3&536870908)>>2]>>>h&1){break t}j=D[D[D[q+64>>2]+12>>2]+(h<<2)>>2];if((j|0)==-1){break t}if((j>>>0)%3|0){d=j-1|0;break t}d=j+2|0}v:{if((d|0)==(f|0)){break v}if(!((k^1)&1|(d|0)!=-1)){if(!M|o&D[D[q>>2]+(t<<2)>>2]){break v}d=D[D[D[q+64>>2]+12>>2]+(v<<2)>>2];if((d|0)==-1){break v}k=0;d=(d>>>0)%3|0?d-1|0:d+2|0}if((d|0)!=-1){continue}}break}j=i;if((j|0)<=0){break p}}if(e){qa(s,0,L)}d=j-1|0;r=(d<<2)+y|0;d=J(d,12)+a|0;v=d;w=D[d- -64>>2];k=0;d=D[g>>2];f=0;while(1){i=D[r>>2];D[r>>2]=i+1;if(i>>>0>=w>>>0){break j}w:{if(D[D[v+60>>2]+(i>>>3&536870908)>>2]>>>i&1){break w}f=f+1|0;if(!e){break w}m=D[(g+16|0)+J(k,12)>>2];i=0;h=0;p=0;if(z>>>0>=3){while(1){l=h<<2;o=l+d|0;D[o>>2]=D[o>>2]+D[m+l>>2];o=l|4;t=o+d|0;D[t>>2]=D[t>>2]+D[m+o>>2];o=l|8;t=o+d|0;D[t>>2]=D[t>>2]+D[m+o>>2];l=l|12;o=l+d|0;D[o>>2]=D[o>>2]+D[m+l>>2];h=h+4|0;p=p+4|0;if((K|0)!=(p|0)){continue}break}}if(!E){break w}while(1){l=h<<2;p=l+d|0;D[p>>2]=D[p>>2]+D[m+l>>2];h=h+1|0;i=i+1|0;if((E|0)!=(i|0)){continue}break}}k=k+1|0;if((k|0)!=(j|0)){continue}break}i=J(e,n);if(!f){break o}if(!e){break l}h=0;d=0;if(z){break n}break m}i=J(e,n)}if(D[a+8>>2]<=0){break k}k=(J(n-1|0,e)<<2)+c|0;j=D[x>>2];h=0;while(1){d=h<<2;f=D[d+k>>2];m=D[a+16>>2];x:{if((f|0)>(m|0)){D[d+j>>2]=m;break x}d=d+j|0;m=D[a+12>>2];if((m|0)>(f|0)){D[d>>2]=m;break x}D[d>>2]=f}h=h+1|0;f=D[a+8>>2];if((h|0)<(f|0)){continue}break}d=0;if((f|0)<=0){break k}f=i<<2;h=f+c|0;k=b+f|0;while(1){i=d<<2;f=i+h|0;i=D[i+k>>2]+D[j+i>>2]|0;D[f>>2]=i;y:{if((i|0)>D[a+16>>2]){i=i-D[a+20>>2]|0}else{if((i|0)>=D[a+12>>2]){break y}i=i+D[a+20>>2]|0}D[f>>2]=i}d=d+1|0;if((d|0)>2]){continue}break}break k}va();T()}while(1){j=h<<2;k=j+s|0;D[k>>2]=D[k>>2]/(f|0);j=(j|4)+s|0;D[j>>2]=D[j>>2]/(f|0);h=h+2|0;d=d+2|0;if((B|0)!=(d|0)){continue}break}}if(!C){break l}d=(h<<2)+s|0;D[d>>2]=D[d>>2]/(f|0)}if(D[a+8>>2]<=0){break k}j=D[x>>2];h=0;while(1){d=h<<2;f=D[d+s>>2];k=D[a+16>>2];z:{if((f|0)>(k|0)){D[d+j>>2]=k;break z}d=d+j|0;k=D[a+12>>2];if((k|0)>(f|0)){D[d>>2]=k;break z}D[d>>2]=f}h=h+1|0;f=D[a+8>>2];if((h|0)<(f|0)){continue}break}d=0;if((f|0)<=0){break k}f=i<<2;h=f+c|0;k=b+f|0;while(1){i=d<<2;f=i+h|0;i=D[i+k>>2]+D[j+i>>2]|0;D[f>>2]=i;A:{if((i|0)>D[a+16>>2]){i=i-D[a+20>>2]|0}else{if((i|0)>=D[a+12>>2]){break A}i=i+D[a+20>>2]|0}D[f>>2]=i}d=d+1|0;if((d|0)>2]){continue}break}}n=n+1|0;F=(u|0)>(n|0);if((n|0)!=(H|0)){continue}break}}a=D[g>>2];if(a){ma(a)}ma(y);a=D[g+52>>2];if(a){D[g+56>>2]=a;ma(a)}a=D[g+40>>2];if(a){D[g+44>>2]=a;ma(a)}a=D[g+28>>2];if(a){D[g+32>>2]=a;ma(a)}a=D[g+16>>2];if(a){D[g+20>>2]=a;ma(a)}$=g- -64|0;return(F^-1)&1}pa();T()}function wd(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;f=$-32|0;$=f;k=D[D[a+4>>2]+44>>2];d=D[a+8>>2];h=D[d>>2];d=D[d+4>>2];D[f+24>>2]=0;D[f+16>>2]=0;D[f+20>>2]=0;e=(d-h>>2>>>0)/3|0;d=D[k+96>>2];g=(D[k+100>>2]-d|0)/12|0;a:{if(e>>>0>g>>>0){j=e-g|0;c=D[k+104>>2];h=D[k+100>>2];if(j>>>0<=(c-h|0)/12>>>0){b:{if(!j){break b}d=J(j,12);j=d;e=d-12|0;g=((e>>>0)/12|0)+1&3;c:{if(!g){d=h;break c}d=h;while(1){c=D[f+20>>2];D[d>>2]=D[f+16>>2];D[d+4>>2]=c;D[d+8>>2]=D[f+24>>2];d=d+12|0;i=i+1|0;if((g|0)!=(i|0)){continue}break}}h=h+j|0;if(e>>>0<36){break b}while(1){c=D[f+20>>2];D[d>>2]=D[f+16>>2];D[d+4>>2]=c;D[d+8>>2]=D[f+24>>2];D[d+20>>2]=D[f+24>>2];c=D[f+20>>2];D[d+12>>2]=D[f+16>>2];D[d+16>>2]=c;D[d+32>>2]=D[f+24>>2];c=D[f+20>>2];D[d+24>>2]=D[f+16>>2];D[d+28>>2]=c;c=D[f+20>>2];D[d+36>>2]=D[f+16>>2];D[d+40>>2]=c;D[d+44>>2]=D[f+24>>2];d=d+48|0;if((h|0)!=(d|0)){continue}break}}D[k+100>>2]=h;break a}d:{d=D[k+96>>2];g=(h-d|0)/12|0;e=g+j|0;if(e>>>0<357913942){c=(c-d|0)/12|0;d=c<<1;l=c>>>0<178956970?d>>>0>e>>>0?d:e:357913941;if(l){if(l>>>0>=357913942){break d}o=na(J(l,12))}c=J(g,12)+o|0;d=c;m=J(j,12);j=m-12|0;e=((j>>>0)/12|0)+1&3;if(e){d=c;while(1){g=D[f+20>>2];D[d>>2]=D[f+16>>2];D[d+4>>2]=g;D[d+8>>2]=D[f+24>>2];d=d+12|0;i=i+1|0;if((e|0)!=(i|0)){continue}break}}e=c+m|0;if(j>>>0>=36){while(1){g=D[f+20>>2];D[d>>2]=D[f+16>>2];D[d+4>>2]=g;D[d+8>>2]=D[f+24>>2];D[d+20>>2]=D[f+24>>2];g=D[f+20>>2];D[d+12>>2]=D[f+16>>2];D[d+16>>2]=g;D[d+32>>2]=D[f+24>>2];g=D[f+20>>2];D[d+24>>2]=D[f+16>>2];D[d+28>>2]=g;g=D[f+20>>2];D[d+36>>2]=D[f+16>>2];D[d+40>>2]=g;D[d+44>>2]=D[f+24>>2];d=d+48|0;if((e|0)!=(d|0)){continue}break}}g=D[k+96>>2];h=h-g|0;d=c+J((h|0)/-12|0,12)|0;if((h|0)>0){oa(d,g,h)}D[k+104>>2]=J(l,12)+o;D[k+100>>2]=e;D[k+96>>2]=d;if(g){ma(g)}break a}pa();T()}sa();T()}if(e>>>0>=g>>>0){break a}D[k+100>>2]=d+J(e,12)}e:{if(D[a+216>>2]==D[a+220>>2]){e=D[a+4>>2];h=D[e+44>>2];d=D[h+100>>2];m=D[h+96>>2];if((d|0)!=(m|0)){d=(d-m|0)/12|0;g=d>>>0>1?d:1;c=0;while(1){k=D[a+8>>2];h=m+J(c,12)|0;l=J(c,3);f:{g:{if((l|0)==-1){i=D[(D[k>>2]+(l<<2)|0)+4>>2];n=-1;d=1;break g}i=-1;n=D[D[k>>2]+(l<<2)>>2];d=l+1|0;if((d|0)==-1){d=0;break g}i=D[D[k>>2]+(d<<2)>>2];d=l+2|0;j=-1;if((d|0)==-1){break f}}j=D[D[k>>2]+(d<<2)>>2]}D[h+8>>2]=j;D[h+4>>2]=i;D[h>>2]=n;c=c+1|0;if((g|0)!=(c|0)){continue}break}}D[D[e+4>>2]+80>>2]=b;c=1;break e}h=0;D[f+24>>2]=0;D[f+16>>2]=0;D[f+20>>2]=0;o=D[a+8>>2];c=D[o>>2];d=D[o+4>>2];D[f+8>>2]=0;D[f>>2]=0;D[f+4>>2]=0;b=0;h:{i:{j:{k:{l:{m:{if((d|0)!=(c|0)){d=d-c|0;if((d|0)<0){break m}b=na(d);D[f>>2]=b;D[f+8>>2]=(d>>2<<2)+b;u=f,v=qa(b,0,d)+d|0,D[u+4>>2]=v}c=D[o+24>>2];if((D[o+28>>2]-c|0)<=0){break i}d=0;while(1){g=D[(q<<2)+c>>2];n:{if((g|0)==-1){break n}o:{if(D[D[a+120>>2]+(q>>>3&536870908)>>2]>>>q&1){break o}s=D[a+216>>2];c=D[a+220>>2];if((s|0)==(c|0)){break o}i=g+2|0;e=(g>>>0)%3|0;t=e?g-1|0:i;c=(c-s|0)/144|0;k=c>>>0>1?c:1;r=0;l=(e|0)!=0|(i|0)!=-1;while(1){e=g<<2;i=J(r,144)+s|0;c=D[e+D[D[i+68>>2]>>2]>>2];p:{if(!(D[D[i+16>>2]+(c>>>3&536870908)>>2]>>>c&1)){break p}c=-1;q:{if(!l){break q}j=D[D[o+12>>2]+(t<<2)>>2];c=-1;if((j|0)==-1){break q}c=j-1|0;if((j>>>0)%3|0){break q}c=j+2|0}if((g|0)==(c|0)){break p}m=D[i+32>>2];j=D[m+e>>2];while(1){i=0;if((c|0)==-1){break h}if((j|0)!=D[m+(c<<2)>>2]){g=c;break o}r:{s:{if((c>>>0)%3|0){i=c-1|0;break s}i=c+2|0;e=-1;if((i|0)==-1){break r}}c=D[D[o+12>>2]+(i<<2)>>2];e=-1;if((c|0)==-1){break r}e=c-1|0;if((c>>>0)%3|0){break r}e=c+2|0}c=e;if((g|0)!=(c|0)){continue}break}}r=r+1|0;if((k|0)!=(r|0)){continue}break}}j=n-d|0;i=j>>2;D[(g<<2)+b>>2]=i;t:{if(n>>>0

>>0){D[n>>2]=g;n=n+4|0;D[f+20>>2]=n;break t}e=i+1|0;if(e>>>0>=1073741824){break l}c=p-d|0;h=c>>1;e=c>>>0<2147483644?e>>>0>>0?h:e:1073741823;if(e){if(e>>>0>=1073741824){break k}h=na(e<<2)}else{h=0}c=h+(i<<2)|0;D[c>>2]=g;p=(e<<2)+h|0;n=c+4|0;if((j|0)>0){oa(h,d,j)}D[f+24>>2]=p;D[f+20>>2]=n;D[f+16>>2]=h;if(d){ma(d);o=D[a+8>>2]}d=h}if((g|0)==-1){break n}u:{if((g>>>0)%3|0){c=g-1|0;break u}c=g+2|0;if((c|0)==-1){break n}}c=D[D[o+12>>2]+(c<<2)>>2];if((c|0)==-1){break n}c=c+((c>>>0)%3|0?-1:2)|0;if((c|0)==-1){break n}i=g;if((g|0)==(c|0)){break n}while(1){e=c;v:{w:{c=D[a+220>>2];k=D[a+216>>2];if((c|0)==(k|0)){break w}c=(c-k|0)/144|0;l=c>>>0>1?c:1;c=0;while(1){m=D[(k+J(c,144)|0)+32>>2];j=e<<2;if(D[m+j>>2]==D[m+(i<<2)>>2]){c=c+1|0;if((l|0)!=(c|0)){continue}break w}break}d=b+j|0;m=n-h|0;j=m>>2;D[d>>2]=j;if(n>>>0

>>0){D[n>>2]=e;n=n+4|0;D[f+20>>2]=n;d=h;break v}i=j+1|0;if(i>>>0>=1073741824){break j}c=p-h|0;d=c>>1;i=c>>>0<2147483644?d>>>0>i>>>0?d:i:1073741823;if(i){if(i>>>0>=1073741824){break k}d=na(i<<2)}else{d=0}c=d+(j<<2)|0;D[c>>2]=e;p=(i<<2)+d|0;n=c+4|0;if((m|0)>0){oa(d,h,m)}D[f+24>>2]=p;D[f+20>>2]=n;D[f+16>>2]=d;if(!h){h=d;break v}ma(h);o=D[a+8>>2];h=d;break v}D[(e<<2)+b>>2]=D[(i<<2)+b>>2]}if((e|0)==-1){break n}x:{if((e>>>0)%3|0){c=e-1|0;break x}c=e+2|0;if((c|0)==-1){break n}}c=D[D[o+12>>2]+(c<<2)>>2];if((c|0)==-1){break n}c=c+((c>>>0)%3|0?-1:2)|0;if((c|0)==-1){break n}i=e;if((c|0)!=(g|0)){continue}break}}q=q+1|0;c=D[o+24>>2];if((q|0)>2]-c>>2){continue}break}break i}pa();T()}pa();T()}sa();T()}pa();T()}m=D[a+4>>2];d=D[m+44>>2];a=D[d+100>>2];k=D[d+96>>2];y:{if((a|0)==(k|0)){break y}d=(a-k|0)/12|0;a=d>>>0>1?d:1;j=a&1;c=0;if(d>>>0>=2){i=a&-2;d=0;while(1){e=J(c,12);l=e+b|0;g=D[l+4>>2];a=D[l>>2];e=e+k|0;D[e+8>>2]=D[l+8>>2];D[e>>2]=a;D[e+4>>2]=g;e=J(c|1,12);l=e+b|0;g=D[l+4>>2];a=D[l>>2];e=e+k|0;D[e+8>>2]=D[l+8>>2];D[e>>2]=a;D[e+4>>2]=g;c=c+2|0;d=d+2|0;if((i|0)!=(d|0)){continue}break}}if(!j){break y}c=J(c,12);g=c+b|0;d=D[g+4>>2];a=D[g>>2];c=c+k|0;D[c+8>>2]=D[g+8>>2];D[c>>2]=a;D[c+4>>2]=d}D[D[m+4>>2]+80>>2]=n-h>>2;i=1}c=i;if(b){ma(b)}if(!h){break e}D[f+20>>2]=h;ma(h)}$=f+32|0;return c} +function Xh(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,E=0,F=0,G=0,H=0,I=0,K=0,L=0;h=$+-64|0;$=h;D[a+8>>2]=e;w=a+32|0;f=D[w>>2];d=D[a+36>>2]-f>>2;a:{b:{if(d>>>0>>0){ra(w,e-d|0);D[h+56>>2]=0;D[h+60>>2]=0;D[h+48>>2]=0;D[h+52>>2]=0;D[h+40>>2]=0;D[h+44>>2]=0;D[h+32>>2]=0;D[h+36>>2]=0;D[h+24>>2]=0;D[h+28>>2]=0;D[h+16>>2]=0;D[h+20>>2]=0;D[h>>2]=0;break b}if(d>>>0>e>>>0){D[a+36>>2]=f+(e<<2)}D[h+56>>2]=0;D[h+60>>2]=0;D[h+48>>2]=0;D[h+52>>2]=0;D[h+40>>2]=0;D[h+44>>2]=0;D[h+32>>2]=0;D[h+36>>2]=0;D[h+24>>2]=0;D[h+28>>2]=0;D[h+16>>2]=0;D[h+20>>2]=0;D[h>>2]=0;d=0;if(!e){break a}}xa(h+16|0,e,h);i=D[h+28>>2];d=D[h+32>>2]}D[h>>2]=0;d=d-i>>2;c:{if(d>>>0>=e>>>0){if(d>>>0<=e>>>0){break c}D[h+32>>2]=(e<<2)+i;break c}xa(h+16|12,e-d|0,h)}D[h>>2]=0;f=D[h+40>>2];d=D[h+44>>2]-f>>2;d:{if(d>>>0>=e>>>0){if(d>>>0<=e>>>0){break d}D[h+44>>2]=f+(e<<2);break d}xa(h+40|0,e-d|0,h)}D[h>>2]=0;f=D[h+52>>2];d=D[h+56>>2]-f>>2;e:{if(d>>>0>=e>>>0){if(d>>>0<=e>>>0){break e}D[h+56>>2]=f+(e<<2);break e}xa(h+52|0,e-d|0,h)}f:{if(D[a+8>>2]<=0){break f}g=D[h+16>>2];j=D[a+32>>2];i=0;while(1){d=i<<2;f=D[d+g>>2];m=D[a+16>>2];g:{if((f|0)>(m|0)){D[d+j>>2]=m;break g}d=d+j|0;m=D[a+12>>2];if((m|0)>(f|0)){D[d>>2]=m;break g}D[d>>2]=f}i=i+1|0;d=D[a+8>>2];if((i|0)<(d|0)){continue}break}if((d|0)<=0){break f}d=0;while(1){g=d<<2;f=g+c|0;g=D[b+g>>2]+D[g+j>>2]|0;D[f>>2]=g;h:{if((g|0)>D[a+16>>2]){g=g-D[a+20>>2]|0}else{if((g|0)>=D[a+12>>2]){break h}g=g+D[a+20>>2]|0}D[f>>2]=g}d=d+1|0;if((d|0)>2]){continue}break}}G=D[a+52>>2];z=D[a+48>>2];x=na(16);d=x;D[d>>2]=0;D[d+4>>2]=0;D[d+8>>2]=0;D[d+12>>2]=0;D[h+8>>2]=0;D[h>>2]=0;D[h+4>>2]=0;i:{if(e){if(e>>>0>=1073741824){break i}d=e<<2;t=na(d);D[h>>2]=t;D[h+8>>2]=d+t;qa(t,0,d)}d=D[a+56>>2];A=D[d>>2];d=D[d+4>>2]-A|0;j:{if((d|0)<5){break j}v=d>>2;H=(v|0)>2?v:2;I=v>>>0>1?v:1;B=e&-2;C=e&1;K=e&-4;E=e&3;y=e-1|0;L=e<<2;F=1;m=1;while(1){k:{l:{m:{n:{if((m|0)!=(I|0)){o:{p:{f=D[(m<<2)+A>>2];if((f|0)==-1){break p}n=D[z+12>>2];d=f+2|0;g=(f>>>0)%3|0;q=n+((g?f-1|0:d)<<2)|0;j=0;u=(g|0)!=0|(d|0)!=-1;k=1;d=f;q:{while(1){g=D[n+(d<<2)>>2];r:{if((g|0)==-1){break r}l=-1;p=D[G>>2];r=D[z>>2];i=p+(D[r+(g<<2)>>2]<<2)|0;o=g+1|0;o=(o>>>0)%3|0?o:g-2|0;if((o|0)!=-1){l=D[r+(o<<2)>>2]}o=D[i>>2];s:{t:{if((g>>>0)%3|0){i=g-1|0;break t}i=g+2|0;s=-1;if((i|0)==-1){break s}}s=D[r+(i<<2)>>2]}if((m|0)<=(o|0)){break r}i=D[p+(l<<2)>>2];if((i|0)>=(m|0)){break r}l=D[p+(s<<2)>>2];if((l|0)>=(m|0)){break r}g=D[(h+16|0)+J(j,12)>>2];u:{if(!e){break u}l=J(e,l);r=J(e,i);p=J(e,o);i=0;s=0;if(y){while(1){D[g+(i<<2)>>2]=(D[(i+l<<2)+c>>2]+D[(i+r<<2)+c>>2]|0)-D[(i+p<<2)+c>>2];o=i|1;D[g+(o<<2)>>2]=(D[(l+o<<2)+c>>2]+D[(o+r<<2)+c>>2]|0)-D[(o+p<<2)+c>>2];i=i+2|0;s=s+2|0;if((B|0)!=(s|0)){continue}break}}if(!C){break u}D[g+(i<<2)>>2]=(D[(i+l<<2)+c>>2]+D[(i+r<<2)+c>>2]|0)-D[(i+p<<2)+c>>2]}g=4;j=j+1|0;if((j|0)==4){break q}}v:{if(k&1){i=d+1|0;d=(i>>>0)%3|0?i:d-2|0;g=-1;if((d|0)==-1){break v}d=D[n+(d<<2)>>2];g=-1;if((d|0)==-1){break v}g=d+1|0;g=(g>>>0)%3|0?g:d-2|0;break v}w:{if((d>>>0)%3|0){i=d-1|0;break w}i=d+2|0;g=-1;if((i|0)==-1){break v}}d=D[n+(i<<2)>>2];g=-1;if((d|0)==-1){break v}g=d-1|0;if((d>>>0)%3|0){break v}g=d+2|0}d=g;x:{if((f|0)==(d|0)){break x}if(!((k^1)&1|(d|0)!=-1)){if(!u){break x}d=D[q>>2];if((d|0)==-1){break x}k=0;d=(d>>>0)%3|0?d-1|0:d+2|0}if((d|0)!=-1){continue}}break}g=j;if((g|0)<=0){break p}}if(e){qa(t,0,L)}d=g-1|0;r=(d<<2)+x|0;d=J(d,12)+a|0;o=d;s=D[d- -64>>2];k=0;d=D[h>>2];f=0;while(1){j=D[r>>2];D[r>>2]=j+1;if(j>>>0>=s>>>0){break j}y:{if(D[D[o+60>>2]+(j>>>3&536870908)>>2]>>>j&1){break y}f=f+1|0;if(!e){break y}j=D[(h+16|0)+J(k,12)>>2];l=0;i=0;p=0;if(y>>>0>=3){while(1){n=i<<2;q=n+d|0;D[q>>2]=D[q>>2]+D[j+n>>2];q=n|4;u=q+d|0;D[u>>2]=D[u>>2]+D[j+q>>2];q=n|8;u=q+d|0;D[u>>2]=D[u>>2]+D[j+q>>2];n=n|12;q=n+d|0;D[q>>2]=D[q>>2]+D[j+n>>2];i=i+4|0;p=p+4|0;if((K|0)!=(p|0)){continue}break}}if(!E){break y}while(1){n=i<<2;p=n+d|0;D[p>>2]=D[p>>2]+D[j+n>>2];i=i+1|0;l=l+1|0;if((E|0)!=(l|0)){continue}break}}k=k+1|0;if((k|0)!=(g|0)){continue}break}g=J(e,m);if(!f){break o}if(!e){break l}i=0;d=0;if(y){break n}break m}g=J(e,m)}if(D[a+8>>2]<=0){break k}k=(J(m-1|0,e)<<2)+c|0;j=D[w>>2];i=0;while(1){d=i<<2;f=D[d+k>>2];l=D[a+16>>2];z:{if((f|0)>(l|0)){D[d+j>>2]=l;break z}d=d+j|0;l=D[a+12>>2];if((l|0)>(f|0)){D[d>>2]=l;break z}D[d>>2]=f}i=i+1|0;f=D[a+8>>2];if((i|0)<(f|0)){continue}break}d=0;if((f|0)<=0){break k}f=g<<2;i=f+c|0;k=b+f|0;while(1){g=d<<2;f=g+i|0;g=D[g+k>>2]+D[g+j>>2]|0;D[f>>2]=g;A:{if((g|0)>D[a+16>>2]){g=g-D[a+20>>2]|0}else{if((g|0)>=D[a+12>>2]){break A}g=g+D[a+20>>2]|0}D[f>>2]=g}d=d+1|0;if((d|0)>2]){continue}break}break k}va();T()}while(1){j=i<<2;k=j+t|0;D[k>>2]=D[k>>2]/(f|0);j=(j|4)+t|0;D[j>>2]=D[j>>2]/(f|0);i=i+2|0;d=d+2|0;if((B|0)!=(d|0)){continue}break}}if(!C){break l}d=(i<<2)+t|0;D[d>>2]=D[d>>2]/(f|0)}if(D[a+8>>2]<=0){break k}j=D[w>>2];i=0;while(1){d=i<<2;f=D[d+t>>2];k=D[a+16>>2];B:{if((f|0)>(k|0)){D[d+j>>2]=k;break B}d=d+j|0;k=D[a+12>>2];if((k|0)>(f|0)){D[d>>2]=k;break B}D[d>>2]=f}i=i+1|0;f=D[a+8>>2];if((i|0)<(f|0)){continue}break}d=0;if((f|0)<=0){break k}f=g<<2;i=f+c|0;k=b+f|0;while(1){g=d<<2;f=g+i|0;g=D[g+k>>2]+D[g+j>>2]|0;D[f>>2]=g;C:{if((g|0)>D[a+16>>2]){g=g-D[a+20>>2]|0}else{if((g|0)>=D[a+12>>2]){break C}g=g+D[a+20>>2]|0}D[f>>2]=g}d=d+1|0;if((d|0)>2]){continue}break}}m=m+1|0;F=(v|0)>(m|0);if((m|0)!=(H|0)){continue}break}}a=D[h>>2];if(a){ma(a)}ma(x);a=D[h+52>>2];if(a){D[h+56>>2]=a;ma(a)}a=D[h+40>>2];if(a){D[h+44>>2]=a;ma(a)}a=D[h+28>>2];if(a){D[h+32>>2]=a;ma(a)}a=D[h+16>>2];if(a){D[h+20>>2]=a;ma(a)}$=h- -64|0;return(F^-1)&1}pa();T()}function Dd(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;i=$-96|0;$=i;g=D[a+4>>2];d=D[g+32>>2];j=D[d+8>>2];f=j;n=D[d+12>>2];e=n;c=D[d+20>>2];o=D[d+16>>2];a:{if((e|0)<=(c|0)&o>>>0>=f>>>0|(c|0)>(e|0)){break a}m=D[d>>2];p=E[m+o|0];f=o+1|0;e=f?c:c+1|0;D[d+16>>2]=f;D[d+20>>2]=e;if((e|0)>=(n|0)&f>>>0>=j>>>0|(e|0)>(n|0)){break a}l=E[f+m|0];f=o+2|0;e=f>>>0<2?c+1|0:c;h=f;D[d+16>>2]=f;D[d+20>>2]=e;q=p<<24>>24;b:{if((q|0)>=0){f=D[a+216>>2];if(p>>>0>=(D[a+220>>2]-f|0)/144>>>0){break a}f=f+J(p,144)|0;if(D[f>>2]<0){break b}break a}if(D[a+212>>2]>=0){break a}f=a+212|0}D[f>>2]=b;c:{d:{e:{f:{g:{h:{f=F[g+36>>1];i:{if(((f<<8|f>>>8)&65535)>>>0>=258){if((e|0)>=(n|0)&h>>>0>=j>>>0|(e|0)>(n|0)){break a}f=E[h+m|0];e=o+3|0;c=e>>>0<3?c+1|0:c;D[d+16>>2]=e;D[d+20>>2]=c;c=f>>>0>1;if(c){break a}c=c?0:f;if(!l){break i}if(!c){break h}break a}if(l){break g}c=0}if((q|0)<0){e=a+184|0}else{d=D[a+216>>2]+J(p,144)|0;B[d+100|0]=0;e=d+104|0}d=e;if((c|0)!=1){break e}e=$-112|0;$=e;m=D[D[a+4>>2]+44>>2];c=na(120);D[c>>2]=8924;D[c+4>>2]=0;D[c+116>>2]=0;D[c+112>>2]=d;D[c+108>>2]=m;D[c+12>>2]=0;D[c+16>>2]=0;D[c+20>>2]=0;D[c+24>>2]=0;D[c+28>>2]=0;D[c+32>>2]=0;D[c+36>>2]=0;D[c+40>>2]=0;D[c+44>>2]=0;D[c+48>>2]=0;D[c+52>>2]=0;D[c+56>>2]=0;D[c+60>>2]=0;D[c+8>>2]=9136;f=c- -64|0;D[f>>2]=0;D[f+4>>2]=0;D[c+72>>2]=0;D[c+76>>2]=0;D[c+80>>2]=0;D[c+84>>2]=0;D[c+88>>2]=0;D[c+104>>2]=0;D[c+96>>2]=0;D[c+100>>2]=0;j=D[a+8>>2];D[e+48>>2]=0;D[e+52>>2]=0;D[e+40>>2]=0;D[e+44>>2]=0;l=e+32|0;f=l;D[f>>2]=0;D[f+4>>2]=0;D[e+24>>2]=0;D[e+28>>2]=0;f=e- -64|0;D[f>>2]=0;D[f+4>>2]=0;D[e+72>>2]=0;D[e+76>>2]=0;D[e+80>>2]=0;D[e+84>>2]=0;D[e+88>>2]=0;D[e+104>>2]=0;D[e+16>>2]=0;D[e+20>>2]=0;D[e+56>>2]=0;D[e+60>>2]=0;D[e+8>>2]=9136;D[e+96>>2]=0;D[e+100>>2]=0;D[e+12>>2]=j;h=D[j>>2];f=D[j+4>>2];B[e+111|0]=0;n=l;l=e+111|0;Ha(n,(f-h>>2>>>0)/3|0,l);f=D[e+12>>2];h=D[f+28>>2];f=D[f+24>>2];B[e+111|0]=0;Ha(e+44|0,h-f>>2,l);D[e+28>>2]=c;D[e+24>>2]=m;D[e+20>>2]=d;D[e+16>>2]=j;d=c+8|0;h=e+8|0;ic(d,h);j:{if((d|0)==(h|0)){D[c+92>>2]=D[h+84>>2];break j}ib(c+56|0,D[h+48>>2],D[h+52>>2]);ib(c+68|0,D[h+60>>2],D[h- -64>>2]);ib(c+80|0,D[h+72>>2],D[h+76>>2]);D[c+92>>2]=D[h+84>>2];k:{l=D[h+92>>2];j=D[h+88>>2];h=l-j|0;m=h>>2;f=D[c+104>>2];g=D[c+96>>2];if(m>>>0<=f-g>>2>>>0){d=D[c+100>>2]-g|0;f=d>>2;h=f>>>0>>0?d+j|0:l;d=h-j|0;if((h|0)!=(j|0)){Ra(g,j,d)}if(f>>>0>>0){d=D[c+100>>2];f=l-h|0;if((f|0)>0){d=oa(d,h,f)+f|0}D[c+100>>2]=d;break k}D[c+100>>2]=d+g;break k}if(g){D[c+100>>2]=g;ma(g);D[c+104>>2]=0;D[c+96>>2]=0;D[c+100>>2]=0;f=0}l:{if((h|0)<0){break l}d=f>>1;d=f>>>0<2147483644?d>>>0>m>>>0?d:m:1073741823;if(d>>>0>=1073741824){break l}f=d<<2;d=na(f);D[c+96>>2]=d;D[c+100>>2]=d;D[c+104>>2]=d+f;if((j|0)!=(l|0)){d=oa(d,j,h)+h|0}D[c+100>>2]=d;break k}pa();T()}}D[e+8>>2]=9136;d=D[e+96>>2];if(d){D[e+100>>2]=d;ma(d)}d=D[e+80>>2];if(d){D[e+84>>2]=d;ma(d)}d=D[e+68>>2];if(d){D[e+72>>2]=d;ma(d)}d=D[e+56>>2];if(d){D[e+60>>2]=d;ma(d)}D[e+8>>2]=9372;d=D[e+44>>2];if(d){ma(d)}d=D[e+32>>2];if(d){ma(d)}$=e+112|0;break d}if((q|0)>=0){break f}break a}if((q|0)<0){break a}}d=D[a+216>>2];f=D[g+44>>2];c=na(80);D[c>>2]=9684;D[c+4>>2]=0;D[c+76>>2]=0;D[c+68>>2]=f;D[c+8>>2]=8624;D[c+12>>2]=0;D[c+16>>2]=0;D[c+20>>2]=0;D[c+24>>2]=0;D[c+28>>2]=0;D[c+32>>2]=0;D[c+36>>2]=0;D[c+40>>2]=0;D[c+44>>2]=0;D[c+48>>2]=0;D[c+52>>2]=0;k=d+J(p,144)|0;e=k+104|0;D[c+72>>2]=e;D[c- -64>>2]=0;D[c+56>>2]=0;D[c+60>>2]=0;D[i+24>>2]=f;D[i+68>>2]=0;D[i+72>>2]=0;D[i+60>>2]=0;D[i+64>>2]=0;D[i+52>>2]=0;D[i+56>>2]=0;D[i+44>>2]=0;D[i+48>>2]=0;D[i+84>>2]=0;D[i+88>>2]=0;D[i+76>>2]=0;D[i+80>>2]=0;D[i+28>>2]=c;d=D[i+28>>2];D[i+8>>2]=D[i+24>>2];D[i+12>>2]=d;D[i+20>>2]=e;e=k+4|0;D[i+16>>2]=e;D[i+36>>2]=0;D[i+40>>2]=0;D[i+32>>2]=8624;d=D[i+20>>2];D[i>>2]=D[i+16>>2];D[i+4>>2]=d;k=i+32|0;Cd(k,e,i);d=c+8|0;ic(d,k);if((d|0)!=(k|0)){ib(c+56|0,D[k+48>>2],D[k+52>>2])}Bd(k);break c}g=$+-64|0;$=g;m=D[D[a+4>>2]+44>>2];c=na(80);D[c>>2]=9392;D[c+4>>2]=0;D[c+76>>2]=0;D[c+72>>2]=d;D[c+68>>2]=m;D[c+8>>2]=9556;D[c+12>>2]=0;D[c+16>>2]=0;D[c+20>>2]=0;D[c+24>>2]=0;D[c+28>>2]=0;D[c+32>>2]=0;D[c+36>>2]=0;D[c+40>>2]=0;D[c+44>>2]=0;D[c+48>>2]=0;D[c+52>>2]=0;D[c- -64>>2]=0;l=c+56|0;e=l;D[e>>2]=0;D[e+4>>2]=0;j=D[a+8>>2];D[g+40>>2]=0;D[g+44>>2]=0;D[g+32>>2]=0;D[g+36>>2]=0;h=g+24|0;e=h;D[e>>2]=0;D[e+4>>2]=0;D[g+16>>2]=0;D[g+20>>2]=0;D[g+56>>2]=0;D[g+8>>2]=0;D[g+12>>2]=0;D[g+48>>2]=0;D[g+52>>2]=0;D[g>>2]=9556;D[g+4>>2]=j;f=D[j>>2];e=D[j+4>>2];B[g+63|0]=0;n=h;h=g+63|0;Ha(n,(e-f>>2>>>0)/3|0,h);e=D[g+4>>2];f=D[e+28>>2];e=D[e+24>>2];B[g+63|0]=0;Ha(g+36|0,f-e>>2,h);D[g+20>>2]=c;D[g+16>>2]=m;D[g+12>>2]=d;D[g+8>>2]=j;ic(c+8|0,g);ib(l,D[g+48>>2],D[g+52>>2]);D[g>>2]=9556;d=D[g+48>>2];if(d){D[g+52>>2]=d;ma(d)}D[g>>2]=9372;d=D[g+36>>2];if(d){ma(d)}d=D[g+24>>2];if(d){ma(d)}$=g- -64|0}if(!c){break a}}c=wc(na(64),c);h=D[a+4>>2];a=c;c=b;m:{n:{if((c|0)>=0){e=h+8|0;b=D[h+12>>2];d=D[h+8>>2];f=b-d>>2;o:{if((f|0)>(c|0)){break o}k=c+1|0;if(c>>>0>=f>>>0){Pb(e,k-f|0);break o}if(f>>>0<=k>>>0){break o}d=d+(k<<2)|0;if((d|0)!=(b|0)){while(1){b=b-4|0;k=D[b>>2];D[b>>2]=0;if(k){ba[D[D[k>>2]+4>>2]](k)}if((b|0)!=(d|0)){continue}break}}D[h+12>>2]=d}d=D[e>>2]+(c<<2)|0;b=D[d>>2];D[d>>2]=a;if(b){break n}break m}b=a;if(!a){break m}}ba[D[D[b>>2]+4>>2]](b)}k=(c^-1)>>>31|0}$=i+96|0;return k|0}function he(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;j=a;a:{b:{c:{d:{e:{f:{g:{h:{a=D[a+8>>2];switch(D[a+28>>2]-1|0){case 4:break c;case 5:break d;case 2:break e;case 3:break f;case 0:break g;case 1:break h;default:break a}}e=B[a+24|0];c=na((e|0)>=0?e:-1);a=D[j+16>>2];if(D[a+80>>2]){h=D[D[a>>2]>>2]+D[a+48>>2]|0}else{h=0}if(!b){break b}a=0;if((e|0)<=0){if((b|0)!=1){h=b&-2;while(1){oa(D[D[D[j+8>>2]+64>>2]>>2]+a|0,c,e);a=a+e|0;oa(a+D[D[D[j+8>>2]+64>>2]>>2]|0,c,e);a=a+e|0;d=d+2|0;if((h|0)!=(d|0)){continue}break}}if(!(b&1)){break b}oa(D[D[D[j+8>>2]+64>>2]>>2]+a|0,c,e);break b}o=e&-4;l=e&3;g=e-1>>>0<3;while(1){a=0;f=0;if(!g){while(1){k=h+(d<<2)|0;B[a+c|0]=D[k>>2];B[(a|1)+c|0]=D[k+4>>2];B[(a|2)+c|0]=D[k+8>>2];B[(a|3)+c|0]=D[k+12>>2];a=a+4|0;d=d+4|0;f=f+4|0;if((o|0)!=(f|0)){continue}break}}f=0;if(l){while(1){B[a+c|0]=D[h+(d<<2)>>2];a=a+1|0;d=d+1|0;f=f+1|0;if((l|0)!=(f|0)){continue}break}}oa(D[D[D[j+8>>2]+64>>2]>>2]+m|0,c,e);m=e+m|0;n=n+1|0;if((n|0)!=(b|0)){continue}break}break b}e=B[a+24|0];c=na((e|0)>=0?e:-1);a=D[j+16>>2];if(D[a+80>>2]){h=D[D[a>>2]>>2]+D[a+48>>2]|0}else{h=0}if(!b){break b}a=0;if((e|0)<=0){if((b|0)!=1){h=b&-2;while(1){oa(D[D[D[j+8>>2]+64>>2]>>2]+a|0,c,e);a=a+e|0;oa(a+D[D[D[j+8>>2]+64>>2]>>2]|0,c,e);a=a+e|0;d=d+2|0;if((h|0)!=(d|0)){continue}break}}if(!(b&1)){break b}oa(D[D[D[j+8>>2]+64>>2]>>2]+a|0,c,e);break b}o=e&-4;l=e&3;g=e-1>>>0<3;while(1){a=0;f=0;if(!g){while(1){k=h+(d<<2)|0;B[a+c|0]=D[k>>2];B[(a|1)+c|0]=D[k+4>>2];B[(a|2)+c|0]=D[k+8>>2];B[(a|3)+c|0]=D[k+12>>2];a=a+4|0;d=d+4|0;f=f+4|0;if((o|0)!=(f|0)){continue}break}}f=0;if(l){while(1){B[a+c|0]=D[h+(d<<2)>>2];a=a+1|0;d=d+1|0;f=f+1|0;if((l|0)!=(f|0)){continue}break}}oa(D[D[D[j+8>>2]+64>>2]>>2]+m|0,c,e);m=e+m|0;n=n+1|0;if((n|0)!=(b|0)){continue}break}break b}g=B[a+24|0];a=g+g|0;c=na(a>>>0>>0?-1:a);a=D[j+16>>2];if(D[a+80>>2]){h=D[D[a>>2]>>2]+D[a+48>>2]|0}else{h=0}if(!b){break b}i=g<<1;a=0;if((g|0)<=0){if((b|0)!=1){h=b&-2;while(1){oa(D[D[D[j+8>>2]+64>>2]>>2]+a|0,c,i);a=a+i|0;oa(a+D[D[D[j+8>>2]+64>>2]>>2]|0,c,i);a=a+i|0;d=d+2|0;if((h|0)!=(d|0)){continue}break}}if(!(b&1)){break b}oa(D[D[D[j+8>>2]+64>>2]>>2]+a|0,c,i);break b}o=g&-4;l=g&3;g=g-1>>>0<3;while(1){a=0;f=0;if(!g){while(1){e=a<<1;k=h+(d<<2)|0;C[e+c>>1]=D[k>>2];C[(e|2)+c>>1]=D[k+4>>2];C[(e|4)+c>>1]=D[k+8>>2];C[(e|6)+c>>1]=D[k+12>>2];a=a+4|0;d=d+4|0;f=f+4|0;if((o|0)!=(f|0)){continue}break}}f=0;if(l){while(1){C[(a<<1)+c>>1]=D[h+(d<<2)>>2];a=a+1|0;d=d+1|0;f=f+1|0;if((l|0)!=(f|0)){continue}break}}oa(D[D[D[j+8>>2]+64>>2]>>2]+n|0,c,i);n=i+n|0;m=m+1|0;if((m|0)!=(b|0)){continue}break}break b}g=B[a+24|0];a=g+g|0;c=na(a>>>0>>0?-1:a);a=D[j+16>>2];if(D[a+80>>2]){h=D[D[a>>2]>>2]+D[a+48>>2]|0}else{h=0}if(!b){break b}i=g<<1;a=0;if((g|0)<=0){if((b|0)!=1){h=b&-2;while(1){oa(D[D[D[j+8>>2]+64>>2]>>2]+a|0,c,i);a=a+i|0;oa(a+D[D[D[j+8>>2]+64>>2]>>2]|0,c,i);a=a+i|0;d=d+2|0;if((h|0)!=(d|0)){continue}break}}if(!(b&1)){break b}oa(D[D[D[j+8>>2]+64>>2]>>2]+a|0,c,i);break b}o=g&-4;l=g&3;g=g-1>>>0<3;while(1){a=0;f=0;if(!g){while(1){e=a<<1;k=h+(d<<2)|0;C[e+c>>1]=D[k>>2];C[(e|2)+c>>1]=D[k+4>>2];C[(e|4)+c>>1]=D[k+8>>2];C[(e|6)+c>>1]=D[k+12>>2];a=a+4|0;d=d+4|0;f=f+4|0;if((o|0)!=(f|0)){continue}break}}f=0;if(l){while(1){C[(a<<1)+c>>1]=D[h+(d<<2)>>2];a=a+1|0;d=d+1|0;f=f+1|0;if((l|0)!=(f|0)){continue}break}}oa(D[D[D[j+8>>2]+64>>2]>>2]+n|0,c,i);n=i+n|0;m=m+1|0;if((m|0)!=(b|0)){continue}break}break b}g=B[a+24|0];i=g<<2;c=na((g|0)!=(g&1073741823)?-1:i);a=D[j+16>>2];if(D[a+80>>2]){h=D[D[a>>2]>>2]+D[a+48>>2]|0}else{h=0}if(!b){break b}a=0;if((g|0)<=0){if((b|0)!=1){h=b&-2;while(1){oa(D[D[D[j+8>>2]+64>>2]>>2]+a|0,c,i);a=a+i|0;oa(a+D[D[D[j+8>>2]+64>>2]>>2]|0,c,i);a=a+i|0;d=d+2|0;if((h|0)!=(d|0)){continue}break}}if(!(b&1)){break b}oa(D[D[D[j+8>>2]+64>>2]>>2]+a|0,c,i);break b}o=g&-4;l=g&3;g=g-1>>>0<3;while(1){a=0;f=0;if(!g){while(1){e=a<<2;k=h+(d<<2)|0;D[e+c>>2]=D[k>>2];D[(e|4)+c>>2]=D[k+4>>2];D[(e|8)+c>>2]=D[k+8>>2];D[(e|12)+c>>2]=D[k+12>>2];a=a+4|0;d=d+4|0;f=f+4|0;if((o|0)!=(f|0)){continue}break}}f=0;if(l){while(1){D[(a<<2)+c>>2]=D[h+(d<<2)>>2];a=a+1|0;d=d+1|0;f=f+1|0;if((l|0)!=(f|0)){continue}break}}oa(D[D[D[j+8>>2]+64>>2]>>2]+n|0,c,i);n=i+n|0;m=m+1|0;if((m|0)!=(b|0)){continue}break}break b}g=B[a+24|0];i=g<<2;c=na((g|0)!=(g&1073741823)?-1:i);a=D[j+16>>2];if(D[a+80>>2]){h=D[D[a>>2]>>2]+D[a+48>>2]|0}else{h=0}if(!b){break b}a=0;if((g|0)<=0){if((b|0)!=1){h=b&-2;while(1){oa(D[D[D[j+8>>2]+64>>2]>>2]+a|0,c,i);a=a+i|0;oa(a+D[D[D[j+8>>2]+64>>2]>>2]|0,c,i);a=a+i|0;d=d+2|0;if((h|0)!=(d|0)){continue}break}}if(!(b&1)){break b}oa(D[D[D[j+8>>2]+64>>2]>>2]+a|0,c,i);break b}o=g&-4;l=g&3;g=g-1>>>0<3;while(1){a=0;f=0;if(!g){while(1){e=a<<2;k=h+(d<<2)|0;D[e+c>>2]=D[k>>2];D[(e|4)+c>>2]=D[k+4>>2];D[(e|8)+c>>2]=D[k+8>>2];D[(e|12)+c>>2]=D[k+12>>2];a=a+4|0;d=d+4|0;f=f+4|0;if((o|0)!=(f|0)){continue}break}}f=0;if(l){while(1){D[(a<<2)+c>>2]=D[h+(d<<2)>>2];a=a+1|0;d=d+1|0;f=f+1|0;if((l|0)!=(f|0)){continue}break}}oa(D[D[D[j+8>>2]+64>>2]>>2]+n|0,c,i);n=i+n|0;m=m+1|0;if((m|0)!=(b|0)){continue}break}}ma(c);c=1}return c|0}function Uh(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,C=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,U=0,V=0,W=0;a:{if((e|0)==2){D[a+8>>2]=2;D[a- -64>>2]=f;H=a+32|0;e=D[H>>2];d=D[a+36>>2]-e|0;b:{if(d>>>0<=7){ra(H,2-(d>>>2|0)|0);break b}if((d|0)==8){break b}D[a+36>>2]=e+8}d=D[a+56>>2];d=D[d+4>>2]-D[d>>2]|0;c:{if((d|0)<=0){f=0;break c}n=a+60|0;I=d>>2;S=(I|0)>1?I:1;U=a+68|0;f=1;while(1){e=D[a+56>>2];d=D[e>>2];if(D[e+4>>2]-d>>2>>>0<=r>>>0){break a}k=$-80|0;$=k;e=-1;d:{e:{i=D[d+(r<<2)>>2];if((i|0)==-1){break e}h=D[n+32>>2];d=i+1|0;d=(d>>>0)%3|0?d:i-2|0;if((d|0)!=-1){e=D[D[h>>2]+(d<<2)>>2]}d=-1;i=i+((i>>>0)%3|0?-1:2)|0;if((i|0)!=-1){d=D[D[h>>2]+(i<<2)>>2]}h=D[n+36>>2];i=D[h>>2];h=D[h+4>>2]-i>>2;if(h>>>0<=e>>>0|d>>>0>=h>>>0){break e}h=D[i+(e<<2)>>2];f:{g:{h:{i:{j:{k:{i=D[i+(d<<2)>>2];if((i|0)>=(r|0)|(h|0)>=(r|0)){break k}d=(i<<3)+c|0;v=D[d+4>>2];e=(h<<3)+c|0;w=D[e+4>>2];x=D[d>>2];C=D[e>>2];if(!((x|0)!=(C|0)|(v|0)!=(w|0))){D[n+8>>2]=C;D[n+12>>2]=w;break j}d=D[D[n+4>>2]+(r<<2)>>2];D[k+72>>2]=0;D[k+76>>2]=0;e=k- -64|0;D[e>>2]=0;D[e+4>>2]=0;D[k+56>>2]=0;D[k+60>>2]=0;e=D[n>>2];if(!E[e+84|0]){d=D[D[e+68>>2]+(d<<2)>>2]}Ia(e,d,B[e+24|0],k+56|0);d=D[D[n+4>>2]+(h<<2)>>2];D[k+48>>2]=0;D[k+52>>2]=0;D[k+40>>2]=0;D[k+44>>2]=0;D[k+32>>2]=0;D[k+36>>2]=0;e=D[n>>2];if(!E[e+84|0]){d=D[D[e+68>>2]+(d<<2)>>2]}Ia(e,d,B[e+24|0],k+32|0);e=D[D[n+4>>2]+(i<<2)>>2];D[k+24>>2]=0;D[k+28>>2]=0;D[k+16>>2]=0;D[k+20>>2]=0;D[k+8>>2]=0;D[k+12>>2]=0;d=D[n>>2];if(!E[d+84|0]){e=D[D[d+68>>2]+(e<<2)>>2]}Ia(d,e,B[d+24|0],k+8|0);J=D[k+44>>2];d=D[k+16>>2];s=D[k+40>>2];e=s;i=D[k+20>>2]-(J+(d>>>0>>0)|0)|0;l=d-e|0;d=fi(l,i,l,i);g=aa;m=d;K=D[k+36>>2];d=D[k+8>>2];F=D[k+32>>2];e=F;j=D[k+12>>2]-(K+(d>>>0>>0)|0)|0;e=d-e|0;o=fi(e,j,e,j);m=m+o|0;d=aa+g|0;d=m>>>0>>0?d+1|0:d;q=m;L=D[k+52>>2];g=D[k+24>>2];G=D[k+48>>2];o=G;m=D[k+28>>2]-(L+(g>>>0>>0)|0)|0;u=g-o|0;p=fi(u,m,u,m);o=q+p|0;g=aa+d|0;t=o;o=o>>>0

>>0?g+1|0:g;if(!(t|o)){break k}M=D[k+64>>2];d=M;N=D[k+68>>2];d=fi(d-s|0,N-((d>>>0>>0)+J|0)|0,l,i);h=aa;g=d;O=D[k+56>>2];d=O;P=D[k+60>>2];p=fi(d-F|0,P-((d>>>0>>0)+K|0)|0,e,j);d=g+p|0;g=aa+h|0;g=d>>>0

>>0?g+1|0:g;h=d;Q=D[k+72>>2];d=Q;R=D[k+76>>2];p=fi(d-G|0,R-((d>>>0>>0)+L|0)|0,u,m);h=h+p|0;d=aa+g|0;y=h;p=h>>>0

>>0?d+1|0:d;d=j>>31;h=d;g=e^d;d=(j^d)-((d>>>0>g>>>0)+d|0)|0;g=g-h|0;q=g;h=i>>31;z=h^l;A=z-h|0;h=(i^h)-((h>>>0>z>>>0)+h|0)|0;g=(d|0)==(h|0)&g>>>0>A>>>0|d>>>0>h>>>0;z=g?q:A;d=g?d:h;h=d;d=m>>31;g=d;A=d^u;d=A-d|0;g=(m^g)-((g>>>0>A>>>0)+g|0)|0;q=(h|0)==(g|0)&d>>>0>>0|h>>>0>g>>>0;g=hi(-1,2147483647,q?z:d,q?h:g)>>>0>>0;h=aa;d=0;if(g&(h|0)<=(p|0)|(h|0)<(p|0)){break f}h=1;d=0;g=M;q=s;s=gi(fi(l,i,y,p),aa,t,o);i=q+s|0;l=aa+J|0;l=i>>>0>>0?l+1|0:l;l=N-((i>>>0>g>>>0)+l|0)|0;i=g-i|0;i=fi(i,l,i,l);l=aa;g=O;q=i;j=gi(fi(e,j,y,p),aa,t,o);e=j+F|0;i=aa+K|0;i=e>>>0>>0?i+1|0:i;i=P-((e>>>0>g>>>0)+i|0)|0;e=g-e|0;j=fi(e,i,e,i);i=q+j|0;e=aa+l|0;e=i>>>0>>0?e+1|0:e;j=i;i=e;e=Q;g=j;m=gi(fi(u,m,y,p),aa,t,o);j=m+G|0;l=aa+L|0;l=j>>>0>>0?l+1|0:l;m=R-((e>>>0>>0)+l|0)|0;e=e-j|0;j=fi(e,m,e,m);e=g+j|0;i=aa+i|0;j=fi(e,e>>>0>>0?i+1|0:i,t,o);e=aa;m=e;if(!e&j>>>0<=1){break i}g=j;e=m;while(1){i=d<<1|h>>>31;h=h<<1;d=i;l=!e&g>>>0>7|(e|0)!=0;g=(e&3)<<30|g>>>2;e=e>>>2|0;if(l){continue}break}break h}if((h|0)<(r|0)){d=h<<1}else{if((r|0)<=0){D[n+8>>2]=0;D[n+12>>2]=0;break j}d=(r<<1)-2|0}d=(d<<2)+c|0;D[n+8>>2]=D[d>>2];D[n+12>>2]=D[d+4>>2]}d=1;break f}d=m;h=j;if(h-1|0){break g}}while(1){e=hi(j,m,h,d)+h|0;g=d+aa|0;g=e>>>0>>0?g+1|0:g;h=(g&1)<<31|e>>>1;d=g>>>1|0;e=fi(h,d,h,d);i=aa;if((m|0)==(i|0)&e>>>0>j>>>0|i>>>0>m>>>0){continue}break}}i=D[n+20>>2];if(i){e=i-1|0;m=D[D[n+16>>2]+(e>>>3&536870908)>>2];D[n+20>>2]=e;j=w;u=v-j|0;g=j>>31;v=(v>>31)-(g+(j>>>0>v>>>0)|0)|0;j=fi(y,p,u,v);l=aa;g=fi(w,g,t,o);j=g+j|0;l=aa+l|0;l=j>>>0>>0?l+1|0:l;q=j;j=C;w=x-j|0;s=j>>31;x=(x>>31)-(s+(j>>>0>x>>>0)|0)|0;j=fi(h,d,w,x);g=j;e=m>>>e&1;m=e?0-j|0:j;j=q+m|0;q=l;l=aa;g=q+(e?0-(l+((g|0)!=0)|0)|0:l)|0;V=n,W=gi(j,j>>>0>>0?g+1|0:g,t,o),D[V+12>>2]=W;j=fi(w,x,y,p);m=aa;g=fi(t,o,C,s);j=g+j|0;l=aa+m|0;l=j>>>0>>0?l+1|0:l;g=j;d=fi(h,d,u,v);j=e?d:0-d|0;h=g+j|0;m=aa;e=(e?m:0-(((d|0)!=0)+m|0)|0)+l|0;V=n,W=gi(h,h>>>0>>0?e+1|0:e,t,o),D[V+8>>2]=W}d=(i|0)!=0}$=k+80|0;break d}va();T()}if(!d){break c}l:{if(D[a+8>>2]<=0){break l}i=D[H>>2];d=0;while(1){e=d<<2;f=D[e+U>>2];h=D[a+16>>2];m:{if((f|0)>(h|0)){D[e+i>>2]=h;break m}e=e+i|0;h=D[a+12>>2];if((h|0)>(f|0)){D[e>>2]=h;break m}D[e>>2]=f}d=d+1|0;f=D[a+8>>2];if((d|0)<(f|0)){continue}break}e=0;if((f|0)<=0){break l}d=r<<3;h=d+c|0;j=b+d|0;while(1){f=e<<2;d=f+h|0;f=D[f+j>>2]+D[f+i>>2]|0;D[d>>2]=f;n:{if((f|0)>D[a+16>>2]){f=f-D[a+20>>2]|0}else{if((f|0)>=D[a+12>>2]){break n}f=f+D[a+20>>2]|0}D[d>>2]=f}e=e+1|0;if((e|0)>2]){continue}break}}r=r+1|0;f=(I|0)>(r|0);if((r|0)!=(S|0)){continue}break}}a=f^1}else{a=0}return a&1}va();T()}function di(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,C=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,U=0,V=0,W=0;a:{if((e|0)==2){D[a+8>>2]=2;D[a- -64>>2]=f;I=a+32|0;e=D[I>>2];d=D[a+36>>2]-e|0;b:{if(d>>>0<=7){ra(I,2-(d>>>2|0)|0);break b}if((d|0)==8){break b}D[a+36>>2]=e+8}d=D[a+56>>2];d=D[d+4>>2]-D[d>>2]|0;c:{if((d|0)<=0){f=0;break c}n=a+60|0;J=d>>2;S=(J|0)>1?J:1;U=a+68|0;f=1;while(1){d=D[a+56>>2];i=D[d>>2];if(D[d+4>>2]-i>>2>>>0<=q>>>0){break a}k=$-80|0;$=k;e=-1;i=D[i+(q<<2)>>2];d=-1;d:{if((i|0)==-1){break d}d=i+1|0;e=(d>>>0)%3|0?d:i-2|0;d=i-1|0;if((i>>>0)%3|0){break d}d=i+2|0}g=D[n+36>>2];i=D[g>>2];e:{f:{g:{h:{i:{g=D[g+4>>2]-i>>2;j=e<<2;e=D[D[n+32>>2]+28>>2];j=D[j+e>>2];if(g>>>0<=j>>>0){break i}d=D[e+(d<<2)>>2];if(d>>>0>=g>>>0){break i}g=D[i+(j<<2)>>2];j:{k:{i=D[i+(d<<2)>>2];if((i|0)>=(q|0)|(g|0)>=(q|0)){break k}d=(i<<3)+c|0;w=D[d+4>>2];e=(g<<3)+c|0;x=D[e+4>>2];y=D[d>>2];F=D[e>>2];if(!((y|0)!=(F|0)|(w|0)!=(x|0))){D[n+8>>2]=F;D[n+12>>2]=x;break j}d=D[D[n+4>>2]+(q<<2)>>2];D[k+72>>2]=0;D[k+76>>2]=0;e=k- -64|0;D[e>>2]=0;D[e+4>>2]=0;D[k+56>>2]=0;D[k+60>>2]=0;e=D[n>>2];if(!E[e+84|0]){d=D[D[e+68>>2]+(d<<2)>>2]}Ia(e,d,B[e+24|0],k+56|0);d=D[D[n+4>>2]+(g<<2)>>2];D[k+48>>2]=0;D[k+52>>2]=0;D[k+40>>2]=0;D[k+44>>2]=0;D[k+32>>2]=0;D[k+36>>2]=0;e=D[n>>2];if(!E[e+84|0]){d=D[D[e+68>>2]+(d<<2)>>2]}Ia(e,d,B[e+24|0],k+32|0);d=D[D[n+4>>2]+(i<<2)>>2];D[k+24>>2]=0;D[k+28>>2]=0;D[k+16>>2]=0;D[k+20>>2]=0;D[k+8>>2]=0;D[k+12>>2]=0;e=D[n>>2];if(!E[e+84|0]){d=D[D[e+68>>2]+(d<<2)>>2]}Ia(e,d,B[e+24|0],k+8|0);K=D[k+44>>2];d=D[k+16>>2];r=D[k+40>>2];e=r;i=D[k+20>>2]-(K+(d>>>0>>0)|0)|0;l=d-e|0;d=fi(l,i,l,i);h=aa;m=d;L=D[k+36>>2];d=D[k+8>>2];G=D[k+32>>2];e=G;j=D[k+12>>2]-(L+(d>>>0>>0)|0)|0;e=d-e|0;o=fi(e,j,e,j);m=m+o|0;d=aa+h|0;d=m>>>0>>0?d+1|0:d;s=m;M=D[k+52>>2];h=D[k+24>>2];H=D[k+48>>2];o=H;m=D[k+28>>2]-(M+(h>>>0>>0)|0)|0;v=h-o|0;p=fi(v,m,v,m);o=s+p|0;h=aa+d|0;u=o;o=o>>>0

>>0?h+1|0:h;if(!(u|o)){break k}s=D[k+64>>2];d=s;N=D[k+68>>2];d=fi(d-r|0,N-((d>>>0>>0)+K|0)|0,l,i);g=aa;h=d;O=D[k+56>>2];d=O;P=D[k+60>>2];p=fi(d-G|0,P-((d>>>0>>0)+L|0)|0,e,j);d=h+p|0;h=aa+g|0;h=d>>>0

>>0?h+1|0:h;g=d;Q=D[k+72>>2];d=Q;R=D[k+76>>2];p=fi(d-H|0,R-((d>>>0>>0)+M|0)|0,v,m);g=g+p|0;d=aa+h|0;z=g;p=g>>>0

${_title}

` + title = _title + } + list += `${_demo}` + } + const menu = document.createElement('div') + menu.className = 'menu' + menu.innerHTML = list + document.body.appendChild(menu) + + // change sessionStorage.target on click, and reload iframe + menu.addEventListener('click', (e: Event) => { + const button = e.target as HTMLElement + if (!button.id) + return + // remove prev iframe to clear memory + document.querySelector('iframe')?.remove() + const target = button.id + if (target && modules[target]) { + addIframe() + document.querySelector('.active')?.classList.remove('active') + button.classList.add('active') + sessionStorage.top = menu.scrollTop + sessionStorage.target = target + } + }) + + // load target on refresh + if (sessionStorage.target) { + const target = sessionStorage.target + const a = document.querySelector(`[id="${target}"]`) + if (a) { + addIframe() + a.classList.add('active') + menu.scrollTop = sessionStorage.top + } + } else { + document.querySelector('a')?.click() + } + + // create an iframe inside page to load sample + function addIframe() { + const iframe = document.createElement('iframe') as HTMLIFrameElement + iframe.srcdoc = ` + + ` + document.body.appendChild(iframe) + } +} \ No newline at end of file diff --git a/tsconfig.build.json b/tsconfig.build.json index ff3ccc70..9bc8d218 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -12,7 +12,7 @@ "baseUrl": "./", "paths": { "../*": ["src/*"], - "@orillusion/*": ["src/libs/*"], + "@orillusion/*": ["packages/*"], "@orillusion/core": ["src"] }, "types": ["vite/client", "@webgpu/types"], @@ -31,5 +31,5 @@ "strict": false }, "include": ["src"], - "exclude": ["node_modules", "src/sample"] + "exclude": ["node_modules"] } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 38cccccf..1e02dcef 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,7 @@ "outDir": "./js", "paths": { "../*": ["src/*"], - "@orillusion/*": ["src/libs/*"], + "@orillusion/*": ["packages/*"], "@orillusion/core": ["src"] }, "types": ["vite/client", "@webgpu/types"], @@ -25,6 +25,6 @@ "allowJs": true, "strict": false }, - "include": ["src", "test", "sample"], + "include": ["src", "test", "samples"], "exclude": ["node_modules", "dist", "public"] } \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index 8e111653..309c5545 100644 --- a/vite.config.js +++ b/vite.config.js @@ -11,7 +11,7 @@ module.exports = defineConfig({ resolve: { alias: { '@orillusion/core': resolve(__dirname, './src/index.ts'), - '@orillusion': resolve(__dirname, './src/libs') + '@orillusion': resolve(__dirname, './packages') }, mainFields: ['module:dev', 'module'] }, From 7bfa165e009252fef2c711678bd689118a08f6f3 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Thu, 4 May 2023 00:11:59 +0800 Subject: [PATCH 070/100] chore: update optionalDeps use elelctron@25(Chromium 114) in test use conventional-changelog to produce changelog --- package.json | 7 +- pnpm-lock.yaml | 1154 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 1135 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 524f130d..d6f20bf5 100644 --- a/package.json +++ b/package.json @@ -24,13 +24,13 @@ "minify:es": "uglifyjs dist/orillusion.es.js -o dist/orillusion.es.js -c -m", "test": "electron test/ci/main.js", "test:ci": "xvfb-maybe -- electron test/ci/main.js", - "test:install": "pnpm i electron@npm:electron-nightly@latest xvfb-maybe -O", "docs": "npm run docs:core && npm run docs:physics && npm run docs:media && npm run docs:stats", "docs:typedoc": "npx typedoc --plugin typedoc-plugin-markdown --plugin ./script/typedoc-plugin-not-exported.js --tsconfig tsconfig.build.json --gitRevision main --hideBreadcrumbs true --allReflectionsHaveOwnDocument true --readme none --excludeInternal --excludePrivate --excludeProtected --sort source-order --out", "docs:core": "npm run docs:typedoc docs/api src/index.ts", "docs:physics": "cd packages/physics && npm run docs", "docs:media": "cd packages/media-extention && npm run docs", - "docs:stats": "cd packages/stats && npm run docs" + "docs:stats": "cd packages/stats && npm run docs", + "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s" }, "devDependencies": { "@webgpu/types": "^0.1.30", @@ -40,7 +40,8 @@ "vite": "^4.2.2" }, "optionalDependencies": { - "electron": "npm:electron-nightly@latest", + "conventional-changelog-cli": "^2.2.2", + "electron": "25.0.0-beta.1", "uglify-js": "^3.17.4", "xvfb-maybe": "^0.2.1" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3e28cd21..5547ead6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2,7 +2,8 @@ lockfileVersion: 5.4 specifiers: '@webgpu/types': ^0.1.30 - electron: npm:electron-nightly@latest + conventional-changelog-cli: ^2.2.2 + electron: 25.0.0-beta.1 typedoc: ^0.24.4 typedoc-plugin-markdown: ^3.15.1 typescript: ^5.0.4 @@ -11,7 +12,8 @@ specifiers: xvfb-maybe: ^0.2.1 optionalDependencies: - electron: /electron-nightly/26.0.0-nightly.20230418 + conventional-changelog-cli: 2.2.2 + electron: 25.0.0-beta.1 uglify-js: 3.17.4 xvfb-maybe: 0.2.1 @@ -24,6 +26,30 @@ devDependencies: packages: + /@babel/code-frame/7.21.4: + resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.18.6 + dev: false + optional: true + + /@babel/helper-validator-identifier/7.19.1: + resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} + engines: {node: '>=6.9.0'} + dev: false + optional: true + + /@babel/highlight/7.18.6: + resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.19.1 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: false + optional: true + /@electron/get/2.0.2: resolution: {integrity: sha512-eFZVFoRXb3GFGd7Ak7W4+6jBl9wBtiZ4AaYOse97ej6mKj5tkyO0dUnUChs1IhJZtx1BENo4/p4WUTXpi6vT+g==} engines: {node: '>=12'} @@ -240,6 +266,12 @@ packages: dev: true optional: true + /@hutson/parse-repository-url/3.0.2: + resolution: {integrity: sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==} + engines: {node: '>=6.9.0'} + dev: false + optional: true + /@sindresorhus/is/4.6.0: resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -259,7 +291,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 18.15.11 + '@types/node': 18.16.3 '@types/responselike': 1.0.0 dev: false optional: true @@ -272,19 +304,29 @@ packages: /@types/keyv/3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 18.15.11 + '@types/node': 18.16.3 + dev: false + optional: true + + /@types/minimist/1.2.2: + resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} + dev: false + optional: true + + /@types/node/18.16.3: + resolution: {integrity: sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==} dev: false optional: true - /@types/node/18.15.11: - resolution: {integrity: sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==} + /@types/normalize-package-data/2.4.1: + resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} dev: false optional: true /@types/responselike/1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 18.15.11 + '@types/node': 18.16.3 dev: false optional: true @@ -292,7 +334,7 @@ packages: resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} requiresBuild: true dependencies: - '@types/node': 18.15.11 + '@types/node': 18.16.3 dev: false optional: true @@ -300,10 +342,57 @@ packages: resolution: {integrity: sha512-9AXJSmL3MzY8ZL//JjudA//q+2kBRGhLBFpkdGksWIuxrMy81nFrCzj2Am+mbh8WoU6rXmv7cY5E3rdlyru2Qg==} dev: true + /JSONStream/1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + dev: false + optional: true + + /add-stream/1.0.0: + resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} + dev: false + optional: true + + /ansi-regex/5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: false + optional: true + /ansi-sequence-parser/1.1.0: resolution: {integrity: sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==} dev: true + /ansi-styles/3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: false + optional: true + + /ansi-styles/4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: false + optional: true + + /array-ify/1.0.0: + resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} + dev: false + optional: true + + /arrify/1.0.1: + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} + dev: false + optional: true + /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true @@ -344,6 +433,41 @@ packages: dev: false optional: true + /camelcase-keys/6.2.2: + resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + map-obj: 4.3.0 + quick-lru: 4.0.1 + dev: false + optional: true + + /camelcase/5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: false + optional: true + + /chalk/2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: false + optional: true + + /cliui/7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: false + optional: true + /clone-response/1.0.3: resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} dependencies: @@ -351,6 +475,230 @@ packages: dev: false optional: true + /color-convert/1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: false + optional: true + + /color-convert/2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: false + optional: true + + /color-name/1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: false + optional: true + + /color-name/1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: false + optional: true + + /compare-func/2.0.0: + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + dev: false + optional: true + + /conventional-changelog-angular/5.0.13: + resolution: {integrity: sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==} + engines: {node: '>=10'} + dependencies: + compare-func: 2.0.0 + q: 1.5.1 + dev: false + optional: true + + /conventional-changelog-atom/2.0.8: + resolution: {integrity: sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw==} + engines: {node: '>=10'} + dependencies: + q: 1.5.1 + dev: false + optional: true + + /conventional-changelog-cli/2.2.2: + resolution: {integrity: sha512-8grMV5Jo8S0kP3yoMeJxV2P5R6VJOqK72IiSV9t/4H5r/HiRqEBQ83bYGuz4Yzfdj4bjaAEhZN/FFbsFXr5bOA==} + engines: {node: '>=10'} + hasBin: true + requiresBuild: true + dependencies: + add-stream: 1.0.0 + conventional-changelog: 3.1.25 + lodash: 4.17.21 + meow: 8.1.2 + tempfile: 3.0.0 + dev: false + optional: true + + /conventional-changelog-codemirror/2.0.8: + resolution: {integrity: sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw==} + engines: {node: '>=10'} + dependencies: + q: 1.5.1 + dev: false + optional: true + + /conventional-changelog-conventionalcommits/4.6.3: + resolution: {integrity: sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g==} + engines: {node: '>=10'} + dependencies: + compare-func: 2.0.0 + lodash: 4.17.21 + q: 1.5.1 + dev: false + optional: true + + /conventional-changelog-core/4.2.4: + resolution: {integrity: sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==} + engines: {node: '>=10'} + dependencies: + add-stream: 1.0.0 + conventional-changelog-writer: 5.0.1 + conventional-commits-parser: 3.2.4 + dateformat: 3.0.3 + get-pkg-repo: 4.2.1 + git-raw-commits: 2.0.11 + git-remote-origin-url: 2.0.0 + git-semver-tags: 4.1.1 + lodash: 4.17.21 + normalize-package-data: 3.0.3 + q: 1.5.1 + read-pkg: 3.0.0 + read-pkg-up: 3.0.0 + through2: 4.0.2 + dev: false + optional: true + + /conventional-changelog-ember/2.0.9: + resolution: {integrity: sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A==} + engines: {node: '>=10'} + dependencies: + q: 1.5.1 + dev: false + optional: true + + /conventional-changelog-eslint/3.0.9: + resolution: {integrity: sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA==} + engines: {node: '>=10'} + dependencies: + q: 1.5.1 + dev: false + optional: true + + /conventional-changelog-express/2.0.6: + resolution: {integrity: sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ==} + engines: {node: '>=10'} + dependencies: + q: 1.5.1 + dev: false + optional: true + + /conventional-changelog-jquery/3.0.11: + resolution: {integrity: sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw==} + engines: {node: '>=10'} + dependencies: + q: 1.5.1 + dev: false + optional: true + + /conventional-changelog-jshint/2.0.9: + resolution: {integrity: sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA==} + engines: {node: '>=10'} + dependencies: + compare-func: 2.0.0 + q: 1.5.1 + dev: false + optional: true + + /conventional-changelog-preset-loader/2.3.4: + resolution: {integrity: sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==} + engines: {node: '>=10'} + dev: false + optional: true + + /conventional-changelog-writer/5.0.1: + resolution: {integrity: sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==} + engines: {node: '>=10'} + hasBin: true + dependencies: + conventional-commits-filter: 2.0.7 + dateformat: 3.0.3 + handlebars: 4.7.7 + json-stringify-safe: 5.0.1 + lodash: 4.17.21 + meow: 8.1.2 + semver: 6.3.0 + split: 1.0.1 + through2: 4.0.2 + dev: false + optional: true + + /conventional-changelog/3.1.25: + resolution: {integrity: sha512-ryhi3fd1mKf3fSjbLXOfK2D06YwKNic1nC9mWqybBHdObPd8KJ2vjaXZfYj1U23t+V8T8n0d7gwnc9XbIdFbyQ==} + engines: {node: '>=10'} + dependencies: + conventional-changelog-angular: 5.0.13 + conventional-changelog-atom: 2.0.8 + conventional-changelog-codemirror: 2.0.8 + conventional-changelog-conventionalcommits: 4.6.3 + conventional-changelog-core: 4.2.4 + conventional-changelog-ember: 2.0.9 + conventional-changelog-eslint: 3.0.9 + conventional-changelog-express: 2.0.6 + conventional-changelog-jquery: 3.0.11 + conventional-changelog-jshint: 2.0.9 + conventional-changelog-preset-loader: 2.3.4 + dev: false + optional: true + + /conventional-commits-filter/2.0.7: + resolution: {integrity: sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==} + engines: {node: '>=10'} + dependencies: + lodash.ismatch: 4.4.0 + modify-values: 1.0.1 + dev: false + optional: true + + /conventional-commits-parser/3.2.4: + resolution: {integrity: sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==} + engines: {node: '>=10'} + hasBin: true + dependencies: + JSONStream: 1.3.5 + is-text-path: 1.0.1 + lodash: 4.17.21 + meow: 8.1.2 + split2: 3.2.2 + through2: 4.0.2 + dev: false + optional: true + + /core-util-is/1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + dev: false + optional: true + + /dargs/7.0.0: + resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} + engines: {node: '>=8'} + dev: false + optional: true + + /dateformat/3.0.3: + resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} + dev: false + optional: true + /debug/2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -376,6 +724,21 @@ packages: dev: false optional: true + /decamelize-keys/1.1.1: + resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} + engines: {node: '>=0.10.0'} + dependencies: + decamelize: 1.2.0 + map-obj: 1.0.1 + dev: false + optional: true + + /decamelize/1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dev: false + optional: true + /decompress-response/6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -404,20 +767,33 @@ packages: dev: false optional: true - /electron-nightly/26.0.0-nightly.20230418: - resolution: {integrity: sha512-6hq27nwZd8DL5/s9TyOpIox9mqDNhAbrvHbuUvQGba8zQngu2OfFroP83LtrisaLLq7BEzAp11fvrvJvDThA+g==} + /dot-prop/5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + dependencies: + is-obj: 2.0.0 + dev: false + optional: true + + /electron/25.0.0-beta.1: + resolution: {integrity: sha512-iUEuOKtjzzENNv+wvpvaMR9iRTjribFAttBTAEvd0Aemvoy8WH1P0UAxe4GxTLkoEpMQUToxqIHZnpN3K2Qcnw==} engines: {node: '>= 12.20.55'} hasBin: true requiresBuild: true dependencies: '@electron/get': 2.0.2 - '@types/node': 18.15.11 + '@types/node': 18.16.3 extract-zip: 2.0.1 transitivePeerDependencies: - supports-color dev: false optional: true + /emoji-regex/8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: false + optional: true + /end-of-stream/1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} dependencies: @@ -431,6 +807,13 @@ packages: dev: false optional: true + /error-ex/1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: false + optional: true + /es6-error/4.1.1: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} dev: false @@ -466,6 +849,18 @@ packages: '@esbuild/win32-x64': 0.17.17 dev: true + /escalade/3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: false + optional: true + + /escape-string-regexp/1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: false + optional: true + /escape-string-regexp/4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -494,6 +889,23 @@ packages: dev: false optional: true + /find-up/2.1.0: + resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} + engines: {node: '>=4'} + dependencies: + locate-path: 2.0.0 + dev: false + optional: true + + /find-up/4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: false + optional: true + /fs-extra/8.1.0: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} @@ -515,6 +927,12 @@ packages: /function-bind/1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + /get-caller-file/2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: false + optional: true + /get-intrinsic/1.2.0: resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} dependencies: @@ -524,6 +942,18 @@ packages: dev: false optional: true + /get-pkg-repo/4.2.1: + resolution: {integrity: sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==} + engines: {node: '>=6.9.0'} + hasBin: true + dependencies: + '@hutson/parse-repository-url': 3.0.2 + hosted-git-info: 4.1.0 + through2: 2.0.5 + yargs: 16.2.0 + dev: false + optional: true + /get-stream/5.2.0: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} @@ -532,6 +962,45 @@ packages: dev: false optional: true + /git-raw-commits/2.0.11: + resolution: {integrity: sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==} + engines: {node: '>=10'} + hasBin: true + dependencies: + dargs: 7.0.0 + lodash: 4.17.21 + meow: 8.1.2 + split2: 3.2.2 + through2: 4.0.2 + dev: false + optional: true + + /git-remote-origin-url/2.0.0: + resolution: {integrity: sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==} + engines: {node: '>=4'} + dependencies: + gitconfiglocal: 1.0.0 + pify: 2.3.0 + dev: false + optional: true + + /git-semver-tags/4.1.1: + resolution: {integrity: sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + meow: 8.1.2 + semver: 6.3.0 + dev: false + optional: true + + /gitconfiglocal/1.0.0: + resolution: {integrity: sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==} + dependencies: + ini: 1.3.8 + dev: false + optional: true + /global-agent/3.0.0: resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} engines: {node: '>=10.0'} @@ -588,7 +1057,18 @@ packages: wordwrap: 1.0.0 optionalDependencies: uglify-js: 3.17.4 - dev: true + + /hard-rejection/2.1.0: + resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} + engines: {node: '>=6'} + dev: false + optional: true + + /has-flag/3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: false + optional: true /has-property-descriptors/1.0.0: resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} @@ -609,12 +1089,25 @@ packages: dependencies: function-bind: 1.1.1 - /http-cache-semantics/4.1.1: - resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + /hosted-git-info/2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: false optional: true - /http2-wrapper/1.0.3: + /hosted-git-info/4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + dependencies: + lru-cache: 6.0.0 + dev: false + optional: true + + /http-cache-semantics/4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + dev: false + optional: true + + /http2-wrapper/1.0.3: resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} engines: {node: '>=10.19.0'} dependencies: @@ -623,22 +1116,88 @@ packages: dev: false optional: true + /indent-string/4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: false + optional: true + + /inherits/2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: false + optional: true + + /ini/1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: false + optional: true + + /is-arrayish/0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: false + optional: true + /is-core-module/2.12.0: resolution: {integrity: sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==} dependencies: has: 1.0.3 - dev: true + + /is-fullwidth-code-point/3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: false + optional: true + + /is-obj/2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + dev: false + optional: true + + /is-plain-obj/1.1.0: + resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} + engines: {node: '>=0.10.0'} + dev: false + optional: true + + /is-text-path/1.0.1: + resolution: {integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==} + engines: {node: '>=0.10.0'} + dependencies: + text-extensions: 1.9.0 + dev: false + optional: true + + /isarray/1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: false + optional: true /isexe/2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: false optional: true + /js-tokens/4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: false + optional: true + /json-buffer/3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} dev: false optional: true + /json-parse-better-errors/1.0.2: + resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} + dev: false + optional: true + + /json-parse-even-better-errors/2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: false + optional: true + /json-stringify-safe/5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} dev: false @@ -655,6 +1214,12 @@ packages: dev: false optional: true + /jsonparse/1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + dev: false + optional: true + /keyv/4.5.2: resolution: {integrity: sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==} dependencies: @@ -662,6 +1227,55 @@ packages: dev: false optional: true + /kind-of/6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + dev: false + optional: true + + /lines-and-columns/1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: false + optional: true + + /load-json-file/4.0.0: + resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} + engines: {node: '>=4'} + dependencies: + graceful-fs: 4.2.11 + parse-json: 4.0.0 + pify: 3.0.0 + strip-bom: 3.0.0 + dev: false + optional: true + + /locate-path/2.0.0: + resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} + engines: {node: '>=4'} + dependencies: + p-locate: 2.0.0 + path-exists: 3.0.0 + dev: false + optional: true + + /locate-path/5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + dev: false + optional: true + + /lodash.ismatch/4.4.0: + resolution: {integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==} + dev: false + optional: true + + /lodash/4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false + optional: true + /lowercase-keys/2.0.0: resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} engines: {node: '>=8'} @@ -680,6 +1294,18 @@ packages: resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} dev: true + /map-obj/1.0.1: + resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} + engines: {node: '>=0.10.0'} + dev: false + optional: true + + /map-obj/4.3.0: + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} + dev: false + optional: true + /marked/4.3.0: resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} engines: {node: '>= 12'} @@ -694,6 +1320,24 @@ packages: dev: false optional: true + /meow/8.1.2: + resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==} + engines: {node: '>=10'} + dependencies: + '@types/minimist': 1.2.2 + camelcase-keys: 6.2.2 + decamelize-keys: 1.1.1 + hard-rejection: 2.1.0 + minimist-options: 4.1.0 + normalize-package-data: 3.0.3 + read-pkg-up: 7.0.1 + redent: 3.0.0 + trim-newlines: 3.0.1 + type-fest: 0.18.1 + yargs-parser: 20.2.9 + dev: false + optional: true + /mimic-response/1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} @@ -706,6 +1350,12 @@ packages: dev: false optional: true + /min-indent/1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + dev: false + optional: true + /minimatch/9.0.0: resolution: {integrity: sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==} engines: {node: '>=16 || 14 >=14.17'} @@ -713,9 +1363,24 @@ packages: brace-expansion: 2.0.1 dev: true + /minimist-options/4.1.0: + resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} + engines: {node: '>= 6'} + dependencies: + arrify: 1.0.1 + is-plain-obj: 1.1.0 + kind-of: 6.0.3 + dev: false + optional: true + /minimist/1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true + + /modify-values/1.0.1: + resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==} + engines: {node: '>=0.10.0'} + dev: false + optional: true /ms/2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -735,7 +1400,27 @@ packages: /neo-async/2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - dev: true + + /normalize-package-data/2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.2 + semver: 5.7.1 + validate-npm-package-license: 3.0.4 + dev: false + optional: true + + /normalize-package-data/3.0.3: + resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} + engines: {node: '>=10'} + dependencies: + hosted-git-info: 4.1.0 + is-core-module: 2.12.0 + semver: 7.5.0 + validate-npm-package-license: 3.0.4 + dev: false + optional: true /normalize-url/6.1.0: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} @@ -762,9 +1447,92 @@ packages: dev: false optional: true + /p-limit/1.3.0: + resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} + engines: {node: '>=4'} + dependencies: + p-try: 1.0.0 + dev: false + optional: true + + /p-limit/2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + dev: false + optional: true + + /p-locate/2.0.0: + resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} + engines: {node: '>=4'} + dependencies: + p-limit: 1.3.0 + dev: false + optional: true + + /p-locate/4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.0 + dev: false + optional: true + + /p-try/1.0.0: + resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} + engines: {node: '>=4'} + dev: false + optional: true + + /p-try/2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + dev: false + optional: true + + /parse-json/4.0.0: + resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} + engines: {node: '>=4'} + dependencies: + error-ex: 1.3.2 + json-parse-better-errors: 1.0.2 + dev: false + optional: true + + /parse-json/5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.21.4 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: false + optional: true + + /path-exists/3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + dev: false + optional: true + + /path-exists/4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: false + optional: true + /path-parse/1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true + + /path-type/3.0.0: + resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} + engines: {node: '>=4'} + dependencies: + pify: 3.0.0 + dev: false + optional: true /pend/1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} @@ -775,6 +1543,18 @@ packages: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} dev: true + /pify/2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + dev: false + optional: true + + /pify/3.0.0: + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} + dev: false + optional: true + /postcss/8.4.23: resolution: {integrity: sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==} engines: {node: ^10 || ^12 || >=14} @@ -784,6 +1564,11 @@ packages: source-map-js: 1.0.2 dev: true + /process-nextick-args/2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + dev: false + optional: true + /progress/2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} @@ -798,12 +1583,102 @@ packages: dev: false optional: true + /q/1.5.1: + resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + dev: false + optional: true + + /quick-lru/4.0.1: + resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} + engines: {node: '>=8'} + dev: false + optional: true + /quick-lru/5.1.1: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} dev: false optional: true + /read-pkg-up/3.0.0: + resolution: {integrity: sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==} + engines: {node: '>=4'} + dependencies: + find-up: 2.1.0 + read-pkg: 3.0.0 + dev: false + optional: true + + /read-pkg-up/7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + dev: false + optional: true + + /read-pkg/3.0.0: + resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==} + engines: {node: '>=4'} + dependencies: + load-json-file: 4.0.0 + normalize-package-data: 2.5.0 + path-type: 3.0.0 + dev: false + optional: true + + /read-pkg/5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} + dependencies: + '@types/normalize-package-data': 2.4.1 + normalize-package-data: 2.5.0 + parse-json: 5.2.0 + type-fest: 0.6.0 + dev: false + optional: true + + /readable-stream/2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: false + optional: true + + /readable-stream/3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + optional: true + + /redent/3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + dev: false + optional: true + + /require-directory/2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: false + optional: true + /resolve-alpn/1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} dev: false @@ -816,7 +1691,6 @@ packages: is-core-module: 2.12.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true /responselike/2.0.1: resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} @@ -846,11 +1720,27 @@ packages: fsevents: 2.3.2 dev: true + /safe-buffer/5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: false + optional: true + + /safe-buffer/5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + optional: true + /semver-compare/1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} dev: false optional: true + /semver/5.7.1: + resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true + dev: false + optional: true + /semver/6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true @@ -891,13 +1781,98 @@ packages: /source-map/0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - dev: true + + /spdx-correct/3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.13 + dev: false + optional: true + + /spdx-exceptions/2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: false + optional: true + + /spdx-expression-parse/3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + dependencies: + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.13 + dev: false + optional: true + + /spdx-license-ids/3.0.13: + resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} + dev: false + optional: true + + /split/1.0.1: + resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} + dependencies: + through: 2.3.8 + dev: false + optional: true + + /split2/3.2.2: + resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} + dependencies: + readable-stream: 3.6.2 + dev: false + optional: true /sprintf-js/1.1.2: resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==} dev: false optional: true + /string-width/4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: false + optional: true + + /string_decoder/1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + dev: false + optional: true + + /string_decoder/1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + optional: true + + /strip-ansi/6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: false + optional: true + + /strip-bom/3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: false + optional: true + + /strip-indent/3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + dependencies: + min-indent: 1.0.1 + dev: false + optional: true + /sumchecker/3.0.1: resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} engines: {node: '>= 8.0'} @@ -908,10 +1883,64 @@ packages: dev: false optional: true + /supports-color/5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: false + optional: true + /supports-preserve-symlinks-flag/1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - dev: true + + /temp-dir/2.0.0: + resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} + engines: {node: '>=8'} + dev: false + optional: true + + /tempfile/3.0.0: + resolution: {integrity: sha512-uNFCg478XovRi85iD42egu+eSFUmmka750Jy7L5tfHI5hQKKtbPnxaSaXAbBqCDYrw3wx4tXjKwci4/QmsZJxw==} + engines: {node: '>=8'} + dependencies: + temp-dir: 2.0.0 + uuid: 3.4.0 + dev: false + optional: true + + /text-extensions/1.9.0: + resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==} + engines: {node: '>=0.10'} + dev: false + optional: true + + /through/2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: false + optional: true + + /through2/2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + dependencies: + readable-stream: 2.3.8 + xtend: 4.0.2 + dev: false + optional: true + + /through2/4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + dependencies: + readable-stream: 3.6.2 + dev: false + optional: true + + /trim-newlines/3.0.1: + resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} + engines: {node: '>=8'} + dev: false + optional: true /type-fest/0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} @@ -919,6 +1948,24 @@ packages: dev: false optional: true + /type-fest/0.18.1: + resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==} + engines: {node: '>=10'} + dev: false + optional: true + + /type-fest/0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} + dev: false + optional: true + + /type-fest/0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + dev: false + optional: true + /typedoc-plugin-markdown/3.15.1_typedoc@0.24.4: resolution: {integrity: sha512-TaXE8gc8s5YepU1Ogyqfkh+khPE1/n4rV5vaoZCNyXvSLv62jWmHf443lHiQh7r07qAimUOKAndaaufAeIUSiQ==} peerDependencies: @@ -961,6 +2008,26 @@ packages: dev: false optional: true + /util-deprecate/1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: false + optional: true + + /uuid/3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + hasBin: true + dev: false + optional: true + + /validate-npm-package-license/3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + dev: false + optional: true + /vite/4.2.2: resolution: {integrity: sha512-PcNtT5HeDxb3QaSqFYkEum8f5sCVe0R3WK20qxgIvNBZPXU/Obxs/+ubBMeE7nLWeCo2LDzv+8hRYSlcaSehig==} engines: {node: ^14.18.0 || >=16.0.0} @@ -1012,13 +2079,28 @@ packages: /wordwrap/1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - dev: true + + /wrap-ansi/7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: false + optional: true /wrappy/1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: false optional: true + /xtend/4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + dev: false + optional: true + /xvfb-maybe/0.2.1: resolution: {integrity: sha512-9IyRz3l6Qyhl6LvnGRF5jMPB4oBEepQnuzvVAFTynP6ACLLSevqigICJ9d/+ofl29m2daeaVBChnPYUnaeJ7yA==} hasBin: true @@ -1031,11 +2113,37 @@ packages: dev: false optional: true + /y18n/5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: false + optional: true + /yallist/4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: false optional: true + /yargs-parser/20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + dev: false + optional: true + + /yargs/16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + dev: false + optional: true + /yauzl/2.10.0: resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} dependencies: From 087075e1cab86a39cd3924d9427e59c151092ccc Mon Sep 17 00:00:00 2001 From: hellmor Date: Thu, 4 May 2023 10:30:58 +0800 Subject: [PATCH 071/100] chore(GI): remove GI setting (#82) remove gi setting and reference of it. fix index.ts is empty --- public | 1 + samples/base/Sample_Base_0.ts | 12 ++++---- src/Engine3D.ts | 29 ------------------- src/components/Transform.ts | 8 ++--- .../graphics/webGpu/shader/RenderShader.ts | 10 +++---- src/gfx/renderJob/jobs/ForwardRenderJob.ts | 4 +-- src/gfx/renderJob/post/OutlinePost.ts | 1 - src/index.ts | 2 +- src/setting/EngineSetting.ts | 5 ---- 9 files changed, 19 insertions(+), 53 deletions(-) create mode 160000 public diff --git a/public b/public new file mode 160000 index 00000000..313900a1 --- /dev/null +++ b/public @@ -0,0 +1 @@ +Subproject commit 313900a1f85dc0e78dbb0ddfd16ecda58ede66b3 diff --git a/samples/base/Sample_Base_0.ts b/samples/base/Sample_Base_0.ts index a903d180..7b612005 100644 --- a/samples/base/Sample_Base_0.ts +++ b/samples/base/Sample_Base_0.ts @@ -8,22 +8,22 @@ class Sample_Base_0 { await Engine3D.init(); // create new Scene let scene = new Scene3D(); - + // add performance stats scene.addComponent(Stats) - + // add an Atmospheric sky enviroment let sky = scene.addComponent(AtmosphericComponent); sky.sunY = 0.6 - + // add a camera object let cameraObj = new Object3D(); scene.addChild(cameraObj); - + // set main camera component with a perspective view let mainCamera = cameraObj.addComponent(Camera3D); mainCamera.perspective(60, Engine3D.aspect, 0.01, 5000.0); - + // add a basic camera controller let hoverCameraController = cameraObj.addComponent(HoverCameraController); hoverCameraController.setCamera(15, -15, 10); @@ -35,7 +35,7 @@ class Sample_Base_0 { let mat = new LitMaterial(); mr.material = mat; scene.addChild(cubeObj); - + // add a basic direct light let lightObj = new Object3D(); lightObj.rotationX = 45; diff --git a/src/Engine3D.ts b/src/Engine3D.ts index 1798d480..9824835a 100644 --- a/src/Engine3D.ts +++ b/src/Engine3D.ts @@ -200,35 +200,6 @@ export class Engine3D { updateFrameRate: 2, debug: false, }, - gi: { - enable: false, - offsetX: 0, - offsetY: 0, - offsetZ: 0, - probeSpace: 64, - probeXCount: 4, - probeYCount: 2, - probeZCount: 4, - probeSize: 32, - probeSourceTextureSize: 2048, - octRTMaxSize: 2048, - octRTSideSize: 16, - maxDistance: 64 * 1.73, - normalBias: 0.25, - depthSharpness: 1, - hysteresis: 0.98, - lerpHysteresis: 0.01, - irradianceChebyshevBias: 0.01, - rayNumber: 144, - irradianceDistanceBias: 32, - indirectIntensity: 1.0, - ddgiGamma: 2.2, - bounceIntensity: 0.025, - probeRoughness: 1, - realTimeGI: false, - debug: false, - autoRenderProbe: false, - }, sky: { type: 'HDRSKY', sky: null, diff --git a/src/components/Transform.ts b/src/components/Transform.ts index 1b24df54..1c17ae97 100644 --- a/src/components/Transform.ts +++ b/src/components/Transform.ts @@ -1,13 +1,13 @@ -import { ComponentBase } from "./ComponentBase"; -import { Object3D } from "../core/entities/Object3D"; import { Scene3D } from "../core/Scene3D"; +import { View3D } from "../core/View3D"; +import { Object3D } from "../core/entities/Object3D"; import { CEvent } from "../event/CEvent"; import { MathUtil } from "../math/MathUtil"; -import { append, makeMatrix44, Matrix4 } from "../math/Matrix4"; +import { Matrix4, makeMatrix44, append } from "../math/Matrix4"; import { Orientation3D } from "../math/Orientation3D"; import { Quaternion } from "../math/Quaternion"; import { Vector3 } from "../math/Vector3"; -import { View3D } from "../core/View3D"; +import { ComponentBase } from "./ComponentBase"; /** * The Transform component contains the position, rotation, and scaling of an object in 3D space. diff --git a/src/gfx/graphics/webGpu/shader/RenderShader.ts b/src/gfx/graphics/webGpu/shader/RenderShader.ts index 01deac09..b8956c4c 100644 --- a/src/gfx/graphics/webGpu/shader/RenderShader.ts +++ b/src/gfx/graphics/webGpu/shader/RenderShader.ts @@ -370,11 +370,11 @@ export class RenderShader extends ShaderBase { this.defineValue[`USE_WORLDPOS`] = false; this.defineValue[`USEGBUFFER`] = false; } - if (Engine3D.setting.gi.enable) { - this.defineValue[`USEGI`] = true; - } else { - this.defineValue[`USEGI`] = false; - } + // if (Engine3D.setting.gi.enable) { + // this.defineValue[`USEGI`] = true; + // } else { + // this.defineValue[`USEGI`] = false; + // } if (Engine3D.setting.material.materialChannelDebug) { this.defineValue[`USE_DEBUG`] = true; } diff --git a/src/gfx/renderJob/jobs/ForwardRenderJob.ts b/src/gfx/renderJob/jobs/ForwardRenderJob.ts index 6be26740..5d8262f9 100644 --- a/src/gfx/renderJob/jobs/ForwardRenderJob.ts +++ b/src/gfx/renderJob/jobs/ForwardRenderJob.ts @@ -31,7 +31,7 @@ export class ForwardRenderJob extends RendererJob { colorPassRenderer.setRenderStates(rtFrame); - if (Engine3D.setting.gi.enable) { + // if (Engine3D.setting.gi.enable) { // this.ddgiProbeRenderer = new DDGIProbeRenderer(GlobalBindGroup.getLightEntries(this.view.scene).irradianceVolume); // this.ddgiProbeRenderer.clusterLightingRender = this.clusterLightingRender; // this.ddgiProbeRenderer.setInputTexture([ @@ -51,7 +51,7 @@ export class ForwardRenderJob extends RendererJob { // this.ddgiProbeRenderer.irradianceColorMap, // this.ddgiProbeRenderer.irradianceDepthMap, // ); - } + // } if (this.postRenderer) { this.postRenderer.setDebugTexture(debugTextures); diff --git a/src/gfx/renderJob/post/OutlinePost.ts b/src/gfx/renderJob/post/OutlinePost.ts index 92c73700..95e3aaa3 100644 --- a/src/gfx/renderJob/post/OutlinePost.ts +++ b/src/gfx/renderJob/post/OutlinePost.ts @@ -19,7 +19,6 @@ import { Vector2 } from '../../../math/Vector2'; import { RTDescriptor } from '../../graphics/webGpu/descriptor/RTDescriptor'; import { GBufferFrame } from '../frame/GBufferFrame'; import { RTFrame } from '../frame/RTFrame'; -import { OutlineSetting } from '../../../setting/post/OutlineSetting'; import { View3D } from '../../../core/View3D'; export class OutlinePostSlot { diff --git a/src/index.ts b/src/index.ts index ecf6a3fb..2ee71ec6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -374,4 +374,4 @@ export * from "./util/Vector3Ex" export * from "./util/ZSorterUtil" export * from "./util/struct/Struct" export * from "./util/struct/StructValue" -export * from "./util/struct/Vector3Struct" +export * from "./util/struct/Vector3Struct" \ No newline at end of file diff --git a/src/setting/EngineSetting.ts b/src/setting/EngineSetting.ts index 24a578bd..a49a7f83 100644 --- a/src/setting/EngineSetting.ts +++ b/src/setting/EngineSetting.ts @@ -34,11 +34,6 @@ export type EngineSetting = { */ shadow: ShadowSetting; - /** - * global illumination setting - */ - gi: GlobalIlluminationSetting; - /** * light setting */ From c663640e4d08e37be33b453f4dfd61a338b284ee Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Thu, 4 May 2023 12:52:26 +0800 Subject: [PATCH 072/100] feat: add a public assets submodule --- .gitmodules | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..a4372cb2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "public"] + path = public + url = git@github.com:orillusion/assets.git From c6af5ed54e397acff635d7472df5a24c2081f0ba Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Thu, 4 May 2023 12:59:35 +0800 Subject: [PATCH 073/100] fix(ci): exit actions on test fail --- test/ci/main.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/ci/main.js b/test/ci/main.js index 79310a9a..b229a303 100644 --- a/test/ci/main.js +++ b/test/ci/main.js @@ -44,6 +44,13 @@ const createWindow = async ()=>{ console.log(`\x1b[33m[${log.target}]\x1b[0m`) console.table(log.result) console.log('\n-----------------') + // quit ci on any test fail + for(let test in log.result){ + if(log.result[test].fail !== 0){ + vite.kill() + process.exit(1) + } + } }) await win.loadURL(HOST + '/test/?auto') From 75ee2e08ecf424e50bdc3df46f23b28c44c723e3 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Thu, 4 May 2023 13:31:11 +0800 Subject: [PATCH 074/100] fix: autoindex on windows --- src/index.ts | 764 +++++++++++++++++++++++++------------------------ vite.config.js | 8 +- 2 files changed, 391 insertions(+), 381 deletions(-) diff --git a/src/index.ts b/src/index.ts index 2ee71ec6..48dd772f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,377 +1,387 @@ -export * from "./Engine3D" -export * from "./assets/Res" -export * from "./assets/shader/ShaderLib" -export * from "./assets/shader/anim/SkeletonAnimation_shader" -export * from "./assets/shader/compute/BlurEffectCreator_compute" -export * from "./assets/shader/core/pass/CastShadowPass_wgsl" -export * from "./assets/shader/core/pass/ZPassShader_vs" -export * from "./assets/shader/core/struct/LightStructFrag" -export * from "./assets/shader/core/struct/VertexAttributes" -export * from "./assets/shader/glsl/Quad_glsl" -export * from "./assets/shader/glsl/Sky_glsl" -export * from "./assets/shader/glsl/post/LUT_glsl" -export * from "./assets/shader/lighting/LightingFunction_frag" -export * from "./assets/shader/lighting/UnLit_frag" -export * from "./assets/shader/materials/ColorLitShader" -export * from "./assets/shader/materials/Lambert_shader" -export * from "./assets/shader/materials/PavementShader" -export * from "./assets/shader/materials/PointShadowDebug" -export * from "./assets/shader/materials/program/ClusterDebug_frag" -export * from "./assets/shader/materials/sky/AtmosphericScatteringSky_shader" -export * from "./assets/shader/materials/sky/CubeSky_Shader" -export * from "./assets/shader/materials/uniforms/MaterialUniform" -export * from "./assets/shader/materials/uniforms/PhysicMaterialUniform_frag" -export * from "./assets/shader/materials/uniforms/UnLitMaterialUniform_frag" -export * from "./assets/shader/materials/uniforms/VideoUniform_frag" -export * from "./assets/shader/math/MathShader" -export * from "./assets/shader/post/Bloom_shader" -export * from "./assets/shader/post/GlobalFog_shader" -export * from "./assets/shader/quad/Quad_shader" -export * from "./components/AtmosphericComponent" -export * from "./components/BillboardComponent" -export * from "./components/ColliderComponent" -export * from "./components/ComponentBase" -export * from "./components/SkeletonAnimationComponent" -export * from "./components/Transform" -export * from "./components/anim/OAnimationEvent" -export * from "./components/anim/curveAnim/curveAnim/AnimationMonitor" -export * from "./components/anim/curveAnim/curveAnim/AttributeAnimCurve" -export * from "./components/anim/curveAnim/curveAnim/PropertyAnimClip" -export * from "./components/anim/curveAnim/curveAnim/PropertyAnimation" -export * from "./components/anim/curveAnim/curveAnim/PropertyAnimationEvent" -export * from "./components/anim/curveAnim/curveAnim/PropertyHelp" -export * from "./components/anim/morphAnim/MorphTargetBlender" -export * from "./components/anim/morphAnim/MorphTargetData" -export * from "./components/anim/morphAnim/MorphTargetFrame" -export * from "./components/anim/morphAnim/MorphTargetKey" -export * from "./components/anim/morphAnim/MorphTarget_shader" -export * from "./components/anim/skeletonAnim/Joint" -export * from "./components/anim/skeletonAnim/JointPose" -export * from "./components/anim/skeletonAnim/Skeleton" -export * from "./components/anim/skeletonAnim/SkeletonAnimationClip" -export * from "./components/anim/skeletonAnim/SkeletonAnimationClipState" -export * from "./components/anim/skeletonAnim/SkeletonAnimationCompute" -export * from "./components/anim/skeletonAnim/SkeletonPose" -export * from "./components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs" -export * from "./components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs" -export * from "./components/anim/skeletonAnim/shader/compute_skeleton_blend" -export * from "./components/anim/skeletonAnim/shader/compute_skeleton_transform" -export * from "./components/audio/AudioListener" -export * from "./components/audio/PositionAudio" -export * from "./components/audio/StaticAudio" -export * from "./components/controller/CameraControllerBase" -export * from "./components/controller/FirstPersonCameraController" -export * from "./components/controller/FlyCameraController" -export * from "./components/controller/HoverCameraController" -export * from "./components/controller/OrbitController" -export * from "./components/controller/ThirdPersonCameraController" -export * from "./components/lights/DirectLight" -export * from "./components/lights/GILighting" -export * from "./components/lights/IESProfiles" -export * from "./components/lights/LightBase" -export * from "./components/lights/LightData" -export * from "./components/lights/PointLight" -export * from "./components/lights/SpotLight" -export * from "./components/post/PostProcessingComponent" -export * from "./components/renderer/InstanceDrawComponent" -export * from "./components/renderer/MaterialComponent" -export * from "./components/renderer/MeshComponent" -export * from "./components/renderer/MeshRenderer" -export * from "./components/renderer/RenderNode" -export * from "./components/renderer/SkinnedMeshRenderer" -export * from "./components/renderer/SkyRenderer" -export * from "./components/shape/BoxColliderShape" -export * from "./components/shape/CapsuleColliderShape" -export * from "./components/shape/ColliderShape" -export * from "./components/shape/MeshColliderShape" -export * from "./components/shape/SphereColliderShape" -export * from "./core/Camera3D" -export * from "./core/CameraType" -export * from "./core/CubeCamera" -export * from "./core/PointShadowCubeCamera" -export * from "./core/Scene3D" -export * from "./core/View3D" -export * from "./core/ViewQuad" -export * from "./core/bound/BoundingBox" -export * from "./core/bound/BoundingSphere" -export * from "./core/bound/Frustum" -export * from "./core/bound/IBound" -export * from "./core/entities/Entity" -export * from "./core/entities/InstancedMesh" -export * from "./core/entities/Object3D" -export * from "./core/geometry/GeometryBase" -export * from "./core/geometry/GeometryIndicesBuffer" -export * from "./core/geometry/GeometryVertexBuffer" -export * from "./core/geometry/GeometryVertexType" -export * from "./core/geometry/VertexAttribute" -export * from "./core/geometry/VertexAttributeData" -export * from "./core/geometry/VertexAttributeName" -export * from "./core/geometry/VertexAttributeSize" -export * from "./core/geometry/VertexAttributeStride" -export * from "./core/geometry/VertexFormat" -export * from "./core/pool/ObjectPool" -export * from "./core/pool/memory/MatrixDO" -export * from "./core/pool/memory/MemoryDO" -export * from "./core/pool/memory/MemoryInfo" -export * from "./core/tree/kdTree/IKDTreeUserData" -export * from "./core/tree/kdTree/KDTreeEntity" -export * from "./core/tree/kdTree/KDTreeNode" -export * from "./core/tree/kdTree/KDTreeSpace" -export * from "./event/CEvent" -export * from "./event/CEventDispatcher" -export * from "./event/CEventListener" -export * from "./event/CResizeEvent" -export * from "./event/KeyCode" -export * from "./event/MouseCode" -export * from "./event/eventConst/KeyEvent" -export * from "./event/eventConst/LoaderEvent" -export * from "./event/eventConst/Object3DEvent" -export * from "./event/eventConst/PointerEvent3D" -export * from "./event/eventConst/UIEvent" -export * from "./gfx/generate/BrdfLUTGenerate" -export * from "./gfx/generate/PassGenerate" -export * from "./gfx/generate/convert/BlurEffectCreator" -export * from "./gfx/generate/convert/ErpImage2CubeMap" -export * from "./gfx/generate/convert/IBLEnvMapCreator" -export * from "./gfx/generate/convert/MergeRGBACreator" -export * from "./gfx/generate/convert/TextureCubeStdCreator" -export * from "./gfx/generate/convert/TextureCubeUtils" -export * from "./gfx/graphics/webGpu/CanvasConfig" -export * from "./gfx/graphics/webGpu/Context3D" -export * from "./gfx/graphics/webGpu/WebGPUConst" -export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup" -export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout" -export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup" -export * from "./gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup" -export * from "./gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup" -export * from "./gfx/graphics/webGpu/core/bindGroups/groups/LightEntries" -export * from "./gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferBase" -export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferType" -export * from "./gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/StorageGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/UniformGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/VertexGPUBuffer" -export * from "./gfx/graphics/webGpu/core/texture/ITexture" -export * from "./gfx/graphics/webGpu/core/texture/Texture" -export * from "./gfx/graphics/webGpu/core/texture/TextureCube" -export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapCompute" -export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapGenerator" -export * from "./gfx/graphics/webGpu/core/uniforms/UniformNode" -export * from "./gfx/graphics/webGpu/descriptor/RTDescriptor" -export * from "./gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator" -export * from "./gfx/graphics/webGpu/shader/ComputeShader" -export * from "./gfx/graphics/webGpu/shader/RenderShader" -export * from "./gfx/graphics/webGpu/shader/ShaderBase" -export * from "./gfx/graphics/webGpu/shader/ShaderStage" -export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexer" -export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexerToken" -export * from "./gfx/graphics/webGpu/shader/converter/GLSLPreprocessor" -export * from "./gfx/graphics/webGpu/shader/converter/GLSLSyntax" -export * from "./gfx/graphics/webGpu/shader/converter/Reader" -export * from "./gfx/graphics/webGpu/shader/converter/ShaderConverter" -export * from "./gfx/graphics/webGpu/shader/converter/StatementNode" -export * from "./gfx/graphics/webGpu/shader/converter/WGSLTranslator" -export * from "./gfx/graphics/webGpu/shader/util/MorePassParser" -export * from "./gfx/graphics/webGpu/shader/util/Preprocessor" -export * from "./gfx/graphics/webGpu/shader/util/ShaderUtil" -export * from "./gfx/graphics/webGpu/shader/value/ConstValue" -export * from "./gfx/graphics/webGpu/shader/value/DefineValue" -export * from "./gfx/graphics/webGpu/shader/value/ShaderReflectionInfo" -export * from "./gfx/graphics/webGpu/shader/value/ShaderState" -export * from "./gfx/graphics/webGpu/shader/value/ShaderValue" -export * from "./gfx/graphics/webGpu/shader/value/UniformValue" -export * from "./gfx/renderJob/GPUContext" -export * from "./gfx/renderJob/collect/CollectInfo" -export * from "./gfx/renderJob/collect/EntityBatchCollect" -export * from "./gfx/renderJob/collect/EntityCollect" -export * from "./gfx/renderJob/collect/RenderGroup" -export * from "./gfx/renderJob/collect/ShadowLightsCollect" -export * from "./gfx/renderJob/config/RTResourceConfig" -export * from "./gfx/renderJob/config/RenderLayer" -export * from "./gfx/renderJob/frame/GBufferFrame" -export * from "./gfx/renderJob/frame/ProbeGBufferFrame" -export * from "./gfx/renderJob/frame/RTFrame" -export * from "./gfx/renderJob/frame/RTResourceMap" -export * from "./gfx/renderJob/jobs/ForwardRenderJob" -export * from "./gfx/renderJob/jobs/RenderMap" -export * from "./gfx/renderJob/jobs/RendererJob" -export * from "./gfx/renderJob/occlusion/OcclusionSystem" -export * from "./gfx/renderJob/passRenderer/RenderContext" -export * from "./gfx/renderJob/passRenderer/RendererBase" -export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingRender" -export * from "./gfx/renderJob/passRenderer/color/ColorPassRenderer" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DRender" -export * from "./gfx/renderJob/passRenderer/graphic/GraphicConfig" -export * from "./gfx/renderJob/passRenderer/graphic/Graphics3DShape" -export * from "./gfx/renderJob/passRenderer/post/PostRenderer" -export * from "./gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer" -export * from "./gfx/renderJob/passRenderer/preDepth/ZCullingCompute" -export * from "./gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer" -export * from "./gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer" -export * from "./gfx/renderJob/passRenderer/state/RendererMask" -export * from "./gfx/renderJob/passRenderer/state/RendererPassState" -export * from "./gfx/renderJob/passRenderer/state/RendererType" -export * from "./gfx/renderJob/post/DepthOfFieldPost" -export * from "./gfx/renderJob/post/FXAAPost" -export * from "./gfx/renderJob/post/GTAOPost" -export * from "./gfx/renderJob/post/GlobalFog" -export * from "./gfx/renderJob/post/HDRBloomPost" -export * from "./gfx/renderJob/post/OutlinePost" -export * from "./gfx/renderJob/post/PostBase" -export * from "./gfx/renderJob/post/SSRPost" -export * from "./gfx/renderJob/post/TAAPost" -export * from "./io/InputSystem" -export * from "./io/PickFire" -export * from "./io/PickResult" -export * from "./io/RayCastMeshDetail" -export * from "./io/TouchData" -export * from "./io/picker/PickCompute" -export * from "./loader/FileLoader" -export * from "./loader/LoaderBase" -export * from "./loader/LoaderData" -export * from "./loader/LoaderFunctions" -export * from "./loader/LoaderManager" -export * from "./loader/parser/B3DMParser" -export * from "./loader/parser/I3DMParser" -export * from "./loader/parser/OBJParser" -export * from "./loader/parser/ParserBase" -export * from "./loader/parser/RGBEParser" -export * from "./loader/parser/b3dm/B3DMLoader" -export * from "./loader/parser/b3dm/B3DMLoaderBase" -export * from "./loader/parser/b3dm/FeatureTable" -export * from "./loader/parser/b3dm/arrayToString" -export * from "./loader/parser/b3dm/readMagicBytes" -export * from "./loader/parser/gltf/GLBParser" -export * from "./loader/parser/gltf/GLTFInfo" -export * from "./loader/parser/gltf/GLTFParser" -export * from "./loader/parser/gltf/GLTFSubParser" -export * from "./loader/parser/gltf/GLTFSubParserCamera" -export * from "./loader/parser/gltf/GLTFSubParserConverter" -export * from "./loader/parser/gltf/GLTFSubParserMaterial" -export * from "./loader/parser/gltf/GLTFSubParserMesh" -export * from "./loader/parser/gltf/GLTFSubParserSkeleton" -export * from "./loader/parser/gltf/GLTFSubParserSkin" -export * from "./loader/parser/gltf/TypeArray" -export * from "./loader/parser/gltf/extends/KHR_draco_mesh_compression" -export * from "./loader/parser/gltf/extends/KHR_lights_punctual" -export * from "./loader/parser/gltf/extends/KHR_materials_clearcoat" -export * from "./loader/parser/gltf/extends/KHR_materials_emissive_strength" -export * from "./loader/parser/gltf/extends/KHR_materials_ior" -export * from "./loader/parser/gltf/extends/KHR_materials_sheen" -export * from "./loader/parser/gltf/extends/KHR_materials_specular" -export * from "./loader/parser/gltf/extends/KHR_materials_transmission" -export * from "./loader/parser/gltf/extends/KHR_materials_unlit" -export * from "./loader/parser/gltf/extends/KHR_materials_variants" -export * from "./loader/parser/gltf/extends/KHR_materials_volume" -export * from "./loader/parser/gltf/extends/KHR_mesh_quantization" -export * from "./loader/parser/gltf/extends/KHR_texture_basisu" -export * from "./loader/parser/gltf/extends/KHR_texture_transform" -export * from "./loader/parser/i3dm/I3DMLoader" -export * from "./loader/parser/i3dm/I3DMLoaderBase" -export * from "./loader/parser/tileRenderer/TileSet" -export * from "./loader/parser/tileRenderer/TilesRenderer" -export * from "./materials/BlendMode" -export * from "./materials/ColorLitMaterial" -export * from "./materials/GlassMaterial" -export * from "./materials/LambertMaterial" -export * from "./materials/LitMaterial" -export * from "./materials/MaterialBase" -export * from "./materials/MaterialPass" -export * from "./materials/MaterialRegister" -export * from "./materials/PavementMaterial" -export * from "./materials/PhysicMaterial" -export * from "./materials/PointMaterial" -export * from "./materials/SkyMaterial" -export * from "./materials/UnLitMaterial" -export * from "./materials/effectPass/OutLinePass" -export * from "./materials/multiPass/CastPointShadowMaterialPass" -export * from "./materials/multiPass/CastShadowMaterialPass" -export * from "./materials/multiPass/DepthMaterialPass" -export * from "./materials/multiPass/GBufferPass" -export * from "./materials/multiPass/SkyGBufferPass" -export * from "./math/AnimationCurve" -export * from "./math/Bezier2D" -export * from "./math/Bezier3D" -export * from "./math/Color" -export * from "./math/HaltonSeq" -export * from "./math/Line" -export * from "./math/MathUtil" -export * from "./math/Matrix3" -export * from "./math/Matrix4" -export * from "./math/Orientation3D" -export * from "./math/ParticleMath" -export * from "./math/ParticleSystemCurves" -export * from "./math/Plane" -export * from "./math/PolynomialCurve" -export * from "./math/Polynomials" -export * from "./math/Quaternion" -export * from "./math/Rand" -export * from "./math/Random" -export * from "./math/Ray" -export * from "./math/Rect" -export * from "./math/TimeInterpolator" -export * from "./math/Triangle" -export * from "./math/UV" -export * from "./math/Vector2" -export * from "./math/Vector3" -export * from "./math/Vector4" -export * from "./setting/EngineSetting" -export * from "./setting/GlobalIlluminationSetting" -export * from "./setting/LightSetting" -export * from "./setting/MaterialSetting" -export * from "./setting/OcclusionQuerySetting" -export * from "./setting/PickSetting" -export * from "./setting/RenderSetting" -export * from "./setting/ShadowSetting" -export * from "./setting/SkySetting" -export * from "./setting/post/BloomSetting" -export * from "./setting/post/DepthOfViewSetting" -export * from "./setting/post/GTAOSetting" -export * from "./setting/post/GlobalFogSetting" -export * from "./setting/post/OutlineSetting" -export * from "./setting/post/SSRSetting" -export * from "./setting/post/TAASetting" -export * from "./shape/BoxGeometry" -export * from "./shape/CylinderGeometry" -export * from "./shape/PlaneGeometry" -export * from "./shape/SphereGeometry" -export * from "./shape/TorusGeometry" -export * from "./textures/AtmosphericScatteringSky" -export * from "./textures/BitmapTexture2D" -export * from "./textures/BitmapTexture2DArray" -export * from "./textures/BitmapTextureCube" -export * from "./textures/Depth2DTextureArray" -export * from "./textures/DepthCubeArrayTexture" -export * from "./textures/DepthCubeTexture" -export * from "./textures/Float16ArrayTexture" -export * from "./textures/Float32ArrayTexture" -export * from "./textures/HDRTexture" -export * from "./textures/HDRTextureCube" -export * from "./textures/LDRTextureCube" -export * from "./textures/SolidColorSky" -export * from "./textures/Uint16Texture" -export * from "./textures/Uint8ArrayTexture" -export * from "./textures/VirtualTexture" -export * from "./util/AxisObject" -export * from "./util/BytesStream" -export * from "./util/CameraUtil" -export * from "./util/Convert" -export * from "./util/GeometryUtil" -export * from "./util/Global" -export * from "./util/KelvinUtil" -export * from "./util/Object3DUtil" -export * from "./util/ProfilerUtil" -export * from "./util/StringUtil" -export * from "./util/Time" -export * from "./util/Vector3Ex" -export * from "./util/ZSorterUtil" -export * from "./util/struct/Struct" -export * from "./util/struct/StructValue" -export * from "./util/struct/Vector3Struct" \ No newline at end of file +export * from "./Engine3D" +export * from "./assets/Res" +export * from "./assets/shader/ShaderLib" +export * from "./assets/shader/anim/SkeletonAnimation_shader" +export * from "./assets/shader/compute/BlurEffectCreator_compute" +export * from "./assets/shader/core/pass/CastShadowPass_wgsl" +export * from "./assets/shader/core/pass/ZPassShader_vs" +export * from "./assets/shader/core/struct/LightStructFrag" +export * from "./assets/shader/core/struct/VertexAttributes" +export * from "./assets/shader/glsl/Quad_glsl" +export * from "./assets/shader/glsl/Sky_glsl" +export * from "./assets/shader/glsl/post/LUT_glsl" +export * from "./assets/shader/lighting/IrradianceVolumeData_frag" +export * from "./assets/shader/lighting/LightingFunction_frag" +export * from "./assets/shader/lighting/UnLit_frag" +export * from "./assets/shader/materials/ColorLitShader" +export * from "./assets/shader/materials/Lambert_shader" +export * from "./assets/shader/materials/PavementShader" +export * from "./assets/shader/materials/PointShadowDebug" +export * from "./assets/shader/materials/materials/sky/AtmosphericScatteringSky_shader" +export * from "./assets/shader/materials/materials/sky/CubeSky_Shader" +export * from "./assets/shader/materials/program/ClusterDebug_frag" +export * from "./assets/shader/materials/sky/AtmosphericScatteringSky_shader" +export * from "./assets/shader/materials/sky/CubeSky_Shader" +export * from "./assets/shader/materials/uniforms/MaterialUniform" +export * from "./assets/shader/materials/uniforms/PhysicMaterialUniform_frag" +export * from "./assets/shader/materials/uniforms/UnLitMaterialUniform_frag" +export * from "./assets/shader/materials/uniforms/VideoUniform_frag" +export * from "./assets/shader/math/MathShader" +export * from "./assets/shader/post/Bloom_shader" +export * from "./assets/shader/post/GlobalFog_shader" +export * from "./assets/shader/quad/Quad_shader" +export * from "./components/AtmosphericComponent" +export * from "./components/BillboardComponent" +export * from "./components/ColliderComponent" +export * from "./components/ComponentBase" +export * from "./components/IComponent" +export * from "./components/SkeletonAnimationComponent" +export * from "./components/Transform" +export * from "./components/anim/OAnimationEvent" +export * from "./components/anim/curveAnim/curveAnim/AnimationMonitor" +export * from "./components/anim/curveAnim/curveAnim/AttributeAnimCurve" +export * from "./components/anim/curveAnim/curveAnim/PropertyAnimClip" +export * from "./components/anim/curveAnim/curveAnim/PropertyAnimation" +export * from "./components/anim/curveAnim/curveAnim/PropertyAnimationEvent" +export * from "./components/anim/curveAnim/curveAnim/PropertyHelp" +export * from "./components/anim/morphAnim/MorphTargetBlender" +export * from "./components/anim/morphAnim/MorphTargetData" +export * from "./components/anim/morphAnim/MorphTargetFrame" +export * from "./components/anim/morphAnim/MorphTargetKey" +export * from "./components/anim/morphAnim/MorphTarget_shader" +export * from "./components/anim/skeletonAnim/Joint" +export * from "./components/anim/skeletonAnim/JointPose" +export * from "./components/anim/skeletonAnim/Skeleton" +export * from "./components/anim/skeletonAnim/SkeletonAnimationClip" +export * from "./components/anim/skeletonAnim/SkeletonAnimationClipState" +export * from "./components/anim/skeletonAnim/SkeletonAnimationCompute" +export * from "./components/anim/skeletonAnim/SkeletonPose" +export * from "./components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs" +export * from "./components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs" +export * from "./components/anim/skeletonAnim/shader/compute_skeleton_blend" +export * from "./components/anim/skeletonAnim/shader/compute_skeleton_transform" +export * from "./components/audio/AudioListener" +export * from "./components/audio/PositionAudio" +export * from "./components/audio/StaticAudio" +export * from "./components/controller/CameraControllerBase" +export * from "./components/controller/FirstPersonCameraController" +export * from "./components/controller/FlyCameraController" +export * from "./components/controller/HoverCameraController" +export * from "./components/controller/OrbitController" +export * from "./components/controller/ThirdPersonCameraController" +export * from "./components/lights/DirectLight" +export * from "./components/lights/GILighting" +export * from "./components/lights/IESProfiles" +export * from "./components/lights/ILight" +export * from "./components/lights/LightBase" +export * from "./components/lights/LightData" +export * from "./components/lights/PointLight" +export * from "./components/lights/SpotLight" +export * from "./components/post/PostProcessingComponent" +export * from "./components/renderer/InstanceDrawComponent" +export * from "./components/renderer/MaterialComponent" +export * from "./components/renderer/MeshComponent" +export * from "./components/renderer/MeshRenderer" +export * from "./components/renderer/RenderNode" +export * from "./components/renderer/SkinnedMeshRenderer" +export * from "./components/renderer/SkyRenderer" +export * from "./components/shape/BoxColliderShape" +export * from "./components/shape/CapsuleColliderShape" +export * from "./components/shape/ColliderShape" +export * from "./components/shape/MeshColliderShape" +export * from "./components/shape/SphereColliderShape" +export * from "./core/Camera3D" +export * from "./core/CameraType" +export * from "./core/CubeCamera" +export * from "./core/PointShadowCubeCamera" +export * from "./core/Scene3D" +export * from "./core/View3D" +export * from "./core/ViewQuad" +export * from "./core/bound/BoundingBox" +export * from "./core/bound/BoundingSphere" +export * from "./core/bound/Frustum" +export * from "./core/bound/IBound" +export * from "./core/entities/Entity" +export * from "./core/entities/InstancedMesh" +export * from "./core/entities/Object3D" +export * from "./core/geometry/GeometryBase" +export * from "./core/geometry/GeometryIndicesBuffer" +export * from "./core/geometry/GeometryVertexBuffer" +export * from "./core/geometry/GeometryVertexType" +export * from "./core/geometry/VertexAttribute" +export * from "./core/geometry/VertexAttributeData" +export * from "./core/geometry/VertexAttributeName" +export * from "./core/geometry/VertexAttributeSize" +export * from "./core/geometry/VertexAttributeStride" +export * from "./core/geometry/VertexFormat" +export * from "./core/pool/ObjectPool" +export * from "./core/pool/memory/MatrixDO" +export * from "./core/pool/memory/MemoryDO" +export * from "./core/pool/memory/MemoryInfo" +export * from "./core/tree/kdTree/IKDTreeUserData" +export * from "./core/tree/kdTree/KDTreeEntity" +export * from "./core/tree/kdTree/KDTreeNode" +export * from "./core/tree/kdTree/KDTreeSpace" +export * from "./event/CEvent" +export * from "./event/CEventDispatcher" +export * from "./event/CEventListener" +export * from "./event/CResizeEvent" +export * from "./event/KeyCode" +export * from "./event/MouseCode" +export * from "./event/eventConst/KeyEvent" +export * from "./event/eventConst/LoaderEvent" +export * from "./event/eventConst/Object3DEvent" +export * from "./event/eventConst/PointerEvent3D" +export * from "./event/eventConst/UIEvent" +export * from "./gfx/data/IrradianceVolume" +export * from "./gfx/generate/BrdfLUTGenerate" +export * from "./gfx/generate/PassGenerate" +export * from "./gfx/generate/convert/BlurEffectCreator" +export * from "./gfx/generate/convert/ErpImage2CubeMap" +export * from "./gfx/generate/convert/IBLEnvMapCreator" +export * from "./gfx/generate/convert/MergeRGBACreator" +export * from "./gfx/generate/convert/TextureCubeStdCreator" +export * from "./gfx/generate/convert/TextureCubeUtils" +export * from "./gfx/graphics/webGpu/CanvasConfig" +export * from "./gfx/graphics/webGpu/Context3D" +export * from "./gfx/graphics/webGpu/WebGPUConst" +export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout" +export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/groups/LightEntries" +export * from "./gfx/graphics/webGpu/core/buffer/ArrayBufferData" +export * from "./gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferBase" +export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferType" +export * from "./gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/StorageGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/UniformGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/VertexGPUBuffer" +export * from "./gfx/graphics/webGpu/core/texture/ITexture" +export * from "./gfx/graphics/webGpu/core/texture/Texture" +export * from "./gfx/graphics/webGpu/core/texture/TextureCube" +export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapCompute" +export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapGenerator" +export * from "./gfx/graphics/webGpu/core/uniforms/UniformNode" +export * from "./gfx/graphics/webGpu/descriptor/RTDescriptor" +export * from "./gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator" +export * from "./gfx/graphics/webGpu/shader/ComputeShader" +export * from "./gfx/graphics/webGpu/shader/RenderShader" +export * from "./gfx/graphics/webGpu/shader/ShaderBase" +export * from "./gfx/graphics/webGpu/shader/ShaderStage" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexer" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexerToken" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLPreprocessor" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLSyntax" +export * from "./gfx/graphics/webGpu/shader/converter/Reader" +export * from "./gfx/graphics/webGpu/shader/converter/ShaderConverter" +export * from "./gfx/graphics/webGpu/shader/converter/StatementNode" +export * from "./gfx/graphics/webGpu/shader/converter/WGSLTranslator" +export * from "./gfx/graphics/webGpu/shader/util/MorePassParser" +export * from "./gfx/graphics/webGpu/shader/util/Preprocessor" +export * from "./gfx/graphics/webGpu/shader/util/ShaderUtil" +export * from "./gfx/graphics/webGpu/shader/value/ConstValue" +export * from "./gfx/graphics/webGpu/shader/value/DefineValue" +export * from "./gfx/graphics/webGpu/shader/value/ShaderReflectionInfo" +export * from "./gfx/graphics/webGpu/shader/value/ShaderState" +export * from "./gfx/graphics/webGpu/shader/value/ShaderValue" +export * from "./gfx/graphics/webGpu/shader/value/UniformValue" +export * from "./gfx/renderJob/GPUContext" +export * from "./gfx/renderJob/collect/CollectInfo" +export * from "./gfx/renderJob/collect/ComponentCollect" +export * from "./gfx/renderJob/collect/EntityBatchCollect" +export * from "./gfx/renderJob/collect/EntityCollect" +export * from "./gfx/renderJob/collect/RenderGroup" +export * from "./gfx/renderJob/collect/ShadowLightsCollect" +export * from "./gfx/renderJob/config/RTResourceConfig" +export * from "./gfx/renderJob/config/RenderLayer" +export * from "./gfx/renderJob/frame/GBufferFrame" +export * from "./gfx/renderJob/frame/ProbeGBufferFrame" +export * from "./gfx/renderJob/frame/RTFrame" +export * from "./gfx/renderJob/frame/RTResourceMap" +export * from "./gfx/renderJob/jobs/ForwardRenderJob" +export * from "./gfx/renderJob/jobs/RenderMap" +export * from "./gfx/renderJob/jobs/RendererJob" +export * from "./gfx/renderJob/occlusion/OcclusionSystem" +export * from "./gfx/renderJob/passRenderer/RenderContext" +export * from "./gfx/renderJob/passRenderer/RendererBase" +export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer" +export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingRender" +export * from "./gfx/renderJob/passRenderer/color/ColorPassRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DRender" +export * from "./gfx/renderJob/passRenderer/graphic/GraphicConfig" +export * from "./gfx/renderJob/passRenderer/graphic/Graphics3DShape" +export * from "./gfx/renderJob/passRenderer/post/PostRenderer" +export * from "./gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer" +export * from "./gfx/renderJob/passRenderer/preDepth/ZCullingCompute" +export * from "./gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer" +export * from "./gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer" +export * from "./gfx/renderJob/passRenderer/state/RendererMask" +export * from "./gfx/renderJob/passRenderer/state/RendererPassState" +export * from "./gfx/renderJob/passRenderer/state/RendererType" +export * from "./gfx/renderJob/post/DepthOfFieldPost" +export * from "./gfx/renderJob/post/FXAAPost" +export * from "./gfx/renderJob/post/GTAOPost" +export * from "./gfx/renderJob/post/GlobalFog" +export * from "./gfx/renderJob/post/HDRBloomPost" +export * from "./gfx/renderJob/post/OutlinePost" +export * from "./gfx/renderJob/post/PostBase" +export * from "./gfx/renderJob/post/SSRPost" +export * from "./gfx/renderJob/post/TAAPost" +export * from "./io/InputSystem" +export * from "./io/PickFire" +export * from "./io/PickResult" +export * from "./io/RayCastMeshDetail" +export * from "./io/TouchData" +export * from "./io/picker/PickCompute" +export * from "./loader/FileLoader" +export * from "./loader/LoaderBase" +export * from "./loader/LoaderData" +export * from "./loader/LoaderFunctions" +export * from "./loader/LoaderManager" +export * from "./loader/parser/B3DMParser" +export * from "./loader/parser/I3DMParser" +export * from "./loader/parser/OBJParser" +export * from "./loader/parser/ParserBase" +export * from "./loader/parser/RGBEParser" +export * from "./loader/parser/b3dm/B3DMLoader" +export * from "./loader/parser/b3dm/B3DMLoaderBase" +export * from "./loader/parser/b3dm/FeatureTable" +export * from "./loader/parser/b3dm/arrayToString" +export * from "./loader/parser/b3dm/readMagicBytes" +export * from "./loader/parser/gltf/GLBParser" +export * from "./loader/parser/gltf/GLTFInfo" +export * from "./loader/parser/gltf/GLTFParser" +export * from "./loader/parser/gltf/GLTFSubParser" +export * from "./loader/parser/gltf/GLTFSubParserCamera" +export * from "./loader/parser/gltf/GLTFSubParserConverter" +export * from "./loader/parser/gltf/GLTFSubParserMaterial" +export * from "./loader/parser/gltf/GLTFSubParserMesh" +export * from "./loader/parser/gltf/GLTFSubParserSkeleton" +export * from "./loader/parser/gltf/GLTFSubParserSkin" +export * from "./loader/parser/gltf/GLTFType" +export * from "./loader/parser/gltf/TypeArray" +export * from "./loader/parser/gltf/extends/KHR_draco_mesh_compression" +export * from "./loader/parser/gltf/extends/KHR_lights_punctual" +export * from "./loader/parser/gltf/extends/KHR_materials_clearcoat" +export * from "./loader/parser/gltf/extends/KHR_materials_emissive_strength" +export * from "./loader/parser/gltf/extends/KHR_materials_ior" +export * from "./loader/parser/gltf/extends/KHR_materials_sheen" +export * from "./loader/parser/gltf/extends/KHR_materials_specular" +export * from "./loader/parser/gltf/extends/KHR_materials_transmission" +export * from "./loader/parser/gltf/extends/KHR_materials_unlit" +export * from "./loader/parser/gltf/extends/KHR_materials_variants" +export * from "./loader/parser/gltf/extends/KHR_materials_volume" +export * from "./loader/parser/gltf/extends/KHR_mesh_quantization" +export * from "./loader/parser/gltf/extends/KHR_texture_basisu" +export * from "./loader/parser/gltf/extends/KHR_texture_transform" +export * from "./loader/parser/i3dm/I3DMLoader" +export * from "./loader/parser/i3dm/I3DMLoaderBase" +export * from "./loader/parser/tileRenderer/TileSet" +export * from "./loader/parser/tileRenderer/TilesRenderer" +export * from "./materials/BlendMode" +export * from "./materials/ColorLitMaterial" +export * from "./materials/GlassMaterial" +export * from "./materials/LambertMaterial" +export * from "./materials/LitMaterial" +export * from "./materials/MaterialBase" +export * from "./materials/MaterialPass" +export * from "./materials/MaterialRegister" +export * from "./materials/PavementMaterial" +export * from "./materials/PhysicMaterial" +export * from "./materials/PointMaterial" +export * from "./materials/SkyMaterial" +export * from "./materials/UnLitMaterial" +export * from "./materials/effectPass/OutLinePass" +export * from "./materials/multiPass/CastPointShadowMaterialPass" +export * from "./materials/multiPass/CastShadowMaterialPass" +export * from "./materials/multiPass/DepthMaterialPass" +export * from "./materials/multiPass/GBufferPass" +export * from "./materials/multiPass/SkyGBufferPass" +export * from "./math/AnimationCurve" +export * from "./math/Bezier2D" +export * from "./math/Bezier3D" +export * from "./math/Color" +export * from "./math/HaltonSeq" +export * from "./math/Line" +export * from "./math/MathUtil" +export * from "./math/Matrix3" +export * from "./math/Matrix4" +export * from "./math/Orientation3D" +export * from "./math/ParticleMath" +export * from "./math/ParticleSystemCurves" +export * from "./math/Plane" +export * from "./math/PolynomialCurve" +export * from "./math/Polynomials" +export * from "./math/Quaternion" +export * from "./math/Rand" +export * from "./math/Random" +export * from "./math/Ray" +export * from "./math/Rect" +export * from "./math/TimeInterpolator" +export * from "./math/Triangle" +export * from "./math/UV" +export * from "./math/Vector2" +export * from "./math/Vector3" +export * from "./math/Vector4" +export * from "./setting/EngineSetting" +export * from "./setting/GlobalIlluminationSetting" +export * from "./setting/LightSetting" +export * from "./setting/MaterialSetting" +export * from "./setting/OcclusionQuerySetting" +export * from "./setting/PickSetting" +export * from "./setting/RenderSetting" +export * from "./setting/ShadowSetting" +export * from "./setting/SkySetting" +export * from "./setting/post/BloomSetting" +export * from "./setting/post/DepthOfViewSetting" +export * from "./setting/post/GTAOSetting" +export * from "./setting/post/GlobalFogSetting" +export * from "./setting/post/OutlineSetting" +export * from "./setting/post/SSRSetting" +export * from "./setting/post/TAASetting" +export * from "./shape/BoxGeometry" +export * from "./shape/CylinderGeometry" +export * from "./shape/PlaneGeometry" +export * from "./shape/SphereGeometry" +export * from "./shape/TorusGeometry" +export * from "./textures/AtmosphericScatteringSky" +export * from "./textures/BitmapTexture2D" +export * from "./textures/BitmapTexture2DArray" +export * from "./textures/BitmapTextureCube" +export * from "./textures/Depth2DTextureArray" +export * from "./textures/DepthCubeArrayTexture" +export * from "./textures/DepthCubeTexture" +export * from "./textures/Float16ArrayTexture" +export * from "./textures/Float32ArrayTexture" +export * from "./textures/HDRTexture" +export * from "./textures/HDRTextureCube" +export * from "./textures/LDRTextureCube" +export * from "./textures/SolidColorSky" +export * from "./textures/Uint16Texture" +export * from "./textures/Uint8ArrayTexture" +export * from "./textures/VirtualTexture" +export * from "./util/AxisObject" +export * from "./util/BytesStream" +export * from "./util/CameraUtil" +export * from "./util/Convert" +export * from "./util/GeometryUtil" +export * from "./util/Global" +export * from "./util/KelvinUtil" +export * from "./util/Object3DUtil" +export * from "./util/ProfilerUtil" +export * from "./util/StringUtil" +export * from "./util/Time" +export * from "./util/Vector3Ex" +export * from "./util/ZSorterUtil" +export * from "./util/struct/Struct" +export * from "./util/struct/StructValue" +export * from "./util/struct/Vector3Struct" diff --git a/vite.config.js b/vite.config.js index 309c5545..a5a31d28 100644 --- a/vite.config.js +++ b/vite.config.js @@ -22,7 +22,7 @@ module.exports = defineConfig({ async function dir(folder, ts = []) { let files = await readdir(folder) for (let f of files) { - let path = resolve(folder, f) + let path = resolve(folder, f).replace(/\\/g, '/') // fix windows path let ls = await lstat(path) if (ls.isDirectory()) { await dir(path, ts) @@ -35,12 +35,12 @@ module.exports = defineConfig({ return ts } async function autoIndex(file) { - if(file && !tsFile.test(file)) + if(file && !tsFile.test(file.replace(/\\/g, '/'))) // fix windows path return let ts = await dir('./src') - let improts = '' + let improts = '', _dir = __dirname.replace(/\\/g, '/') + '/src' // fix windows path for (let path of ts) { - improts += `export * from "${path.replace(__dirname + '/src', '.').slice(0, -3)}"\r\n` + improts += `export * from "${path.replace(_dir, '.').slice(0, -3)}"\r\n` } let content = await readFile(resolve(__dirname, './src/index.ts'), 'utf-8') if (improts !== content) { From 6c54b26cead1e97d07d78a9d44804930e9c1811b Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Thu, 4 May 2023 14:27:13 +0800 Subject: [PATCH 075/100] chore: fix samples path --- src/Engine3D.ts | 7 ------- tsconfig.json | 3 ++- vite.config.js | 3 ++- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/Engine3D.ts b/src/Engine3D.ts index 9824835a..f789746d 100644 --- a/src/Engine3D.ts +++ b/src/Engine3D.ts @@ -19,7 +19,6 @@ import { ComponentCollect } from './gfx/renderJob/collect/ComponentCollect'; /** * Orillusion 3D Engine - * @notExported * @group engine3D */ export class Engine3D { @@ -323,9 +322,3 @@ export class Engine3D { if (this._lateRender) this._lateRender(); } } - -/** - * Orillusion 3D - * @group engine3D - */ -// export let Engine3D = new _Engine3D(); diff --git a/tsconfig.json b/tsconfig.json index 1e02dcef..5277d54a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,8 @@ "paths": { "../*": ["src/*"], "@orillusion/*": ["packages/*"], - "@orillusion/core": ["src"] + "@orillusion/core": ["src"], + "@samples/*": ["samples/*"] }, "types": ["vite/client", "@webgpu/types"], // for dev diff --git a/vite.config.js b/vite.config.js index a5a31d28..242df888 100644 --- a/vite.config.js +++ b/vite.config.js @@ -11,7 +11,8 @@ module.exports = defineConfig({ resolve: { alias: { '@orillusion/core': resolve(__dirname, './src/index.ts'), - '@orillusion': resolve(__dirname, './packages') + '@orillusion': resolve(__dirname, './packages'), + '@samples': resolve(__dirname, './samples') }, mainFields: ['module:dev', 'module'] }, From 22843ba494ba88cbb29e3f228e61c7a149dca7d2 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Thu, 4 May 2023 16:29:49 +0800 Subject: [PATCH 076/100] feat: add debug gui for samples (#89) add debug gui for samples --- samples/base/Sample_Base_0.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/samples/base/Sample_Base_0.ts b/samples/base/Sample_Base_0.ts index 7b612005..11b1c64e 100644 --- a/samples/base/Sample_Base_0.ts +++ b/samples/base/Sample_Base_0.ts @@ -1,5 +1,6 @@ import { AtmosphericComponent, BoxGeometry, Camera3D, DirectLight, Engine3D, HoverCameraController, KelvinUtil, LitMaterial, MeshRenderer, Object3D, Scene3D, View3D } from '@orillusion/core'; import { Stats } from '@orillusion/stats' +import * as dat from 'https://unpkg.com/dat.gui@0.7.9/build/dat.gui.module.js' // simple base demo class Sample_Base_0 { @@ -53,6 +54,20 @@ class Sample_Base_0 { // start render Engine3D.startRenderView(view); + + // debug GUI + const GUIHelp = new dat.GUI({name: 'Orillusion'}) + GUIHelp.addFolder('Transform'); + GUIHelp.add(cubeObj.transform, 'x', -10.0, 10.0, 0.01); + GUIHelp.add(cubeObj.transform, 'y', -10.0, 10.0, 0.01); + GUIHelp.add(cubeObj.transform, 'z', -10.0, 10.0, 0.01); + GUIHelp.add(cubeObj.transform, 'rotationX', 0.0, 360.0, 0.01); + GUIHelp.add(cubeObj.transform, 'rotationY', 0.0, 360.0, 0.01); + GUIHelp.add(cubeObj.transform, 'rotationZ', 0.0, 360.0, 0.01); + GUIHelp.add(cubeObj.transform, 'scaleX', 0.0, 2.0, 0.01); + GUIHelp.add(cubeObj.transform, 'scaleY', 0.0, 2.0, 0.01); + GUIHelp.add(cubeObj.transform, 'scaleZ', 0.0, 2.0, 0.01); + GUIHelp.endFolder(); } } From f3873adff81f28c944eb81925eecf3b4342ec295 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Thu, 4 May 2023 19:18:19 +0800 Subject: [PATCH 077/100] chore: fix wgsl exports (#92) fix export wgsl fix mouse pick compute bug --- packages/media-extention/VideoMaterial.ts | 2 +- src/assets/shader/ShaderLib.ts | 63 +- ...urce_cs.wgsl => ClusterBoundsSource_cs.ts} | 4 +- .../shader/cluster/ClusterLighting_cs.ts | 141 +++ .../shader/cluster/ClusterLighting_cs.wgsl | 139 --- .../BLUR_CsShader.ts} | 4 +- src/assets/shader/compute/BLUR_CsShader.wgsl | 40 - .../compute/BlurEffectCreator_compute.ts | 100 --- .../shader/compute/BlurEffectCreator_cs.ts | 94 ++ .../shader/compute/DepthOfView_CsShader.wgsl | 81 -- .../DepthOfView_cs.ts} | 4 +- .../ErpImage2CubeMapCreateCube_compute.wgsl | 65 -- .../compute/ErpImage2CubeMapCreateCube_cs.ts | 68 ++ .../ErpImage2CubeMapRgbe2rgba_compute.wgsl | 32 - .../compute/ErpImage2CubeMapRgbe2rgba_cs.ts | 35 + src/assets/shader/compute/GTAOCs.wgsl | 133 --- src/assets/shader/compute/GTAO_cs.ts | 135 +++ .../compute/IBLEnvMapCreator_compute.wgsl | 174 ---- .../shader/compute/IBLEnvMapCreator_cs.ts | 178 ++++ src/assets/shader/compute/MergeRGBA_Cs.wgsl | 29 - src/assets/shader/compute/MergeRGBA_cs.ts | 31 + .../compute/MultiBouncePass_Shader.wgsl | 185 ---- .../shader/compute/MultiBouncePass_cs.ts | 186 ++++ .../shader/compute/OutLineBlendColor.wgsl | 40 - .../shader/compute/OutLineBlendColor_cs.ts | 42 + ...cOutline.wgsl => OutlineCalcOutline_cs.ts} | 25 +- src/assets/shader/compute/OutlineCs.wgsl | 120 --- src/assets/shader/compute/Outline_cs.ts | 123 +++ .../shader/compute/Picker_CsShader.wgsl | 65 -- src/assets/shader/compute/Picker_cs.ts | 68 ++ .../{SSAO_CsShader.wgsl => SSAO_cs.ts} | 9 +- ...Color_Shader.wgsl => SSR_BlendColor_cs.ts} | 8 +- src/assets/shader/compute/SSR_IS_Shader.wgsl | 82 -- .../SSR_IS_cs.ts} | 8 +- .../shader/compute/SSR_RayTrace_Shader.wgsl | 315 ------- .../SSR_RayTrace_cs.ts} | 50 +- src/assets/shader/compute/TAACopyTex.wgsl | 18 - src/assets/shader/compute/TAACopyTex_cs.ts | 21 + src/assets/shader/compute/TAASharpTex.wgsl | 41 - src/assets/shader/compute/TAASharpTex_cs.ts | 42 + src/assets/shader/compute/TAA_cs.ts | 155 ++++ src/assets/shader/compute/TAAcs.wgsl | 155 ---- src/assets/shader/core/base/Common_frag.ts | 29 + src/assets/shader/core/base/Common_frag.wgsl | 26 - src/assets/shader/core/base/Common_vert.ts | 12 + src/assets/shader/core/base/Common_vert.wgsl | 11 - src/assets/shader/core/common/BrdfLut_frag.ts | 6 + .../shader/core/common/BrdfLut_frag.wgsl | 4 - src/assets/shader/core/common/EnvMap_frag.ts | 10 + .../shader/core/common/EnvMap_frag.wgsl | 9 - .../shader/core/common/GlobalUniform.ts | 39 + .../shader/core/common/GlobalUniform.wgsl | 37 - .../shader/core/common/InstanceUniform.ts | 9 + .../shader/core/common/InstanceUniform.wgsl | 7 - .../common/WorldMatrixUniform.ts} | 5 +- .../core/common/WorldMatrixUniform.wgsl | 9 - src/assets/shader/core/inline/Inline_vert.ts | 50 ++ .../shader/core/inline/Inline_vert.wgsl | 49 -- .../shader/core/pass/CastShadowPass_wgsl.ts | 196 ----- .../shader/core/pass/CastShadow_pass.ts | 195 ++++ ...ingShader_cs.wgsl => FrustumCulling_cs.ts} | 4 + .../{GBuffer_shader.wgsl => GBuffer_pass.ts} | 3 + ...{SkyGBuffer_fs.wgsl => SkyGBuffer_pass.ts} | 4 + src/assets/shader/core/pass/ZPassShader_cs.ts | 15 + .../shader/core/pass/ZPassShader_cs.wgsl | 13 - src/assets/shader/core/pass/ZPassShader_fs.ts | 11 + .../shader/core/pass/ZPassShader_fs.wgsl | 9 - src/assets/shader/core/pass/ZPassShader_vs.ts | 4 +- .../core/struct/ColorPassFragmentOutput.ts | 15 + .../core/struct/ColorPassFragmentOutput.wgsl | 11 - .../core/struct/EmptyFrag_CommonFragment.ts | 34 + .../core/struct/EmptyFrag_CommonFragment.wgsl | 30 - .../core/struct/EmptyFrag_FragmentOutput.ts | 15 + .../core/struct/EmptyFrag_FragmentOutput.wgsl | 10 - .../shader/core/struct/FragmentVarying.ts | 23 + .../shader/core/struct/FragmentVarying.wgsl | 20 - src/assets/shader/core/struct/LightStruct.ts | 108 +++ .../shader/core/struct/LightStruct.wgsl | 106 --- .../shader/core/struct/LightStructFrag.ts | 27 +- src/assets/shader/core/struct/ShadingInput.ts | 20 + .../shader/core/struct/ShadingInput.wgsl | 18 - .../shader/core/struct/VertexAttributes.ts | 209 +++-- .../shader/graphic/Graphic3DShader_fs.ts | 35 + .../shader/graphic/Graphic3DShader_fs.wgsl | 30 - .../shader/graphic/Graphic3DShader_vs.ts | 29 + .../shader/graphic/Graphic3DShader_vs.wgsl | 27 - .../lighting/{BRDF_frag.wgsl => BRDF_frag.ts} | 7 +- src/assets/shader/lighting/BxDF_frag.ts | 163 ++++ src/assets/shader/lighting/BxDF_frag.wgsl | 161 ---- .../shader/lighting/IESProfiles_frag.ts | 36 + .../shader/lighting/IESProfiles_frag.wgsl | 32 - .../lighting/IrradianceVolumeData_frag.ts | 79 +- ...rradiance_frag.wgsl => Irradiance_frag.ts} | 6 +- .../shader/lighting/LightingFunction_frag.ts | 247 +++--- src/assets/shader/lighting/UnLit_frag.ts | 24 +- src/assets/shader/materials/GlassShader.ts | 38 + src/assets/shader/materials/GlassShader.wgsl | 36 - src/assets/shader/materials/LitShader.ts | 23 + src/assets/shader/materials/LitShader.wgsl | 22 - src/assets/shader/materials/OutlinePass.ts | 83 ++ src/assets/shader/materials/OutlinePass.wgsl | 80 -- src/assets/shader/materials/PBRLItShader.ts | 105 +++ src/assets/shader/materials/PBRLItShader.wgsl | 106 --- .../shader/materials/{UnLit.wgsl => UnLit.ts} | 5 +- .../ErpImage2CubeMapCreateCube_compute.wgsl | 65 -- .../ErpImage2CubeMapRgbe2rgba_compute.wgsl | 32 - .../shader/materials/compute/GTAOCs.wgsl | 133 --- .../compute/IBLEnvMapCreator_compute.wgsl | 174 ---- .../materials/compute/MergeRGBA_Cs.wgsl | 29 - .../compute/MultiBouncePass_Shader.wgsl | 185 ---- .../materials/compute/OutLineBlendColor.wgsl | 40 - .../materials/compute/OutlineCalcOutline.wgsl | 86 -- .../shader/materials/compute/OutlineCs.wgsl | 120 --- .../materials/compute/Picker_CsShader.wgsl | 65 -- .../materials/compute/SSAO_CsShader.wgsl | 99 --- .../compute/SSR_BlendColor_Shader.wgsl | 45 - .../shader/materials/compute/TAACopyTex.wgsl | 18 - .../shader/materials/compute/TAASharpTex.wgsl | 41 - .../shader/materials/compute/TAAcs.wgsl | 155 ---- .../materials/core/base/Common_frag.wgsl | 26 - .../materials/core/base/Common_vert.wgsl | 11 - .../materials/core/common/BrdfLut_frag.wgsl | 4 - .../materials/core/common/EnvMap_frag.wgsl | 9 - .../materials/core/common/GlobalUniform.wgsl | 37 - .../core/common/InstanceUniform.wgsl | 7 - .../materials/core/inline/Inline_vert.wgsl | 49 -- .../materials/graphic/Graphic3DShader_fs.wgsl | 30 - .../materials/graphic/Graphic3DShader_vs.wgsl | 27 - .../materials/materials/GlassShader.wgsl | 36 - .../shader/materials/materials/LitShader.wgsl | 22 - .../materials/materials/OutlinePass.wgsl | 80 -- .../materials/materials/PBRLItShader.wgsl | 106 --- .../shader/materials/materials/UnLit.wgsl | 28 - .../shader/materials/math/FastMathShader.wgsl | 31 - .../shader/materials/post/FSAAShader.wgsl | 76 -- ...{BxdfDebug_frag.wgsl => BxdfDebug_frag.ts} | 7 +- .../materials/program/Clearcoat_frag.ts | 21 + .../materials/program/Clearcoat_frag.wgsl | 16 - ...{NormalMap_frag.wgsl => NormalMap_frag.ts} | 6 +- .../materials/program/ShadowMapping_frag.ts | 142 +++ .../materials/program/ShadowMapping_frag.wgsl | 142 --- .../sky/AtmosphericScatteringSky_shader.ts | 311 ------- .../shader/materials/sky/CubeSky_Shader.ts | 98 --- .../shader/materials/utils/BRDFLUT.wgsl | 112 --- .../shader/materials/utils/ColorUtil.wgsl | 99 --- .../materials/utils/GenerayRandomDir.wgsl | 23 - src/assets/shader/math/FastMathShader.ts | 34 + src/assets/shader/math/FastMathShader.wgsl | 31 - src/assets/shader/post/FSAAShader.wgsl | 76 -- src/assets/shader/post/FXAAShader.ts | 79 ++ src/assets/shader/post/GlobalFog_shader.ts | 2 +- src/assets/shader/quad/Quad_shader.ts | 307 +++---- .../sky/AtmosphericScatteringSky_shader.ts | 0 .../materials => }/sky/CubeSky_Shader.ts | 0 src/assets/shader/utils/BRDFLUT.ts | 115 +++ src/assets/shader/utils/BRDFLUT.wgsl | 112 --- src/assets/shader/utils/ColorUtil.ts | 99 +++ src/assets/shader/utils/ColorUtil.wgsl | 99 --- src/assets/shader/utils/GenerayRandomDir.ts | 25 + src/assets/shader/utils/GenerayRandomDir.wgsl | 23 - src/gfx/generate/BrdfLUTGenerate.ts | 2 +- src/gfx/generate/convert/BlurEffectCreator.ts | 4 +- src/gfx/generate/convert/ErpImage2CubeMap.ts | 8 +- src/gfx/generate/convert/IBLEnvMapCreator.ts | 5 +- src/gfx/generate/convert/MergeRGBACreator.ts | 4 +- .../webGpu/core/buffer/GPUBufferBase.ts | 26 +- .../cluster/ClusterLightingRender.ts | 5 +- .../graphic/Graphic3DFixedRenderPipeline.ts | 4 +- .../passRenderer/post/PostRenderer.ts | 4 +- .../passRenderer/preDepth/ZCullingCompute.ts | 2 +- src/gfx/renderJob/post/DepthOfFieldPost.ts | 4 +- src/gfx/renderJob/post/FXAAPost.ts | 4 +- src/gfx/renderJob/post/GTAOPost.ts | 14 +- src/gfx/renderJob/post/GlobalFog.ts | 1 - src/gfx/renderJob/post/OutlinePost.ts | 12 +- src/gfx/renderJob/post/SSRPost.ts | 12 +- src/gfx/renderJob/post/TAAPost.ts | 12 +- src/index.ts | 831 ++++++++++-------- src/io/picker/PickCompute.ts | 10 +- src/materials/GlassMaterial.ts | 2 +- src/materials/PointMaterial.ts | 2 +- src/materials/UnLitMaterial.ts | 2 +- src/materials/effectPass/OutLinePass.ts | 51 -- .../multiPass/CastPointShadowMaterialPass.ts | 8 +- .../multiPass/CastShadowMaterialPass.ts | 8 +- src/materials/multiPass/DepthMaterialPass.ts | 2 +- src/materials/multiPass/GBufferPass.ts | 6 +- src/materials/multiPass/SkyGBufferPass.ts | 4 +- src/textures/AtmosphericScatteringSky.ts | 2 +- test/util.ts | 1 + vite.config.js | 2 +- 191 files changed, 4016 insertions(+), 6979 deletions(-) rename src/assets/shader/cluster/{ClusterBoundsSource_cs.wgsl => ClusterBoundsSource_cs.ts} (98%) create mode 100644 src/assets/shader/cluster/ClusterLighting_cs.ts delete mode 100644 src/assets/shader/cluster/ClusterLighting_cs.wgsl rename src/assets/shader/{materials/compute/BLUR_CsShader.wgsl => compute/BLUR_CsShader.ts} (96%) delete mode 100644 src/assets/shader/compute/BLUR_CsShader.wgsl delete mode 100644 src/assets/shader/compute/BlurEffectCreator_compute.ts create mode 100644 src/assets/shader/compute/BlurEffectCreator_cs.ts delete mode 100644 src/assets/shader/compute/DepthOfView_CsShader.wgsl rename src/assets/shader/{materials/compute/DepthOfView_CsShader.wgsl => compute/DepthOfView_cs.ts} (98%) delete mode 100644 src/assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl create mode 100644 src/assets/shader/compute/ErpImage2CubeMapCreateCube_cs.ts delete mode 100644 src/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl create mode 100644 src/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_cs.ts delete mode 100644 src/assets/shader/compute/GTAOCs.wgsl create mode 100644 src/assets/shader/compute/GTAO_cs.ts delete mode 100644 src/assets/shader/compute/IBLEnvMapCreator_compute.wgsl create mode 100644 src/assets/shader/compute/IBLEnvMapCreator_cs.ts delete mode 100644 src/assets/shader/compute/MergeRGBA_Cs.wgsl create mode 100644 src/assets/shader/compute/MergeRGBA_cs.ts delete mode 100644 src/assets/shader/compute/MultiBouncePass_Shader.wgsl create mode 100644 src/assets/shader/compute/MultiBouncePass_cs.ts delete mode 100644 src/assets/shader/compute/OutLineBlendColor.wgsl create mode 100644 src/assets/shader/compute/OutLineBlendColor_cs.ts rename src/assets/shader/compute/{OutlineCalcOutline.wgsl => OutlineCalcOutline_cs.ts} (93%) delete mode 100644 src/assets/shader/compute/OutlineCs.wgsl create mode 100644 src/assets/shader/compute/Outline_cs.ts delete mode 100644 src/assets/shader/compute/Picker_CsShader.wgsl create mode 100644 src/assets/shader/compute/Picker_cs.ts rename src/assets/shader/compute/{SSAO_CsShader.wgsl => SSAO_cs.ts} (98%) rename src/assets/shader/compute/{SSR_BlendColor_Shader.wgsl => SSR_BlendColor_cs.ts} (91%) delete mode 100644 src/assets/shader/compute/SSR_IS_Shader.wgsl rename src/assets/shader/{materials/compute/SSR_IS_Shader.wgsl => compute/SSR_IS_cs.ts} (98%) delete mode 100644 src/assets/shader/compute/SSR_RayTrace_Shader.wgsl rename src/assets/shader/{materials/compute/SSR_RayTrace_Shader.wgsl => compute/SSR_RayTrace_cs.ts} (94%) delete mode 100644 src/assets/shader/compute/TAACopyTex.wgsl create mode 100644 src/assets/shader/compute/TAACopyTex_cs.ts delete mode 100644 src/assets/shader/compute/TAASharpTex.wgsl create mode 100644 src/assets/shader/compute/TAASharpTex_cs.ts create mode 100644 src/assets/shader/compute/TAA_cs.ts delete mode 100644 src/assets/shader/compute/TAAcs.wgsl create mode 100644 src/assets/shader/core/base/Common_frag.ts delete mode 100644 src/assets/shader/core/base/Common_frag.wgsl create mode 100644 src/assets/shader/core/base/Common_vert.ts delete mode 100644 src/assets/shader/core/base/Common_vert.wgsl create mode 100644 src/assets/shader/core/common/BrdfLut_frag.ts delete mode 100644 src/assets/shader/core/common/BrdfLut_frag.wgsl create mode 100644 src/assets/shader/core/common/EnvMap_frag.ts delete mode 100644 src/assets/shader/core/common/EnvMap_frag.wgsl create mode 100644 src/assets/shader/core/common/GlobalUniform.ts delete mode 100644 src/assets/shader/core/common/GlobalUniform.wgsl create mode 100644 src/assets/shader/core/common/InstanceUniform.ts delete mode 100644 src/assets/shader/core/common/InstanceUniform.wgsl rename src/assets/shader/{materials/core/common/WorldMatrixUniform.wgsl => core/common/WorldMatrixUniform.ts} (71%) delete mode 100644 src/assets/shader/core/common/WorldMatrixUniform.wgsl create mode 100644 src/assets/shader/core/inline/Inline_vert.ts delete mode 100644 src/assets/shader/core/inline/Inline_vert.wgsl delete mode 100644 src/assets/shader/core/pass/CastShadowPass_wgsl.ts create mode 100644 src/assets/shader/core/pass/CastShadow_pass.ts rename src/assets/shader/core/pass/{FrustumCullingShader_cs.wgsl => FrustumCulling_cs.ts} (98%) rename src/assets/shader/core/pass/{GBuffer_shader.wgsl => GBuffer_pass.ts} (97%) rename src/assets/shader/core/pass/{SkyGBuffer_fs.wgsl => SkyGBuffer_pass.ts} (96%) create mode 100644 src/assets/shader/core/pass/ZPassShader_cs.ts delete mode 100644 src/assets/shader/core/pass/ZPassShader_cs.wgsl create mode 100644 src/assets/shader/core/pass/ZPassShader_fs.ts delete mode 100644 src/assets/shader/core/pass/ZPassShader_fs.wgsl create mode 100644 src/assets/shader/core/struct/ColorPassFragmentOutput.ts delete mode 100644 src/assets/shader/core/struct/ColorPassFragmentOutput.wgsl create mode 100644 src/assets/shader/core/struct/EmptyFrag_CommonFragment.ts delete mode 100644 src/assets/shader/core/struct/EmptyFrag_CommonFragment.wgsl create mode 100644 src/assets/shader/core/struct/EmptyFrag_FragmentOutput.ts delete mode 100644 src/assets/shader/core/struct/EmptyFrag_FragmentOutput.wgsl create mode 100644 src/assets/shader/core/struct/FragmentVarying.ts delete mode 100644 src/assets/shader/core/struct/FragmentVarying.wgsl create mode 100644 src/assets/shader/core/struct/LightStruct.ts delete mode 100644 src/assets/shader/core/struct/LightStruct.wgsl create mode 100644 src/assets/shader/core/struct/ShadingInput.ts delete mode 100644 src/assets/shader/core/struct/ShadingInput.wgsl create mode 100644 src/assets/shader/graphic/Graphic3DShader_fs.ts delete mode 100644 src/assets/shader/graphic/Graphic3DShader_fs.wgsl create mode 100644 src/assets/shader/graphic/Graphic3DShader_vs.ts delete mode 100644 src/assets/shader/graphic/Graphic3DShader_vs.wgsl rename src/assets/shader/lighting/{BRDF_frag.wgsl => BRDF_frag.ts} (99%) create mode 100644 src/assets/shader/lighting/BxDF_frag.ts delete mode 100644 src/assets/shader/lighting/BxDF_frag.wgsl create mode 100644 src/assets/shader/lighting/IESProfiles_frag.ts delete mode 100644 src/assets/shader/lighting/IESProfiles_frag.wgsl rename src/assets/shader/lighting/{Irradiance_frag.wgsl => Irradiance_frag.ts} (99%) create mode 100644 src/assets/shader/materials/GlassShader.ts delete mode 100644 src/assets/shader/materials/GlassShader.wgsl create mode 100644 src/assets/shader/materials/LitShader.ts delete mode 100644 src/assets/shader/materials/LitShader.wgsl create mode 100644 src/assets/shader/materials/OutlinePass.ts delete mode 100644 src/assets/shader/materials/OutlinePass.wgsl create mode 100644 src/assets/shader/materials/PBRLItShader.ts delete mode 100644 src/assets/shader/materials/PBRLItShader.wgsl rename src/assets/shader/materials/{UnLit.wgsl => UnLit.ts} (94%) delete mode 100644 src/assets/shader/materials/compute/ErpImage2CubeMapCreateCube_compute.wgsl delete mode 100644 src/assets/shader/materials/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl delete mode 100644 src/assets/shader/materials/compute/GTAOCs.wgsl delete mode 100644 src/assets/shader/materials/compute/IBLEnvMapCreator_compute.wgsl delete mode 100644 src/assets/shader/materials/compute/MergeRGBA_Cs.wgsl delete mode 100644 src/assets/shader/materials/compute/MultiBouncePass_Shader.wgsl delete mode 100644 src/assets/shader/materials/compute/OutLineBlendColor.wgsl delete mode 100644 src/assets/shader/materials/compute/OutlineCalcOutline.wgsl delete mode 100644 src/assets/shader/materials/compute/OutlineCs.wgsl delete mode 100644 src/assets/shader/materials/compute/Picker_CsShader.wgsl delete mode 100644 src/assets/shader/materials/compute/SSAO_CsShader.wgsl delete mode 100644 src/assets/shader/materials/compute/SSR_BlendColor_Shader.wgsl delete mode 100644 src/assets/shader/materials/compute/TAACopyTex.wgsl delete mode 100644 src/assets/shader/materials/compute/TAASharpTex.wgsl delete mode 100644 src/assets/shader/materials/compute/TAAcs.wgsl delete mode 100644 src/assets/shader/materials/core/base/Common_frag.wgsl delete mode 100644 src/assets/shader/materials/core/base/Common_vert.wgsl delete mode 100644 src/assets/shader/materials/core/common/BrdfLut_frag.wgsl delete mode 100644 src/assets/shader/materials/core/common/EnvMap_frag.wgsl delete mode 100644 src/assets/shader/materials/core/common/GlobalUniform.wgsl delete mode 100644 src/assets/shader/materials/core/common/InstanceUniform.wgsl delete mode 100644 src/assets/shader/materials/core/inline/Inline_vert.wgsl delete mode 100644 src/assets/shader/materials/graphic/Graphic3DShader_fs.wgsl delete mode 100644 src/assets/shader/materials/graphic/Graphic3DShader_vs.wgsl delete mode 100644 src/assets/shader/materials/materials/GlassShader.wgsl delete mode 100644 src/assets/shader/materials/materials/LitShader.wgsl delete mode 100644 src/assets/shader/materials/materials/OutlinePass.wgsl delete mode 100644 src/assets/shader/materials/materials/PBRLItShader.wgsl delete mode 100644 src/assets/shader/materials/materials/UnLit.wgsl delete mode 100644 src/assets/shader/materials/math/FastMathShader.wgsl delete mode 100644 src/assets/shader/materials/post/FSAAShader.wgsl rename src/assets/shader/materials/program/{BxdfDebug_frag.wgsl => BxdfDebug_frag.ts} (98%) create mode 100644 src/assets/shader/materials/program/Clearcoat_frag.ts delete mode 100644 src/assets/shader/materials/program/Clearcoat_frag.wgsl rename src/assets/shader/materials/program/{NormalMap_frag.wgsl => NormalMap_frag.ts} (96%) create mode 100644 src/assets/shader/materials/program/ShadowMapping_frag.ts delete mode 100644 src/assets/shader/materials/program/ShadowMapping_frag.wgsl delete mode 100644 src/assets/shader/materials/sky/AtmosphericScatteringSky_shader.ts delete mode 100644 src/assets/shader/materials/sky/CubeSky_Shader.ts delete mode 100644 src/assets/shader/materials/utils/BRDFLUT.wgsl delete mode 100644 src/assets/shader/materials/utils/ColorUtil.wgsl delete mode 100644 src/assets/shader/materials/utils/GenerayRandomDir.wgsl create mode 100644 src/assets/shader/math/FastMathShader.ts delete mode 100644 src/assets/shader/math/FastMathShader.wgsl delete mode 100644 src/assets/shader/post/FSAAShader.wgsl create mode 100644 src/assets/shader/post/FXAAShader.ts rename src/assets/shader/{materials/materials => }/sky/AtmosphericScatteringSky_shader.ts (100%) rename src/assets/shader/{materials/materials => }/sky/CubeSky_Shader.ts (100%) create mode 100644 src/assets/shader/utils/BRDFLUT.ts delete mode 100644 src/assets/shader/utils/BRDFLUT.wgsl create mode 100644 src/assets/shader/utils/ColorUtil.ts delete mode 100644 src/assets/shader/utils/ColorUtil.wgsl create mode 100644 src/assets/shader/utils/GenerayRandomDir.ts delete mode 100644 src/assets/shader/utils/GenerayRandomDir.wgsl delete mode 100644 src/materials/effectPass/OutLinePass.ts diff --git a/packages/media-extention/VideoMaterial.ts b/packages/media-extention/VideoMaterial.ts index 07da7914..25cda244 100644 --- a/packages/media-extention/VideoMaterial.ts +++ b/packages/media-extention/VideoMaterial.ts @@ -1,6 +1,6 @@ import { Color, Engine3D, MaterialBase, ShaderLib, Texture, Vector4, registerMaterial } from '@orillusion/core'; -import VideoShader from './VideoShader.wgsl?raw' +import VideoShader from "./VideoShader.wgsl?raw"; /** * Video Material diff --git a/src/assets/shader/ShaderLib.ts b/src/assets/shader/ShaderLib.ts index d502502d..1fb0789e 100644 --- a/src/assets/shader/ShaderLib.ts +++ b/src/assets/shader/ShaderLib.ts @@ -1,40 +1,40 @@ -import BRDF_frag from "./lighting/BRDF_frag.wgsl?raw"; import { Bloom_shader } from './post/Bloom_shader'; -import BrdfLut_frag from "./core/common/BrdfLut_frag.wgsl?raw"; -import BxDF_frag from "./lighting/BxDF_frag.wgsl?raw"; -import BxdfDebug_frag from "./materials/program/BxdfDebug_frag.wgsl?raw"; -import Clearcoat_frag from "./materials/program/Clearcoat_frag.wgsl?raw"; import { ClusterDebug_frag } from './materials/program/ClusterDebug_frag'; -import ColorPassFragmentOutput from "./core/struct/ColorPassFragmentOutput.wgsl?raw"; -import ColorUtil from './utils/ColorUtil.wgsl?raw' -import Common_frag from "./core/base/Common_frag.wgsl?raw"; -import Common_vert from "./core/base/Common_vert.wgsl?raw"; -import { CubeSky_Shader } from './materials/sky/CubeSky_Shader'; -import EnvMap_frag from "./core/common/EnvMap_frag.wgsl?raw"; -import FastMathShader from "./math/FastMathShader.wgsl?raw"; -import FragmentVarying from "./core/struct/FragmentVarying.wgsl?raw"; -import GenerayRandomDir from './utils/GenerayRandomDir.wgsl?raw' -import GlobalUniform from "./core/common/GlobalUniform.wgsl?raw"; -import IESProfiles_frag from './lighting/IESProfiles_frag.wgsl?raw' -import Inline_vert from "./core/inline/Inline_vert.wgsl?raw"; -import InstanceUniform from "./core/common/InstanceUniform.wgsl?raw"; -import Irradiance_frag from "./lighting/Irradiance_frag.wgsl?raw"; +import { CubeSky_Shader } from './sky/CubeSky_Shader'; import { LightStructFrag } from './core/struct/LightStructFrag'; import { LightingFunction_frag } from './lighting/LightingFunction_frag'; -import LitShader from '../shader/materials/LitShader.wgsl?raw' import { MathShader } from './math/MathShader'; -import NormalMap_frag from "./materials/program/NormalMap_frag.wgsl?raw"; -import PBRLItShader from '../shader/materials/PBRLItShader.wgsl?raw' import { PhysicMaterialUniform_frag } from './materials/uniforms/PhysicMaterialUniform_frag'; -import { Quad_shader } from './quad/Quad_shader'; -import ShadingInput from "./core/struct/ShadingInput.wgsl?raw"; -import ShadowMapping_frag from "./materials/program/ShadowMapping_frag.wgsl?raw"; import { UnLitMaterialUniform_frag } from './materials/uniforms/UnLitMaterialUniform_frag'; import { UnLit_frag } from './lighting/UnLit_frag'; import { VertexAttributes } from './core/struct/VertexAttributes'; import { VideoUniform_frag } from './materials/uniforms/VideoUniform_frag'; -import WorldMatrixUniform from "./core/common/WorldMatrixUniform.wgsl?raw"; import { IrradianceVolumeData_frag } from "./lighting/IrradianceVolumeData_frag"; +import { Inline_vert } from './core/inline/Inline_vert'; +import { Common_frag } from './core/base/Common_frag'; +import { Common_vert } from './core/base/Common_vert'; +import { BrdfLut_frag } from './core/common/BrdfLut_frag'; +import { EnvMap_frag } from './core/common/EnvMap_frag'; +import { GlobalUniform } from './core/common/GlobalUniform'; +import { InstanceUniform } from './core/common/InstanceUniform'; +import { WorldMatrixUniform } from './core/common/WorldMatrixUniform'; +import { FastMathShader } from './math/FastMathShader'; +import { NormalMap_frag } from './materials/program/NormalMap_frag'; +import { FragmentVarying } from './core/struct/FragmentVarying'; +import { ColorPassFragmentOutput } from './core/struct/ColorPassFragmentOutput'; +import { ShadingInput } from './core/struct/ShadingInput'; +import { IESProfiles_frag } from './lighting/IESProfiles_frag'; +import { ShadowMapping_frag } from './materials/program/ShadowMapping_frag'; +import { Irradiance_frag } from './lighting/Irradiance_frag'; +import { BRDF_frag } from './lighting/BRDF_frag'; +import { BxDF_frag } from './lighting/BxDF_frag'; +import { Clearcoat_frag } from './materials/program/Clearcoat_frag'; +import { LitShader } from './materials/LitShader'; +import { PBRLItShader } from './materials/PBRLItShader'; +import { BxdfDebug_frag } from './materials/program/BxdfDebug_frag'; +import { Quad_depth2d_frag_wgsl, Quad_depthCube_frag_wgsl, Quad_frag_wgsl, Quad_vert_wgsl } from './quad/Quad_shader'; +import { ColorUtil } from './utils/ColorUtil'; +import { GenerayRandomDir } from './utils/GenerayRandomDir'; /** * @internal @@ -87,10 +87,10 @@ export class ShaderLib { ShaderLib.register('ClusterDebug_frag', ClusterDebug_frag); ShaderLib.register('BxdfDebug_frag', BxdfDebug_frag); ShaderLib.register('GenerayRandomDir', GenerayRandomDir); - ShaderLib.register('Quad_vert_wgsl', Quad_shader.Quad_vert_wgsl); - ShaderLib.register('Quad_frag_wgsl', Quad_shader.Quad_frag_wgsl); - ShaderLib.register('Quad_depth2d_frag_wgsl', Quad_shader.Quad_depth2d_frag_wgsl); - ShaderLib.register('Quad_depthCube_frag_wgsl', Quad_shader.Quad_depthCube_frag_wgsl); + ShaderLib.register('Quad_vert_wgsl', Quad_vert_wgsl); + ShaderLib.register('Quad_frag_wgsl', Quad_frag_wgsl); + ShaderLib.register('Quad_depth2d_frag_wgsl', Quad_depth2d_frag_wgsl); + ShaderLib.register('Quad_depthCube_frag_wgsl', Quad_depthCube_frag_wgsl); ShaderLib.register('sky_vs_frag_wgsl', CubeSky_Shader.sky_vs_frag_wgsl); ShaderLib.register('sky_fs_frag_wgsl', CubeSky_Shader.sky_fs_frag_wgsl); ShaderLib.register('Bloom_Brightness_frag_wgsl', Bloom_shader.Bloom_Brightness_frag_wgsl); @@ -100,14 +100,11 @@ export class ShaderLib { public static register(keyName: string, code: string) { if (!ShaderLib[keyName.toLowerCase()]) { - // console.warn(`The registered shader already exists: ${keyName}`); ShaderLib[keyName.toLowerCase()] = code; } } public static getShader(keyName: string): string { - // let shaderName = keyName.toLowerCase() ; - // let shaderSource = "" if (ShaderLib[keyName.toLowerCase()]) { return ShaderLib[keyName.toLowerCase()]; } diff --git a/src/assets/shader/cluster/ClusterBoundsSource_cs.wgsl b/src/assets/shader/cluster/ClusterBoundsSource_cs.ts similarity index 98% rename from src/assets/shader/cluster/ClusterBoundsSource_cs.wgsl rename to src/assets/shader/cluster/ClusterBoundsSource_cs.ts index ed0ebe5f..b54d144f 100644 --- a/src/assets/shader/cluster/ClusterBoundsSource_cs.wgsl +++ b/src/assets/shader/cluster/ClusterBoundsSource_cs.ts @@ -1,3 +1,4 @@ +export let ClusterBoundsSource_cs: string = /* wgsl */` #include "GlobalUniform" struct ClusterBox{ @@ -96,4 +97,5 @@ clusterBox.minPoint = vec4(minPointAABB,f32(tileIndex)) ; clusterBox.maxPoint = vec4(maxPointAABB,f32(tileIndex)) ; clusterBuffer[tileIndex] = clusterBox; - } \ No newline at end of file + } +` \ No newline at end of file diff --git a/src/assets/shader/cluster/ClusterLighting_cs.ts b/src/assets/shader/cluster/ClusterLighting_cs.ts new file mode 100644 index 00000000..6e43afe0 --- /dev/null +++ b/src/assets/shader/cluster/ClusterLighting_cs.ts @@ -0,0 +1,141 @@ +export let ClusterLighting_cs: string = /*wgsl*/` +#include "GlobalUniform" + +struct ClusterBox{ + minPoint:vec4, + maxPoint:vec4 +} + +struct Light { + index:f32, + lightType:i32, + radius:f32, + linear:f32, + + position:vec3, + lightMatrixIndex:f32, + + direction:vec3, + quadratic:f32, + + lightColor:vec3, + intensity:f32, + + innerCutOff :f32, + outerCutOff:f32, + range :f32, + castShadow:f32, + + lightTangent:vec3, + ies:f32, +}; + +struct LightIndex +{ + count:f32, + start:f32, + empty0:f32, + empty1:f32, +}; + +struct ClustersUniform{ + clusterTileX:f32, + clusterTileY:f32, + clusterTileZ:f32, + numLights:f32, + maxNumLightsPerCluster:f32, + near:f32, + far:f32, + screenWidth:f32, + screenHeight:f32, + clusterPix:f32, +} + +struct Uniforms { + matrix : array> +}; + + + +var clusterTileX:f32 ; +var clusterTileY:f32 ; +var clusterTileZ:f32 ; + +@group(0) @binding(1) var models : Uniforms; +@group(0) @binding(2) var clustersUniform : ClustersUniform; +@group(0) @binding(3) var clusterBuffer : array; +@group(0) @binding(4) var lightBuffer : array; +@group(0) @binding(5) var lightAssignBuffer : array; +@group(0) @binding(6) var assignTable : array; + +fn gridToIndex(i:vec3) -> u32{ + return i.z * u32(clusterTileX) * u32(clusterTileY) + i.y * u32(clusterTileX) + i.x ; +} + +fn GetSqdisPointAABB( pos:vec3, clusterIndex:u32 ) -> f32 +{ + var sqDistance = 0.0; + let cluster = clusterBuffer[clusterIndex]; + for (var i = 0u; i < 3u; i+=1u) + { + var v = pos[i]; + if (v < cluster.minPoint[i]) + { + let diff = cluster.minPoint[i] - v; + sqDistance += diff * diff; + } + + if (v > cluster.maxPoint[i]) + { + let diff = v - cluster.maxPoint[i]; + sqDistance += diff * diff; + } + } + return sqDistance; +} + +fn TestSphereAABB( lightIndex:i32 , clusterIndex : u32 ) -> bool +{ + let light = lightBuffer[lightIndex]; + let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; + var radius = light.range * 2.0 ; + let spherePos = globalUniform.viewMat * vec4(lightPos.xyz, 1.0) ; + let sqDistance = GetSqdisPointAABB(spherePos.xyz , clusterIndex); + return sqDistance <= (radius*radius); +} + + + +@compute @workgroup_size(16,12,1) +fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(local_invocation_id) local_invocation_id : vec3 ){ + clusterTileX = clustersUniform.clusterTileX; + clusterTileY = clustersUniform.clusterTileY; + clusterTileZ = clustersUniform.clusterTileZ; + // cluster ID + let i = local_invocation_id.x ; + let j = local_invocation_id.y ; + let k = workgroup_id.x ; + + var clusterId_3D = vec3(i,j,k); + var clusterId_1D = gridToIndex(clusterId_3D); + + var startIndex = i32(clusterId_1D) * i32(clustersUniform.maxNumLightsPerCluster) ; + var endIndex = startIndex; + + for(var lightID = 0 ; lightID < i32(clustersUniform.numLights) ; lightID+=1) + { + if(!TestSphereAABB(lightID, clusterId_1D)) { + continue; + }; + lightAssignBuffer[endIndex] = f32(lightID); + endIndex += 1 ; + } + + // workgroupBarrier(); + + var idx: LightIndex; + idx.count = f32(endIndex-startIndex); + idx.start = f32(startIndex); + assignTable[clusterId_1D] = idx; +} +` \ No newline at end of file diff --git a/src/assets/shader/cluster/ClusterLighting_cs.wgsl b/src/assets/shader/cluster/ClusterLighting_cs.wgsl deleted file mode 100644 index 7a6c2e25..00000000 --- a/src/assets/shader/cluster/ClusterLighting_cs.wgsl +++ /dev/null @@ -1,139 +0,0 @@ - #include "GlobalUniform" - - struct ClusterBox{ - minPoint:vec4, - maxPoint:vec4 - } - - struct Light { - index:f32, - lightType:i32, - radius:f32, - linear:f32, - - position:vec3, - lightMatrixIndex:f32, - - direction:vec3, - quadratic:f32, - - lightColor:vec3, - intensity:f32, - - innerCutOff :f32, - outerCutOff:f32, - range :f32, - castShadow:f32, - - lightTangent:vec3, - ies:f32, - }; - - struct LightIndex - { - count:f32, - start:f32, - empty0:f32, - empty1:f32, - }; - - struct ClustersUniform{ - clusterTileX:f32, - clusterTileY:f32, - clusterTileZ:f32, - numLights:f32, - maxNumLightsPerCluster:f32, - near:f32, - far:f32, - screenWidth:f32, - screenHeight:f32, - clusterPix:f32, - } - - struct Uniforms { - matrix : array> - }; - - - - var clusterTileX:f32 ; - var clusterTileY:f32 ; - var clusterTileZ:f32 ; - - @group(0) @binding(1) var models : Uniforms; - @group(0) @binding(2) var clustersUniform : ClustersUniform; - @group(0) @binding(3) var clusterBuffer : array; - @group(0) @binding(4) var lightBuffer : array; - @group(0) @binding(5) var lightAssignBuffer : array; - @group(0) @binding(6) var assignTable : array; - - fn gridToIndex(i:vec3) -> u32{ - return i.z * u32(clusterTileX) * u32(clusterTileY) + i.y * u32(clusterTileX) + i.x ; - } - - fn GetSqdisPointAABB( pos:vec3, clusterIndex:u32 ) -> f32 - { - var sqDistance = 0.0; - let cluster = clusterBuffer[clusterIndex]; - for (var i = 0u; i < 3u; i+=1u) - { - var v = pos[i]; - if (v < cluster.minPoint[i]) - { - let diff = cluster.minPoint[i] - v; - sqDistance += diff * diff; - } - - if (v > cluster.maxPoint[i]) - { - let diff = v - cluster.maxPoint[i]; - sqDistance += diff * diff; - } - } - return sqDistance; - } - - fn TestSphereAABB( lightIndex:i32 , clusterIndex : u32 ) -> bool - { - let light = lightBuffer[lightIndex]; - let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; - var radius = light.range * 2.0 ; - let spherePos = globalUniform.viewMat * vec4(lightPos.xyz, 1.0) ; - let sqDistance = GetSqdisPointAABB(spherePos.xyz , clusterIndex); - return sqDistance <= (radius*radius); - } - - - - @compute @workgroup_size(16,12,1) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(local_invocation_id) local_invocation_id : vec3 ){ - clusterTileX = clustersUniform.clusterTileX; - clusterTileY = clustersUniform.clusterTileY; - clusterTileZ = clustersUniform.clusterTileZ; - // cluster ID - let i = local_invocation_id.x ; - let j = local_invocation_id.y ; - let k = workgroup_id.x ; - - var clusterId_3D = vec3(i,j,k); - var clusterId_1D = gridToIndex(clusterId_3D); - - var startIndex = i32(clusterId_1D) * i32(clustersUniform.maxNumLightsPerCluster) ; - var endIndex = startIndex; - - for(var lightID = 0 ; lightID < i32(clustersUniform.numLights) ; lightID+=1) - { - if(!TestSphereAABB(lightID, clusterId_1D)) { - continue; - }; - lightAssignBuffer[endIndex] = f32(lightID); - endIndex += 1 ; - } - - // workgroupBarrier(); - - var idx: LightIndex; - idx.count = f32(endIndex-startIndex); - idx.start = f32(startIndex); - assignTable[clusterId_1D] = idx; - } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/BLUR_CsShader.wgsl b/src/assets/shader/compute/BLUR_CsShader.ts similarity index 96% rename from src/assets/shader/materials/compute/BLUR_CsShader.wgsl rename to src/assets/shader/compute/BLUR_CsShader.ts index e5dd6680..072dd06e 100644 --- a/src/assets/shader/materials/compute/BLUR_CsShader.wgsl +++ b/src/assets/shader/compute/BLUR_CsShader.ts @@ -1,3 +1,4 @@ +export let BLUR_CsShader: string = /* wgsl */` #include "GlobalUniform" struct UniformData { @@ -37,4 +38,5 @@ fn CsMain( @builtin(global_invocation_id) globalInvocation_id : vec3) var fResult = result.r / ii ; var color = textureLoad(colorMap, fragCoord , 0 ); textureStore(outTex, fragCoord , vec4(color.rgb * fResult,1.0) ); -} \ No newline at end of file +} +` \ No newline at end of file diff --git a/src/assets/shader/compute/BLUR_CsShader.wgsl b/src/assets/shader/compute/BLUR_CsShader.wgsl deleted file mode 100644 index e5dd6680..00000000 --- a/src/assets/shader/compute/BLUR_CsShader.wgsl +++ /dev/null @@ -1,40 +0,0 @@ -#include "GlobalUniform" - -struct UniformData { - radius: f32 , - bias: f32, - aoPower: f32 , - blurSize: f32 , -}; - -// @group(0) @binding(0) var standUniform: GlobalUniform; -@group(0) @binding(0) var uniformData: UniformData; -@group(0) @binding(1) var colorMap : texture_2d; -// @group(0) @binding(2) var ssaoMapSampler : sampler; -@group(0) @binding(2) var ssaoMap : texture_2d; -@group(0) @binding(3) var outTex : texture_storage_2d; - -@compute @workgroup_size( 8 , 8 ) -fn CsMain( @builtin(global_invocation_id) globalInvocation_id : vec3) -{ - var fragCoord = vec2( globalInvocation_id.xy ); - - var texSize = vec2(textureDimensions(ssaoMap).xy); - var texCoord = vec2(fragCoord) / texSize ; - - let blurSize = i32(uniformData.blurSize); - - var result = vec4(0.0) ; - var ii = 0.0 ; - for (var i = -2; i < 2 ; i+=1) { - for (var j = -2; j < 2 ; j+=1) { - var offset = vec2( i , j ) ; - result += textureLoad(ssaoMap, fragCoord + offset, 0 ); - // result += textureSampleLevel(ssaoMap,ssaoMapSampler, vec2( fragCoord + offset) / texSize , 0.0 ); - ii += 1.0 ; - } - } - var fResult = result.r / ii ; - var color = textureLoad(colorMap, fragCoord , 0 ); - textureStore(outTex, fragCoord , vec4(color.rgb * fResult,1.0) ); -} \ No newline at end of file diff --git a/src/assets/shader/compute/BlurEffectCreator_compute.ts b/src/assets/shader/compute/BlurEffectCreator_compute.ts deleted file mode 100644 index ec336c78..00000000 --- a/src/assets/shader/compute/BlurEffectCreator_compute.ts +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @internal - */ -export class BlurEffectCreator_compute { - public static sample_rgba8unorm = /* wgsl */` - - struct ImageSize { - srcWidth : i32, - srcHeight : i32, - dstWidth : i32, - dstHeight : i32, - }; - - @group(0) @binding(0) var size : ImageSize; - @group(0) @binding(1) var inputTexture : texture_2d; - @group(0) @binding(2) var outputTexture : texture_storage_2d; - - @compute @workgroup_size(8, 8, 1) - fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { - var uv:vec2 = vec2(f32(GlobalInvocationID.x) / f32(size.dstWidth), f32(GlobalInvocationID.y) / f32(size.dstHeight)); - uv = uv * vec2(f32(size.srcWidth), f32(size.srcHeight)); - var dstId:vec2 = vec2(i32(GlobalInvocationID.x), i32(GlobalInvocationID.y)); - var srcId:vec2 = vec2(i32(GlobalInvocationID.x * 2u), i32(GlobalInvocationID.y * 2u)); - textureStore(outputTexture, dstId, textureLoad(inputTexture, srcId, 0)); - } - `; - - public static blur_rgba8unorm = /* wgsl */ ` - - struct ImageSize { - srcWidth : i32, - srcHeight : i32, - dstWidth : i32, - dstHeight : i32, - }; - - @group(0) @binding(0) var size : ImageSize; - @group(0) @binding(1) var inputTexture : texture_2d; - @group(0) @binding(2) var outputTexture : texture_storage_2d; - - fn repeat_i32(id:i32, max:i32) -> i32 { - var ret = id; - if(id < 0) { - ret = max + id; - } - if(id >= max) { - ret = id - max; - } - return ret; - } - - fn clamp_i32(id:i32, max:i32) -> i32 { - var ret = id; - if(id < 0) { - ret = 0; - } - if(id >= max) { - ret = max - 1; - } - return ret; - } - - fn blur(idx:u32) -> vec4 { - var id:vec2; - id.y = i32(idx) / size.srcWidth; - id.x = i32(idx) - i32(id.y) * size.srcWidth; - var _BlurSpread:i32 = 1; - var result = vec4(0.0, 0.0, 0.0, 0.0); - let g:array = array(0.4026, 0.2442, 0.0545); - var uv:vec2; - for (var h:i32 = 0; h < 5; h = h + 1) { - let offsetU:i32 = (h - 2) * _BlurSpread; - uv.x = id.x + offsetU; - uv.x = clamp_i32(uv.x, size.srcWidth); - for (var v:i32 = 0; v < 5; v = v + 1) { - let offsetV:i32 = (v - 2) * _BlurSpread; - uv.y = id.y + offsetV; - uv.y = clamp(uv.y, 0, size.srcHeight); - let weightU:i32 = abs(h - 2); - let weightV:i32 = abs(v - 2); - let resultWeight:f32 = g[weightU] * g[weightV]; - var colorf32:vec4 = textureLoad(inputTexture, uv, 0); - let sampleColor:vec4 = vec4(colorf32 * resultWeight); - result = result + sampleColor; - } - } - - return result; - } - - @compute @workgroup_size(8, 8, 1) - fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { - var uv:vec2 = vec2(f32(GlobalInvocationID.x) / f32(size.dstWidth), f32(GlobalInvocationID.y) / f32(size.dstHeight)); - uv = uv * vec2(f32(size.srcWidth), f32(size.srcHeight)); - let srcIdx = i32(uv.y) * size.srcWidth + i32(uv.x); - var dstId:vec2 = vec2(i32(GlobalInvocationID.x), i32(GlobalInvocationID.y)); - textureStore(outputTexture, dstId, blur(u32(srcIdx))); - } -`; -} diff --git a/src/assets/shader/compute/BlurEffectCreator_cs.ts b/src/assets/shader/compute/BlurEffectCreator_cs.ts new file mode 100644 index 00000000..def9c40d --- /dev/null +++ b/src/assets/shader/compute/BlurEffectCreator_cs.ts @@ -0,0 +1,94 @@ +export let BlurEffectCreatorSample_cs: string = /*wgsl*/ ` + struct ImageSize { + srcWidth: i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32, + }; + + @group(0) @binding(0) varsize : ImageSize; + @group(0) @binding(1) var inputTexture: texture_2d; + @group(0) @binding(2) var outputTexture: texture_storage_2d; + + @compute @workgroup_size(8, 8, 1) + fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + var uv: vec2 = vec2(f32(GlobalInvocationID.x) / f32(size.dstWidth), f32(GlobalInvocationID.y) / f32(size.dstHeight)); + uv = uv * vec2(f32(size.srcWidth), f32(size.srcHeight)); + var dstId: vec2 = vec2(i32(GlobalInvocationID.x), i32(GlobalInvocationID.y)); + var srcId: vec2 = vec2(i32(GlobalInvocationID.x * 2u), i32(GlobalInvocationID.y * 2u)); + textureStore(outputTexture, dstId, textureLoad(inputTexture, srcId, 0)); + } +` + +export let BlurEffectCreatorBlur_cs: string = /*wgsl*/ ` + struct ImageSize { + srcWidth: i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32, + }; + + @group(0) @binding(0) varsize : ImageSize; + @group(0) @binding(1) var inputTexture: texture_2d; + @group(0) @binding(2) var outputTexture: texture_storage_2d; + + fn repeat_i32(id: i32, max: i32) -> i32 { + var ret = id; + if (id < 0) { + ret = max + id; + } + if (id >= max) { + ret = id - max; + } + return ret; + } + + fn clamp_i32(id: i32, max: i32) -> i32 { + var ret = id; + if (id < 0) { + ret = 0; + } + if (id >= max) { + ret = max - 1; + } + return ret; + } + + fn blur(idx: u32) -> vec4 < f32 > { + var id: vec2; + id.y = i32(idx) / size.srcWidth; + id.x = i32(idx) - i32(id.y) * size.srcWidth; + var _BlurSpread: i32 = 1; + var result = vec4(0.0, 0.0, 0.0, 0.0); + let g: array < f32, 3u > = array (0.4026, 0.2442, 0.0545); + var uv: vec2; + for(var h: i32 = 0; h< 5; h = h + 1) { + let offsetU: i32 = (h - 2) * _BlurSpread; + uv.x = id.x + offsetU; + uv.x = clamp_i32(uv.x, size.srcWidth); + for (var v: i32 = 0; v < 5; v = v + 1) { + let offsetV: i32 = (v - 2) * _BlurSpread; + uv.y = id.y + offsetV; + uv.y = clamp(uv.y, 0, size.srcHeight); + let weightU: i32 = abs(h - 2); + let weightV: i32 = abs(v - 2); + let resultWeight: f32 = g[weightU] * g[weightV]; + var colorf32: vec4 = textureLoad(inputTexture, uv, 0); + let sampleColor: vec4 = vec4(colorf32 * resultWeight); + result = result + sampleColor; + } + } + + return result; + } + + @compute @workgroup_size(8, 8, 1) + fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + var uv: vec2 = vec2(f32(GlobalInvocationID.x) / f32(size.dstWidth), f32(GlobalInvocationID.y) / f32(size.dstHeight)); + uv = uv * vec2(f32(size.srcWidth), f32(size.srcHeight)); + let srcIdx = i32(uv.y) * size.srcWidth + i32(uv.x); + var dstId: vec2 = vec2(i32(GlobalInvocationID.x), i32(GlobalInvocationID.y)); + textureStore(outputTexture, dstId, blur(u32(srcIdx))); + } +` + diff --git a/src/assets/shader/compute/DepthOfView_CsShader.wgsl b/src/assets/shader/compute/DepthOfView_CsShader.wgsl deleted file mode 100644 index f8420bda..00000000 --- a/src/assets/shader/compute/DepthOfView_CsShader.wgsl +++ /dev/null @@ -1,81 +0,0 @@ -#include "GlobalUniform" - - struct BlurSetting{ - near: f32, - far: f32, - pixelOffset: f32, - } - - @group(0) @binding(0) var standUniform: GlobalUniform; - @group(0) @binding(1) var blurSetting: BlurSetting; - - @group(0) @binding(2) var positionBufferTex : texture_2d; - @group(0) @binding(3) var normalBufferTex : texture_2d; - @group(0) @binding(4) var inTexSampler : sampler; - @group(0) @binding(5) var inTex : texture_2d; - @group(0) @binding(6) var outTex : texture_storage_2d; - - var cameraPosition: vec3; - var texSize: vec2; - var fragCoord: vec2; - var texelSize: vec2; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - texSize = textureDimensions(inTex).xy; - texelSize = 1.0 / vec2(texSize - 1); - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - cameraPosition = vec3(standUniform.cameraWorldMatrix[3].xyz); - let wPosition:vec3 = textureLoad(positionBufferTex, fragCoord , 0).xyz; - var distance = length(wPosition - cameraPosition); - var oc:vec4 = textureLoad(inTex, fragCoord, 0); - if(distance > blurSetting.near){ - let normal = textureLoad(normalBufferTex, fragCoord, 0); - var pixelScale = 0.5; - if(normal.w > 0.5){ - distance = min(distance, blurSetting.far); - pixelScale = (distance - blurSetting.near) / (blurSetting.far - blurSetting.near); - } - oc = mixBlurColor(oc, fragCoord, blurSetting.pixelOffset, pixelScale); - } - textureStore(outTex, fragCoord, oc); - } - - fn mixBlurColor(orginColor:vec4, coord:vec2, pixelOffset:f32, scale:f32) -> vec4 { - - let uv = vec2(coord); - var uv0 = (uv + scale * vec2( pixelOffset, pixelOffset)) * texelSize; - var uv1 = (uv + scale * vec2(-pixelOffset, pixelOffset)) * texelSize; - var uv2 = (uv + scale * vec2(-pixelOffset, -pixelOffset)) * texelSize; - var uv3 = (uv + scale * vec2( pixelOffset, -pixelOffset)) * texelSize; - - uv0.x = processUVEdge(uv0.x); - uv0.y = processUVEdge(uv0.y); - uv1.x = processUVEdge(uv1.x); - uv1.y = processUVEdge(uv1.y); - uv2.x = processUVEdge(uv2.x); - uv2.y = processUVEdge(uv2.y); - uv3.x = processUVEdge(uv3.x); - uv3.y = processUVEdge(uv3.y); - - var ob = vec4(0.0); - ob += textureSampleLevel(inTex, inTexSampler, uv0, 0.0); - ob += textureSampleLevel(inTex, inTexSampler, uv1, 0.0); - ob += textureSampleLevel(inTex, inTexSampler, uv2, 0.0); - ob += textureSampleLevel(inTex, inTexSampler, uv3, 0.0); - return mix(orginColor, ob * 0.25, scale); - } - - fn processUVEdge(v: f32) -> f32{ - var value = v; - if(value < 0.0){ - value = - value; - }else if(value > 1.0){ - value = 2.0 - value; - } - return value; - } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/DepthOfView_CsShader.wgsl b/src/assets/shader/compute/DepthOfView_cs.ts similarity index 98% rename from src/assets/shader/materials/compute/DepthOfView_CsShader.wgsl rename to src/assets/shader/compute/DepthOfView_cs.ts index f8420bda..1b8dc97e 100644 --- a/src/assets/shader/materials/compute/DepthOfView_CsShader.wgsl +++ b/src/assets/shader/compute/DepthOfView_cs.ts @@ -1,3 +1,4 @@ +export let DepthOfView_cs: string = /*wgsl*/ ` #include "GlobalUniform" struct BlurSetting{ @@ -78,4 +79,5 @@ value = 2.0 - value; } return value; - } \ No newline at end of file + } +` diff --git a/src/assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl b/src/assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl deleted file mode 100644 index f765bfd8..00000000 --- a/src/assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl +++ /dev/null @@ -1,65 +0,0 @@ -struct ImageSize { - srcWidth : i32, - srcHeight : i32, - dstWidth : i32, - dstHeight : i32 -}; - -@group(0) @binding(0) var size : ImageSize; -@group(0) @binding(1) var faceRotation: array>; -@group(0) @binding(2) var inputTexSampler : sampler; -@group(0) @binding(3) var inputTex : texture_2d; - -@group(1) @binding(0) var outputBuffer0 : texture_storage_2d_array; - -fn SampleSphericalMap(v: vec3) -> vec2 { - var uv:vec2 = vec2(atan2(v.z, v.x), asin(v.y)); - //uv = (uv * (vec2(0.1590999960899353, 0.3183000087738037) + vec2(0.0010000000474974513))); - uv = uv * vec2(0.1590999960899353, 0.3183000087738037); - uv = uv + vec2(0.5); - uv = clamp(uv, vec2(0.0), vec2(1.0)); - return uv; -} - - -fn applyQuaternion(position:vec3, q:vec4) -> vec3{ - let x:f32 = position.x; - let y:f32 = position.y; - let z:f32 = position.z; - - let qx:f32 = q.x; - let qy:f32 = q.y; - let qz:f32 = q.z; - let qw:f32 = q.w; - - let ix:f32 = qw * x + qy * z - qz * y; - let iy:f32 = qw * y + qz * x - qx * z; - let iz:f32 = qw * z + qx * y - qy * x; - let iw:f32 = -qx * x - qy * y - qz * z; - - var ret: vec3; - ret.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; - ret.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; - ret.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; - - return ret; -} - -fn convertIdToDir3(uv_i32:vec2, quaternion:vec4) -> vec3{ - var uv_f32:vec2 = vec2(uv_i32.xy); - var halfSize:f32 = f32(size.dstWidth / 2); - var worldDirection:vec3 = vec3(uv_f32.x - halfSize, uv_f32.y - halfSize, -halfSize); - worldDirection = normalize(worldDirection); - worldDirection = applyQuaternion(worldDirection, quaternion); - return worldDirection; -} - -@compute @workgroup_size(8, 8, 1) -fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { - let coord = vec2(GlobalInvocationID.xy); - let quaternion = faceRotation[GlobalInvocationID.z]; - var worldDirection:vec3 = convertIdToDir3(coord, quaternion); - let uv_f32:vec2 = SampleSphericalMap(worldDirection); - let oc = textureSampleLevel(inputTex, inputTexSampler, uv_f32 , 0.0); - textureStore(outputBuffer0, coord, i32(GlobalInvocationID.z), oc); -} \ No newline at end of file diff --git a/src/assets/shader/compute/ErpImage2CubeMapCreateCube_cs.ts b/src/assets/shader/compute/ErpImage2CubeMapCreateCube_cs.ts new file mode 100644 index 00000000..9a594216 --- /dev/null +++ b/src/assets/shader/compute/ErpImage2CubeMapCreateCube_cs.ts @@ -0,0 +1,68 @@ +export let ErpImage2CubeMapCreateCube_cs: string = /*wgsl*/ ` + struct ImageSize { + srcWidth : i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32 + }; + + @group(0) @binding(0) var size : ImageSize; + @group(0) @binding(1) var faceRotation: array>; + @group(0) @binding(2) var inputTexSampler : sampler; + @group(0) @binding(3) var inputTex : texture_2d; + + @group(1) @binding(0) var outputBuffer0 : texture_storage_2d_array; + + fn SampleSphericalMap(v: vec3) -> vec2 { + var uv:vec2 = vec2(atan2(v.z, v.x), asin(v.y)); + //uv = (uv * (vec2(0.1590999960899353, 0.3183000087738037) + vec2(0.0010000000474974513))); + uv = uv * vec2(0.1590999960899353, 0.3183000087738037); + uv = uv + vec2(0.5); + uv = clamp(uv, vec2(0.0), vec2(1.0)); + return uv; + } + + + fn applyQuaternion(position:vec3, q:vec4) -> vec3{ + let x:f32 = position.x; + let y:f32 = position.y; + let z:f32 = position.z; + + let qx:f32 = q.x; + let qy:f32 = q.y; + let qz:f32 = q.z; + let qw:f32 = q.w; + + let ix:f32 = qw * x + qy * z - qz * y; + let iy:f32 = qw * y + qz * x - qx * z; + let iz:f32 = qw * z + qx * y - qy * x; + let iw:f32 = -qx * x - qy * y - qz * z; + + var ret: vec3; + ret.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + ret.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + ret.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + + return ret; + } + + fn convertIdToDir3(uv_i32:vec2, quaternion:vec4) -> vec3{ + var uv_f32:vec2 = vec2(uv_i32.xy); + var halfSize:f32 = f32(size.dstWidth / 2); + var worldDirection:vec3 = vec3(uv_f32.x - halfSize, uv_f32.y - halfSize, -halfSize); + worldDirection = normalize(worldDirection); + worldDirection = applyQuaternion(worldDirection, quaternion); + return worldDirection; + } + + @compute @workgroup_size(8, 8, 1) + fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let coord = vec2(GlobalInvocationID.xy); + let quaternion = faceRotation[GlobalInvocationID.z]; + var worldDirection:vec3 = convertIdToDir3(coord, quaternion); + let uv_f32:vec2 = SampleSphericalMap(worldDirection); + let oc = textureSampleLevel(inputTex, inputTexSampler, uv_f32 , 0.0); + textureStore(outputBuffer0, coord, i32(GlobalInvocationID.z), oc); + } +` + diff --git a/src/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl b/src/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl deleted file mode 100644 index aece1023..00000000 --- a/src/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl +++ /dev/null @@ -1,32 +0,0 @@ -struct ImageSize { - srcWidth : i32, - srcHeight : i32, - dstWidth : i32, - dstHeight : i32 -}; - -@group(0) @binding(0) var size : ImageSize; -@group(0) @binding(1) var tex_in: array>; -@group(0) @binding(2) var outputBuffer : texture_storage_2d; - -@compute @workgroup_size(8, 8, 1) -fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { - let fragCoord = vec2(i32(GlobalInvocationID.x), i32(GlobalInvocationID.y)); - var oc:vec4 = tex_in[fragCoord.y * size.srcWidth + fragCoord.x] / 256.0; - var e = pow(2.0, oc.w * 255.0 - 128.0); - oc = oc * e; - oc = scaleByThreshold(oc, 40.0); - textureStore(outputBuffer, fragCoord , vec4(oc.xyz, 1.0) ); -} - -fn scaleByThreshold(color:vec4, threshold:f32) -> vec4{ - var oc = color; - let brightness = length(vec3(oc.xyz)); - var scale = brightness / threshold; - if(scale > 1.0){ - scale = 1.0 / pow(scale, 0.7); - oc = oc * scale; - } - oc.a = 1.0; - return oc; -} \ No newline at end of file diff --git a/src/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_cs.ts b/src/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_cs.ts new file mode 100644 index 00000000..4c6f676f --- /dev/null +++ b/src/assets/shader/compute/ErpImage2CubeMapRgbe2rgba_cs.ts @@ -0,0 +1,35 @@ +export let ErpImage2CubeMapRgbe2rgba_cs: string = /*wgsl*/ ` + struct ImageSize { + srcWidth : i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32 + }; + + @group(0) @binding(0) var size : ImageSize; + @group(0) @binding(1) var tex_in: array>; + @group(0) @binding(2) var outputBuffer : texture_storage_2d; + + @compute @workgroup_size(8, 8, 1) + fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let fragCoord = vec2(i32(GlobalInvocationID.x), i32(GlobalInvocationID.y)); + var oc:vec4 = tex_in[fragCoord.y * size.srcWidth + fragCoord.x] / 256.0; + var e = pow(2.0, oc.w * 255.0 - 128.0); + oc = oc * e; + oc = scaleByThreshold(oc, 40.0); + textureStore(outputBuffer, fragCoord , vec4(oc.xyz, 1.0) ); + } + + fn scaleByThreshold(color:vec4, threshold:f32) -> vec4{ + var oc = color; + let brightness = length(vec3(oc.xyz)); + var scale = brightness / threshold; + if(scale > 1.0){ + scale = 1.0 / pow(scale, 0.7); + oc = oc * scale; + } + oc.a = 1.0; + return oc; + } +` + diff --git a/src/assets/shader/compute/GTAOCs.wgsl b/src/assets/shader/compute/GTAOCs.wgsl deleted file mode 100644 index 74210c98..00000000 --- a/src/assets/shader/compute/GTAOCs.wgsl +++ /dev/null @@ -1,133 +0,0 @@ -#include "GlobalUniform" - - struct GTAO{ - maxDistance: f32, - maxPixel: f32, - darkFactor: f32, - rayMarchSegment: f32, - cameraNear: f32, - cameraFar: f32, - viewPortWidth: f32, - viewPortHeight: f32, - multiBounce: f32, - blendColor: f32, - slot1: f32, - slot2: f32, - } - - @group(0) @binding(0) var standUniform: GlobalUniform; - @group(0) @binding(1) var gtaoData: GTAO; - @group(0) @binding(2) var directions : array>; - @group(0) @binding(3) var aoBuffer : array; - - @group(0) @binding(4) var posTex : texture_2d; - @group(0) @binding(5) var normalTex : texture_2d; - @group(0) @binding(6) var inTex : texture_2d; - @group(0) @binding(7) var outTex : texture_storage_2d; - - var texSize: vec2; - var fragCoord: vec2; - var wPosition: vec3; - var wNormal: vec4; - var maxPixelScaled: f32; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - texSize = textureDimensions(inTex).xy; - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - wNormal = textureLoad(normalTex, fragCoord, 0); - wNormal = vec4(wNormal.rgb,wNormal.w) ; - var oc = textureLoad(inTex, fragCoord, 0); - let index = fragCoord.x + fragCoord.y * i32(texSize.x); - let lastFactor = aoBuffer[index]; - var newFactor = 0.0; - if(wNormal.w < 0.5){//sky - - }else{ - wPosition = textureLoad(posTex, fragCoord, 0).xyz; - let ndc = standUniform.projMat * standUniform.viewMat * vec4(wPosition, 1.0); - let ndcZ = ndc.z / ndc.w; - maxPixelScaled = calcPixelByNDC(ndcZ); - newFactor = rayMarch(); - } - - var factor:f32 = mix(lastFactor, newFactor, 0.6); - aoBuffer[index] = factor; - factor = blurFactor(factor); - factor = 1.0 - factor * gtaoData.darkFactor; - var gtao = vec3(factor); - if(gtaoData.multiBounce > 0.5){ - gtao = MultiBounce(factor, oc.xyz); - } - - var outColor = gtao; - if(gtaoData.blendColor > 0.5){ - outColor = oc.xyz * gtao; - } - textureStore(outTex, fragCoord , vec4(outColor, oc.w)); - } - - fn MultiBounce(AO:f32, Albedo:vec3) -> vec3 - { - var A = 2 * Albedo - 0.33; - var B = -4.8 * Albedo + 0.64; - var C = 2.75 * Albedo + 0.69; - return max(vec3(AO), ((AO * A + B) * AO + C) * AO); - } - - fn calcPixelByNDC(ndcZ:f32) -> f32{ - let nearAspect = gtaoData.cameraNear / (gtaoData.cameraFar - gtaoData.cameraNear); - let aspect = (1.0 + nearAspect) / (ndcZ + nearAspect); - var viewPortMax = max(gtaoData.viewPortWidth, gtaoData.viewPortHeight); - var maxPixel = min(viewPortMax, gtaoData.maxPixel * aspect); - maxPixel = max(0.1, maxPixel); - return maxPixel; - } - - fn blurFactor(centerFactor:f32) -> f32{ - var coord0 = clamp(fragCoord + vec2(1, 0) , vec2(0), vec2(texSize - 1)); - var coord1 = clamp(fragCoord + vec2(-1, 0), vec2(0), vec2(texSize - 1)); - var coord2 = clamp(fragCoord + vec2(0, 1) , vec2(0), vec2(texSize - 1)); - var coord3 = clamp(fragCoord + vec2(0, -1), vec2(0), vec2(texSize - 1)); - var index0 = coord0.x + coord0.y * i32(texSize.x); - var index1 = coord1.x + coord1.y * i32(texSize.x); - var index2 = coord2.x + coord2.y * i32(texSize.x); - var index3 = coord3.x + coord3.y * i32(texSize.x); - let factor0:f32 = aoBuffer[index0]; - let factor1:f32 = aoBuffer[index1]; - let factor2:f32 = aoBuffer[index2]; - let factor3:f32 = aoBuffer[index3]; - var factor = 0.25 * (factor0 + factor1 + factor2 + factor3); - factor = mix(factor, centerFactor, 0.8); - return factor; - } - - fn rayMarch() -> f32{ - let originNormal = normalize(vec3(wNormal.xyz) * 2.0 - 1.0); - let stepPixel = maxPixelScaled / gtaoData.rayMarchSegment; - var totalWeight:f32 = 0.001; - var darkWeight:f32 = 0.0; - for(var i:i32 = 0; i < 8; i += 1){ - let dirVec2 = directions[i]; - for(var j:f32 = 1.1; j < maxPixelScaled; j += stepPixel){ - var sampleCoord = vec2(dirVec2 * j) + fragCoord; - sampleCoord = clamp(sampleCoord, vec2(0), vec2(texSize - 1)); - let samplePosition = textureLoad(posTex, sampleCoord, 0).xyz; - let distanceVec2 = samplePosition - wPosition; - let distance = length(distanceVec2); - if(distance < gtaoData.maxDistance){ - let sampleDir = normalize(distanceVec2); - var factor = max(0.0, dot(sampleDir, originNormal) - 0.1); - factor *= 1.0 - distance / gtaoData.maxDistance; - darkWeight += factor; - totalWeight += 1.0; - } - } - } - - return darkWeight/totalWeight ; - } \ No newline at end of file diff --git a/src/assets/shader/compute/GTAO_cs.ts b/src/assets/shader/compute/GTAO_cs.ts new file mode 100644 index 00000000..e2cbf5ee --- /dev/null +++ b/src/assets/shader/compute/GTAO_cs.ts @@ -0,0 +1,135 @@ +export let GTAO_cs: string = /*wgsl*/ ` + #include "GlobalUniform" + + struct GTAO{ + maxDistance: f32, + maxPixel: f32, + darkFactor: f32, + rayMarchSegment: f32, + cameraNear: f32, + cameraFar: f32, + viewPortWidth: f32, + viewPortHeight: f32, + multiBounce: f32, + blendColor: f32, + slot1: f32, + slot2: f32, + } + + @group(0) @binding(0) var standUniform: GlobalUniform; + @group(0) @binding(1) var gtaoData: GTAO; + @group(0) @binding(2) var directions : array>; + @group(0) @binding(3) var aoBuffer : array; + + @group(0) @binding(4) var posTex : texture_2d; + @group(0) @binding(5) var normalTex : texture_2d; + @group(0) @binding(6) var inTex : texture_2d; + @group(0) @binding(7) var outTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + var wPosition: vec3; + var wNormal: vec4; + var maxPixelScaled: f32; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(inTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + wNormal = textureLoad(normalTex, fragCoord, 0); + wNormal = vec4(wNormal.rgb,wNormal.w) ; + var oc = textureLoad(inTex, fragCoord, 0); + let index = fragCoord.x + fragCoord.y * i32(texSize.x); + let lastFactor = aoBuffer[index]; + var newFactor = 0.0; + if(wNormal.w < 0.5){//sky + + }else{ + wPosition = textureLoad(posTex, fragCoord, 0).xyz; + let ndc = standUniform.projMat * standUniform.viewMat * vec4(wPosition, 1.0); + let ndcZ = ndc.z / ndc.w; + maxPixelScaled = calcPixelByNDC(ndcZ); + newFactor = rayMarch(); + } + + var factor:f32 = mix(lastFactor, newFactor, 0.6); + aoBuffer[index] = factor; + factor = blurFactor(factor); + factor = 1.0 - factor * gtaoData.darkFactor; + var gtao = vec3(factor); + if(gtaoData.multiBounce > 0.5){ + gtao = MultiBounce(factor, oc.xyz); + } + + var outColor = gtao; + if(gtaoData.blendColor > 0.5){ + outColor = oc.xyz * gtao; + } + textureStore(outTex, fragCoord , vec4(outColor, oc.w)); + } + + fn MultiBounce(AO:f32, Albedo:vec3) -> vec3 + { + var A = 2 * Albedo - 0.33; + var B = -4.8 * Albedo + 0.64; + var C = 2.75 * Albedo + 0.69; + return max(vec3(AO), ((AO * A + B) * AO + C) * AO); + } + + fn calcPixelByNDC(ndcZ:f32) -> f32{ + let nearAspect = gtaoData.cameraNear / (gtaoData.cameraFar - gtaoData.cameraNear); + let aspect = (1.0 + nearAspect) / (ndcZ + nearAspect); + var viewPortMax = max(gtaoData.viewPortWidth, gtaoData.viewPortHeight); + var maxPixel = min(viewPortMax, gtaoData.maxPixel * aspect); + maxPixel = max(0.1, maxPixel); + return maxPixel; + } + + fn blurFactor(centerFactor:f32) -> f32{ + var coord0 = clamp(fragCoord + vec2(1, 0) , vec2(0), vec2(texSize - 1)); + var coord1 = clamp(fragCoord + vec2(-1, 0), vec2(0), vec2(texSize - 1)); + var coord2 = clamp(fragCoord + vec2(0, 1) , vec2(0), vec2(texSize - 1)); + var coord3 = clamp(fragCoord + vec2(0, -1), vec2(0), vec2(texSize - 1)); + var index0 = coord0.x + coord0.y * i32(texSize.x); + var index1 = coord1.x + coord1.y * i32(texSize.x); + var index2 = coord2.x + coord2.y * i32(texSize.x); + var index3 = coord3.x + coord3.y * i32(texSize.x); + let factor0:f32 = aoBuffer[index0]; + let factor1:f32 = aoBuffer[index1]; + let factor2:f32 = aoBuffer[index2]; + let factor3:f32 = aoBuffer[index3]; + var factor = 0.25 * (factor0 + factor1 + factor2 + factor3); + factor = mix(factor, centerFactor, 0.8); + return factor; + } + + fn rayMarch() -> f32{ + let originNormal = normalize(vec3(wNormal.xyz) * 2.0 - 1.0); + let stepPixel = maxPixelScaled / gtaoData.rayMarchSegment; + var totalWeight:f32 = 0.001; + var darkWeight:f32 = 0.0; + for(var i:i32 = 0; i < 8; i += 1){ + let dirVec2 = directions[i]; + for(var j:f32 = 1.1; j < maxPixelScaled; j += stepPixel){ + var sampleCoord = vec2(dirVec2 * j) + fragCoord; + sampleCoord = clamp(sampleCoord, vec2(0), vec2(texSize - 1)); + let samplePosition = textureLoad(posTex, sampleCoord, 0).xyz; + let distanceVec2 = samplePosition - wPosition; + let distance = length(distanceVec2); + if(distance < gtaoData.maxDistance){ + let sampleDir = normalize(distanceVec2); + var factor = max(0.0, dot(sampleDir, originNormal) - 0.1); + factor *= 1.0 - distance / gtaoData.maxDistance; + darkWeight += factor; + totalWeight += 1.0; + } + } + } + + return darkWeight/totalWeight ; + } + ` \ No newline at end of file diff --git a/src/assets/shader/compute/IBLEnvMapCreator_compute.wgsl b/src/assets/shader/compute/IBLEnvMapCreator_compute.wgsl deleted file mode 100644 index 4ab1a1ef..00000000 --- a/src/assets/shader/compute/IBLEnvMapCreator_compute.wgsl +++ /dev/null @@ -1,174 +0,0 @@ -struct ImageSize { - srcWidth : i32, - srcHeight : i32, - dstWidth : i32, - dstHeight : i32 -}; - -@group(0) @binding(0) var size : ImageSize; -@group(0) @binding(1) var faceRotation: array>; -@group(0) @binding(2) var inputTexSampler : sampler; -@group(0) @binding(3) var inputTex : texture_2d; - -@group(1) @binding(0) var blurSetting : vec4; -@group(1) @binding(1) var outputBuffer0 : texture_storage_2d_array; - -var PI: f32 = 3.14159265359; - -fn applyQuaternion(position:vec3, q:vec4) -> vec3{ - let x:f32 = position.x; - let y:f32 = position.y; - let z:f32 = position.z; - - let qx:f32 = q.x; - let qy:f32 = q.y; - let qz:f32 = q.z; - let qw:f32 = q.w; - - let ix:f32 = qw * x + qy * z - qz * y; - let iy:f32 = qw * y + qz * x - qx * z; - let iz:f32 = qw * z + qx * y - qy * x; - let iw:f32 = -qx * x - qy * y - qz * z; - - var ret: vec3; - ret.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; - ret.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; - ret.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; - - return ret; -} - -fn convertIdToDir3(uv_i32:vec2, quaternion:vec4) -> vec3{ - var uv_f32:vec2 = vec2(uv_i32.xy); - var halfSize:f32 = f32(size.dstWidth / 2); - var worldDirection:vec3 = vec3(uv_f32.x - halfSize, uv_f32.y - halfSize, -halfSize); - worldDirection = normalize(worldDirection); - worldDirection = applyQuaternion(worldDirection, quaternion); - return worldDirection; -} - -fn VanDerCorpus(n0:u32, base0:u32) -> f32 -{ - var n = n0; - var base = base0; - var invBase:f32 = 1.0 / f32(base); - var denom:f32 = 1.0; - var result:f32 = 0.0; - - for(var i:u32 = 0u; i < 32u; i = i + 1u) - { - if(n > 0u) - { - denom = f32(n) % 2.0; - result = result + denom * invBase; - invBase = invBase / 2.0; - n = u32(f32(n) / 2.0); - } - } - - return result; -} - -fn HammersleyNoBitOps(i:u32, N:u32) -> vec2 -{ - return vec2(f32(i)/f32(N), VanDerCorpus(i, 2u)); -} - -fn hammersley( i : u32 , N : u32 ) -> vec2 -{ - // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html - var bits = (i << 16u) | (i >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - var rdi = f32(bits) * 2.3283064365386963e-10; - return vec2(f32(i) /f32(N), rdi); -} - -fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 -{ - var a = roughness*roughness; - - var phi = 2.0 * PI * Xi.x; - var cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); - var sinTheta = sqrt(1.0 - cosTheta*cosTheta); - - // from spherical coordinates to cartesian coordinates - var H:vec3; - H.x = cos(phi) * sinTheta; - H.y = sin(phi) * sinTheta; - H.z = cosTheta; - - // from tangent-space vector to world-space sample vector - var up:vec3; - if(abs(N.z) < 0.999) - { - up = vec3(0.0, 0.0, 1.0); - } - else - { - up = vec3(1.0, 0.0, 0.0); - } - var tangent:vec3 = normalize(cross(up, N)); - var bitangent:vec3 = cross(N, tangent); - var sampleVec:vec3 = tangent * H.x + bitangent * H.y + N * H.z; - return normalize(sampleVec); -} - -fn multiSample(localPos:vec3, roughness:f32) -> vec4 -{ - var N: vec3 = normalize(localPos); - var R: vec3 = N; - var V: vec3 = R; - - let SAMPLE_COUNT:u32 = 1024u; - var totalWeight:f32 = 0.0; - var prefilteredColor:vec3 = vec3(0.0, 0.0, 0.0); - for(var i:u32 = 0u; i < SAMPLE_COUNT; i = i + 1u) - { - var Xi:vec2 = hammersley(i, SAMPLE_COUNT); - var H :vec3 = ImportanceSampleGGX(Xi, N, roughness); - var L :vec3 = normalize(2.0 * dot(V, H) * H - V); - - var NdotL:f32 = max(dot(N, L), 0.0); - if(NdotL > 0.0) - { - var att = 1.0 ;//( f32(SAMPLE_COUNT - i) / f32(SAMPLE_COUNT)) ; - - prefilteredColor = prefilteredColor + sampleColor(L).rgb * NdotL; - prefilteredColor = prefilteredColor * att ; - totalWeight = totalWeight + NdotL; - } - } - prefilteredColor = prefilteredColor / totalWeight; - - return vec4(prefilteredColor, 1.0); -} - -fn SampleSphericalMap(v: vec3) -> vec2 { - var uv:vec2 = vec2(atan2(v.z, v.x), asin(v.y)); - //uv = (uv * (vec2(0.1590999960899353, 0.3183000087738037) + vec2(0.0010000000474974513))); - uv = uv * vec2(0.1590999960899353, 0.3183000087738037); - uv = uv + vec2(0.5); - uv = clamp(uv, vec2(0.0), vec2(1.0)); - return uv; -} - -fn sampleColor(d:vec3) -> vec4 -{ - let uv_f32:vec2 = SampleSphericalMap(d); - let oc = textureSampleLevel(inputTex, inputTexSampler, uv_f32 , 0.0); - //let dir = vec3(-d.x, -d.y, d.z); - //var oc:vec4 = textureSampleLevel(cubeMap, cubeMapSampler, dir, 0.0); - return oc; -} - -@compute @workgroup_size(8, 8, 1) -fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { - let coord = vec2(GlobalInvocationID.xy); - let quaternion = faceRotation[GlobalInvocationID.z]; - var worldDirection:vec3 = convertIdToDir3(coord, quaternion); - var oc:vec4 = multiSample(worldDirection, blurSetting.x); - textureStore(outputBuffer0, coord, i32(GlobalInvocationID.z), oc); -} diff --git a/src/assets/shader/compute/IBLEnvMapCreator_cs.ts b/src/assets/shader/compute/IBLEnvMapCreator_cs.ts new file mode 100644 index 00000000..1727f4fd --- /dev/null +++ b/src/assets/shader/compute/IBLEnvMapCreator_cs.ts @@ -0,0 +1,178 @@ +export let IBLEnvMapCreator_cs: string = /*wgsl*/ ` + struct ImageSize { + srcWidth : i32, + srcHeight : i32, + dstWidth : i32, + dstHeight : i32 + }; + + @group(0) @binding(0) var size : ImageSize; + @group(0) @binding(1) var faceRotation: array>; + @group(0) @binding(2) var inputTexSampler : sampler; + @group(0) @binding(3) var inputTex : texture_2d; + + @group(1) @binding(0) var blurSetting : vec4; + @group(1) @binding(1) var outputBuffer0 : texture_storage_2d_array; + + var PI: f32 = 3.14159265359; + + fn applyQuaternion(position:vec3, q:vec4) -> vec3{ + let x:f32 = position.x; + let y:f32 = position.y; + let z:f32 = position.z; + + let qx:f32 = q.x; + let qy:f32 = q.y; + let qz:f32 = q.z; + let qw:f32 = q.w; + + let ix:f32 = qw * x + qy * z - qz * y; + let iy:f32 = qw * y + qz * x - qx * z; + let iz:f32 = qw * z + qx * y - qy * x; + let iw:f32 = -qx * x - qy * y - qz * z; + + var ret: vec3; + ret.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + ret.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + ret.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + + return ret; + } + + fn convertIdToDir3(uv_i32:vec2, quaternion:vec4) -> vec3{ + var uv_f32:vec2 = vec2(uv_i32.xy); + var halfSize:f32 = f32(size.dstWidth / 2); + var worldDirection:vec3 = vec3(uv_f32.x - halfSize, uv_f32.y - halfSize, -halfSize); + worldDirection = normalize(worldDirection); + worldDirection = applyQuaternion(worldDirection, quaternion); + return worldDirection; + } + + fn VanDerCorpus(n0:u32, base0:u32) -> f32 + { + var n = n0; + var base = base0; + var invBase:f32 = 1.0 / f32(base); + var denom:f32 = 1.0; + var result:f32 = 0.0; + + for(var i:u32 = 0u; i < 32u; i = i + 1u) + { + if(n > 0u) + { + denom = f32(n) % 2.0; + result = result + denom * invBase; + invBase = invBase / 2.0; + n = u32(f32(n) / 2.0); + } + } + + return result; + } + + fn HammersleyNoBitOps(i:u32, N:u32) -> vec2 + { + return vec2(f32(i)/f32(N), VanDerCorpus(i, 2u)); + } + + fn hammersley( i : u32 , N : u32 ) -> vec2 + { + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + var bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + var rdi = f32(bits) * 2.3283064365386963e-10; + return vec2(f32(i) /f32(N), rdi); + } + + fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 + { + var a = roughness*roughness; + + var phi = 2.0 * PI * Xi.x; + var cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); + var sinTheta = sqrt(1.0 - cosTheta*cosTheta); + + // from spherical coordinates to cartesian coordinates + var H:vec3; + H.x = cos(phi) * sinTheta; + H.y = sin(phi) * sinTheta; + H.z = cosTheta; + + // from tangent-space vector to world-space sample vector + var up:vec3; + if(abs(N.z) < 0.999) + { + up = vec3(0.0, 0.0, 1.0); + } + else + { + up = vec3(1.0, 0.0, 0.0); + } + var tangent:vec3 = normalize(cross(up, N)); + var bitangent:vec3 = cross(N, tangent); + var sampleVec:vec3 = tangent * H.x + bitangent * H.y + N * H.z; + return normalize(sampleVec); + } + + fn multiSample(localPos:vec3, roughness:f32) -> vec4 + { + var N: vec3 = normalize(localPos); + var R: vec3 = N; + var V: vec3 = R; + + let SAMPLE_COUNT:u32 = 1024u; + var totalWeight:f32 = 0.0; + var prefilteredColor:vec3 = vec3(0.0, 0.0, 0.0); + for(var i:u32 = 0u; i < SAMPLE_COUNT; i = i + 1u) + { + var Xi:vec2 = hammersley(i, SAMPLE_COUNT); + var H :vec3 = ImportanceSampleGGX(Xi, N, roughness); + var L :vec3 = normalize(2.0 * dot(V, H) * H - V); + + var NdotL:f32 = max(dot(N, L), 0.0); + if(NdotL > 0.0) + { + var att = 1.0 ;//( f32(SAMPLE_COUNT - i) / f32(SAMPLE_COUNT)) ; + + prefilteredColor = prefilteredColor + sampleColor(L).rgb * NdotL; + prefilteredColor = prefilteredColor * att ; + totalWeight = totalWeight + NdotL; + } + } + prefilteredColor = prefilteredColor / totalWeight; + + return vec4(prefilteredColor, 1.0); + } + + fn SampleSphericalMap(v: vec3) -> vec2 { + var uv:vec2 = vec2(atan2(v.z, v.x), asin(v.y)); + //uv = (uv * (vec2(0.1590999960899353, 0.3183000087738037) + vec2(0.0010000000474974513))); + uv = uv * vec2(0.1590999960899353, 0.3183000087738037); + uv = uv + vec2(0.5); + uv = clamp(uv, vec2(0.0), vec2(1.0)); + return uv; + } + + fn sampleColor(d:vec3) -> vec4 + { + let uv_f32:vec2 = SampleSphericalMap(d); + let oc = textureSampleLevel(inputTex, inputTexSampler, uv_f32 , 0.0); + //let dir = vec3(-d.x, -d.y, d.z); + //var oc:vec4 = textureSampleLevel(cubeMap, cubeMapSampler, dir, 0.0); + return oc; + } + + @compute @workgroup_size(8, 8, 1) + fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let coord = vec2(GlobalInvocationID.xy); + let quaternion = faceRotation[GlobalInvocationID.z]; + var worldDirection:vec3 = convertIdToDir3(coord, quaternion); + var oc:vec4 = multiSample(worldDirection, blurSetting.x); + textureStore(outputBuffer0, coord, i32(GlobalInvocationID.z), oc); + } + +` + diff --git a/src/assets/shader/compute/MergeRGBA_Cs.wgsl b/src/assets/shader/compute/MergeRGBA_Cs.wgsl deleted file mode 100644 index c4ad1034..00000000 --- a/src/assets/shader/compute/MergeRGBA_Cs.wgsl +++ /dev/null @@ -1,29 +0,0 @@ - -@group(0) @binding(0) var textureR : texture_2d; -@group(0) @binding(1) var textureG : texture_2d; -@group(0) @binding(2) var textureB : texture_2d; -@group(0) @binding(3) var textureA : texture_2d; -@group(0) @binding(4) var outTex : texture_storage_2d; - -@compute @workgroup_size(8, 8, 1) -fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { - let size = textureDimensions(outTex); - let fragCoord : vec2 = vec2(GlobalInvocationID.xy); - var uv:vec2; - uv.x = f32(fragCoord.x)/f32(size.x); - uv.y = f32(fragCoord.y)/f32(size.y); - var oc:vec4 = textureSampleLevel(atlasTexture, atlasTextureSampler, targetUV, 0.0); - - let sizeR = textureDimensions(textureR); - let sizeG = textureDimensions(textureG); - let sizeB = textureDimensions(textureB); - let sizeA = textureDimensions(textureA); - - var tr = textureLoad(textureR, vec2(uv * sizeR) , 0 ) ; - var tg = textureLoad(textureG, vec2(uv * sizeG) , 0 ) ; - var tb = textureLoad(textureB, vec2(uv * sizeB) , 0 ) ; - var ta = textureLoad(textureA, vec2(uv * sizeA) , 0 ) ; - - let color = vec4(tr,tg,tb,ta); - textureStore(outTex, fragCoord , vec4(color)); -} diff --git a/src/assets/shader/compute/MergeRGBA_cs.ts b/src/assets/shader/compute/MergeRGBA_cs.ts new file mode 100644 index 00000000..023389af --- /dev/null +++ b/src/assets/shader/compute/MergeRGBA_cs.ts @@ -0,0 +1,31 @@ +export let MergeRGBA_cs: string = /*wgsl*/ ` + @group(0) @binding(0) var textureR : texture_2d; + @group(0) @binding(1) var textureG : texture_2d; + @group(0) @binding(2) var textureB : texture_2d; + @group(0) @binding(3) var textureA : texture_2d; + @group(0) @binding(4) var outTex : texture_storage_2d; + + @compute @workgroup_size(8, 8, 1) + fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { + let size = textureDimensions(outTex); + let fragCoord : vec2 = vec2(GlobalInvocationID.xy); + var uv:vec2; + uv.x = f32(fragCoord.x)/f32(size.x); + uv.y = f32(fragCoord.y)/f32(size.y); + var oc:vec4 = textureSampleLevel(atlasTexture, atlasTextureSampler, targetUV, 0.0); + + let sizeR = textureDimensions(textureR); + let sizeG = textureDimensions(textureG); + let sizeB = textureDimensions(textureB); + let sizeA = textureDimensions(textureA); + + var tr = textureLoad(textureR, vec2(uv * sizeR) , 0 ) ; + var tg = textureLoad(textureG, vec2(uv * sizeG) , 0 ) ; + var tb = textureLoad(textureB, vec2(uv * sizeB) , 0 ) ; + var ta = textureLoad(textureA, vec2(uv * sizeA) , 0 ) ; + + let color = vec4(tr,tg,tb,ta); + textureStore(outTex, fragCoord , vec4(color)); + } + +` diff --git a/src/assets/shader/compute/MultiBouncePass_Shader.wgsl b/src/assets/shader/compute/MultiBouncePass_Shader.wgsl deleted file mode 100644 index a5eb8983..00000000 --- a/src/assets/shader/compute/MultiBouncePass_Shader.wgsl +++ /dev/null @@ -1,185 +0,0 @@ - - #include "MathShader" - #include "IrradianceVolumeData_frag" - - -struct IrradianceField { - probeStartPosition: vec4, - probeCounts:vec4, - probeStep:f32, - irradianceTextureWidth:f32, - irradianceTextureHeight:f32, - irradianceProbeSideLength:f32, -}; - - @group(0) @binding(0) var outputBuffer : texture_storage_2d; - @group(0) @binding(1) var uniformData : IrradianceVolumeData ; - - @group(1) @binding(0) var normalMapSampler : sampler; - @group(1) @binding(1) var normalMap : texture_2d; - - @group(1) @binding(2) var colorMapSampler : sampler; - @group(1) @binding(3) var colorMap : texture_2d; - - @group(1) @binding(4) var litMapSampler : sampler; - @group(1) @binding(5) var litMap : texture_2d; - - @group(1) @binding(6) var irradianceMapSampler : sampler; - @group(1) @binding(7) var irradianceMap : texture_2d; - - var wsn:vec3; - var ulitColor:vec4; - var litColor:vec4; - var irradianceFieldSurface : IrradianceField ; - var probeID:u32; - - var quaternion:vec4 = vec4(0.0, -0.7071067811865475, 0.7071067811865475, 0.0); - -fn getIrradianceFieldSurface() -> IrradianceField{ - let data = uniformData; - irradianceFieldSurface.probeStartPosition = vec4(data.startX, data.startY, data.startZ, 0.0); - irradianceFieldSurface.probeCounts = vec4(data.gridXCount, data.gridYCount, data.gridZCount, 0.0); - irradianceFieldSurface.probeStep = data.ProbeSpace; - irradianceFieldSurface.irradianceTextureWidth = data.OctRTMaxSize; - irradianceFieldSurface.irradianceTextureHeight = data.OctRTMaxSize; - irradianceFieldSurface.irradianceProbeSideLength = data.OctRTSideSize; - return irradianceFieldSurface; -} - - fn rotateDir(n:vec3) -> vec3{ - return normalize(applyQuaternion(-n, quaternion)); - } - - fn sampleLitColor(uv:vec2) -> vec4 - { - var oc1:vec4 = textureSampleLevel(litMap, litMapSampler, vec2(0.0), 0.0); - var oc:vec4 = textureLoad(litMap, uv, 0); - return oc; - } - - fn sampleNormal(uv:vec2) -> vec4 - { - var oc1:vec4 = textureSampleLevel(normalMap, normalMapSampler, vec2(0.0), 0.0); - var oc:vec4 = textureLoad(normalMap, uv, 0); - return oc; - } - - fn sampleColor(uv:vec2) -> vec4 - { - var oc1:vec4 = textureSampleLevel(colorMap, colorMapSampler, vec2(0.0), 0.0); - var oc:vec4 = textureLoad(colorMap, uv, 0); - return oc; - } - - fn sampleProbe(fragCoord:vec2){ - var uv = vec2(i32(fragCoord.x), i32(fragCoord.y)) ; - - litColor = sampleLitColor(uv); - - var normalMap = sampleNormal(uv); - wsn = normalMap.xyz * 2.0 - 1.0; - - ulitColor = sampleColor(uv); - } - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain(@builtin(global_invocation_id) globalInvocation_id : vec3) - { - getIrradianceFieldSurface(); - var fragCoord = vec2( globalInvocation_id.x, globalInvocation_id.y); - probeID = globalInvocation_id.z; - fragCoord = fragCoord + getCoordOffset(probeID); - - sampleProbe(fragCoord); - - let irradiance = getIrradianceColor(); - let result = blendIrradianceColor(irradiance); - textureStore(outputBuffer, vec2(fragCoord), result); - } - - fn blendIrradianceColor(irradiance:vec4) -> vec4{ - var bounceColor = irradiance * ulitColor; - let bounceIntensity = getBounceIntensity(uniformData.bounceIntensity); - let conservation1 = 1.0 / sqrt((1.0 + bounceIntensity * 0.55)); - let conservation2 = 1.0 / sqrt((1.0 + bounceIntensity)); - var result = litColor * conservation2 + bounceColor * sqrt(bounceIntensity) * conservation1; - return vec4(result.xyz, litColor.w); - } - - fn getBounceIntensity(intensity:f32) -> f32 { - var value = clamp(intensity, 0.0, 1.0) * 10.0; - return value; - } - - fn getCoordOffset(id:u32) -> vec2{ - var fullCol = u32(uniformData.ProbeSourceTextureSize / uniformData.ProbeSize); - var offsetSampleUv = vec2( (id / fullCol) * 6u , id % fullCol) * u32(uniformData.ProbeSize); - return offsetSampleUv; - } - - fn getIrradianceColor() -> vec4{ - var probeIrradiance: vec4 = vec4(0.0); - if(length(wsn) > 0.01){ - probeIrradiance = getIrrdiaceIndex(i32(probeID), wsn); - } - return probeIrradiance; - } - - fn getIrrdiaceIndex(index:i32, wsn:vec3) -> vec4{ - var wsN = rotateDir(wsn.xyz); - var texCoord:vec2 = textureCoordFromDirection(wsN, - index, - irradianceFieldSurface.irradianceTextureWidth, - irradianceFieldSurface.irradianceTextureHeight, - irradianceFieldSurface.irradianceProbeSideLength); - - var probeIrradiance: vec3 = textureSampleLevel(irradianceMap, irradianceMapSampler, texCoord, 0.0).xyz; - return vec4(probeIrradiance, 1.0); - } - - fn textureCoordFromDirection(dir:vec3, probeIndex:i32, width:f32, height:f32, sideLength:f32) -> vec2 - { - var uv = getWriteOctUVByID(dir, u32(probeIndex), sideLength) ; - uv.x = uv.x / irradianceFieldSurface.irradianceTextureWidth; - uv.y = uv.y / irradianceFieldSurface.irradianceTextureHeight; - return uv ; - } - - fn getWriteOctUVByID(dir:vec3 , probeID:u32, size: f32) -> vec2 - { - var blockCount = u32(irradianceFieldSurface.probeCounts.x * irradianceFieldSurface.probeCounts.z) ; - var offsetX = (probeID % blockCount) % u32(irradianceFieldSurface.probeCounts.x) ; - var offsetY = u32(irradianceFieldSurface.probeCounts.z - 1.0) - (probeID % blockCount) / u32(irradianceFieldSurface.probeCounts.x) ; - var offsetZ = probeID / blockCount ; - - var pixelCoord = (( octEncode(dir) + 1.0 ) * 0.5) * vec2(size,size) ; - - var blockOffset = vec2(0.0); - blockOffset.x = f32(offsetX) * size; - blockOffset.y = f32(offsetY) * size + f32(offsetZ) * f32(irradianceFieldSurface.probeCounts.z) * size; - - let mapHeight = u32(irradianceFieldSurface.irradianceTextureHeight); - var probeCounts:vec3 = vec3(irradianceFieldSurface.probeCounts.xyz); - - var gridOffsetFrom = vec2(blockOffset) + 1; - var gridOffsetTo = offsetByCol(gridOffsetFrom, size, mapHeight, probeCounts); - - pixelCoord = pixelCoord + vec2(gridOffsetTo - 1) + vec2(vec2(vec2(gridOffsetTo) / size) * 2); - - return pixelCoord + 1.0 ; - } - - fn offsetByCol(pixelCoord0:vec2, octSideSize:f32, mapHeight:u32, counts:vec3) -> vec2 - { - var pixelCoord = pixelCoord0; - let blockSize:vec2 = vec2(i32(octSideSize * counts.x), i32(octSideSize * counts.z)); - let blockSizeYBorder:i32 = i32((octSideSize + 2.0) * counts.z); - let blockMaxRowBorder:i32 = i32(mapHeight) / blockSizeYBorder; - let pixelCountYMax:i32 = blockMaxRowBorder * i32(octSideSize * counts.z); - let col:i32 = pixelCoord.y / pixelCountYMax; - - pixelCoord.x = col * i32(octSideSize * counts.x) + pixelCoord.x; - pixelCoord.y = pixelCoord.y % pixelCountYMax; - - return pixelCoord; - } diff --git a/src/assets/shader/compute/MultiBouncePass_cs.ts b/src/assets/shader/compute/MultiBouncePass_cs.ts new file mode 100644 index 00000000..826a86df --- /dev/null +++ b/src/assets/shader/compute/MultiBouncePass_cs.ts @@ -0,0 +1,186 @@ + +export let MultiBouncePass_cs: string = /*wgsl*/ ` + #include "MathShader" + #include "IrradianceVolumeData_frag" + + struct IrradianceField { + probeStartPosition: vec4, + probeCounts:vec4, + probeStep:f32, + irradianceTextureWidth:f32, + irradianceTextureHeight:f32, + irradianceProbeSideLength:f32, + }; + + @group(0) @binding(0) var outputBuffer : texture_storage_2d; + @group(0) @binding(1) var uniformData : IrradianceVolumeData ; + + @group(1) @binding(0) var normalMapSampler : sampler; + @group(1) @binding(1) var normalMap : texture_2d; + + @group(1) @binding(2) var colorMapSampler : sampler; + @group(1) @binding(3) var colorMap : texture_2d; + + @group(1) @binding(4) var litMapSampler : sampler; + @group(1) @binding(5) var litMap : texture_2d; + + @group(1) @binding(6) var irradianceMapSampler : sampler; + @group(1) @binding(7) var irradianceMap : texture_2d; + + var wsn:vec3; + var ulitColor:vec4; + var litColor:vec4; + var irradianceFieldSurface : IrradianceField ; + var probeID:u32; + + var quaternion:vec4 = vec4(0.0, -0.7071067811865475, 0.7071067811865475, 0.0); + + fn getIrradianceFieldSurface() -> IrradianceField{ + let data = uniformData; + irradianceFieldSurface.probeStartPosition = vec4(data.startX, data.startY, data.startZ, 0.0); + irradianceFieldSurface.probeCounts = vec4(data.gridXCount, data.gridYCount, data.gridZCount, 0.0); + irradianceFieldSurface.probeStep = data.ProbeSpace; + irradianceFieldSurface.irradianceTextureWidth = data.OctRTMaxSize; + irradianceFieldSurface.irradianceTextureHeight = data.OctRTMaxSize; + irradianceFieldSurface.irradianceProbeSideLength = data.OctRTSideSize; + return irradianceFieldSurface; + } + + fn rotateDir(n:vec3) -> vec3{ + return normalize(applyQuaternion(-n, quaternion)); + } + + fn sampleLitColor(uv:vec2) -> vec4 + { + var oc1:vec4 = textureSampleLevel(litMap, litMapSampler, vec2(0.0), 0.0); + var oc:vec4 = textureLoad(litMap, uv, 0); + return oc; + } + + fn sampleNormal(uv:vec2) -> vec4 + { + var oc1:vec4 = textureSampleLevel(normalMap, normalMapSampler, vec2(0.0), 0.0); + var oc:vec4 = textureLoad(normalMap, uv, 0); + return oc; + } + + fn sampleColor(uv:vec2) -> vec4 + { + var oc1:vec4 = textureSampleLevel(colorMap, colorMapSampler, vec2(0.0), 0.0); + var oc:vec4 = textureLoad(colorMap, uv, 0); + return oc; + } + + fn sampleProbe(fragCoord:vec2){ + var uv = vec2(i32(fragCoord.x), i32(fragCoord.y)) ; + + litColor = sampleLitColor(uv); + + var normalMap = sampleNormal(uv); + wsn = normalMap.xyz * 2.0 - 1.0; + + ulitColor = sampleColor(uv); + } + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain(@builtin(global_invocation_id) globalInvocation_id : vec3) + { + getIrradianceFieldSurface(); + var fragCoord = vec2( globalInvocation_id.x, globalInvocation_id.y); + probeID = globalInvocation_id.z; + fragCoord = fragCoord + getCoordOffset(probeID); + + sampleProbe(fragCoord); + + let irradiance = getIrradianceColor(); + let result = blendIrradianceColor(irradiance); + textureStore(outputBuffer, vec2(fragCoord), result); + } + + fn blendIrradianceColor(irradiance:vec4) -> vec4{ + var bounceColor = irradiance * ulitColor; + let bounceIntensity = getBounceIntensity(uniformData.bounceIntensity); + let conservation1 = 1.0 / sqrt((1.0 + bounceIntensity * 0.55)); + let conservation2 = 1.0 / sqrt((1.0 + bounceIntensity)); + var result = litColor * conservation2 + bounceColor * sqrt(bounceIntensity) * conservation1; + return vec4(result.xyz, litColor.w); + } + + fn getBounceIntensity(intensity:f32) -> f32 { + var value = clamp(intensity, 0.0, 1.0) * 10.0; + return value; + } + + fn getCoordOffset(id:u32) -> vec2{ + var fullCol = u32(uniformData.ProbeSourceTextureSize / uniformData.ProbeSize); + var offsetSampleUv = vec2( (id / fullCol) * 6u , id % fullCol) * u32(uniformData.ProbeSize); + return offsetSampleUv; + } + + fn getIrradianceColor() -> vec4{ + var probeIrradiance: vec4 = vec4(0.0); + if(length(wsn) > 0.01){ + probeIrradiance = getIrrdiaceIndex(i32(probeID), wsn); + } + return probeIrradiance; + } + + n getIrrdiaceIndex(index:i32, wsn:vec3) -> vec4{ + var wsN = rotateDir(wsn.xyz); + var texCoord:vec2 = textureCoordFromDirection(wsN, + index, + irradianceFieldSurface.irradianceTextureWidth, + irradianceFieldSurface.irradianceTextureHeight, + irradianceFieldSurface.irradianceProbeSideLength); + + var probeIrradiance: vec3 = textureSampleLevel(irradianceMap, irradianceMapSampler, texCoord, 0.0).xyz; + return vec4(probeIrradiance, 1.0); + } + + fn textureCoordFromDirection(dir:vec3, probeIndex:i32, width:f32, height:f32, sideLength:f32) -> vec2 + { + var uv = getWriteOctUVByID(dir, u32(probeIndex), sideLength) ; + uv.x = uv.x / irradianceFieldSurface.irradianceTextureWidth; + uv.y = uv.y / irradianceFieldSurface.irradianceTextureHeight; + return uv ; + } + + fn getWriteOctUVByID(dir:vec3 , probeID:u32, size: f32) -> vec2 + { + var blockCount = u32(irradianceFieldSurface.probeCounts.x * irradianceFieldSurface.probeCounts.z) ; + var offsetX = (probeID % blockCount) % u32(irradianceFieldSurface.probeCounts.x) ; + var offsetY = u32(irradianceFieldSurface.probeCounts.z - 1.0) - (probeID % blockCount) / u32(irradianceFieldSurface.probeCounts.x) ; + var offsetZ = probeID / blockCount ; + + var pixelCoord = (( octEncode(dir) + 1.0 ) * 0.5) * vec2(size,size) ; + + var blockOffset = vec2(0.0); + blockOffset.x = f32(offsetX) * size; + blockOffset.y = f32(offsetY) * size + f32(offsetZ) * f32(irradianceFieldSurface.probeCounts.z) * size; + + let mapHeight = u32(irradianceFieldSurface.irradianceTextureHeight); + var probeCounts:vec3 = vec3(irradianceFieldSurface.probeCounts.xyz); + + var gridOffsetFrom = vec2(blockOffset) + 1; + var gridOffsetTo = offsetByCol(gridOffsetFrom, size, mapHeight, probeCounts); + + pixelCoord = pixelCoord + vec2(gridOffsetTo - 1) + vec2(vec2(vec2(gridOffsetTo) / size) * 2); + + return pixelCoord + 1.0 ; + } + + fn offsetByCol(pixelCoord0:vec2, octSideSize:f32, mapHeight:u32, counts:vec3) -> vec2 + { + var pixelCoord = pixelCoord0; + let blockSize:vec2 = vec2(i32(octSideSize * counts.x), i32(octSideSize * counts.z)); + let blockSizeYBorder:i32 = i32((octSideSize + 2.0) * counts.z); + let blockMaxRowBorder:i32 = i32(mapHeight) / blockSizeYBorder; + let pixelCountYMax:i32 = blockMaxRowBorder * i32(octSideSize * counts.z); + let col:i32 = pixelCoord.y / pixelCountYMax; + + pixelCoord.x = col * i32(octSideSize * counts.x) + pixelCoord.x; + pixelCoord.y = pixelCoord.y % pixelCountYMax; + + return pixelCoord; + } +` diff --git a/src/assets/shader/compute/OutLineBlendColor.wgsl b/src/assets/shader/compute/OutLineBlendColor.wgsl deleted file mode 100644 index 70779dba..00000000 --- a/src/assets/shader/compute/OutLineBlendColor.wgsl +++ /dev/null @@ -1,40 +0,0 @@ -struct OutlineSettingData{ - strength: f32, - useAddMode: f32, - outlinePixel: f32, - fadeOutlinePixel: f32, - lowTexWidth: f32, - lowTexHeight: f32, - slot0: f32, - slot1: f32, - } - - @group(0) @binding(0) var outlineSetting: OutlineSettingData; - @group(0) @binding(1) var inTex : texture_2d; - @group(0) @binding(2) var lowTexSampler : sampler; - @group(0) @binding(3) var lowTex : texture_2d; - @group(0) @binding(4) var outlineTex : texture_storage_2d; - - var texSize: vec2; - var fragCoord: vec2; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - texSize = textureDimensions(outlineTex).xy; - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - - let uv01 = vec2(fragCoord) / (vec2(texSize) - 1.0); - let outLineColor = textureSampleLevel(lowTex, lowTexSampler, uv01, 0.0) * outlineSetting.strength; - var newOC = textureLoad(inTex, fragCoord, 0); - var blendColor:vec3 = vec3(0.0); - if(outlineSetting.useAddMode > 0.5){ - blendColor = vec3(newOC.xyz) + vec3(outLineColor.xyz) * outLineColor.w; - }else{ - blendColor = mix(vec3(newOC.xyz), vec3(outLineColor.xyz), outLineColor.w); - } - textureStore(outlineTex, fragCoord , vec4(blendColor, newOC.w)); - } \ No newline at end of file diff --git a/src/assets/shader/compute/OutLineBlendColor_cs.ts b/src/assets/shader/compute/OutLineBlendColor_cs.ts new file mode 100644 index 00000000..41612229 --- /dev/null +++ b/src/assets/shader/compute/OutLineBlendColor_cs.ts @@ -0,0 +1,42 @@ +export let OutLineBlendColor_cs: string = /*wgsl*/ ` + struct OutlineSettingData{ + strength: f32, + useAddMode: f32, + outlinePixel: f32, + fadeOutlinePixel: f32, + lowTexWidth: f32, + lowTexHeight: f32, + slot0: f32, + slot1: f32, + } + + @group(0) @binding(0) var outlineSetting: OutlineSettingData; + @group(0) @binding(1) var inTex : texture_2d; + @group(0) @binding(2) var lowTexSampler : sampler; + @group(0) @binding(3) var lowTex : texture_2d; + @group(0) @binding(4) var outlineTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(outlineTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + + let uv01 = vec2(fragCoord) / (vec2(texSize) - 1.0); + let outLineColor = textureSampleLevel(lowTex, lowTexSampler, uv01, 0.0) * outlineSetting.strength; + var newOC = textureLoad(inTex, fragCoord, 0); + var blendColor:vec3 = vec3(0.0); + if(outlineSetting.useAddMode > 0.5){ + blendColor = vec3(newOC.xyz) + vec3(outLineColor.xyz) * outLineColor.w; + }else{ + blendColor = mix(vec3(newOC.xyz), vec3(outLineColor.xyz), outLineColor.w); + } + textureStore(outlineTex, fragCoord , vec4(blendColor, newOC.w)); + } +` diff --git a/src/assets/shader/compute/OutlineCalcOutline.wgsl b/src/assets/shader/compute/OutlineCalcOutline_cs.ts similarity index 93% rename from src/assets/shader/compute/OutlineCalcOutline.wgsl rename to src/assets/shader/compute/OutlineCalcOutline_cs.ts index 792dc1c1..4832a7ee 100644 --- a/src/assets/shader/compute/OutlineCalcOutline.wgsl +++ b/src/assets/shader/compute/OutlineCalcOutline_cs.ts @@ -1,4 +1,6 @@ -struct OutlineSettingData{ + +export let OutlineCalcOutline_cs: string = /*wgsl*/ ` + struct OutlineSettingData{ strength: f32, useAddMode: f32, outlinePixel: f32, @@ -8,35 +10,35 @@ struct OutlineSettingData{ slot0: f32, slot1: f32, } - - struct OutlineSlotData{ + + struct OutlineSlotData{ color: vec3, count: f32, } - + struct OutlineWeightData{ slotIndex:f32, outerSlotIndex:f32, entityIndex:f32, weight:f32 } - + struct OutlineEntities{ list: array, } - + @group(0) @binding(0) var outlineSetting: OutlineSettingData; @group(0) @binding(1) var slotsBuffer : array; @group(0) @binding(2) var weightBuffer : array; @group(0) @binding(3) var entitiesBuffer : array; @group(0) @binding(4) var indexTexture : texture_2d; - + var texSize: vec2; var lowSize: vec2; var fragCoord: vec2; var fragCoordLow: vec2; var coordIndex: i32; - + var fragOutline: OutlineWeightData; @compute @workgroup_size( 8 , 8 , 1 ) @@ -64,11 +66,11 @@ struct OutlineSettingData{ fragOutline.weight = 0.0; if(fragOutline.entityIndex >= 0.0){ - fragOutline.slotIndex = f32(matchOutlineSlot()); + fragOutline.slotIndex = f32(matchOutlineSlot()); } weightBuffer[coordIndex] = fragOutline; } - + fn matchOutlineSlot() -> i32 { for(var i:i32 = 0; i < 8; i ++){ @@ -83,4 +85,5 @@ struct OutlineSettingData{ } } return -1; - } \ No newline at end of file + } +` diff --git a/src/assets/shader/compute/OutlineCs.wgsl b/src/assets/shader/compute/OutlineCs.wgsl deleted file mode 100644 index fd288996..00000000 --- a/src/assets/shader/compute/OutlineCs.wgsl +++ /dev/null @@ -1,120 +0,0 @@ -struct OutlineSettingData{ - strength: f32, - useAddMode: f32, - outlinePixel: f32, - fadeOutlinePixel: f32, - lowTexWidth: f32, - lowTexHeight: f32, - slot0: f32, - slot1: f32, - } - - struct OutlineSlotData{ - color: vec3, - count: f32, - } - - struct OutlineWeightData{ - slotIndex:f32, - outerSlotIndex:f32, - entityIndex:f32, - weight:f32 - } - - @group(0) @binding(0) var outlineSetting: OutlineSettingData; - @group(0) @binding(1) var slotsBuffer : array; - @group(0) @binding(2) var weightBuffer : array; - @group(0) @binding(3) var oldOutlineColor : array>; - @group(0) @binding(4) var lowTex : texture_storage_2d; - - var texSize: vec2; - var fragCoord: vec2; - var coordIndex: i32; - var fragOutline: OutlineWeightData; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - texSize = textureDimensions(lowTex).xy; - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - - coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); - fragOutline = weightBuffer[coordIndex]; - - var blendColor = vec3(0.0); - var newOC = vec4(0.0); - - calcOutline(); - let outerSlotIndex:i32 = i32(round(fragOutline.outerSlotIndex)); - if(outerSlotIndex >= 0){ - let outLineColor = slotsBuffer[outerSlotIndex].color; - newOC = vec4(outLineColor, fragOutline.weight); - } - - let coordIndex0 = fragCoord.x + 1 + (fragCoord.y - 1) * i32(texSize.x); - let coordIndex1 = fragCoord.x - 1 + (fragCoord.y - 1) * i32(texSize.x); - let coordIndex2 = fragCoord.x + (fragCoord.y + 1) * i32(texSize.x); - - let oldOC = oldOutlineColor[coordIndex]; - let oldOC0 = oldOutlineColor[coordIndex0]; - let oldOC1 = oldOutlineColor[coordIndex1]; - let oldOC2 = oldOutlineColor[coordIndex2]; - - newOC = mix((oldOC + oldOC0 + oldOC1 + oldOC2) * 0.25, newOC, 0.4); - - oldOutlineColor[coordIndex] = newOC; - textureStore(lowTex, fragCoord, newOC); - } - - fn calcOutline() - { - let outlinePixel = outlineSetting.outlinePixel; - let fadeOutlinePixel = outlineSetting.fadeOutlinePixel; - let pixelRadius = outlinePixel + fadeOutlinePixel; - let minX = max(0.0, f32(fragCoord.x) - pixelRadius); - let maxX = min(f32(texSize.x), f32(fragCoord.x) + pixelRadius); - let minY = max(0.0, f32(fragCoord.y) - pixelRadius); - let maxY = min(f32(texSize.y), f32(fragCoord.y) + pixelRadius); - var coordTemp_f32 = vec2(0.0); - var coordCurrent_f32 = vec2(fragCoord); - var tempCoordIndex = 0; - var tempWeightData: OutlineWeightData; - for(var x:f32 = minX; x < maxX; x += 1.0){ - for(var y:f32 = minY; y < maxY; y += 1.0){ - coordTemp_f32.x = x; - coordTemp_f32.y = y; - let distanceToOuter = length(coordTemp_f32 - coordCurrent_f32); - if(distanceToOuter < pixelRadius){ - var coord_i32 = vec2(coordTemp_f32); - tempCoordIndex = coord_i32.x + coord_i32.y * i32(texSize.x); - tempWeightData = weightBuffer[tempCoordIndex]; - let outlineGap = abs(tempWeightData.slotIndex - fragOutline.slotIndex); - if(outlineGap > 0.1){ - if(tempWeightData.slotIndex > fragOutline.slotIndex){ - if(abs(tempWeightData.slotIndex - fragOutline.outerSlotIndex) < 0.1){ - fragOutline.weight = max(fragOutline.weight, calcWeight(pixelRadius, distanceToOuter, outlinePixel)); - fragOutline.outerSlotIndex = tempWeightData.slotIndex; - weightBuffer[tempCoordIndex] = tempWeightData; - }else if(tempWeightData.slotIndex > fragOutline.outerSlotIndex){ - fragOutline.weight = calcWeight(pixelRadius, distanceToOuter, outlinePixel); - fragOutline.outerSlotIndex = tempWeightData.slotIndex; - weightBuffer[tempCoordIndex] = tempWeightData; - } - } - } - } - } - } - } - - fn calcWeight(radius:f32, distance0:f32, outlinePixel:f32) -> f32{ - let distance = distance0 - outlinePixel; - if(distance < 0.0){ - return 1.0; - } - var ret = 1.0 - distance / (radius - outlinePixel); - return ret; - } \ No newline at end of file diff --git a/src/assets/shader/compute/Outline_cs.ts b/src/assets/shader/compute/Outline_cs.ts new file mode 100644 index 00000000..d999957a --- /dev/null +++ b/src/assets/shader/compute/Outline_cs.ts @@ -0,0 +1,123 @@ +export let Outline_cs: string = /*wgsl*/ ` + struct OutlineSettingData{ + strength: f32, + useAddMode: f32, + outlinePixel: f32, + fadeOutlinePixel: f32, + lowTexWidth: f32, + lowTexHeight: f32, + slot0: f32, + slot1: f32, + } + + struct OutlineSlotData{ + color: vec3, + count: f32, + } + + struct OutlineWeightData{ + slotIndex:f32, + outerSlotIndex:f32, + entityIndex:f32, + weight:f32 + } + + @group(0) @binding(0) var outlineSetting: OutlineSettingData; + @group(0) @binding(1) var slotsBuffer : array; + @group(0) @binding(2) var weightBuffer : array; + @group(0) @binding(3) var oldOutlineColor : array>; + @group(0) @binding(4) var lowTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + var coordIndex: i32; + var fragOutline: OutlineWeightData; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(lowTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + + coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); + fragOutline = weightBuffer[coordIndex]; + + var blendColor = vec3(0.0); + var newOC = vec4(0.0); + + calcOutline(); + let outerSlotIndex:i32 = i32(round(fragOutline.outerSlotIndex)); + if(outerSlotIndex >= 0){ + let outLineColor = slotsBuffer[outerSlotIndex].color; + newOC = vec4(outLineColor, fragOutline.weight); + } + + let coordIndex0 = fragCoord.x + 1 + (fragCoord.y - 1) * i32(texSize.x); + let coordIndex1 = fragCoord.x - 1 + (fragCoord.y - 1) * i32(texSize.x); + let coordIndex2 = fragCoord.x + (fragCoord.y + 1) * i32(texSize.x); + + let oldOC = oldOutlineColor[coordIndex]; + let oldOC0 = oldOutlineColor[coordIndex0]; + let oldOC1 = oldOutlineColor[coordIndex1]; + let oldOC2 = oldOutlineColor[coordIndex2]; + + newOC = mix((oldOC + oldOC0 + oldOC1 + oldOC2) * 0.25, newOC, 0.4); + + oldOutlineColor[coordIndex] = newOC; + textureStore(lowTex, fragCoord, newOC); + } + + fn calcOutline() + { + let outlinePixel = outlineSetting.outlinePixel; + let fadeOutlinePixel = outlineSetting.fadeOutlinePixel; + let pixelRadius = outlinePixel + fadeOutlinePixel; + let minX = max(0.0, f32(fragCoord.x) - pixelRadius); + let maxX = min(f32(texSize.x), f32(fragCoord.x) + pixelRadius); + let minY = max(0.0, f32(fragCoord.y) - pixelRadius); + let maxY = min(f32(texSize.y), f32(fragCoord.y) + pixelRadius); + var coordTemp_f32 = vec2(0.0); + var coordCurrent_f32 = vec2(fragCoord); + var tempCoordIndex = 0; + var tempWeightData: OutlineWeightData; + for(var x:f32 = minX; x < maxX; x += 1.0){ + for(var y:f32 = minY; y < maxY; y += 1.0){ + coordTemp_f32.x = x; + coordTemp_f32.y = y; + let distanceToOuter = length(coordTemp_f32 - coordCurrent_f32); + if(distanceToOuter < pixelRadius){ + var coord_i32 = vec2(coordTemp_f32); + tempCoordIndex = coord_i32.x + coord_i32.y * i32(texSize.x); + tempWeightData = weightBuffer[tempCoordIndex]; + let outlineGap = abs(tempWeightData.slotIndex - fragOutline.slotIndex); + if(outlineGap > 0.1){ + if(tempWeightData.slotIndex > fragOutline.slotIndex){ + if(abs(tempWeightData.slotIndex - fragOutline.outerSlotIndex) < 0.1){ + fragOutline.weight = max(fragOutline.weight, calcWeight(pixelRadius, distanceToOuter, outlinePixel)); + fragOutline.outerSlotIndex = tempWeightData.slotIndex; + weightBuffer[tempCoordIndex] = tempWeightData; + }else if(tempWeightData.slotIndex > fragOutline.outerSlotIndex){ + fragOutline.weight = calcWeight(pixelRadius, distanceToOuter, outlinePixel); + fragOutline.outerSlotIndex = tempWeightData.slotIndex; + weightBuffer[tempCoordIndex] = tempWeightData; + } + } + } + } + } + } + } + + fn calcWeight(radius:f32, distance0:f32, outlinePixel:f32) -> f32{ + let distance = distance0 - outlinePixel; + if(distance < 0.0){ + return 1.0; + } + var ret = 1.0 - distance / (radius - outlinePixel); + return ret; + } +` + diff --git a/src/assets/shader/compute/Picker_CsShader.wgsl b/src/assets/shader/compute/Picker_CsShader.wgsl deleted file mode 100644 index b6257e13..00000000 --- a/src/assets/shader/compute/Picker_CsShader.wgsl +++ /dev/null @@ -1,65 +0,0 @@ -struct GlobalUniform { - projMat: mat4x4, - viewMat: mat4x4, - cameraWorldMatrix: mat4x4, - pvMatrixInv : mat4x4, - shadowMatrix: array,8>, - CameraPos: vec3, - - frame: f32, - time: f32, - delta: f32, - shadowBias: f32, - skyExposure: f32, - renderPassState:f32, - quadScale: f32, - hdrExposure: f32, - - renderState_left: i32, - renderState_right: i32, - renderState_split: f32, - - mouseX: f32, - mouseY: f32, - windowWidth: f32, - windowHeight: f32, - - near: f32, - far: f32, - - pointShadowBias: f32, - shadowMapSize: f32, - shadowSoft: f32, - }; - -struct PickResult{ - pick_meshID:f32, - pick_meshID2:f32, - pick_UV:vec2, - pick_Position:vec4, - pick_Normal:vec4, - pick_Tangent:vec4, -} - -@group(0) @binding(0) var standUniform: GlobalUniform; -@group(0) @binding(1) var outBuffer: PickResult; -@group(0) @binding(2) var visibleMap : texture_2d; - -@compute @workgroup_size( 1 ) -fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) -{ - var result:PickResult ; - // result.pick_meshID - let texSize = textureDimensions(visibleMap).xy; - let screenPoint = vec2(standUniform.mouseX/standUniform.windowWidth,standUniform.mouseY/standUniform.windowHeight); - - let mouseUV = screenPoint * vec2(texSize.xy); - let info = textureLoad(visibleMap, vec2(mouseUV) , 0); - - outBuffer.pick_meshID = f32(info.w) ; - outBuffer.pick_meshID2 = f32(info.w) ; - outBuffer.pick_Tangent = vec4(2.0,2.0,2.0,2.0) ; - outBuffer.pick_UV = vec2(standUniform.mouseX,standUniform.mouseY) ; - outBuffer.pick_Position = vec4(info.xyzw) ; - outBuffer.pick_Normal = vec4(info.xyzw) ; -} \ No newline at end of file diff --git a/src/assets/shader/compute/Picker_cs.ts b/src/assets/shader/compute/Picker_cs.ts new file mode 100644 index 00000000..61c7696d --- /dev/null +++ b/src/assets/shader/compute/Picker_cs.ts @@ -0,0 +1,68 @@ + +export let Picker_cs: string = /*wgsl*/ ` + struct GlobalUniform { + projMat: mat4x4, + viewMat: mat4x4, + cameraWorldMatrix: mat4x4, + pvMatrixInv : mat4x4, + shadowMatrix: array,8>, + CameraPos: vec3, + + frame: f32, + time: f32, + delta: f32, + shadowBias: f32, + skyExposure: f32, + renderPassState:f32, + quadScale: f32, + hdrExposure: f32, + + renderState_left: i32, + renderState_right: i32, + renderState_split: f32, + + mouseX: f32, + mouseY: f32, + windowWidth: f32, + windowHeight: f32, + + near: f32, + far: f32, + + pointShadowBias: f32, + shadowMapSize: f32, + shadowSoft: f32, + }; + + struct PickResult{ + pick_meshID:f32, + pick_meshID2:f32, + pick_UV:vec2, + pick_Position:vec4, + pick_Normal:vec4, + pick_Tangent:vec4, + } + + @group(0) @binding(0) var standUniform: GlobalUniform; + @group(0) @binding(1) var outBuffer: PickResult; + @group(0) @binding(2) var visibleMap : texture_2d; + + @compute @workgroup_size( 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + var result:PickResult ; + // result.pick_meshID + let texSize = textureDimensions(visibleMap).xy; + let screenPoint = vec2(standUniform.mouseX/standUniform.windowWidth,standUniform.mouseY/standUniform.windowHeight); + + let mouseUV = screenPoint * vec2(texSize.xy); + let info = textureLoad(visibleMap, vec2(mouseUV) , 0); + + outBuffer.pick_meshID = f32(info.w) ; + outBuffer.pick_meshID2 = f32(info.w) ; + outBuffer.pick_Tangent = vec4(2.0,2.0,2.0,2.0) ; + outBuffer.pick_UV = vec2(standUniform.mouseX,standUniform.mouseY) ; + outBuffer.pick_Position = vec4(info.xyzw) ; + outBuffer.pick_Normal = vec4(info.xyzw) ; + } +` diff --git a/src/assets/shader/compute/SSAO_CsShader.wgsl b/src/assets/shader/compute/SSAO_cs.ts similarity index 98% rename from src/assets/shader/compute/SSAO_CsShader.wgsl rename to src/assets/shader/compute/SSAO_cs.ts index da8b0ac8..60864622 100644 --- a/src/assets/shader/compute/SSAO_CsShader.wgsl +++ b/src/assets/shader/compute/SSAO_cs.ts @@ -1,7 +1,5 @@ - - - #include "GlobalUniform" - +export let SSAO_cs: string = /*wgsl*/ ` +#include "GlobalUniform" struct UniformData { radius: f32 , bias: f32, @@ -96,4 +94,7 @@ textureStore(outTex, fragCoord , vec4(occlusion)); } +` + + diff --git a/src/assets/shader/compute/SSR_BlendColor_Shader.wgsl b/src/assets/shader/compute/SSR_BlendColor_cs.ts similarity index 91% rename from src/assets/shader/compute/SSR_BlendColor_Shader.wgsl rename to src/assets/shader/compute/SSR_BlendColor_cs.ts index e6d6e3df..d66af8b2 100644 --- a/src/assets/shader/compute/SSR_BlendColor_Shader.wgsl +++ b/src/assets/shader/compute/SSR_BlendColor_cs.ts @@ -1,6 +1,5 @@ - - - @group(0) @binding(0) var rayTraceBuffer : array; +export let SSR_BlendColor_cs: string = /*wgsl*/ ` +@group(0) @binding(0) var rayTraceBuffer : array; @group(0) @binding(1) var colorMap : texture_2d; @group(0) @binding(2) var ssrMapSampler : sampler; @group(0) @binding(3) var ssrMap : texture_2d; @@ -43,3 +42,6 @@ outColor.a = color.a ; textureStore(outTex, fragCoord , outColor ); } + +` + diff --git a/src/assets/shader/compute/SSR_IS_Shader.wgsl b/src/assets/shader/compute/SSR_IS_Shader.wgsl deleted file mode 100644 index e110ad1b..00000000 --- a/src/assets/shader/compute/SSR_IS_Shader.wgsl +++ /dev/null @@ -1,82 +0,0 @@ - - - struct SSRUniformData { - ssrBufferSizeX: f32, - ssrBufferSizeY: f32, - colorMapSizeX: f32, - colorMapSizeY: f32, - - fadeEdgeRatio: f32, - rayMarchRatio: f32, - fadeDistanceMin: f32, - fadeDistanceMax: f32, - - mixThreshold: f32, - roughnessThreshold: f32, - reflectionRatio: f32, - powDotRN: f32, - - randomSeedX: f32, - randomSeedY: f32, - slot1: f32, - slot2: f32, - }; - - struct RayTraceRetData{ - skyColor:vec3, - roughness:f32, - - hitCoord:vec2, - alpha:f32, - fresnel:f32, - } - - @group(0) @binding(0) var ssrUniform: SSRUniformData; - @group(0) @binding(1) var rayTraceBuffer : array; - @group(0) @binding(2) var ssrColorData : array>; - @group(0) @binding(3) var historyPosition : array>; - - @group(0) @binding(4) var colorMap: texture_2d; - @group(0) @binding(5) var outTex : texture_storage_2d; - - var ssrBufferCoord: vec2; - var colorTexSize: vec2; - var bufferData: RayTraceRetData; - var ssrBufferSize: vec2; - var coordIndex: i32; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - ssrBufferCoord = vec2( globalInvocation_id.xy ); - ssrBufferSize = vec2(i32(ssrUniform.ssrBufferSizeX), i32(ssrUniform.ssrBufferSizeY)); - colorTexSize = vec2(i32(ssrUniform.colorMapSizeX), i32(ssrUniform.colorMapSizeY)); - - if(ssrBufferCoord.x >= ssrBufferSize.x || ssrBufferCoord.y >= ssrBufferSize.y){ - return; - } - - coordIndex = ssrBufferCoord.x + ssrBufferCoord.y * ssrBufferSize.x; - bufferData = rayTraceBuffer[coordIndex]; - var oc = vec4(0.0, 0.0, 0.0, -1.0); - - var mixFactor = historyPosition[coordIndex].w; - - if(bufferData.alpha >= 0.0 && bufferData.roughness < ssrUniform.roughnessThreshold){ - let roughness = clamp(bufferData.roughness, 0.0, 1.0); - let prefilterColor = bufferData.skyColor; - var ssrColor = textureLoad(colorMap, vec2(bufferData.hitCoord), 0); - ssrColor.w = bufferData.alpha; - oc = ssrColor; - } - let skyColor = vec4(bufferData.skyColor, 1.0); - oc = mix(oc, skyColor, 1.0 - bufferData.alpha); - - let lastColor = ssrColorData[coordIndex]; - var newColor = mix(oc, lastColor, mixFactor); - newColor.w = oc.w; - - ssrColorData[coordIndex] = newColor; - - textureStore(outTex, ssrBufferCoord , newColor); - } diff --git a/src/assets/shader/materials/compute/SSR_IS_Shader.wgsl b/src/assets/shader/compute/SSR_IS_cs.ts similarity index 98% rename from src/assets/shader/materials/compute/SSR_IS_Shader.wgsl rename to src/assets/shader/compute/SSR_IS_cs.ts index e110ad1b..24c30728 100644 --- a/src/assets/shader/materials/compute/SSR_IS_Shader.wgsl +++ b/src/assets/shader/compute/SSR_IS_cs.ts @@ -1,5 +1,4 @@ - - +export let SSR_IS_cs: string = /*wgsl*/ ` struct SSRUniformData { ssrBufferSizeX: f32, ssrBufferSizeY: f32, @@ -35,7 +34,7 @@ @group(0) @binding(1) var rayTraceBuffer : array; @group(0) @binding(2) var ssrColorData : array>; @group(0) @binding(3) var historyPosition : array>; - + @group(0) @binding(4) var colorMap: texture_2d; @group(0) @binding(5) var outTex : texture_storage_2d; @@ -80,3 +79,6 @@ textureStore(outTex, ssrBufferCoord , newColor); } +` + + diff --git a/src/assets/shader/compute/SSR_RayTrace_Shader.wgsl b/src/assets/shader/compute/SSR_RayTrace_Shader.wgsl deleted file mode 100644 index cc3d8261..00000000 --- a/src/assets/shader/compute/SSR_RayTrace_Shader.wgsl +++ /dev/null @@ -1,315 +0,0 @@ - - - #include "GlobalUniform" - - struct SSRUniformData { - ssrBufferSizeX: f32, - ssrBufferSizeY: f32, - colorMapSizeX: f32, - colorMapSizeY: f32, - - fadeEdgeRatio: f32, - rayMarchRatio: f32, - fadeDistanceMin: f32, - fadeDistanceMax: f32, - - mixThreshold: f32, - roughnessThreshold: f32, - reflectionRatio: f32, - powDotRN: f32, - - randomSeedX: f32, - randomSeedY: f32, - slot1: f32, - slot2: f32, - }; - - struct HitData{ - hitPos:vec3, - hitNormal:vec3, - fadeAlpha:vec4, - hitCoord:vec2, - hitResult:i32, - hitSky:i32, - }; - - struct RayTraceRetData{ - skyColor:vec3, - roughness:f32, - - hitCoord:vec2, - alpha:f32, - fresnel:f32, - } - - @group(0) @binding(0) var standUniform: GlobalUniform; - @group(0) @binding(1) var ssrUniform: SSRUniformData; - @group(0) @binding(2) var rayTraceBuffer : array; - @group(0) @binding(4) var historyPosition : array>; - - @group(0) @binding(5) var zBufferTexture : texture_2d; - @group(0) @binding(6) var normalBufferTex : texture_2d; - @group(0) @binding(7) var materialBufferTex : texture_2d; - @group(0) @binding(8) var prefilterMapSampler: sampler; - @group(0) @binding(9) var prefilterMap: texture_cube; - - var rayOrigin: vec3; - var rayDirection: vec3; - var cameraPosition: vec3; - var reflectionDir: vec3; - var colorTexSize: vec2; - var fragCoordColor: vec2; - var ssrBufferCoord: vec2; - var ssrBufferSize: vec2; - var hitData: HitData; - var rayTraceRet: RayTraceRetData; - var worldPosition: vec3; - var worldNormal: vec3; - var roughness: f32; - var fresnel: f32; - - var historyPos: vec3; - var coordIndex: i32; - - var PI: f32 = 3.14159; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - ssrBufferCoord = vec2( globalInvocation_id.xy); - ssrBufferSize = vec2(i32(ssrUniform.ssrBufferSizeX), i32(ssrUniform.ssrBufferSizeY)); - if(ssrBufferCoord.x >= ssrBufferSize.x || ssrBufferCoord.y >= ssrBufferSize.y){ - return; - } - coordIndex = ssrBufferCoord.x + ssrBufferCoord.y * ssrBufferSize.x; - - colorTexSize = vec2(i32(ssrUniform.colorMapSizeX), i32(ssrUniform.colorMapSizeY)); - fragCoordColor = convertColorCoordFromSSRCoord(ssrBufferCoord); - - hitData.fadeAlpha = vec4(0.0); - hitData.hitCoord = vec2(0); - hitData.hitResult = 0; - hitData.hitNormal = vec3(0.0, 1.0, 0.0); - hitData.hitSky = 1; - - worldPosition = textureLoad(zBufferTexture, fragCoordColor , 0).xyz; - historyPos = historyPosition[coordIndex].xyz; - - var mixFactor = 0.2; - if(length(historyPos - worldPosition) < ssrUniform.mixThreshold){ - mixFactor = 0.9; - } - historyPosition[coordIndex] = vec4(worldPosition, mixFactor); - - let normal_v4 = textureLoad(normalBufferTex, fragCoordColor , 0); - worldNormal = normalize(vec3(normal_v4.xyz) * 2.0 - 1.0); - let materialData = textureLoad(materialBufferTex, fragCoordColor , 0 ); - let roughness = materialData.g * (1.0 - materialData.b); - fresnel = (1.0 - roughness) * ssrUniform.reflectionRatio; - - cameraPosition = vec3(standUniform.cameraWorldMatrix[3].xyz); - rayOrigin = vec3(worldPosition.xyz); - - rayDirection = normalize(vec3(worldPosition.xyz - cameraPosition)); - - var randomSeed = fract(ssrUniform.randomSeedX + worldPosition.x); - rand_seed.x = randomSeed; - rand_seed.y = fract(ssrUniform.randomSeedY + worldPosition.y + worldPosition.z); - randomSeed = rand(); - - let normalRandom = makeRandomDirection(worldNormal, u32(randomSeed * 256.0), 256, roughness); - - reflectionDir = normalize(reflect(rayDirection, normalRandom)); - - if(normal_v4.w > 0.5 && roughness < ssrUniform.roughnessThreshold){ - let uvOrigin = vec2(f32(fragCoordColor.x), f32(fragCoordColor.y)); - let rayMarchPosition = rayOrigin + reflectionDir * 100.0; - var uvRayMarch = standUniform.projMat * (standUniform.viewMat * vec4(rayMarchPosition, 1.0)); - var uvOffset = (vec2(uvRayMarch.xy / uvRayMarch.w) + 1.0) * 0.5; - uvOffset.y = 1.0 - uvOffset.y; - uvOffset = uvOffset * vec2(colorTexSize - 1) - uvOrigin; - uvOffset = normalize(uvOffset); - - rayTrace(uvOffset); - if(hitData.hitResult == 1){ - hidingArtifact(); - rayTraceRet.alpha = hitData.fadeAlpha.x * hitData.fadeAlpha.y * hitData.fadeAlpha.z * hitData.fadeAlpha.w; - if(hitData.hitSky == 1){ - rayTraceRet.alpha = 0.0; - } - }else{ - rayTraceRet.alpha = 0.0; - } - rayTraceRet.skyColor = getSkyColor(); - }else{ - rayTraceRet.alpha = -1.0; - rayTraceRet.skyColor = vec3(0.0); - } - - rayTraceRet.roughness = roughness; - rayTraceRet.fresnel = fresnel; - rayTraceRet.hitCoord = vec2(hitData.hitCoord); - - let index:i32 = ssrBufferCoord.x + ssrBufferCoord.y * ssrBufferSize.x; - rayTraceBuffer[index] = rayTraceRet; - } - -fn makeRandomDirection(srcDirection:vec3, i:u32, SAMPLE_COUNT:u32, roughness:f32) -> vec3 -{ - var N: vec3 = normalize(srcDirection); - var Xi:vec2 = hammersley(i, SAMPLE_COUNT); - return ImportanceSampleGGX(Xi, N, roughness); -} - -fn hammersley( i : u32 , N : u32 ) -> vec2 -{ - // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html - var bits = (i << 16u) | (i >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - var rdi = f32(bits) * 2.3283064365386963e-10; - return vec2(f32(i) /f32(N), rdi); -} - -fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 -{ - var a = roughness*roughness; - - var phi = 2.0 * PI * Xi.x; - var cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); - var sinTheta = sqrt(1.0 - cosTheta*cosTheta); - - // from spherical coordinates to cartesian coordinates - var H:vec3; - H.x = cos(phi) * sinTheta; - H.y = sin(phi) * sinTheta; - H.z = cosTheta; - - // from tangent-space vector to world-space sample vector - var up:vec3; - if(abs(N.z) < 0.999) - { - up = vec3(0.0, 0.0, 1.0); - } - else - { - up = vec3(1.0, 0.0, 0.0); - } - var tangent:vec3 = normalize(cross(up, N)); - var bitangent:vec3 = cross(N, tangent); - var sampleVec:vec3 = tangent * H.x + bitangent * H.y + N * H.z; - return normalize(sampleVec); -} - - var rand_seed :vec2 = vec2(0.0); - fn rand() -> f32 { - rand_seed.x = fract(cos(dot(rand_seed, vec2(23.14077926, 232.61690225))) * 136.8168); - rand_seed.y = fract(cos(dot(rand_seed, vec2(54.47856553, 345.84153136))) * 534.7645); - return rand_seed.y; - } - - fn getSkyColor() -> vec3{ - let calcRoughness = clamp(roughness, 0.0, 1.0); - let MAX_REFLECTION_LOD = f32(textureNumLevels(prefilterMap)) ; - var prefilterColor = textureSampleLevel(prefilterMap, prefilterMapSampler, reflectionDir, calcRoughness * MAX_REFLECTION_LOD); - return LinearToGammaSpace(vec3(prefilterColor.xyz)) * standUniform.skyExposure; - } - - fn LinearToGammaSpace(linRGB: vec3) -> vec3 { - var linRGB1 = max(linRGB, vec3(0.0)); - linRGB1 = pow(linRGB1, vec3(0.4166666567325592)); - return max(((1.0549999475479126 * linRGB1) - vec3(0.054999999701976776)), vec3(0.0)); - } - - fn convertColorCoordFromSSRCoord(coord:vec2) -> vec2{ - let color_ssr_ratio = ssrUniform.colorMapSizeX / ssrUniform.ssrBufferSizeX; - let targetCoord = vec2(coord) * color_ssr_ratio; - return vec2(targetCoord); - } - - fn hidingArtifact(){ - let texSizeF32 = vec2(f32(colorTexSize.x), f32(colorTexSize.y)); - let halfTexSizeF32 = texSizeF32 * 0.5; - - //near screen edge - var distance2Center = abs(vec2(f32(hitData.hitCoord.x), f32(hitData.hitCoord.y)) - halfTexSizeF32); - let halfEdgeSize:f32 = min(texSizeF32.x, texSizeF32.y) * clamp(0.01, ssrUniform.fadeEdgeRatio, 1.0) * 0.5; - var distance2Edge = min(vec2(halfEdgeSize), halfTexSizeF32 - distance2Center); - var ratioXY = distance2Edge / halfEdgeSize; - hitData.fadeAlpha.x = sqrt(ratioXY.x * ratioXY.y); - - //back face hit - var backFaceBias = max(0.0, dot(hitData.hitNormal, -reflectionDir)); - hitData.fadeAlpha.y = pow(backFaceBias, max(0.0001, ssrUniform.powDotRN)); - - //screen distance ratio - let maxLength = max(f32(colorTexSize.x), f32(colorTexSize.y)) * ssrUniform.rayMarchRatio; - let screenPointer = hitData.hitCoord - fragCoordColor; - var screenDistance = length(vec2(f32(screenPointer.x), f32(screenPointer.y))); - screenDistance = clamp(screenDistance / maxLength, 0.0, 1.0); - hitData.fadeAlpha.z = 1.0 - screenDistance; - - //position distance ratio - var fadeDistance = length(vec3(hitData.hitPos - cameraPosition)); - var dFar = ssrUniform.fadeDistanceMax; - var dNear = ssrUniform.fadeDistanceMin; - dFar = max(1.0, dFar); - dNear = clamp(dNear, 0.001, dFar - 0.001); - fadeDistance = clamp(fadeDistance, dNear, dFar); - fadeDistance = (fadeDistance - dNear) / (dFar - dNear); - hitData.fadeAlpha.w = 1.0 - fadeDistance; - } - - fn rayTrace(rayMarchDir:vec2){ - let stepLength = 4.0; - let maxLength = max(f32(colorTexSize.x), f32(colorTexSize.y)) * ssrUniform.rayMarchRatio; - for(var i:f32 = 1.0; i < maxLength; i = i + stepLength){ - let offsetFloat32 = i * rayMarchDir; - var uv = fragCoordColor + vec2(i32(offsetFloat32.x), i32(offsetFloat32.y)); - let hitRet = rayInterestScene(uv); - if(hitRet > 0){ - hitData.hitResult = hitRet; - break; - } - } - if(hitData.hitResult == 1){ - let fromUV = hitData.hitCoord; - for(var i:f32 = -stepLength; i <= 0.0; i = i + 1.0){ - let offsetFloat32 = i * rayMarchDir; - var uv = fromUV + vec2(i32(offsetFloat32.x), i32(offsetFloat32.y)); - let hitRet = rayInterestScene(uv); - if(hitRet == 1){ - let WN = textureLoad(normalBufferTex, hitData.hitCoord , 0 ); - if(WN.w > 0.5){ - hitData.hitSky = 0; - } - let normal = vec3(WN.xyz) * 2.0 - 1.0; - hitData.hitNormal = normalize(vec3(normal.xyz)); - break; - } - } - } - } - - fn rayInterestScene(uv:vec2) -> i32 { - if(uv.x < 0 || uv.y < 0 || uv.x >= colorTexSize.x || uv.y >= colorTexSize.y){ - return 2; - }else{ - let hitPos = textureLoad(zBufferTexture, uv , 0 ); - let testDir = normalize(vec3(hitPos.xyz - rayOrigin)); - let cosValue = dot(reflectionDir, testDir); - - if(cosValue > 0.9996){ - let cross1 = cross(reflectionDir, -rayDirection); - let cross2 = cross(reflectionDir, testDir); - if(dot(cross1, cross2) > 0.0){ - hitData.hitPos = vec3(hitPos.xyz); - hitData.hitCoord = uv; - return 1; - } - } - } - return 0; - } diff --git a/src/assets/shader/materials/compute/SSR_RayTrace_Shader.wgsl b/src/assets/shader/compute/SSR_RayTrace_cs.ts similarity index 94% rename from src/assets/shader/materials/compute/SSR_RayTrace_Shader.wgsl rename to src/assets/shader/compute/SSR_RayTrace_cs.ts index cc3d8261..9456b838 100644 --- a/src/assets/shader/materials/compute/SSR_RayTrace_Shader.wgsl +++ b/src/assets/shader/compute/SSR_RayTrace_cs.ts @@ -1,5 +1,4 @@ - - +export let SSR_RayTrace_cs: string = /*wgsl*/ ` #include "GlobalUniform" struct SSRUniformData { @@ -67,10 +66,10 @@ var worldNormal: vec3; var roughness: f32; var fresnel: f32; - + var historyPos: vec3; var coordIndex: i32; - + var PI: f32 = 3.14159; @compute @workgroup_size( 8 , 8 , 1 ) @@ -153,16 +152,16 @@ let index:i32 = ssrBufferCoord.x + ssrBufferCoord.y * ssrBufferSize.x; rayTraceBuffer[index] = rayTraceRet; } - -fn makeRandomDirection(srcDirection:vec3, i:u32, SAMPLE_COUNT:u32, roughness:f32) -> vec3 -{ + + fn makeRandomDirection(srcDirection:vec3, i:u32, SAMPLE_COUNT:u32, roughness:f32) -> vec3 + { var N: vec3 = normalize(srcDirection); var Xi:vec2 = hammersley(i, SAMPLE_COUNT); return ImportanceSampleGGX(Xi, N, roughness); -} + } -fn hammersley( i : u32 , N : u32 ) -> vec2 -{ + fn hammersley( i : u32 , N : u32 ) -> vec2 + { // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html var bits = (i << 16u) | (i >> 16u); bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); @@ -171,10 +170,10 @@ fn hammersley( i : u32 , N : u32 ) -> vec2 bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); var rdi = f32(bits) * 2.3283064365386963e-10; return vec2(f32(i) /f32(N), rdi); -} + } -fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 -{ + fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 + { var a = roughness*roughness; var phi = 2.0 * PI * Xi.x; @@ -188,7 +187,7 @@ fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 H.z = cosTheta; // from tangent-space vector to world-space sample vector - var up:vec3; + var up:vec3; if(abs(N.z) < 0.999) { up = vec3(0.0, 0.0, 1.0); @@ -197,19 +196,19 @@ fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 { up = vec3(1.0, 0.0, 0.0); } - var tangent:vec3 = normalize(cross(up, N)); - var bitangent:vec3 = cross(N, tangent); - var sampleVec:vec3 = tangent * H.x + bitangent * H.y + N * H.z; - return normalize(sampleVec); -} - - var rand_seed :vec2 = vec2(0.0); - fn rand() -> f32 { + var tangent:vec3 = normalize(cross(up, N)); + var bitangent:vec3 = cross(N, tangent); + var sampleVec:vec3 = tangent * H.x + bitangent * H.y + N * H.z; + return normalize(sampleVec); + } + + var rand_seed :vec2 = vec2(0.0); + fn rand() -> f32 { rand_seed.x = fract(cos(dot(rand_seed, vec2(23.14077926, 232.61690225))) * 136.8168); rand_seed.y = fract(cos(dot(rand_seed, vec2(54.47856553, 345.84153136))) * 534.7645); return rand_seed.y; } - + fn getSkyColor() -> vec3{ let calcRoughness = clamp(roughness, 0.0, 1.0); let MAX_REFLECTION_LOD = f32(textureNumLevels(prefilterMap)) ; @@ -222,7 +221,7 @@ fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 linRGB1 = pow(linRGB1, vec3(0.4166666567325592)); return max(((1.0549999475479126 * linRGB1) - vec3(0.054999999701976776)), vec3(0.0)); } - + fn convertColorCoordFromSSRCoord(coord:vec2) -> vec2{ let color_ssr_ratio = ssrUniform.colorMapSizeX / ssrUniform.ssrBufferSizeX; let targetCoord = vec2(coord) * color_ssr_ratio; @@ -313,3 +312,6 @@ fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 } return 0; } +` + + diff --git a/src/assets/shader/compute/TAACopyTex.wgsl b/src/assets/shader/compute/TAACopyTex.wgsl deleted file mode 100644 index 4993fda2..00000000 --- a/src/assets/shader/compute/TAACopyTex.wgsl +++ /dev/null @@ -1,18 +0,0 @@ - @group(0) @binding(0) var preColor : array>; - @group(0) @binding(1) var preColorTex : texture_storage_2d; - - var texSize: vec2; - var fragCoord: vec2; - var coordIndex: i32; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - texSize = textureDimensions(preColorTex).xy; - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); - textureStore(preColorTex, fragCoord , preColor[coordIndex]); - } \ No newline at end of file diff --git a/src/assets/shader/compute/TAACopyTex_cs.ts b/src/assets/shader/compute/TAACopyTex_cs.ts new file mode 100644 index 00000000..913135b7 --- /dev/null +++ b/src/assets/shader/compute/TAACopyTex_cs.ts @@ -0,0 +1,21 @@ +export let TAACopyTex_cs: string = /*wgsl*/ ` + @group(0) @binding(0) var preColor : array>; + @group(0) @binding(1) var preColorTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + var coordIndex: i32; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(preColorTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); + textureStore(preColorTex, fragCoord , preColor[coordIndex]); + } + ` + diff --git a/src/assets/shader/compute/TAASharpTex.wgsl b/src/assets/shader/compute/TAASharpTex.wgsl deleted file mode 100644 index e57576c8..00000000 --- a/src/assets/shader/compute/TAASharpTex.wgsl +++ /dev/null @@ -1,41 +0,0 @@ - - struct TAAData{ - preProjMatrix: mat4x4, - preViewMatrix: mat4x4, - jitterFrameIndex: f32, - blendFactor: f32, - sharpFactor: f32, - sharpPreBlurFactor: f32, - jitterX: f32, - jitterY: f32, - slot0: f32, - slot1: f32, - } - @group(0) @binding(0) var taaData: TAAData; - @group(0) @binding(1) var inTex : texture_2d; - @group(0) @binding(2) var outTex : texture_storage_2d; - - var texSize: vec2; - var fragCoord: vec2; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - texSize = textureDimensions(outTex).xy; - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - - let c0 = textureLoad(inTex, vec2(fragCoord.x, fragCoord.y - 1), 0); - let c1 = textureLoad(inTex, vec2(fragCoord.x, fragCoord.y + 1), 0); - let c2 = textureLoad(inTex, vec2(fragCoord.x - 1, fragCoord.y), 0); - let c3 = textureLoad(inTex, vec2(fragCoord.x + 1, fragCoord.y), 0); - - var roundColor = (c0 + c1 + c2 + c3) * 0.25; - let originColor = textureLoad(inTex, fragCoord, 0); - let blurColor = mix(roundColor, originColor, taaData.sharpPreBlurFactor); - var oc = (originColor - blurColor * taaData.sharpFactor) / (1.0 - taaData.sharpFactor); - oc = clamp(oc, vec4(0.0), oc); - textureStore(outTex, fragCoord , oc); - } \ No newline at end of file diff --git a/src/assets/shader/compute/TAASharpTex_cs.ts b/src/assets/shader/compute/TAASharpTex_cs.ts new file mode 100644 index 00000000..a9a797b8 --- /dev/null +++ b/src/assets/shader/compute/TAASharpTex_cs.ts @@ -0,0 +1,42 @@ +export let TAASharpTex_cs: string = /*wgsl*/ ` + struct TAAData{ + preProjMatrix: mat4x4, + preViewMatrix: mat4x4, + jitterFrameIndex: f32, + blendFactor: f32, + sharpFactor: f32, + sharpPreBlurFactor: f32, + jitterX: f32, + jitterY: f32, + slot0: f32, + slot1: f32, + } + @group(0) @binding(0) var taaData: TAAData; + @group(0) @binding(1) var inTex : texture_2d; + @group(0) @binding(2) var outTex : texture_storage_2d; + + var texSize: vec2; + var fragCoord: vec2; + + @compute @workgroup_size( 8 , 8 , 1 ) + fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) + { + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(outTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + + let c0 = textureLoad(inTex, vec2(fragCoord.x, fragCoord.y - 1), 0); + let c1 = textureLoad(inTex, vec2(fragCoord.x, fragCoord.y + 1), 0); + let c2 = textureLoad(inTex, vec2(fragCoord.x - 1, fragCoord.y), 0); + let c3 = textureLoad(inTex, vec2(fragCoord.x + 1, fragCoord.y), 0); + + var roundColor = (c0 + c1 + c2 + c3) * 0.25; + let originColor = textureLoad(inTex, fragCoord, 0); + let blurColor = mix(roundColor, originColor, taaData.sharpPreBlurFactor); + var oc = (originColor - blurColor * taaData.sharpFactor) / (1.0 - taaData.sharpFactor); + oc = clamp(oc, vec4(0.0), oc); + textureStore(outTex, fragCoord , oc); + } +` diff --git a/src/assets/shader/compute/TAA_cs.ts b/src/assets/shader/compute/TAA_cs.ts new file mode 100644 index 00000000..510088fc --- /dev/null +++ b/src/assets/shader/compute/TAA_cs.ts @@ -0,0 +1,155 @@ +export let TAA_cs: string = /*wgsl*/ ` +#include "GlobalUniform" + +struct TAAData{ + preProjMatrix: mat4x4, + preViewMatrix: mat4x4, + jitterFrameIndex: f32, + blendFactor: f32, + sharpFactor: f32, + sharpPreBlurFactor: f32, + jitterX: f32, + jitterY: f32, + slot0: f32, + slot1: f32, +} + +@group(0) @binding(0) var standUniform: GlobalUniform; +@group(0) @binding(1) var taaData: TAAData; +@group(0) @binding(2) var preColorBuffer : array>; + +@group(0) @binding(3) var preColorTexSampler : sampler; +@group(0) @binding(4) var preColorTex : texture_2d; +@group(0) @binding(5) var posTex : texture_2d; +@group(0) @binding(6) var inTexSampler : sampler; +@group(0) @binding(7) var inTex : texture_2d; +@group(0) @binding(8) var outTex : texture_storage_2d; + +var texSize: vec2; +var fragCoord: vec2; +var coordIndex: i32; +var color_min: vec4; +var color_max: vec4; +var color_avg: vec4; +var re_proj_uv01: vec2; +var FLT_EPS:f32 = 5.960464478e-8; // 2^-24, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f) + +@compute @workgroup_size( 8 , 8 , 1 ) +fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) +{ + fragCoord = vec2( globalInvocation_id.xy ); + texSize = textureDimensions(inTex).xy; + if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ + return; + } + let frame = standUniform.frame; + coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); + + let oc = blendColor(); + preColorBuffer[coordIndex] = oc; + textureStore(outTex, fragCoord , oc); +} + +fn blendColor() -> vec4 +{ + var preCoord = fragCoord; + var mixWeight = 1.0; + re_proj_uv01 = vec2(0.0); + var reProjectionCoord:vec2 = vec2(fragCoord); + //var jitterUVOffset = 0.5 * vec2(taaData.jitterX, -taaData.jitterY); + if(taaData.jitterFrameIndex > 0.5){ + var wPos = textureLoad(posTex, fragCoord, 0); + let ndc = taaData.preProjMatrix * (taaData.preViewMatrix * vec4(wPos.xyz, 1.0)); + re_proj_uv01 = vec2(ndc.x, -ndc.y) / ndc.w; + re_proj_uv01 = (re_proj_uv01 + 1.0) * 0.5; + + if(re_proj_uv01.x >= 0.0 && re_proj_uv01.x <= 1.0 && re_proj_uv01.y >= 0.0 && re_proj_uv01.y <= 1.0){ + mixWeight = taaData.blendFactor; + //reProjectionCoord = re_proj_uv01 + jitterUVOffset; + reProjectionCoord.x = re_proj_uv01.x * f32(texSize.x - 1); + reProjectionCoord.y = re_proj_uv01.y * f32(texSize.y - 1); + preCoord = vec2(reProjectionCoord); + }else{ + //outside of screen + mixWeight = 1.0; + } + } + + var curUV01 = vec2(fragCoord) / vec2(texSize - 1); + //curUV01 += jitterUVOffset; + + let curColor = textureSampleLevel(inTex, inTexSampler, curUV01, 0.0); + + let preIndex = preCoord.x + preCoord.y * i32(texSize.x); + var preColor = textureSampleLevel(preColorTex, preColorTexSampler, re_proj_uv01, 0.0); + + //minmax9(fragCoord); + minmax4(fragCoord); + + preColor = clip_aabb(color_min.xyz, color_max.xyz, color_avg, preColor); + var outColor = mix(preColor, curColor, mixWeight); + + return outColor; +} + +fn clampCoord(coord0:vec2) -> vec2{ + return clamp(coord0, vec2(0), vec2(texSize - 1)); +} + +fn minmax4(coord:vec2) { + let uv0 = clampCoord(vec2(coord.x - 1, coord.y)); + let uv1 = clampCoord(vec2(coord.x, coord.y - 1)); + let uv2 = clampCoord(vec2(coord.x, coord.y + 1)); + let uv3 = clampCoord(vec2(coord.x + 1, coord.y)); + + let c0 = textureLoad(inTex, uv0, 0); + let c1 = textureLoad(inTex, uv1, 0); + let c2 = textureLoad(inTex, uv2, 0); + let c3 = textureLoad(inTex, uv3, 0); + + color_min = min(c0, min(c1, min(c2, c3))); + color_max = max(c0, max(c1, max(c2, c3))); + color_avg = (c0 + c1 + c2 + c3) * 0.25; + } + + fn minmax9(coord:vec2) { + let uv0 = clampCoord(vec2(coord.x - 1, coord.y - 1)); + let uv1 = clampCoord(vec2(coord.x - 1, coord.y)); + let uv2 = clampCoord(vec2(coord.x - 1, coord.y + 1)); + let uv3 = clampCoord(vec2(coord.x, coord.y - 1)); + let uv4 = clampCoord(vec2(coord.x, coord.y)); + let uv5 = clampCoord(vec2(coord.x, coord.y + 1)); + let uv6 = clampCoord(vec2(coord.x + 1, coord.y - 1)); + let uv7 = clampCoord(vec2(coord.x + 1, coord.y)); + let uv8 = clampCoord(vec2(coord.x + 1, coord.y + 1)); + + let ctl = textureLoad(inTex, uv0, 0); + let ctc = textureLoad(inTex, uv1, 0); + let ctr = textureLoad(inTex, uv2, 0); + let cml = textureLoad(inTex, uv3, 0); + let cmc = textureLoad(inTex, uv4, 0); + let cmr = textureLoad(inTex, uv5, 0); + let cbl = textureLoad(inTex, uv6, 0); + let cbc = textureLoad(inTex, uv7, 0); + let cbr = textureLoad(inTex, uv8, 0); + + color_min = min(ctl, min(ctc, min(ctr, min(cml, min(cmc, min(cmr, min(cbl, min(cbc, cbr)))))))); + color_max = max(ctl, max(ctc, max(ctr, max(cml, max(cmc, max(cmr, max(cbl, max(cbc, cbr)))))))); + color_avg = (ctl + ctc + ctr + cml + cmc + cmr + cbl + cbc + cbr) / 9.0; + } + + fn clip_aabb(aabb_max:vec3, aabb_min:vec3, color_avg:vec4, input_texel:vec4) -> vec4 + { + var p_clip:vec3 = 0.5 * (aabb_max + aabb_min); + var e_clip:vec3 = 0.5 * (aabb_max - aabb_min) + FLT_EPS; + var v_clip:vec4 = input_texel - vec4(p_clip, color_avg.w); + var v_unit:vec3 = v_clip.xyz / e_clip; + var a_unit:vec3 = abs(v_unit); + var ma_unit:f32 = max(a_unit.x, max(a_unit.y, a_unit.z)); + + if (ma_unit > 1.0){ + return vec4(p_clip, color_avg.w) + v_clip / ma_unit; + }else{ + return input_texel; + } + }` diff --git a/src/assets/shader/compute/TAAcs.wgsl b/src/assets/shader/compute/TAAcs.wgsl deleted file mode 100644 index 6c82bc0a..00000000 --- a/src/assets/shader/compute/TAAcs.wgsl +++ /dev/null @@ -1,155 +0,0 @@ - - #include "GlobalUniform" - - struct TAAData{ - preProjMatrix: mat4x4, - preViewMatrix: mat4x4, - jitterFrameIndex: f32, - blendFactor: f32, - sharpFactor: f32, - sharpPreBlurFactor: f32, - jitterX: f32, - jitterY: f32, - slot0: f32, - slot1: f32, - } - - @group(0) @binding(0) var standUniform: GlobalUniform; - @group(0) @binding(1) var taaData: TAAData; - @group(0) @binding(2) var preColorBuffer : array>; - - @group(0) @binding(3) var preColorTexSampler : sampler; - @group(0) @binding(4) var preColorTex : texture_2d; - @group(0) @binding(5) var posTex : texture_2d; - @group(0) @binding(6) var inTexSampler : sampler; - @group(0) @binding(7) var inTex : texture_2d; - @group(0) @binding(8) var outTex : texture_storage_2d; - - var texSize: vec2; - var fragCoord: vec2; - var coordIndex: i32; - var color_min: vec4; - var color_max: vec4; - var color_avg: vec4; - var re_proj_uv01: vec2; - var FLT_EPS:f32 = 5.960464478e-8; // 2^-24, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f) - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - texSize = textureDimensions(inTex).xy; - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - let frame = standUniform.frame; - coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); - - let oc = blendColor(); - preColorBuffer[coordIndex] = oc; - textureStore(outTex, fragCoord , oc); - } - - fn blendColor() -> vec4 - { - var preCoord = fragCoord; - var mixWeight = 1.0; - re_proj_uv01 = vec2(0.0); - var reProjectionCoord:vec2 = vec2(fragCoord); - //var jitterUVOffset = 0.5 * vec2(taaData.jitterX, -taaData.jitterY); - if(taaData.jitterFrameIndex > 0.5){ - var wPos = textureLoad(posTex, fragCoord, 0); - let ndc = taaData.preProjMatrix * (taaData.preViewMatrix * vec4(wPos.xyz, 1.0)); - re_proj_uv01 = vec2(ndc.x, -ndc.y) / ndc.w; - re_proj_uv01 = (re_proj_uv01 + 1.0) * 0.5; - - if(re_proj_uv01.x >= 0.0 && re_proj_uv01.x <= 1.0 && re_proj_uv01.y >= 0.0 && re_proj_uv01.y <= 1.0){ - mixWeight = taaData.blendFactor; - //reProjectionCoord = re_proj_uv01 + jitterUVOffset; - reProjectionCoord.x = re_proj_uv01.x * f32(texSize.x - 1); - reProjectionCoord.y = re_proj_uv01.y * f32(texSize.y - 1); - preCoord = vec2(reProjectionCoord); - }else{ - //outside of screen - mixWeight = 1.0; - } - } - - var curUV01 = vec2(fragCoord) / vec2(texSize - 1); - //curUV01 += jitterUVOffset; - - let curColor = textureSampleLevel(inTex, inTexSampler, curUV01, 0.0); - - let preIndex = preCoord.x + preCoord.y * i32(texSize.x); - var preColor = textureSampleLevel(preColorTex, preColorTexSampler, re_proj_uv01, 0.0); - - //minmax9(fragCoord); - minmax4(fragCoord); - - preColor = clip_aabb(color_min.xyz, color_max.xyz, color_avg, preColor); - var outColor = mix(preColor, curColor, mixWeight); - - return outColor; - } - - fn clampCoord(coord0:vec2) -> vec2{ - return clamp(coord0, vec2(0), vec2(texSize - 1)); - } - - fn minmax4(coord:vec2) { - let uv0 = clampCoord(vec2(coord.x - 1, coord.y)); - let uv1 = clampCoord(vec2(coord.x, coord.y - 1)); - let uv2 = clampCoord(vec2(coord.x, coord.y + 1)); - let uv3 = clampCoord(vec2(coord.x + 1, coord.y)); - - let c0 = textureLoad(inTex, uv0, 0); - let c1 = textureLoad(inTex, uv1, 0); - let c2 = textureLoad(inTex, uv2, 0); - let c3 = textureLoad(inTex, uv3, 0); - - color_min = min(c0, min(c1, min(c2, c3))); - color_max = max(c0, max(c1, max(c2, c3))); - color_avg = (c0 + c1 + c2 + c3) * 0.25; - } - - fn minmax9(coord:vec2) { - let uv0 = clampCoord(vec2(coord.x - 1, coord.y - 1)); - let uv1 = clampCoord(vec2(coord.x - 1, coord.y)); - let uv2 = clampCoord(vec2(coord.x - 1, coord.y + 1)); - let uv3 = clampCoord(vec2(coord.x, coord.y - 1)); - let uv4 = clampCoord(vec2(coord.x, coord.y)); - let uv5 = clampCoord(vec2(coord.x, coord.y + 1)); - let uv6 = clampCoord(vec2(coord.x + 1, coord.y - 1)); - let uv7 = clampCoord(vec2(coord.x + 1, coord.y)); - let uv8 = clampCoord(vec2(coord.x + 1, coord.y + 1)); - - let ctl = textureLoad(inTex, uv0, 0); - let ctc = textureLoad(inTex, uv1, 0); - let ctr = textureLoad(inTex, uv2, 0); - let cml = textureLoad(inTex, uv3, 0); - let cmc = textureLoad(inTex, uv4, 0); - let cmr = textureLoad(inTex, uv5, 0); - let cbl = textureLoad(inTex, uv6, 0); - let cbc = textureLoad(inTex, uv7, 0); - let cbr = textureLoad(inTex, uv8, 0); - - color_min = min(ctl, min(ctc, min(ctr, min(cml, min(cmc, min(cmr, min(cbl, min(cbc, cbr)))))))); - color_max = max(ctl, max(ctc, max(ctr, max(cml, max(cmc, max(cmr, max(cbl, max(cbc, cbr)))))))); - color_avg = (ctl + ctc + ctr + cml + cmc + cmr + cbl + cbc + cbr) / 9.0; - } - - fn clip_aabb(aabb_max:vec3, aabb_min:vec3, color_avg:vec4, input_texel:vec4) -> vec4 - { - var p_clip:vec3 = 0.5 * (aabb_max + aabb_min); - var e_clip:vec3 = 0.5 * (aabb_max - aabb_min) + FLT_EPS; - var v_clip:vec4 = input_texel - vec4(p_clip, color_avg.w); - var v_unit:vec3 = v_clip.xyz / e_clip; - var a_unit:vec3 = abs(v_unit); - var ma_unit:f32 = max(a_unit.x, max(a_unit.y, a_unit.z)); - - if (ma_unit > 1.0){ - return vec4(p_clip, color_avg.w) + v_clip / ma_unit; - }else{ - return input_texel; - } - } \ No newline at end of file diff --git a/src/assets/shader/core/base/Common_frag.ts b/src/assets/shader/core/base/Common_frag.ts new file mode 100644 index 00000000..f4667a0c --- /dev/null +++ b/src/assets/shader/core/base/Common_frag.ts @@ -0,0 +1,29 @@ +export let Common_frag: string = /*wgsl*/ ` + #include "GlobalUniform" + #include "FragmentVarying" + #include "ColorPassFragmentOutput" + #include "ShadingInput" + + var ORI_FragmentOutput: FragmentOutput; + var ORI_VertexVarying: FragmentVarying; + var ORI_ShadingInput: ShadingInput; + @fragment + fn FragMain( vertex_varying:FragmentVarying ) -> FragmentOutput { + ORI_VertexVarying = vertex_varying; + ORI_FragmentOutput.color = vec4(1.0, 0.0, 0.0, 1.0); + #if USE_WORLDPOS + ORI_FragmentOutput.worldPos = ORI_VertexVarying.vWorldPos; + #endif + #if USEGBUFFER + ORI_FragmentOutput.worldNormal = vec4(ORI_ShadingInput.Normal.rgb ,1.0); + ORI_FragmentOutput.material = vec4(0.0,1.0,0.0,0.0); + #endif + frag(); + #if USE_DEBUG + debugFragmentOut(); + #endif + + return ORI_FragmentOutput ; + } +` + diff --git a/src/assets/shader/core/base/Common_frag.wgsl b/src/assets/shader/core/base/Common_frag.wgsl deleted file mode 100644 index cf46db9c..00000000 --- a/src/assets/shader/core/base/Common_frag.wgsl +++ /dev/null @@ -1,26 +0,0 @@ -#include "GlobalUniform" -#include "FragmentVarying" -#include "ColorPassFragmentOutput" -#include "ShadingInput" - -var ORI_FragmentOutput: FragmentOutput; -var ORI_VertexVarying: FragmentVarying; -var ORI_ShadingInput: ShadingInput; -@fragment -fn FragMain( vertex_varying:FragmentVarying ) -> FragmentOutput { - ORI_VertexVarying = vertex_varying; - ORI_FragmentOutput.color = vec4(1.0, 0.0, 0.0, 1.0); - #if USE_WORLDPOS - ORI_FragmentOutput.worldPos = ORI_VertexVarying.vWorldPos; - #endif - #if USEGBUFFER - ORI_FragmentOutput.worldNormal = vec4(ORI_ShadingInput.Normal.rgb ,1.0); - ORI_FragmentOutput.material = vec4(0.0,1.0,0.0,0.0); - #endif - frag(); - #if USE_DEBUG - debugFragmentOut(); - #endif - - return ORI_FragmentOutput ; -} diff --git a/src/assets/shader/core/base/Common_vert.ts b/src/assets/shader/core/base/Common_vert.ts new file mode 100644 index 00000000..e456d252 --- /dev/null +++ b/src/assets/shader/core/base/Common_vert.ts @@ -0,0 +1,12 @@ +export let Common_vert: string = /*wgsl*/ ` + #include "WorldMatrixUniform" + #include "VertexAttributes_vert" + #include "GlobalUniform" + #include "Inline_vert" + @vertex + fn VertMain( vertex:VertexAttributes ) -> VertexOutput { + vertex_inline(vertex); + vert(vertex); + return ORI_VertexOut ; + } +` \ No newline at end of file diff --git a/src/assets/shader/core/base/Common_vert.wgsl b/src/assets/shader/core/base/Common_vert.wgsl deleted file mode 100644 index e5b674ae..00000000 --- a/src/assets/shader/core/base/Common_vert.wgsl +++ /dev/null @@ -1,11 +0,0 @@ -#include "WorldMatrixUniform" -#include "VertexAttributes_vert" -#include "GlobalUniform" -#include "Inline_vert" -@vertex -fn VertMain( vertex:VertexAttributes ) -> VertexOutput { - vertex_inline(vertex); - vert(vertex); - return ORI_VertexOut ; -} - diff --git a/src/assets/shader/core/common/BrdfLut_frag.ts b/src/assets/shader/core/common/BrdfLut_frag.ts new file mode 100644 index 00000000..392920ce --- /dev/null +++ b/src/assets/shader/core/common/BrdfLut_frag.ts @@ -0,0 +1,6 @@ +export let BrdfLut_frag: string = /*wgsl*/ ` + @group(1) @binding(auto) + var brdflutMapSampler: sampler; + @group(1) @binding(auto) + var brdflutMap: texture_2d; +` \ No newline at end of file diff --git a/src/assets/shader/core/common/BrdfLut_frag.wgsl b/src/assets/shader/core/common/BrdfLut_frag.wgsl deleted file mode 100644 index 6a10ea79..00000000 --- a/src/assets/shader/core/common/BrdfLut_frag.wgsl +++ /dev/null @@ -1,4 +0,0 @@ -@group(1) @binding(auto) -var brdflutMapSampler: sampler; -@group(1) @binding(auto) -var brdflutMap: texture_2d; \ No newline at end of file diff --git a/src/assets/shader/core/common/EnvMap_frag.ts b/src/assets/shader/core/common/EnvMap_frag.ts new file mode 100644 index 00000000..aa4e0067 --- /dev/null +++ b/src/assets/shader/core/common/EnvMap_frag.ts @@ -0,0 +1,10 @@ +export let EnvMap_frag: string = /*wgsl*/ ` + @group(1) @binding(auto) + var prefilterMapSampler: sampler; + @group(1) @binding(auto) + var prefilterMap: texture_cube; + @group(1) @binding(auto) + var envMapSampler: sampler; + @group(1) @binding(auto) + var envMap: texture_cube; +` \ No newline at end of file diff --git a/src/assets/shader/core/common/EnvMap_frag.wgsl b/src/assets/shader/core/common/EnvMap_frag.wgsl deleted file mode 100644 index a26b3e5e..00000000 --- a/src/assets/shader/core/common/EnvMap_frag.wgsl +++ /dev/null @@ -1,9 +0,0 @@ - -@group(1) @binding(auto) -var prefilterMapSampler: sampler; -@group(1) @binding(auto) -var prefilterMap: texture_cube; -@group(1) @binding(auto) -var envMapSampler: sampler; -@group(1) @binding(auto) -var envMap: texture_cube; \ No newline at end of file diff --git a/src/assets/shader/core/common/GlobalUniform.ts b/src/assets/shader/core/common/GlobalUniform.ts new file mode 100644 index 00000000..ab6026b7 --- /dev/null +++ b/src/assets/shader/core/common/GlobalUniform.ts @@ -0,0 +1,39 @@ +export let GlobalUniform: string = /*wgsl*/ ` + struct GlobalUniform { + projMat: mat4x4, + viewMat: mat4x4, + cameraWorldMatrix: mat4x4, + pvMatrixInv : mat4x4, + shadowMatrix: array,8>, + CameraPos: vec3, + + frame: f32, + time: f32, + delta: f32, + shadowBias: f32, + skyExposure: f32, + renderPassState:f32, + quadScale: f32, + hdrExposure: f32, + + renderState_left: i32, + renderState_right: i32, + renderState_split: f32, + + mouseX: f32, + mouseY: f32, + windowWidth: f32, + windowHeight: f32, + + near: f32, + far: f32, + + pointShadowBias: f32, + shadowMapSize: f32, + shadowSoft: f32, + }; + + @group(0) @binding(0) + var globalUniform: GlobalUniform; +` + diff --git a/src/assets/shader/core/common/GlobalUniform.wgsl b/src/assets/shader/core/common/GlobalUniform.wgsl deleted file mode 100644 index 8cd5e057..00000000 --- a/src/assets/shader/core/common/GlobalUniform.wgsl +++ /dev/null @@ -1,37 +0,0 @@ - - struct GlobalUniform { - projMat: mat4x4, - viewMat: mat4x4, - cameraWorldMatrix: mat4x4, - pvMatrixInv : mat4x4, - shadowMatrix: array,8>, - CameraPos: vec3, - - frame: f32, - time: f32, - delta: f32, - shadowBias: f32, - skyExposure: f32, - renderPassState:f32, - quadScale: f32, - hdrExposure: f32, - - renderState_left: i32, - renderState_right: i32, - renderState_split: f32, - - mouseX: f32, - mouseY: f32, - windowWidth: f32, - windowHeight: f32, - - near: f32, - far: f32, - - pointShadowBias: f32, - shadowMapSize: f32, - shadowSoft: f32, - }; - - @group(0) @binding(0) - var globalUniform: GlobalUniform; diff --git a/src/assets/shader/core/common/InstanceUniform.ts b/src/assets/shader/core/common/InstanceUniform.ts new file mode 100644 index 00000000..d5c876e8 --- /dev/null +++ b/src/assets/shader/core/common/InstanceUniform.ts @@ -0,0 +1,9 @@ +export let InstanceUniform: string = /*wgsl*/ ` + #if USE_INSTANCEDRAW + struct InstanceUniform { + matrixIDs : array + }; + @group(2) @binding(7) + var instanceDrawID : InstanceUniform; + #endif +` \ No newline at end of file diff --git a/src/assets/shader/core/common/InstanceUniform.wgsl b/src/assets/shader/core/common/InstanceUniform.wgsl deleted file mode 100644 index b3b943e4..00000000 --- a/src/assets/shader/core/common/InstanceUniform.wgsl +++ /dev/null @@ -1,7 +0,0 @@ -#if USE_INSTANCEDRAW - struct InstanceUniform { - matrixIDs : array - }; - @group(2) @binding(7) - var instanceDrawID : InstanceUniform; -#endif \ No newline at end of file diff --git a/src/assets/shader/materials/core/common/WorldMatrixUniform.wgsl b/src/assets/shader/core/common/WorldMatrixUniform.ts similarity index 71% rename from src/assets/shader/materials/core/common/WorldMatrixUniform.wgsl rename to src/assets/shader/core/common/WorldMatrixUniform.ts index 2f61b771..12368208 100644 --- a/src/assets/shader/materials/core/common/WorldMatrixUniform.wgsl +++ b/src/assets/shader/core/common/WorldMatrixUniform.ts @@ -1,9 +1,8 @@ - +export let WorldMatrixUniform: string = /*wgsl*/ ` struct Uniforms { matrix : array> }; @group(0) @binding(1) var models : Uniforms; - - +` diff --git a/src/assets/shader/core/common/WorldMatrixUniform.wgsl b/src/assets/shader/core/common/WorldMatrixUniform.wgsl deleted file mode 100644 index 2f61b771..00000000 --- a/src/assets/shader/core/common/WorldMatrixUniform.wgsl +++ /dev/null @@ -1,9 +0,0 @@ - - struct Uniforms { - matrix : array> - }; - - @group(0) @binding(1) - var models : Uniforms; - - diff --git a/src/assets/shader/core/inline/Inline_vert.ts b/src/assets/shader/core/inline/Inline_vert.ts new file mode 100644 index 00000000..734ff7ee --- /dev/null +++ b/src/assets/shader/core/inline/Inline_vert.ts @@ -0,0 +1,50 @@ +export let Inline_vert: string = /*wgsl*/ ` + #include "MathShader" + #include "FastMathShader" + #include "InstanceUniform" + + var ORI_MATRIX_P: mat4x4; + var ORI_MATRIX_V: mat4x4; + var ORI_MATRIX_M: mat4x4; + var ORI_MATRIX_PV: mat4x4; + var ORI_MATRIX_PVInv: mat4x4; + var ORI_MATRIX_World: mat4x4; + var ORI_CAMERAMATRIX: mat4x4; + var ORI_NORMALMATRIX: mat3x3; + var ORI_CameraWorldDir: vec3; + + var TIME: vec4; + var MOUSE: vec4; + var SCREEN: vec4; + + var ProjectionParams: vec4; + + fn vertex_inline(vertex:VertexAttributes){ + TIME.x = globalUniform.frame; + TIME.y = globalUniform.time; + TIME.z = globalUniform.delta; + + MOUSE.x = globalUniform.mouseX; + MOUSE.y = globalUniform.mouseY; + + SCREEN.x = globalUniform.windowWidth; + SCREEN.y = globalUniform.windowHeight; + + ProjectionParams.x = globalUniform.near; + ProjectionParams.y = globalUniform.far; + ProjectionParams.z = 1.0 + 1.0 / globalUniform.far; + + ORI_MATRIX_P = globalUniform.projMat ; + ORI_MATRIX_V = globalUniform.viewMat ; + ORI_MATRIX_PV = ORI_MATRIX_P * ORI_MATRIX_V ; + ORI_MATRIX_PVInv = globalUniform.pvMatrixInv ; + ORI_CAMERAMATRIX = globalUniform.cameraWorldMatrix ; + + ORI_MATRIX_M = models.matrix[u32(vertex.index)]; + + #if USE_INSTANCEDRAW + let modelID = instanceDrawID.matrixIDs[vertex.index]; + ORI_MATRIX_M = models.matrix[modelID]; + #endif + } +` diff --git a/src/assets/shader/core/inline/Inline_vert.wgsl b/src/assets/shader/core/inline/Inline_vert.wgsl deleted file mode 100644 index d3ce06cf..00000000 --- a/src/assets/shader/core/inline/Inline_vert.wgsl +++ /dev/null @@ -1,49 +0,0 @@ - - #include "MathShader" - #include "FastMathShader" - #include "InstanceUniform" - - var ORI_MATRIX_P: mat4x4; - var ORI_MATRIX_V: mat4x4; - var ORI_MATRIX_M: mat4x4; - var ORI_MATRIX_PV: mat4x4; - var ORI_MATRIX_PVInv: mat4x4; - var ORI_MATRIX_World: mat4x4; - var ORI_CAMERAMATRIX: mat4x4; - var ORI_NORMALMATRIX: mat3x3; - var ORI_CameraWorldDir: vec3; - - var TIME: vec4; - var MOUSE: vec4; - var SCREEN: vec4; - - var ProjectionParams: vec4; - - fn vertex_inline(vertex:VertexAttributes){ - TIME.x = globalUniform.frame; - TIME.y = globalUniform.time; - TIME.z = globalUniform.delta; - - MOUSE.x = globalUniform.mouseX; - MOUSE.y = globalUniform.mouseY; - - SCREEN.x = globalUniform.windowWidth; - SCREEN.y = globalUniform.windowHeight; - - ProjectionParams.x = globalUniform.near; - ProjectionParams.y = globalUniform.far; - ProjectionParams.z = 1.0 + 1.0 / globalUniform.far; - - ORI_MATRIX_P = globalUniform.projMat ; - ORI_MATRIX_V = globalUniform.viewMat ; - ORI_MATRIX_PV = ORI_MATRIX_P * ORI_MATRIX_V ; - ORI_MATRIX_PVInv = globalUniform.pvMatrixInv ; - ORI_CAMERAMATRIX = globalUniform.cameraWorldMatrix ; - - ORI_MATRIX_M = models.matrix[u32(vertex.index)]; - - #if USE_INSTANCEDRAW - let modelID = instanceDrawID.matrixIDs[vertex.index]; - ORI_MATRIX_M = models.matrix[modelID]; - #endif - } \ No newline at end of file diff --git a/src/assets/shader/core/pass/CastShadowPass_wgsl.ts b/src/assets/shader/core/pass/CastShadowPass_wgsl.ts deleted file mode 100644 index e35f12a9..00000000 --- a/src/assets/shader/core/pass/CastShadowPass_wgsl.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { SkeletonAnimation_shader } from "../../anim/SkeletonAnimation_shader"; -import { MorphTarget_shader } from "../../../../components/anim/morphAnim/MorphTarget_shader"; - -export class CastShadow { - public static shadowCastMap_vert_wgsl: string = /* wgsl */ ` - #include "WorldMatrixUniform" - #include "GlobalUniform" - - struct VertexOutput { - @location(0) fragUV: vec2, - @builtin(position) member: vec4 - }; - - #if USE_MORPHTARGETS - ${MorphTarget_shader.getMorphTargetShaderBinding(2, 1)} - #endif - - #if USE_SKELETON - ${SkeletonAnimation_shader.groupBindingAndFunctions(2, 1)} - #endif - - var worldMatrix: mat4x4; - - struct VertexAttributes{ - @builtin(instance_index) index : u32, - @location(0) position: vec3, - @location(1) normal: vec3, - @location(2) uv: vec2, - @location(3) TEXCOORD_1: vec2, - - #if USE_TANGENT - @location(4) TANGENT: vec4, - #if USE_SKELETON - @location(5) joints0: vec4, - @location(6) weights0: vec4, - #if USE_JOINT_VEC8 - @location(7) joints1: vec4, - @location(8) weights1: vec4, - #endif - #elseif USE_MORPHTARGETS - ${MorphTarget_shader.getMorphTargetAttr(5)} - #endif - #elseif USE_SKELETON - @location(4) joints0: vec4, - @location(5) weights0: vec4, - #if USE_JOINT_VEC8 - @location(6) joints1: vec4, - @location(7) weights1: vec4, - #endif - #elseif USE_MORPHTARGETS - ${MorphTarget_shader.getMorphTargetAttr(4)} - #endif - } - - @vertex - fn main(vertex:VertexAttributes) -> VertexOutput { - worldMatrix = models.matrix[vertex.index]; - let shadowMatrix: mat4x4 = globalUniform.projMat * globalUniform.viewMat ; - var vertexPosition = vertex.position.xyz; - var vertexNormal = vertex.normal.xyz; - - #if USE_MORPHTARGETS - ${MorphTarget_shader.getMorphTargetCalcVertex()} - #endif - - #if USE_SKELETON - #if USE_JOINT_VEC8 - worldMatrix *= getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); - #else - worldMatrix *= getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); - #endif - #endif - - var worldPos = worldMatrix * vec4(vertexPosition, 1.0) ; - var vPos = shadowMatrix * worldPos; - return VertexOutput(vertex.uv, vPos ); - } - `; - public static castPointShadowMap_vert_wgsl: string = /* wgsl */ ` - #include "WorldMatrixUniform" - #include "GlobalUniform" - - struct VertexOutput { - @location(0) fragUV: vec2, - @location(1) worldPos: vec3, - @builtin(position) member: vec4 - }; - - #if USE_MORPHTARGETS - ${MorphTarget_shader.getMorphTargetShaderBinding(2, 1)} - ##endif - - #if USE_SKELETON - ${SkeletonAnimation_shader.groupBindingAndFunctions(2, 1)} - #endif - - var worldMatrix: mat4x4; - - struct VertexAttributes{ - @builtin(instance_index) index : u32, - @location(0) position: vec3, - @location(1) normal: vec3, - @location(2) uv: vec2, - @location(3) TEXCOORD_1: vec2, - - #if USE_TANGENT - @location(4) TANGENT: vec4, - #if USE_SKELETON - @location(5) joints0: vec4, - @location(6) weights0: vec4, - #if USE_JOINT_VEC8 - @location(7) joints1: vec4, - @location(8) weights1: vec4, - #endif - #elseif USE_MORPHTARGETS - ${MorphTarget_shader.getMorphTargetAttr(5)} - #endif - #elseif USE_SKELETON - @location(4) joints0: vec4, - @location(5) weights0: vec4, - #if USE_JOINT_VEC8 - @location(6) joints1: vec4, - @location(7) weights1: vec4, - #endif - #elseif USE_MORPHTARGETS - ${MorphTarget_shader.getMorphTargetAttr(4)} - #endif - } - - @vertex - fn main(vertex:VertexAttributes) -> VertexOutput { - worldMatrix = models.matrix[vertex.index]; - let shadowMatrix: mat4x4 = globalUniform.projMat * globalUniform.viewMat ; - var vertexPosition = vertex.position.xyz; - - #if USE_MORPHTARGETS - ${MorphTarget_shader.getMorphTargetCalcVertex()} - #endif - - #if USE_SKELETON - #if USE_JOINT_VEC8 - worldMatrix *= getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); - #else - worldMatrix *= getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); - #endif - #endif - - var worldPos = worldMatrix * vec4(vertexPosition, 1.0) ; - var vPos = shadowMatrix * worldPos; - return VertexOutput(vertex.uv, worldPos.xyz , vPos ); - } - `; - public static shadowCastMap_frag_wgsl: string = /* wgsl */ ` - #if USE_ALPHACUT - @group(1) @binding(0) - var baseMapSampler: sampler; - @group(1) @binding(1) - var baseMap: texture_2d; - #endif - - struct FragmentOutput { - @location(0) o_Target: vec4, - @builtin(frag_depth) out_depth: f32 - }; - - struct MaterialUniform { - lightWorldPos: vec3, - cameraFar: f32, - }; - - @group(2) @binding(0) - var materialUniform: MaterialUniform; - - @fragment - fn main(@location(0) fragUV: vec2 , @location(1) worldPos:vec3 ) -> FragmentOutput { - var distance = length(worldPos.xyz - materialUniform.lightWorldPos ) ; - distance = distance / materialUniform.cameraFar ; - - #if USE_ALPHACUT - let Albedo = textureSample(baseMap,baseMapSampler,fragUV); - var fragOut:FragmentOutput; - if(Albedo.w > 0.5){ - fragOut = FragmentOutput(vec4(0.0),distance); - } - // if(Albedo.w > 0.5){ - // fragOut = FragmentOutput(vec4(0.0),distance); - // }else{ - // discard; - // } - return fragOut ; - #else - fragOut = FragmentOutput(vec4(0.0),distance); - #endif - } - `; -} diff --git a/src/assets/shader/core/pass/CastShadow_pass.ts b/src/assets/shader/core/pass/CastShadow_pass.ts new file mode 100644 index 00000000..6cddb701 --- /dev/null +++ b/src/assets/shader/core/pass/CastShadow_pass.ts @@ -0,0 +1,195 @@ +import { SkeletonAnimation_shader } from "../../anim/SkeletonAnimation_shader"; +import { MorphTarget_shader } from "../../../../components/anim/morphAnim/MorphTarget_shader"; +export let shadowCastMap_vert: string = /*wgsl*/ ` +#include "WorldMatrixUniform" +#include "GlobalUniform" + +struct VertexOutput { + @location(0) fragUV: vec2, + @builtin(position) member: vec4 +}; + +#if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetShaderBinding(2, 1)} +#endif + +#if USE_SKELETON + ${SkeletonAnimation_shader.groupBindingAndFunctions(2, 1)} +#endif + +var worldMatrix: mat4x4; + +struct VertexAttributes{ + @builtin(instance_index) index : u32, + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) uv: vec2, + @location(3) TEXCOORD_1: vec2, + + #if USE_TANGENT + @location(4) TANGENT: vec4, + #if USE_SKELETON + @location(5) joints0: vec4, + @location(6) weights0: vec4, + #if USE_JOINT_VEC8 + @location(7) joints1: vec4, + @location(8) weights1: vec4, + #endif + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(5)} + #endif + #elseif USE_SKELETON + @location(4) joints0: vec4, + @location(5) weights0: vec4, + #if USE_JOINT_VEC8 + @location(6) joints1: vec4, + @location(7) weights1: vec4, + #endif + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(4)} + #endif +} + +@vertex +fn main(vertex:VertexAttributes) -> VertexOutput { + worldMatrix = models.matrix[vertex.index]; + let shadowMatrix: mat4x4 = globalUniform.projMat * globalUniform.viewMat ; + var vertexPosition = vertex.position.xyz; + var vertexNormal = vertex.normal.xyz; + + #if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetCalcVertex()} + #endif + + #if USE_SKELETON + #if USE_JOINT_VEC8 + worldMatrix *= getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); + #else + worldMatrix *= getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); + #endif + #endif + + var worldPos = worldMatrix * vec4(vertexPosition, 1.0) ; + var vPos = shadowMatrix * worldPos; + return VertexOutput(vertex.uv, vPos ); +} +` + +export let castPointShadowMap_vert: string = /*wgsl*/ ` +#include "WorldMatrixUniform" +#include "GlobalUniform" + +struct VertexOutput { + @location(0) fragUV: vec2, + @location(1) worldPos: vec3, + @builtin(position) member: vec4 +}; + +#if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetShaderBinding(2, 1)} +##endif + +#if USE_SKELETON + ${SkeletonAnimation_shader.groupBindingAndFunctions(2, 1)} +#endif + +var worldMatrix: mat4x4; + +struct VertexAttributes{ + @builtin(instance_index) index : u32, + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) uv: vec2, + @location(3) TEXCOORD_1: vec2, + + #if USE_TANGENT + @location(4) TANGENT: vec4, + #if USE_SKELETON + @location(5) joints0: vec4, + @location(6) weights0: vec4, + #if USE_JOINT_VEC8 + @location(7) joints1: vec4, + @location(8) weights1: vec4, + #endif + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(5)} + #endif + #elseif USE_SKELETON + @location(4) joints0: vec4, + @location(5) weights0: vec4, + #if USE_JOINT_VEC8 + @location(6) joints1: vec4, + @location(7) weights1: vec4, + #endif + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(4)} + #endif +} + +@vertex +fn main(vertex:VertexAttributes) -> VertexOutput { + worldMatrix = models.matrix[vertex.index]; + let shadowMatrix: mat4x4 = globalUniform.projMat * globalUniform.viewMat ; + var vertexPosition = vertex.position.xyz; + + #if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetCalcVertex()} + #endif + + #if USE_SKELETON + #if USE_JOINT_VEC8 + worldMatrix *= getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); + #else + worldMatrix *= getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); + #endif + #endif + + var worldPos = worldMatrix * vec4(vertexPosition, 1.0) ; + var vPos = shadowMatrix * worldPos; + return VertexOutput(vertex.uv, worldPos.xyz , vPos ); +} +` + +export let shadowCastMap_frag: string = /*wgsl*/ ` +#if USE_ALPHACUT +@group(1) @binding(0) +var baseMapSampler: sampler; +@group(1) @binding(1) +var baseMap: texture_2d; +#endif + +struct FragmentOutput { + @location(0) o_Target: vec4, + @builtin(frag_depth) out_depth: f32 +}; + +struct MaterialUniform { +lightWorldPos: vec3, +cameraFar: f32, +}; + +@group(2) @binding(0) +var materialUniform: MaterialUniform; + +@fragment +fn main(@location(0) fragUV: vec2 , @location(1) worldPos:vec3 ) -> FragmentOutput { +var distance = length(worldPos.xyz - materialUniform.lightWorldPos ) ; +distance = distance / materialUniform.cameraFar ; + +#if USE_ALPHACUT + let Albedo = textureSample(baseMap,baseMapSampler,fragUV); + var fragOut:FragmentOutput; + if(Albedo.w > 0.5){ + fragOut = FragmentOutput(vec4(0.0),distance); + } +// if(Albedo.w > 0.5){ +// fragOut = FragmentOutput(vec4(0.0),distance); +// }else{ +// discard; +// } + return fragOut ; +#else + fragOut = FragmentOutput(vec4(0.0),distance); +#endif +} +` \ No newline at end of file diff --git a/src/assets/shader/core/pass/FrustumCullingShader_cs.wgsl b/src/assets/shader/core/pass/FrustumCulling_cs.ts similarity index 98% rename from src/assets/shader/core/pass/FrustumCullingShader_cs.wgsl rename to src/assets/shader/core/pass/FrustumCulling_cs.ts index 2ae4cfb2..c69488a8 100644 --- a/src/assets/shader/core/pass/FrustumCullingShader_cs.wgsl +++ b/src/assets/shader/core/pass/FrustumCulling_cs.ts @@ -1,3 +1,4 @@ +export let FrustumCulling_cs: string = /*wgsl*/ ` struct ConstUniform { projMat: mat4x4, viewMat: mat4x4, @@ -121,3 +122,6 @@ fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_inv outBuffer[id] = f32(isIn); } +` + + diff --git a/src/assets/shader/core/pass/GBuffer_shader.wgsl b/src/assets/shader/core/pass/GBuffer_pass.ts similarity index 97% rename from src/assets/shader/core/pass/GBuffer_shader.wgsl rename to src/assets/shader/core/pass/GBuffer_pass.ts index 7b1968a2..fcb55f91 100644 --- a/src/assets/shader/core/pass/GBuffer_shader.wgsl +++ b/src/assets/shader/core/pass/GBuffer_pass.ts @@ -1,3 +1,4 @@ +export let GBuffer_pass: string = /*wgsl*/ ` #include "Common_vert" #include "FragmentVarying" #include "GlobalUniform" @@ -69,3 +70,5 @@ fn convertToHDRRGB( color : vec3 , ins:f32 ) -> vec3 { hdrColor.b = color.b * pow(2.4, ins); return hdrColor; } +` + diff --git a/src/assets/shader/core/pass/SkyGBuffer_fs.wgsl b/src/assets/shader/core/pass/SkyGBuffer_pass.ts similarity index 96% rename from src/assets/shader/core/pass/SkyGBuffer_fs.wgsl rename to src/assets/shader/core/pass/SkyGBuffer_pass.ts index d18ac870..72add096 100644 --- a/src/assets/shader/core/pass/SkyGBuffer_fs.wgsl +++ b/src/assets/shader/core/pass/SkyGBuffer_pass.ts @@ -1,3 +1,4 @@ +export let SkyGBuffer_pass: string = /*wgsl*/ ` #include "GlobalUniform" struct uniformData { @@ -38,3 +39,6 @@ fn main(@location(0) fragUV: vec2, @location(1) vWorldPos: vec4, @loca let o_Position = vec4(vWorldPos.xyz,100000.0) ; return FragmentOutput(o_Position,o_Normal,o_Color); } +` + + diff --git a/src/assets/shader/core/pass/ZPassShader_cs.ts b/src/assets/shader/core/pass/ZPassShader_cs.ts new file mode 100644 index 00000000..25de3885 --- /dev/null +++ b/src/assets/shader/core/pass/ZPassShader_cs.ts @@ -0,0 +1,15 @@ +export let ZPassShader_cs: string = /*wgsl*/ ` + @group(0) @binding(0) var visibleBuffer: array; + @group(0) @binding(1) var zBufferTexture : texture_2d; + + @compute @workgroup_size(8, 8, 1) + fn CsMain( @builtin(global_invocation_id) globalInvocation_id : vec3 ) { + var fragCoord = vec2( globalInvocation_id.xy ); + let md = textureLoad(zBufferTexture,fragCoord,0); + + let meshID = i32(floor( md.w + 0.1 )); + if (meshID >= 0) { + visibleBuffer[meshID] = 1.0 ; + } + } +` diff --git a/src/assets/shader/core/pass/ZPassShader_cs.wgsl b/src/assets/shader/core/pass/ZPassShader_cs.wgsl deleted file mode 100644 index f43accc9..00000000 --- a/src/assets/shader/core/pass/ZPassShader_cs.wgsl +++ /dev/null @@ -1,13 +0,0 @@ -@group(0) @binding(0) var visibleBuffer: array; -@group(0) @binding(1) var zBufferTexture : texture_2d; - -@compute @workgroup_size(8, 8, 1) -fn CsMain( @builtin(global_invocation_id) globalInvocation_id : vec3 ) { - var fragCoord = vec2( globalInvocation_id.xy ); - let md = textureLoad(zBufferTexture,fragCoord,0); - - let meshID = i32(floor( md.w + 0.1 )); - if (meshID >= 0) { - visibleBuffer[meshID] = 1.0 ; - } -} diff --git a/src/assets/shader/core/pass/ZPassShader_fs.ts b/src/assets/shader/core/pass/ZPassShader_fs.ts new file mode 100644 index 00000000..a772b082 --- /dev/null +++ b/src/assets/shader/core/pass/ZPassShader_fs.ts @@ -0,0 +1,11 @@ +export let ZPassShader_fs: string = /*wgsl*/ ` + struct FragmentOutput { + @location(0) o_Target: vec4 + }; + + @fragment + fn main(@location(0) vID: f32, @location(1) vPos:vec3) -> FragmentOutput { + var op = vec4( vPos, vID); + return FragmentOutput(op); + } +` diff --git a/src/assets/shader/core/pass/ZPassShader_fs.wgsl b/src/assets/shader/core/pass/ZPassShader_fs.wgsl deleted file mode 100644 index 4d1d8ea9..00000000 --- a/src/assets/shader/core/pass/ZPassShader_fs.wgsl +++ /dev/null @@ -1,9 +0,0 @@ -struct FragmentOutput { - @location(0) o_Target: vec4 -}; - -@fragment -fn main(@location(0) vID: f32, @location(1) vPos:vec3) -> FragmentOutput { - var op = vec4( vPos, vID); - return FragmentOutput(op); -} diff --git a/src/assets/shader/core/pass/ZPassShader_vs.ts b/src/assets/shader/core/pass/ZPassShader_vs.ts index 54995fd2..2e1d8412 100644 --- a/src/assets/shader/core/pass/ZPassShader_vs.ts +++ b/src/assets/shader/core/pass/ZPassShader_vs.ts @@ -1,7 +1,7 @@ import { MorphTarget_shader } from "../../../../components/anim/morphAnim/MorphTarget_shader"; import { SkeletonAnimation_shader } from "../../anim/SkeletonAnimation_shader"; -export let ZPassShader_vs: string = /* wgsl */ ` +export let ZPassShader_vs: string = /*wgsl*/ ` #include "GlobalUniform" struct VertexOutput { @@ -96,4 +96,4 @@ export let ZPassShader_vs: string = /* wgsl */ ` let a = 1.0 / (globalUniform.near - globalUniform.far); return (globalUniform.near*globalUniform.far*a) / (depth + globalUniform.far * a) ; } -`; +` \ No newline at end of file diff --git a/src/assets/shader/core/struct/ColorPassFragmentOutput.ts b/src/assets/shader/core/struct/ColorPassFragmentOutput.ts new file mode 100644 index 00000000..6d754e99 --- /dev/null +++ b/src/assets/shader/core/struct/ColorPassFragmentOutput.ts @@ -0,0 +1,15 @@ + + +export let ColorPassFragmentOutput: string = /*wgsl*/ ` + struct FragmentOutput { + @location(0) color: vec4, + #if USE_WORLDPOS + @location(1) worldPos: vec4, + #endif + #if USEGBUFFER + @location(2) worldNormal: vec4, + @location(3) material: vec4, + #endif + // @builtin(frag_depth) out_depth: f32 + }; +` diff --git a/src/assets/shader/core/struct/ColorPassFragmentOutput.wgsl b/src/assets/shader/core/struct/ColorPassFragmentOutput.wgsl deleted file mode 100644 index b05fee10..00000000 --- a/src/assets/shader/core/struct/ColorPassFragmentOutput.wgsl +++ /dev/null @@ -1,11 +0,0 @@ -struct FragmentOutput { - @location(0) color: vec4, - #if USE_WORLDPOS - @location(1) worldPos: vec4, - #endif - #if USEGBUFFER - @location(2) worldNormal: vec4, - @location(3) material: vec4, - #endif - // @builtin(frag_depth) out_depth: f32 -}; diff --git a/src/assets/shader/core/struct/EmptyFrag_CommonFragment.ts b/src/assets/shader/core/struct/EmptyFrag_CommonFragment.ts new file mode 100644 index 00000000..dd02a234 --- /dev/null +++ b/src/assets/shader/core/struct/EmptyFrag_CommonFragment.ts @@ -0,0 +1,34 @@ +export let EmptyFrag_CommonFragment: string = /*wgsl*/ ` + #include "FragmentVarying" + #include "FragmentOutput.wgsl" + #include "GlobalUniform" + #include "Lit_Parmers.wgsl" + #include "PBRLit.wgsl" + + var ORI_FragmentOutput: FragmentOutput; + var ORI_VertexVarying: FragmentVarying; + var ORI_ShadingInput: ShadingStruct; + + @fragment + fn FragMain( vertex_varying:FragmentVarying ) -> FragmentOutput { + ORI_VertexVarying = vertex_varying; + ORI_FragmentOutput.color = vec4(1.0, 0.0, 0.0, 1.0); + + #if USE_WORLDPOS + ORI_FragmentOutput.worldPos = ORI_VertexVarying.vWorldPos; + #endif + #if USEGBUFFER + ORI_FragmentOutput.worldNormal = vec4(ORI_VertexVarying.vWorldNormal,1.0); + ORI_FragmentOutput.material = vec4(0.0,1.0,0.0,0.0); + #endif + + frag(); + + #if USE_DEBUG + debugFragmentOut(); + #endif + return ORI_FragmentOutput ; + } +` + + diff --git a/src/assets/shader/core/struct/EmptyFrag_CommonFragment.wgsl b/src/assets/shader/core/struct/EmptyFrag_CommonFragment.wgsl deleted file mode 100644 index e2b621e1..00000000 --- a/src/assets/shader/core/struct/EmptyFrag_CommonFragment.wgsl +++ /dev/null @@ -1,30 +0,0 @@ -#include "FragmentVarying" -#include "FragmentOutput.wgsl" -#include "GlobalUniform" -#include "Lit_Parmers.wgsl" -#include "PBRLit.wgsl" - -var ORI_FragmentOutput: FragmentOutput; -var ORI_VertexVarying: FragmentVarying; -var ORI_ShadingInput: ShadingStruct; - -@fragment -fn FragMain( vertex_varying:FragmentVarying ) -> FragmentOutput { - ORI_VertexVarying = vertex_varying; - ORI_FragmentOutput.color = vec4(1.0, 0.0, 0.0, 1.0); - - #if USE_WORLDPOS - ORI_FragmentOutput.worldPos = ORI_VertexVarying.vWorldPos; - #endif - #if USEGBUFFER - ORI_FragmentOutput.worldNormal = vec4(ORI_VertexVarying.vWorldNormal,1.0); - ORI_FragmentOutput.material = vec4(0.0,1.0,0.0,0.0); - #endif - - frag(); - - #if USE_DEBUG - debugFragmentOut(); - #endif - return ORI_FragmentOutput ; -} diff --git a/src/assets/shader/core/struct/EmptyFrag_FragmentOutput.ts b/src/assets/shader/core/struct/EmptyFrag_FragmentOutput.ts new file mode 100644 index 00000000..ed07e1eb --- /dev/null +++ b/src/assets/shader/core/struct/EmptyFrag_FragmentOutput.ts @@ -0,0 +1,15 @@ + + + +export let EmptyFrag_FragmentOutput: string = /*wgsl*/ ` + struct FragmentOutput { + @location(0) color: vec4, + #if USE_WORLDPOS + @location(1) worldPos: vec4, + #endif + #if USEGBUFFER + @location(2) worldNormal: vec4, + @location(3) material: vec4 + #endif + }; +` \ No newline at end of file diff --git a/src/assets/shader/core/struct/EmptyFrag_FragmentOutput.wgsl b/src/assets/shader/core/struct/EmptyFrag_FragmentOutput.wgsl deleted file mode 100644 index 3c306828..00000000 --- a/src/assets/shader/core/struct/EmptyFrag_FragmentOutput.wgsl +++ /dev/null @@ -1,10 +0,0 @@ -struct FragmentOutput { - @location(0) color: vec4, - #if USE_WORLDPOS - @location(1) worldPos: vec4, - #endif - #if USEGBUFFER - @location(2) worldNormal: vec4, - @location(3) material: vec4 - #endif -}; diff --git a/src/assets/shader/core/struct/FragmentVarying.ts b/src/assets/shader/core/struct/FragmentVarying.ts new file mode 100644 index 00000000..b3f36f66 --- /dev/null +++ b/src/assets/shader/core/struct/FragmentVarying.ts @@ -0,0 +1,23 @@ + +export let FragmentVarying: string = /*wgsl*/ ` + struct FragmentVarying { + @location(0) fragUV0: vec2, + @location(1) fragUV1: vec2, + @location(2) viewPosition: vec4, + @location(3) fragPosition: vec4, + @location(4) vWorldPos: vec4, + @location(5) vWorldNormal: vec3, + @location(6) vColor: vec4, + + #if USE_SHADOWMAPING + @location(7) vShadowPos: vec4, + #endif + + #if USE_TANGENT + @location(8) TANGENT: vec4, + #endif + + @builtin(front_facing) face: bool, + @builtin(position) fragCoord : vec4 + }; +` diff --git a/src/assets/shader/core/struct/FragmentVarying.wgsl b/src/assets/shader/core/struct/FragmentVarying.wgsl deleted file mode 100644 index 0d790ea4..00000000 --- a/src/assets/shader/core/struct/FragmentVarying.wgsl +++ /dev/null @@ -1,20 +0,0 @@ -struct FragmentVarying { - @location(0) fragUV0: vec2, - @location(1) fragUV1: vec2, - @location(2) viewPosition: vec4, - @location(3) fragPosition: vec4, - @location(4) vWorldPos: vec4, - @location(5) vWorldNormal: vec3, - @location(6) vColor: vec4, - - #if USE_SHADOWMAPING - @location(7) vShadowPos: vec4, - #endif - - #if USE_TANGENT - @location(8) TANGENT: vec4, - #endif - - @builtin(front_facing) face: bool, - @builtin(position) fragCoord : vec4 -}; diff --git a/src/assets/shader/core/struct/LightStruct.ts b/src/assets/shader/core/struct/LightStruct.ts new file mode 100644 index 00000000..b497bce1 --- /dev/null +++ b/src/assets/shader/core/struct/LightStruct.ts @@ -0,0 +1,108 @@ +export let LightStruct: string = /*wgsl*/ ` + struct LightData { + index:f32, + lightType:i32, + radius:f32, + linear:f32, + + position:vec3, + lightMatrixIndex:f32, + + direction:vec3, + quadratic:f32, + + lightColor:vec3, + intensity:f32, + + innerCutOff :f32, + outerCutOff:f32, + range :f32, + castShadow:i32, + + lightTangent:vec3, + ies:f32, + }; + + const PointLightType = 1; + const DirectLightType = 2; + const SpotLightType = 3; + + struct ClusterBox { + minPoint:vec4, + maxPoint:vec4 + }; + + struct LightIndex { + count:f32, + start:f32, + empty0:f32, + empty1:f32, + }; + + struct ClustersUniform { + clusterTileX:f32, + clusterTileY:f32, + clusterTileZ:f32, + numLights:f32, + maxNumLightsPerCluster:f32, + near:f32, + far:f32, + screenWidth:f32, + screenHeight:f32, + clusterPix:f32, + }; + + @group(2) @binding(1) + var lightBuffer: array; + @group(2) @binding(2) + var clustersUniform : ClustersUniform; + @group(2) @binding(3) + var lightAssignBuffer : array; + @group(2) @binding(4) + var assignTable : array; + #if DEBUG_CLUSTER + @group(2) @binding(5) + var clusterBuffer : array; + #endif + + fn getLight( index:i32 ) -> LightData { + let lightId = i32(lightAssignBuffer[index]); + var lightData = lightBuffer[lightId]; + return lightData ; + } + + fn linear01Depth(depth : f32) -> f32 { + return globalUniform.far * globalUniform.near / fma(depth, globalUniform.near-globalUniform.far, globalUniform.far); + } + + fn getTile(fragCoord : vec4) -> vec3 { + var coord = fragCoord ; + coord.z = linear01Depth(coord.z) ; + + let sliceScale = f32(clustersUniform.clusterTileZ) / log2(globalUniform.far / globalUniform.near); + let sliceBias = -(f32(clustersUniform.clusterTileZ) * log2(globalUniform.near) / log2(globalUniform.far / globalUniform.near)); + let zTile = u32(max(log2(coord.z) * sliceScale + sliceBias, 0.0)); + return vec3(u32(coord.x / (clustersUniform.screenWidth / f32(clustersUniform.clusterTileX))), + u32(coord.y / (clustersUniform.screenHeight / f32(clustersUniform.clusterTileY))), + zTile); + } + + fn getCluster(fragCoord : vec4) -> LightIndex { + let tile = getTile(fragCoord); + let id = tile.x + + tile.y * u32(clustersUniform.clusterTileX) + + tile.z * u32(clustersUniform.clusterTileX) * u32(clustersUniform.clusterTileY); + return assignTable[id]; + } + + #if DEBUG_CLUSTER + fn getClusterIndex(fragCoord : vec4) -> u32 { + let tile = getTile(fragCoord); + let id = tile.x + + tile.y * u32(clustersUniform.clusterTileX) + + tile.z * u32(clustersUniform.clusterTileX) * u32(clustersUniform.clusterTileY); + return id; + // return 0u ; + } + #endif +` diff --git a/src/assets/shader/core/struct/LightStruct.wgsl b/src/assets/shader/core/struct/LightStruct.wgsl deleted file mode 100644 index 9a53b8f4..00000000 --- a/src/assets/shader/core/struct/LightStruct.wgsl +++ /dev/null @@ -1,106 +0,0 @@ -struct LightData { - index:f32, - lightType:i32, - radius:f32, - linear:f32, - - position:vec3, - lightMatrixIndex:f32, - - direction:vec3, - quadratic:f32, - - lightColor:vec3, - intensity:f32, - - innerCutOff :f32, - outerCutOff:f32, - range :f32, - castShadow:i32, - - lightTangent:vec3, - ies:f32, -}; - -const PointLightType = 1; -const DirectLightType = 2; -const SpotLightType = 3; - -struct ClusterBox { - minPoint:vec4, - maxPoint:vec4 -}; - -struct LightIndex { - count:f32, - start:f32, - empty0:f32, - empty1:f32, -}; - -struct ClustersUniform { - clusterTileX:f32, - clusterTileY:f32, - clusterTileZ:f32, - numLights:f32, - maxNumLightsPerCluster:f32, - near:f32, - far:f32, - screenWidth:f32, - screenHeight:f32, - clusterPix:f32, -}; - -@group(2) @binding(1) -var lightBuffer: array; -@group(2) @binding(2) -var clustersUniform : ClustersUniform; -@group(2) @binding(3) -var lightAssignBuffer : array; -@group(2) @binding(4) -var assignTable : array; -#if DEBUG_CLUSTER - @group(2) @binding(5) - var clusterBuffer : array; -#endif - -fn getLight( index:i32 ) -> LightData { - let lightId = i32(lightAssignBuffer[index]); - var lightData = lightBuffer[lightId]; - return lightData ; -} - -fn linear01Depth(depth : f32) -> f32 { - return globalUniform.far * globalUniform.near / fma(depth, globalUniform.near-globalUniform.far, globalUniform.far); -} - -fn getTile(fragCoord : vec4) -> vec3 { - var coord = fragCoord ; - coord.z = linear01Depth(coord.z) ; - - let sliceScale = f32(clustersUniform.clusterTileZ) / log2(globalUniform.far / globalUniform.near); - let sliceBias = -(f32(clustersUniform.clusterTileZ) * log2(globalUniform.near) / log2(globalUniform.far / globalUniform.near)); - let zTile = u32(max(log2(coord.z) * sliceScale + sliceBias, 0.0)); - return vec3(u32(coord.x / (clustersUniform.screenWidth / f32(clustersUniform.clusterTileX))), - u32(coord.y / (clustersUniform.screenHeight / f32(clustersUniform.clusterTileY))), - zTile); -} - -fn getCluster(fragCoord : vec4) -> LightIndex { - let tile = getTile(fragCoord); - let id = tile.x + - tile.y * u32(clustersUniform.clusterTileX) + - tile.z * u32(clustersUniform.clusterTileX) * u32(clustersUniform.clusterTileY); - return assignTable[id]; -} - -#if DEBUG_CLUSTER - fn getClusterIndex(fragCoord : vec4) -> u32 { - let tile = getTile(fragCoord); - let id = tile.x + - tile.y * u32(clustersUniform.clusterTileX) + - tile.z * u32(clustersUniform.clusterTileX) * u32(clustersUniform.clusterTileY); - return id; - // return 0u ; - } -#endif diff --git a/src/assets/shader/core/struct/LightStructFrag.ts b/src/assets/shader/core/struct/LightStructFrag.ts index 2abf2f23..97553296 100644 --- a/src/assets/shader/core/struct/LightStructFrag.ts +++ b/src/assets/shader/core/struct/LightStructFrag.ts @@ -1,9 +1,4 @@ - -/** - * @internal - */ - -export let LightStructFrag: string = /* wgsl */ ` +export let LightStructFrag: string = /*wgsl*/ ` struct LightData { index:f32, lightType:i32, @@ -39,10 +34,10 @@ export let LightStructFrag: string = /* wgsl */ ` struct LightIndex { - count:f32, - start:f32, - empty0:f32, - empty1:f32, + count:f32, + start:f32, + empty0:f32, + empty1:f32, }; struct ClustersUniform{ @@ -89,16 +84,16 @@ export let LightStructFrag: string = /* wgsl */ ` let sliceBias = -(f32(clustersUniform.clusterTileZ) * log2(globalUniform.near) / log2(globalUniform.far / globalUniform.near)); let zTile = u32(max(log2(coord.z) * sliceScale + sliceBias, 0.0)); return vec3(u32(coord.x / (clustersUniform.screenWidth / f32(clustersUniform.clusterTileX))), - u32(coord.y / (clustersUniform.screenHeight / f32(clustersUniform.clusterTileY))), - zTile); + u32(coord.y / (clustersUniform.screenHeight / f32(clustersUniform.clusterTileY))), + zTile); } fn getCluster(fragCoord : vec4) -> LightIndex { - let tile = getTile(fragCoord); - let id = tile.x + + let tile = getTile(fragCoord); + let id = tile.x + tile.y * u32(clustersUniform.clusterTileX) + tile.z * u32(clustersUniform.clusterTileX) * u32(clustersUniform.clusterTileY); - return assignTable[id]; + return assignTable[id]; } #if DEBUG_CLUSTER @@ -111,4 +106,4 @@ export let LightStructFrag: string = /* wgsl */ ` // return 0u ; } #endif - `; +` \ No newline at end of file diff --git a/src/assets/shader/core/struct/ShadingInput.ts b/src/assets/shader/core/struct/ShadingInput.ts new file mode 100644 index 00000000..e9bcc5e2 --- /dev/null +++ b/src/assets/shader/core/struct/ShadingInput.ts @@ -0,0 +1,20 @@ +export let ShadingInput: string = /*wgsl*/ ` + struct ShadingInput{ + BaseColor:vec4, + Roughness:f32, + Metallic:f32, + Specular:f32, + EmissiveColor:vec4, + SurfaceColor:vec4, + Normal:vec3, + Tangent:vec4, + WorldPositionOffset:vec3, + AmbientOcclusion:f32, + PixelDepthOffset:f32, + + Opacity:f32, + OpacityMask:f32, + + Refraction:f32, + } +` diff --git a/src/assets/shader/core/struct/ShadingInput.wgsl b/src/assets/shader/core/struct/ShadingInput.wgsl deleted file mode 100644 index 725b8078..00000000 --- a/src/assets/shader/core/struct/ShadingInput.wgsl +++ /dev/null @@ -1,18 +0,0 @@ -struct ShadingInput{ - BaseColor:vec4, - Roughness:f32, - Metallic:f32, - Specular:f32, - EmissiveColor:vec4, - SurfaceColor:vec4, - Normal:vec3, - Tangent:vec4, - WorldPositionOffset:vec3, - AmbientOcclusion:f32, - PixelDepthOffset:f32, - - Opacity:f32, - OpacityMask:f32, - - Refraction:f32, -} diff --git a/src/assets/shader/core/struct/VertexAttributes.ts b/src/assets/shader/core/struct/VertexAttributes.ts index 91d66388..03329e78 100644 --- a/src/assets/shader/core/struct/VertexAttributes.ts +++ b/src/assets/shader/core/struct/VertexAttributes.ts @@ -1,114 +1,105 @@ import { SkeletonAnimation_shader } from "../../anim/SkeletonAnimation_shader"; import { MorphTarget_shader } from "../../../../components/anim/morphAnim/MorphTarget_shader"; - -export let VertexAttributes: string = /* wgsl */ ` - - #if USE_MORPHTARGETS - ${MorphTarget_shader.getMorphTargetShaderBinding(3, 0)} - #endif - +export let VertexAttributes: string = /*wgsl*/ ` + #if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetShaderBinding(3, 0)} + #endif + + #if USE_SKELETON + ${SkeletonAnimation_shader.groupBindingAndFunctions(3, 0)} + #endif + + struct VertexAttributes{ + @builtin(instance_index) index : u32, + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) uv: vec2, + @location(3) TEXCOORD_1: vec2, + + #if USE_TANGENT + @location(4) TANGENT: vec4, #if USE_SKELETON - ${SkeletonAnimation_shader.groupBindingAndFunctions(3, 0)} + @location(5) joints0: vec4, + @location(6) weights0: vec4, + #if USE_JOINT_VEC8 + @location(7) joints1: vec4, + @location(8) weights1: vec4, #endif - - struct VertexAttributes{ - @builtin(instance_index) index : u32, - @location(0) position: vec3, - @location(1) normal: vec3, - @location(2) uv: vec2, - @location(3) TEXCOORD_1: vec2, - - #if USE_TANGENT - @location(4) TANGENT: vec4, - #if USE_SKELETON - @location(5) joints0: vec4, - @location(6) weights0: vec4, - #if USE_JOINT_VEC8 - @location(7) joints1: vec4, - @location(8) weights1: vec4, - #endif - #elseif USE_MORPHTARGETS - ${MorphTarget_shader.getMorphTargetAttr(5)} - #endif - #elseif USE_SKELETON - @location(4) joints0: vec4, - @location(5) weights0: vec4, - #if USE_JOINT_VEC8 - @location(6) joints1: vec4, - @location(7) weights1: vec4, - #endif - #elseif USE_MORPHTARGETS - ${MorphTarget_shader.getMorphTargetAttr(4)} - #endif - } - - struct VertexOutput { - @location(0) varying_UV0: vec2, - @location(1) varying_UV1: vec2, - @location(2) varying_ViewPos: vec4, - @location(3) varying_Clip: vec4, - @location(4) varying_WPos: vec4, - @location(5) varying_WNormal: vec3, - @location(6) varying_Color: vec4, - - #if USE_SHADOWMAPING - @location(7) varying_ShadowPos: vec4, - #endif - - #if USE_TANGENT - @location(8) varying_Tangent: vec4, - #endif - - @builtin(position) member: vec4 - }; - - var ORI_VertexOut: VertexOutput ; - - fn ORI_Vert(vertex:VertexAttributes){ - var vertexPosition = vertex.position; - var vertexNormal = vertex.normal; - - #if USE_MORPHTARGETS - ${MorphTarget_shader.getMorphTargetCalcVertex()} - #endif - - #if USE_SKELETON - #if USE_JOINT_VEC8 - let skeletonNormal = getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); - ORI_MATRIX_M *= skeletonNormal ; - // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; - #else - let skeletonNormal = getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); - ORI_MATRIX_M *= skeletonNormal ; - // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; - #endif - #endif - - // #if USE_SHADOWMAPING - // var shadowPos = globalUniform.shadowMatrix * ORI_MATRIX_M * vec4(vertex.position.xyz, 1.0) ; - // ORI_VertexOut.varying_ShadowPos = shadowPos ; - // #endif - - #if USE_TANGENT - ORI_VertexOut.varying_Tangent = vertex.TANGENT ; - #endif - - ORI_NORMALMATRIX = transpose(inverse( mat3x3(ORI_MATRIX_M[0].xyz,ORI_MATRIX_M[1].xyz,ORI_MATRIX_M[2].xyz) )); - - var worldPos = (ORI_MATRIX_M * vec4(vertexPosition.xyz, 1.0)); - var viewPosition = ORI_MATRIX_V * worldPos; - var clipPosition = ORI_MATRIX_P * viewPosition ; - - ORI_CameraWorldDir = normalize(ORI_CAMERAMATRIX[3].xyz - worldPos.xyz) ; - - ORI_VertexOut.varying_UV0 = vertex.uv.xy ; - ORI_VertexOut.varying_UV1 = vertex.TEXCOORD_1.xy; - ORI_VertexOut.varying_ViewPos = viewPosition / viewPosition.w; - ORI_VertexOut.varying_Clip = clipPosition ; - ORI_VertexOut.varying_WPos = worldPos ; - ORI_VertexOut.varying_WPos.w = f32(vertex.index); - ORI_VertexOut.varying_WNormal = normalize(ORI_NORMALMATRIX * vertexNormal.xyz) ; - ORI_VertexOut.member = clipPosition ; - } - `; \ No newline at end of file + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(5)} + #endif + #elseif USE_SKELETON + @location(4) joints0: vec4, + @location(5) weights0: vec4, + #if USE_JOINT_VEC8 + @location(6) joints1: vec4, + @location(7) weights1: vec4, + #endif + #elseif USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetAttr(4)} + #endif + } + + struct VertexOutput { + @location(0) varying_UV0: vec2, + @location(1) varying_UV1: vec2, + @location(2) varying_ViewPos: vec4, + @location(3) varying_Clip: vec4, + @location(4) varying_WPos: vec4, + @location(5) varying_WNormal: vec3, + @location(6) varying_Color: vec4, + + #if USE_SHADOWMAPING + @location(7) varying_ShadowPos: vec4, + #endif + + #if USE_TANGENT + @location(8) varying_Tangent: vec4, + #endif + + @builtin(position) member: vec4 + }; + + var ORI_VertexOut: VertexOutput ; + + fn ORI_Vert(vertex:VertexAttributes){ + var vertexPosition = vertex.position; + var vertexNormal = vertex.normal; + + #if USE_MORPHTARGETS + ${MorphTarget_shader.getMorphTargetCalcVertex()} + #endif + + #if USE_SKELETON + #if USE_JOINT_VEC8 + let skeletonNormal = getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); + ORI_MATRIX_M *= skeletonNormal ; + #else + let skeletonNormal = getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); + ORI_MATRIX_M *= skeletonNormal ; + #endif + #endif + + #if USE_TANGENT + ORI_VertexOut.varying_Tangent = vertex.TANGENT ; + #endif + + ORI_NORMALMATRIX = transpose(inverse( mat3x3(ORI_MATRIX_M[0].xyz,ORI_MATRIX_M[1].xyz,ORI_MATRIX_M[2].xyz) )); + + var worldPos = (ORI_MATRIX_M * vec4(vertexPosition.xyz, 1.0)); + var viewPosition = ORI_MATRIX_V * worldPos; + var clipPosition = ORI_MATRIX_P * viewPosition ; + + ORI_CameraWorldDir = normalize(ORI_CAMERAMATRIX[3].xyz - worldPos.xyz) ; + + ORI_VertexOut.varying_UV0 = vertex.uv.xy ; + ORI_VertexOut.varying_UV1 = vertex.TEXCOORD_1.xy; + ORI_VertexOut.varying_ViewPos = viewPosition / viewPosition.w; + ORI_VertexOut.varying_Clip = clipPosition ; + ORI_VertexOut.varying_WPos = worldPos ; + ORI_VertexOut.varying_WPos.w = f32(vertex.index); + ORI_VertexOut.varying_WNormal = normalize(ORI_NORMALMATRIX * vertexNormal.xyz) ; + ORI_VertexOut.member = clipPosition ; + } +` \ No newline at end of file diff --git a/src/assets/shader/graphic/Graphic3DShader_fs.ts b/src/assets/shader/graphic/Graphic3DShader_fs.ts new file mode 100644 index 00000000..518f25f3 --- /dev/null +++ b/src/assets/shader/graphic/Graphic3DShader_fs.ts @@ -0,0 +1,35 @@ + + + +export let Graphic3DShader_fs: string = /*wgsl*/ ` + struct FragmentOutput { + @location(0) color: vec4, + // #if USE_WORLDPOS + @location(1) worldPos: vec4, + // #endif + // #if USEGBUFFER + @location(2) worldNormal: vec4, + @location(3) material: vec4 + // #endif + }; + + @fragment + fn main( + @location(0) vWorldPos: vec4, + @location(1) varying_Color: vec4, + ) -> FragmentOutput { + var result: FragmentOutput; + + // #if USE_WORLDPOS + result.worldPos = vWorldPos; + // #endif + + // #if USEGBUFFER + // result.worldNormal = vec4(0.0, 0.0, 0.0, 1.0); + result.material = vec4(0.0, 1.0, 0.0, 0.0); + // #endif + + result.color = varying_Color; + return result; + } +` \ No newline at end of file diff --git a/src/assets/shader/graphic/Graphic3DShader_fs.wgsl b/src/assets/shader/graphic/Graphic3DShader_fs.wgsl deleted file mode 100644 index f0b039eb..00000000 --- a/src/assets/shader/graphic/Graphic3DShader_fs.wgsl +++ /dev/null @@ -1,30 +0,0 @@ -struct FragmentOutput { - @location(0) color: vec4, - // #if USE_WORLDPOS - @location(1) worldPos: vec4, - // #endif - // #if USEGBUFFER - @location(2) worldNormal: vec4, - @location(3) material: vec4 - // #endif -}; - -@fragment -fn main( - @location(0) vWorldPos: vec4, - @location(1) varying_Color: vec4, -) -> FragmentOutput { - var result: FragmentOutput; - - // #if USE_WORLDPOS - result.worldPos = vWorldPos; - // #endif - - // #if USEGBUFFER - // result.worldNormal = vec4(0.0, 0.0, 0.0, 1.0); - result.material = vec4(0.0, 1.0, 0.0, 0.0); - // #endif - - result.color = varying_Color; - return result; -} diff --git a/src/assets/shader/graphic/Graphic3DShader_vs.ts b/src/assets/shader/graphic/Graphic3DShader_vs.ts new file mode 100644 index 00000000..c26c24f2 --- /dev/null +++ b/src/assets/shader/graphic/Graphic3DShader_vs.ts @@ -0,0 +1,29 @@ +export let Graphic3DShader_vs: string = /*wgsl*/ ` + #include "WorldMatrixUniform" + #include "GlobalUniform" + + struct VertexAttributes { + @location(0) position: vec4, + @location(1) color: vec4, + } + + struct VertexOutput { + @location(0) varying_WPos: vec4, + @location(1) varying_Color: vec4, + @builtin(position) member: vec4 + }; + + @vertex + fn main( vertex:VertexAttributes ) -> VertexOutput { + var worldMatrix = models.matrix[u32(vertex.position.w)]; + var worldPos = (worldMatrix * vec4(vertex.position.xyz, 1.0)); + var viewPosition = ((globalUniform.viewMat) * worldPos); + var clipPosition = globalUniform.projMat * viewPosition; + + var ORI_VertexOut: VertexOutput; + ORI_VertexOut.varying_WPos = worldPos; + ORI_VertexOut.varying_Color = vertex.color; + ORI_VertexOut.member = clipPosition; + return ORI_VertexOut; + } +` \ No newline at end of file diff --git a/src/assets/shader/graphic/Graphic3DShader_vs.wgsl b/src/assets/shader/graphic/Graphic3DShader_vs.wgsl deleted file mode 100644 index 336abcde..00000000 --- a/src/assets/shader/graphic/Graphic3DShader_vs.wgsl +++ /dev/null @@ -1,27 +0,0 @@ -#include "WorldMatrixUniform" -#include "GlobalUniform" - -struct VertexAttributes { - @location(0) position: vec4, - @location(1) color: vec4, -} - -struct VertexOutput { - @location(0) varying_WPos: vec4, - @location(1) varying_Color: vec4, - @builtin(position) member: vec4 -}; - -@vertex -fn main( vertex:VertexAttributes ) -> VertexOutput { - var worldMatrix = models.matrix[u32(vertex.position.w)]; - var worldPos = (worldMatrix * vec4(vertex.position.xyz, 1.0)); - var viewPosition = ((globalUniform.viewMat) * worldPos); - var clipPosition = globalUniform.projMat * viewPosition; - - var ORI_VertexOut: VertexOutput; - ORI_VertexOut.varying_WPos = worldPos; - ORI_VertexOut.varying_Color = vertex.color; - ORI_VertexOut.member = clipPosition; - return ORI_VertexOut; -} diff --git a/src/assets/shader/lighting/BRDF_frag.wgsl b/src/assets/shader/lighting/BRDF_frag.ts similarity index 99% rename from src/assets/shader/lighting/BRDF_frag.wgsl rename to src/assets/shader/lighting/BRDF_frag.ts index 365208d0..0981f1f6 100644 --- a/src/assets/shader/lighting/BRDF_frag.wgsl +++ b/src/assets/shader/lighting/BRDF_frag.ts @@ -1,5 +1,5 @@ - - #include "Clearcoat_frag" +export let BRDF_frag: string = /*wgsl*/ ` +#include "Clearcoat_frag" #include "EnvMap_frag" #include "BrdfLut_frag" @@ -289,7 +289,6 @@ return layer * vec3((Fd + Fr * (1.0 - Fc)) * (1.0 - Fc) + Frc) * ( 0.5 + NoL * 0.5 ) ; } - fn approximate_coating(base:vec3 , clearColor: vec3, n:vec3 , v:vec3 , light:LightData ) -> vec3 { let clearcoatRoughnessFactor = clamp(materialUniform.clearcoatRoughnessFactor,0.084,1.0); var clearcoatAlpha = clearcoatRoughnessFactor * clearcoatRoughnessFactor + fragData.ClearcoatRoughness; @@ -312,3 +311,5 @@ // return clearcoat_brdf;+ fragData.ClearcoatRoughness return mix(base,clearcoat_brdf,materialUniform.clearcoatWeight ) ; } +` + diff --git a/src/assets/shader/lighting/BxDF_frag.ts b/src/assets/shader/lighting/BxDF_frag.ts new file mode 100644 index 00000000..838de425 --- /dev/null +++ b/src/assets/shader/lighting/BxDF_frag.ts @@ -0,0 +1,163 @@ +export let BxDF_frag: string = /*wgsl*/ ` + #include "Clearcoat_frag" + #include "BRDF_frag" + #include "MathShader" + #include "FastMathShader" + #include "Common_frag" + #include "GlobalUniform" + + #include "PhysicMaterialUniform_frag" + #include "NormalMap_frag" + #include "LightingFunction_frag" + #include "Irradiance_frag" + #include "ColorUtil_frag" + #include "BxdfDebug_frag" + + + + //ORI_ShadingInput + fn initFragData() { + fragData.Albedo = ORI_ShadingInput.BaseColor ; + fragData.Ao = ORI_ShadingInput.AmbientOcclusion ; + fragData.Roughness = max(ORI_ShadingInput.Roughness,0.003) ; + fragData.Metallic = ORI_ShadingInput.Metallic ; + fragData.Emissive = ORI_ShadingInput.EmissiveColor.rgb ; + fragData.N = ORI_ShadingInput.Normal; + fragData.V = normalize(globalUniform.cameraWorldMatrix[3].xyz - ORI_VertexVarying.vWorldPos.xyz) ; + + let R = 2.0 * dot( fragData.V , fragData.N ) * fragData.N - fragData.V ; + fragData.R = R;//reflect( fragData.V , -fragData.N ) ; + + fragData.NoV = saturate(dot(fragData.N, fragData.V)) ; + + fragData.F0 = mix(vec3(0.04), fragData.Albedo.rgb, fragData.Metallic); + + fragData.F = computeFresnelSchlick(fragData.NoV, fragData.F0); + fragData.KD = vec3(fragData.F) ; + fragData.KS = vec3(0.0) ; + + fragData.Indirect = 0.0 ; + fragData.Reflectance = 1.0 ; + + fragData.DiffuseColor = fragData.Albedo.rgb * (1.0 - fragData.Metallic); + fragData.SpecularColor = mix(vec3(1.0), fragData.Albedo.rgb, fragData.Metallic); + + fragData.ClearcoatRoughness = 0.0 ; + #if USE_CLEARCOAT_ROUGHNESS + fragData.ClearcoatRoughness = getClearcoatRoughnees() ; + #endif + } + + fn BxDFShading(){ + initFragData(); + + var color = vec3(0.0); + + let lightIndex = getCluster(ORI_VertexVarying.fragCoord); + let start = max(lightIndex.start, 0.0); + let count = max(lightIndex.count, 0.0); + let end = max(start + count , 0.0); + for(var i:i32 = i32(start) ; i < i32(end); i += 1 ) + { + let light = getLight(i32(i)); + + switch (light.lightType) { + case PointLightType: { + color += pointLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; + } + case DirectLightType: { + color += directLighting( fragData.Albedo.rgb ,fragData.N,fragData.V,fragData.Roughness , light , globalUniform.shadowBias) ; + } + case SpotLightType: { + color += spotLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; + } + default: { + } + } + } + + var kS = FresnelSchlickRoughness(fragData.NoV, fragData.F0, fragData.Roughness ); + var kD = vec3(1.0) - kS; + kD = kD * (1.0 - fragData.Metallic); + kD = max(vec3(0.04),kD) ; + + let MAX_REFLECTION_LOD = f32(textureNumLevels(prefilterMap)) ; + var diffuseIrradiance: vec3 = vec3(0.0);// + + #if USE_SKYLIGHT + var prefilterTex: vec3 = globalUniform.skyExposure * (textureSampleLevel(prefilterMap, prefilterMapSampler, fragData.N.xyz, 8.0 ).rgb); + prefilterTex = LinearToGammaSpace(prefilterTex); + var skyLight = kD * fragData.Albedo.xyz * prefilterTex; + // color += skyLight ; + #endif + + var envRef = kS * approximateSpecularIBL( fragData.SpecularColor , fragData.Roughness , fragData.R ) ;//* (materialUniform.ior - 1.0) ; + + var irradiance = diffuseIrradiance ; + #if USEGI + irradiance += getIrradiance().rgb ; + #else + irradiance += globalUniform.skyExposure * LinearToGammaSpace(textureSampleLevel(prefilterMap, prefilterMapSampler, fragData.N.xyz, 0.8 * (MAX_REFLECTION_LOD) ).rgb); + #endif + + fragData.Irradiance = irradiance; + + + var diffuseIBL = fragData.Albedo.rgb * irradiance.rgb ; + // var ambientIBL = kD * fragData.Albedo.rgb * fragData.Ao; + fragData.EnvColor = materialUniform.envIntensity * envRef ; + + ORI_FragmentOutput.color = vec4(0.0); + + #if USE_CLEARCOAT + for(var i:i32 = i32(start) ; i < i32(end); i = i + 1 ) + { + let light = getLight(i); + switch (light.lightType) { + case PointLightType: { + color += pointLighting(fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; + } + case DirectLightType: { + color += directLighting( fragData.Albedo.rgb ,fragData.N,fragData.V,fragData.Roughness , light , globalUniform.shadowBias) ; + } + case SpotLightType: { + color += spotLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; + } + default: { + } + } + } + #endif + + // // Using stripped down, 'pure log', formula. Parameterized by grey points and dynamic range covered. + #if USEGBUFFER + var normal_rgba8unorm = (ORI_VertexVarying.vWorldNormal + 1.0) * 0.5; + normal_rgba8unorm = clamp(normal_rgba8unorm, vec3(0.0), vec3(1.0)); + #endif + + // ORI_FragmentOutput.color = vec4(ORI_FragmentOutput.color.xyz,fragData.Albedo.a) ; + #if USE_WORLDPOS + ORI_FragmentOutput.worldPos = vec4(ORI_VertexVarying.vWorldPos.xyzw); + #endif + + #if USEGBUFFER + ORI_FragmentOutput.worldNormal = vec4(normal_rgba8unorm,1.0); + ORI_FragmentOutput.material = vec4(1.0,fragData.Roughness,fragData.Metallic,1.0); + #endif + + // color = pow(color.rgb,vec3(2.0)); + + color += diffuseIBL ; + // color += ambientIBL ; + color += fragData.EnvColor * fragData.Ao ; + color += fragData.Emissive.xyz ; + + //-1 1 + // color = diffuseIBL ; + ORI_FragmentOutput.color = vec4(color.rgb,fragData.Albedo.a) ; + + // let gamma = 2.0 ; + // ORI_FragmentOutput.color = pow(ORI_FragmentOutput.color,vec4(gamma,gamma,gamma,1.0)); + } + ` + diff --git a/src/assets/shader/lighting/BxDF_frag.wgsl b/src/assets/shader/lighting/BxDF_frag.wgsl deleted file mode 100644 index 684fcc20..00000000 --- a/src/assets/shader/lighting/BxDF_frag.wgsl +++ /dev/null @@ -1,161 +0,0 @@ - - #include "Clearcoat_frag" - #include "BRDF_frag" - #include "MathShader" - #include "FastMathShader" - #include "Common_frag" - #include "GlobalUniform" - - #include "PhysicMaterialUniform_frag" - #include "NormalMap_frag" - #include "LightingFunction_frag" - #include "Irradiance_frag" - #include "ColorUtil_frag" - #include "BxdfDebug_frag" - - - - //ORI_ShadingInput - fn initFragData() { - fragData.Albedo = ORI_ShadingInput.BaseColor ; - fragData.Ao = ORI_ShadingInput.AmbientOcclusion ; - fragData.Roughness = max(ORI_ShadingInput.Roughness,0.003) ; - fragData.Metallic = ORI_ShadingInput.Metallic ; - fragData.Emissive = ORI_ShadingInput.EmissiveColor.rgb ; - fragData.N = ORI_ShadingInput.Normal; - fragData.V = normalize(globalUniform.cameraWorldMatrix[3].xyz - ORI_VertexVarying.vWorldPos.xyz) ; - - let R = 2.0 * dot( fragData.V , fragData.N ) * fragData.N - fragData.V ; - fragData.R = R;//reflect( fragData.V , -fragData.N ) ; - - fragData.NoV = saturate(dot(fragData.N, fragData.V)) ; - - fragData.F0 = mix(vec3(0.04), fragData.Albedo.rgb, fragData.Metallic); - - fragData.F = computeFresnelSchlick(fragData.NoV, fragData.F0); - fragData.KD = vec3(fragData.F) ; - fragData.KS = vec3(0.0) ; - - fragData.Indirect = 0.0 ; - fragData.Reflectance = 1.0 ; - - fragData.DiffuseColor = fragData.Albedo.rgb * (1.0 - fragData.Metallic); - fragData.SpecularColor = mix(vec3(1.0), fragData.Albedo.rgb, fragData.Metallic); - - fragData.ClearcoatRoughness = 0.0 ; - #if USE_CLEARCOAT_ROUGHNESS - fragData.ClearcoatRoughness = getClearcoatRoughnees() ; - #endif - } - - fn BxDFShading(){ - initFragData(); - - var color = vec3(0.0); - - let lightIndex = getCluster(ORI_VertexVarying.fragCoord); - let start = max(lightIndex.start, 0.0); - let count = max(lightIndex.count, 0.0); - let end = max(start + count , 0.0); - for(var i:i32 = i32(start) ; i < i32(end); i += 1 ) - { - let light = getLight(i32(i)); - - switch (light.lightType) { - case PointLightType: { - color += pointLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; - } - case DirectLightType: { - color += directLighting( fragData.Albedo.rgb ,fragData.N,fragData.V,fragData.Roughness , light , globalUniform.shadowBias) ; - } - case SpotLightType: { - color += spotLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; - } - default: { - } - } - } - - var kS = FresnelSchlickRoughness(fragData.NoV, fragData.F0, fragData.Roughness ); - var kD = vec3(1.0) - kS; - kD = kD * (1.0 - fragData.Metallic); - kD = max(vec3(0.04),kD) ; - - let MAX_REFLECTION_LOD = f32(textureNumLevels(prefilterMap)) ; - var diffuseIrradiance: vec3 = vec3(0.0);// - - #if USE_SKYLIGHT - var prefilterTex: vec3 = globalUniform.skyExposure * (textureSampleLevel(prefilterMap, prefilterMapSampler, fragData.N.xyz, 8.0 ).rgb); - prefilterTex = LinearToGammaSpace(prefilterTex); - var skyLight = kD * fragData.Albedo.xyz * prefilterTex; - // color += skyLight ; - #endif - - var envRef = kS * approximateSpecularIBL( fragData.SpecularColor , fragData.Roughness , fragData.R ) ;//* (materialUniform.ior - 1.0) ; - - var irradiance = diffuseIrradiance ; - #if USEGI - irradiance += getIrradiance().rgb ; - #else - irradiance += globalUniform.skyExposure * LinearToGammaSpace(textureSampleLevel(prefilterMap, prefilterMapSampler, fragData.N.xyz, 0.8 * (MAX_REFLECTION_LOD) ).rgb); - #endif - - fragData.Irradiance = irradiance; - - - var diffuseIBL = fragData.Albedo.rgb * irradiance.rgb ; - // var ambientIBL = kD * fragData.Albedo.rgb * fragData.Ao; - fragData.EnvColor = materialUniform.envIntensity * envRef ; - - ORI_FragmentOutput.color = vec4(0.0); - - #if USE_CLEARCOAT - for(var i:i32 = i32(start) ; i < i32(end); i = i + 1 ) - { - let light = getLight(i); - switch (light.lightType) { - case PointLightType: { - color += pointLighting(fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; - } - case DirectLightType: { - color += directLighting( fragData.Albedo.rgb ,fragData.N,fragData.V,fragData.Roughness , light , globalUniform.shadowBias) ; - } - case SpotLightType: { - color += spotLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; - } - default: { - } - } - } - #endif - - // // Using stripped down, 'pure log', formula. Parameterized by grey points and dynamic range covered. - #if USEGBUFFER - var normal_rgba8unorm = (ORI_VertexVarying.vWorldNormal + 1.0) * 0.5; - normal_rgba8unorm = clamp(normal_rgba8unorm, vec3(0.0), vec3(1.0)); - #endif - - // ORI_FragmentOutput.color = vec4(ORI_FragmentOutput.color.xyz,fragData.Albedo.a) ; - #if USE_WORLDPOS - ORI_FragmentOutput.worldPos = vec4(ORI_VertexVarying.vWorldPos.xyzw); - #endif - - #if USEGBUFFER - ORI_FragmentOutput.worldNormal = vec4(normal_rgba8unorm,1.0); - ORI_FragmentOutput.material = vec4(1.0,fragData.Roughness,fragData.Metallic,1.0); - #endif - - // color = pow(color.rgb,vec3(2.0)); - - color += diffuseIBL ; - // color += ambientIBL ; - color += fragData.EnvColor * fragData.Ao ; - color += fragData.Emissive.xyz ; - - //-1 1 - // color = diffuseIBL ; - ORI_FragmentOutput.color = vec4(color.rgb,fragData.Albedo.a) ; - - // let gamma = 2.0 ; - // ORI_FragmentOutput.color = pow(ORI_FragmentOutput.color,vec4(gamma,gamma,gamma,1.0)); - } diff --git a/src/assets/shader/lighting/IESProfiles_frag.ts b/src/assets/shader/lighting/IESProfiles_frag.ts new file mode 100644 index 00000000..771041ce --- /dev/null +++ b/src/assets/shader/lighting/IESProfiles_frag.ts @@ -0,0 +1,36 @@ +export let IESProfiles_frag: string = /*wgsl*/ ` + #if USE_IES_PROFILE + @group(1) @binding(auto) + var iesTextureArrayMapSampler : sampler; + @group(1) @binding(auto) + var iesTextureArrayMap: texture_2d_array ; + #endif + + fn getLightIESProfileAtt( wPos : vec3 , light:LightData ) -> f32 + { + #if USE_IES_PROFILE + let tangent = vec3(1.0,0.0,0.0); + let lightBitangent = normalize( cross( tangent, light.direction ) ); + let lightMatrix = mat4x4( vec4(light.direction.xyz, 0.0), vec4(lightBitangent.xyz, 0.0), vec4(tangent.xyz, 0.0), vec4(0.0, 0.0, 0.0, 1.0) ); + let lightMatrixInv = transpose(lightMatrix); + let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; + let l = lightPos - wPos; + let toLight = normalize(l); + let localToLight = (vec4(toLight.xyz, 0.0) * lightMatrixInv).xyz; + let dotProd = dot(toLight, light.direction); + let angle = asin(dotProd); + let normAngle = (angle / PI) + 0.5 ; + let tangentAngle = atan2( -localToLight.z, -localToLight.x ); + let normTangentAngle = tangentAngle / (PI * 2.0) + 0.5 ; + if(light.ies >= 0.0){ + return textureSampleLevel(iesTextureArrayMap, iesTextureArrayMapSampler, vec2(normAngle , normTangentAngle) , i32(light.ies) , 0.0).r ; + }else{ + return 1.0; + } + #else + return 1.0; + #endif + } + +` + diff --git a/src/assets/shader/lighting/IESProfiles_frag.wgsl b/src/assets/shader/lighting/IESProfiles_frag.wgsl deleted file mode 100644 index b44d48fa..00000000 --- a/src/assets/shader/lighting/IESProfiles_frag.wgsl +++ /dev/null @@ -1,32 +0,0 @@ -#if USE_IES_PROFILE - @group(1) @binding(auto) - var iesTextureArrayMapSampler : sampler; - @group(1) @binding(auto) - var iesTextureArrayMap: texture_2d_array ; -#endif - -fn getLightIESProfileAtt( wPos : vec3 , light:LightData ) -> f32 -{ - #if USE_IES_PROFILE - let tangent = vec3(1.0,0.0,0.0); - let lightBitangent = normalize( cross( tangent, light.direction ) ); - let lightMatrix = mat4x4( vec4(light.direction.xyz, 0.0), vec4(lightBitangent.xyz, 0.0), vec4(tangent.xyz, 0.0), vec4(0.0, 0.0, 0.0, 1.0) ); - let lightMatrixInv = transpose(lightMatrix); - let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; - let l = lightPos - wPos; - let toLight = normalize(l); - let localToLight = (vec4(toLight.xyz, 0.0) * lightMatrixInv).xyz; - let dotProd = dot(toLight, light.direction); - let angle = asin(dotProd); - let normAngle = (angle / PI) + 0.5 ; - let tangentAngle = atan2( -localToLight.z, -localToLight.x ); - let normTangentAngle = tangentAngle / (PI * 2.0) + 0.5 ; - if(light.ies >= 0.0){ - return textureSampleLevel(iesTextureArrayMap, iesTextureArrayMapSampler, vec2(normAngle , normTangentAngle) , i32(light.ies) , 0.0).r ; - }else{ - return 1.0; - } - #else - return 1.0; - #endif -} diff --git a/src/assets/shader/lighting/IrradianceVolumeData_frag.ts b/src/assets/shader/lighting/IrradianceVolumeData_frag.ts index 414a03ee..510baa86 100644 --- a/src/assets/shader/lighting/IrradianceVolumeData_frag.ts +++ b/src/assets/shader/lighting/IrradianceVolumeData_frag.ts @@ -1,49 +1,48 @@ -export let IrradianceVolumeData_frag: string = - ` +export let IrradianceVolumeData_frag: string = /*wgsl*/ ` struct IrradianceVolumeData { - //0 - orientationIndex:f32, - hysteresis:f32, - OctRTSideSize:f32, - OctRTMaxSize:f32, + //0 + orientationIndex:f32, + hysteresis:f32, + OctRTSideSize:f32, + OctRTMaxSize:f32, - //1 - startX:f32, - startY:f32, - startZ:f32, - ProbeSpace:f32, + //1 + startX:f32, + startY:f32, + startZ:f32, + ProbeSpace:f32, - //2 - gridXCount:f32, - gridYCount:f32, - gridZCount:f32, - maxDistance:f32, + //2 + gridXCount:f32, + gridYCount:f32, + gridZCount:f32, + maxDistance:f32, - //3 - depthSharpness:f32, - ProbeSourceTextureSize:f32, - ProbeSize:f32, - bounceIntensity:f32, + //3 + depthSharpness:f32, + ProbeSourceTextureSize:f32, + ProbeSize:f32, + bounceIntensity:f32, - //4 - probeRoughness:f32, - normalBias:f32, - irradianceChebyshevBias:f32, - rayNumber:f32, + //4 + probeRoughness:f32, + normalBias:f32, + irradianceChebyshevBias:f32, + rayNumber:f32, - //5 - irradianceDistanceBias:f32, - indirectIntensity:f32, - ddgiGamma:f32, - lerpHysteresis:f32, - //6 + //5 + irradianceDistanceBias:f32, + indirectIntensity:f32, + ddgiGamma:f32, + lerpHysteresis:f32, + //6 - debugX:f32, - debugY:f32, - debugZ:f32, - slot0:f32, + debugX:f32, + debugY:f32, + debugZ:f32, + slot0:f32, - //.. - v7:vec4, -} + //.. + v7:vec4, + } ` \ No newline at end of file diff --git a/src/assets/shader/lighting/Irradiance_frag.wgsl b/src/assets/shader/lighting/Irradiance_frag.ts similarity index 99% rename from src/assets/shader/lighting/Irradiance_frag.wgsl rename to src/assets/shader/lighting/Irradiance_frag.ts index 672ccd6e..90b3222e 100644 --- a/src/assets/shader/lighting/Irradiance_frag.wgsl +++ b/src/assets/shader/lighting/Irradiance_frag.ts @@ -1,5 +1,5 @@ - - #include "IrradianceVolumeData_frag" +export let Irradiance_frag: string = /*wgsl*/ ` +#include "IrradianceVolumeData_frag" fn pow3( x : f32 ) -> f32 { var xx = x*x; @@ -275,3 +275,5 @@ return vec4(irradiance,1.0) ; } +` + diff --git a/src/assets/shader/lighting/LightingFunction_frag.ts b/src/assets/shader/lighting/LightingFunction_frag.ts index c0887bd3..730b1b53 100644 --- a/src/assets/shader/lighting/LightingFunction_frag.ts +++ b/src/assets/shader/lighting/LightingFunction_frag.ts @@ -1,136 +1,135 @@ +export let LightingFunction_frag: string = /*wgsl*/ ` +#include "BRDF_frag" +#include "LightStruct" +#include "ShadowMapping_frag" + +#if USE_IES_PROFILE + #include "IESProfiles_frag" +#endif + + + +const LUMEN = 10.764; + + + +fn calcAttenuation( d : f32 , falloffStart : f32 , falloffEnd : f32)-> f32 +{ + // Linear falloff. + return saturate((falloffEnd-d) / (falloffEnd - falloffStart)); +} + +fn directLighting( albedo:vec3, N:vec3, V:vec3, roughness:f32 , light:LightData , shadowBias:f32 ) -> vec3 { + var color = vec3(0.0) ; + #if USE_LIGHT + var L = -normalize(light.direction.xyz) ; + let lightCC = pow( light.lightColor.rgb,vec3(2.2)); + var lightColor = getHDRColor( lightCC.rgb , light.linear ) ; + var att = light.intensity / LUMEN ; + if(light.castShadow>=0){ + #if USE_SHADOWMAPING + att *= shadowStrut.directShadowVisibility[light.castShadow] ; + #endif + } + + #if USE_LAMBERT + color = vec3(1.0,0.5,1.0) ; + #endif + + #if USE_BRDF + color = simpleBRDF(albedo,N,V,L,att,lightColor,fragData.Roughness) ; + #endif + #endif + return color ; +} + +fn pointLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, roughness:f32 , light:LightData ) -> vec3 { + var color = vec3(0.0) ; + let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; + var dir = lightPos.xyz - WP ; + let dist = length(dir); + if(dist != 0.0){ + dir *= 1.0 / dist ; + } + if( abs(dist) < light.range ){ + var L = dir ; + var atten = 1.0 ; + atten = 1.0 - smoothstep(0.0,light.range,dist) ; + atten *= 1.0 / max(light.radius,0.001) * light.intensity / LUMEN; + if( light.castShadow >= 0 ) + { + atten *= shadowStrut.pointShadows[light.castShadow] ; + } -export let LightingFunction_frag: string = /* wgsl */ ` - #include "BRDF_frag" - #include "LightStruct" - #include "ShadowMapping_frag" - - #if USE_IES_PROFILE - #include "IESProfiles_frag" - #endif - - - - const LUMEN = 10.764; + #if USE_IES_PROFILE + atten *= getLightIESProfileAtt(WP,light); + #endif + var lightColor = light.lightColor.rgb ; + lightColor = getHDRColor(lightColor , light.linear ) ; + // lightColor = LinearToSrgbBranchless(lightColor.rgb) ; + #if USE_LAMBERT + color = vec3(1.0,0.5,1.0) ; + #endif - fn calcAttenuation( d : f32 , falloffStart : f32 , falloffEnd : f32)-> f32 - { - // Linear falloff. - return saturate((falloffEnd-d) / (falloffEnd - falloffStart)); + #if USE_BRDF + color = (simpleBRDF(albedo,N,V,L,atten,lightColor,fragData.Roughness)) ; + #endif + } + return color ; +} + +fn getDistanceAtten( light:LightData , dist : f32 ) -> f32 { + return 1.0 - smoothstep(0.0,light.range,dist) ; +} + +fn spotLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, roughness:f32 , light:LightData ) -> vec3 { + let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; + var dir = lightPos.xyz - WP ; + let dist = length(dir) ; + if(dist != 0.0){ + dir *= 1.0 / dist ; } - - fn directLighting( albedo:vec3, N:vec3, V:vec3, roughness:f32 , light:LightData , shadowBias:f32 ) -> vec3 { - var color = vec3(0.0) ; - #if USE_LIGHT - var L = -normalize(light.direction.xyz) ; - let lightCC = pow( light.lightColor.rgb,vec3(2.2)); - var lightColor = getHDRColor( lightCC.rgb , light.linear ) ; - var att = light.intensity / LUMEN ; - if(light.castShadow>=0){ - #if USE_SHADOWMAPING - att *= shadowStrut.directShadowVisibility[light.castShadow] ; - #endif + var color = vec3(0.0) ; + if( abs(dist) < light.range * 2.0 ){ + var L = dir ; + let theta = dot(-L, normalize(light.direction)); + let angle = acos(theta) ; + var atten = 1.0 ; + var lightColor = light.lightColor.rgb ; + + atten = 1.0 - smoothstep(0.0,light.range,dist) ; + atten *= 1.0 / max(light.radius,0.1) * light.intensity / LUMEN; + if(angle < light.outerCutOff){ + if(angle > light.innerCutOff){ + atten *= 1.0 - smoothstep(light.innerCutOff, light.outerCutOff, angle) ; + + } + }else{ + atten = 0.0 ; + } + + if( light.castShadow >= 0 ) + { + atten *= shadowStrut.pointShadows[light.castShadow] ; + } - #if USE_LAMBERT - color = vec3(1.0,0.5,1.0) ; - #endif + #if USE_IES_PROFILE + atten *= getLightIESProfileAtt(WP,light); + #endif - #if USE_BRDF - color = simpleBRDF(albedo,N,V,L,att,lightColor,fragData.Roughness) ; - #endif - #endif - return color ; - } + lightColor = getHDRColor(lightColor , light.linear ) ; - fn pointLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, roughness:f32 , light:LightData ) -> vec3 { - var color = vec3(0.0) ; - let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; - var dir = lightPos.xyz - WP ; - let dist = length(dir); - if(dist != 0.0){ - dir *= 1.0 / dist ; - } - if( abs(dist) < light.range ){ - var L = dir ; - var atten = 1.0 ; - atten = 1.0 - smoothstep(0.0,light.range,dist) ; - atten *= 1.0 / max(light.radius,0.001) * light.intensity / LUMEN; - if( light.castShadow >= 0 ) - { - atten *= shadowStrut.pointShadows[light.castShadow] ; - } - - #if USE_IES_PROFILE - atten *= getLightIESProfileAtt(WP,light); - #endif - - var lightColor = light.lightColor.rgb ; - lightColor = getHDRColor(lightColor , light.linear ) ; - // lightColor = LinearToSrgbBranchless(lightColor.rgb) ; - - #if USE_LAMBERT - color = vec3(1.0,0.5,1.0) ; - #endif - - #if USE_BRDF - color = (simpleBRDF(albedo,N,V,L,atten,lightColor,fragData.Roughness)) ; - #endif - } - return color ; - } + #if USE_LAMBERT + color = vec3(1.0,0.5,1.0) ; + #endif - fn getDistanceAtten( light:LightData , dist : f32 ) -> f32 { - return 1.0 - smoothstep(0.0,light.range,dist) ; - } - - fn spotLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, roughness:f32 , light:LightData ) -> vec3 { - let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; - var dir = lightPos.xyz - WP ; - let dist = length(dir) ; - if(dist != 0.0){ - dir *= 1.0 / dist ; - } - var color = vec3(0.0) ; - if( abs(dist) < light.range * 2.0 ){ - var L = dir ; - let theta = dot(-L, normalize(light.direction)); - let angle = acos(theta) ; - var atten = 1.0 ; - var lightColor = light.lightColor.rgb ; - - atten = 1.0 - smoothstep(0.0,light.range,dist) ; - atten *= 1.0 / max(light.radius,0.1) * light.intensity / LUMEN; - if(angle < light.outerCutOff){ - if(angle > light.innerCutOff){ - atten *= 1.0 - smoothstep(light.innerCutOff, light.outerCutOff, angle) ; - - - } - }else{ - atten = 0.0 ; - } - - if( light.castShadow >= 0 ) - { - atten *= shadowStrut.pointShadows[light.castShadow] ; - } - - #if USE_IES_PROFILE - atten *= getLightIESProfileAtt(WP,light); - #endif - - lightColor = getHDRColor(lightColor , light.linear ) ; - - #if USE_LAMBERT - color = vec3(1.0,0.5,1.0) ; - #endif - - #if USE_BRDF - color = (simpleBRDF(albedo,N,V,L,atten,lightColor,fragData.Roughness)) ; - #endif - } - return color ; + #if USE_BRDF + color = (simpleBRDF(albedo,N,V,L,atten,lightColor,fragData.Roughness)) ; + #endif } + return color ; +} ` diff --git a/src/assets/shader/lighting/UnLit_frag.ts b/src/assets/shader/lighting/UnLit_frag.ts index 23550c9f..f8d7e62f 100644 --- a/src/assets/shader/lighting/UnLit_frag.ts +++ b/src/assets/shader/lighting/UnLit_frag.ts @@ -4,22 +4,22 @@ export let UnLit_frag: string = /*wgsl*/ ` fn UnLit(){ - let alpha = ORI_ShadingInput.BaseColor.a ; - ORI_FragmentOutput.color = vec4(ORI_ShadingInput.BaseColor.rgb * alpha , alpha) ; + let alpha = ORI_ShadingInput.BaseColor.a ; + ORI_FragmentOutput.color = vec4(ORI_ShadingInput.BaseColor.rgb * alpha , alpha) ; - #if USE_WORLDPOS - ORI_FragmentOutput.worldPos = vec4(ORI_VertexVarying.vWorldPos.xyzw); - #endif + #if USE_WORLDPOS + ORI_FragmentOutput.worldPos = vec4(ORI_VertexVarying.vWorldPos.xyzw); + #endif - #if USEGBUFFER - var normal_rgba8unorm = (ORI_VertexVarying.vWorldNormal + 1.0) * 0.5; - normal_rgba8unorm = clamp(normal_rgba8unorm, vec3(0.0), vec3(1.0)); - ORI_FragmentOutput.worldNormal = vec4(normal_rgba8unorm,1.0); - ORI_FragmentOutput.material = vec4(1.0,1.0,0.0,1.0); - #endif + #if USEGBUFFER + var normal_rgba8unorm = (ORI_VertexVarying.vWorldNormal + 1.0) * 0.5; + normal_rgba8unorm = clamp(normal_rgba8unorm, vec3(0.0), vec3(1.0)); + ORI_FragmentOutput.worldNormal = vec4(normal_rgba8unorm,1.0); + ORI_FragmentOutput.material = vec4(1.0,1.0,0.0,1.0); + #endif } fn debugFragmentOut(){ } -` +` \ No newline at end of file diff --git a/src/assets/shader/materials/GlassShader.ts b/src/assets/shader/materials/GlassShader.ts new file mode 100644 index 00000000..2f213b09 --- /dev/null +++ b/src/assets/shader/materials/GlassShader.ts @@ -0,0 +1,38 @@ +export let GlassShader: string = /*wgsl*/ ` + #include "Common_vert" + #include "Common_frag" + #include "UnLit_frag" + #include "UnLitMaterialUniform_frag" + + // @group(1) @binding(auto) + // var noes_MapSampler: sampler; + // @group(1) @binding(auto) + // var noes_Map: texture_2d; + + @group(1) @binding(auto) + var splitTexture_MapSampler: sampler; + @group(1) @binding(auto) + var splitTexture_Map: texture_2d; + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + var screenUV = ORI_VertexVarying.fragPosition.xy / ORI_VertexVarying.fragPosition.w; + screenUV = (screenUV.xy + 1.0) * 0.5; + screenUV.y = 1.0 - screenUV.y; + + screenUV.x = clamp(sin(screenUV.x * 1.0),0.0,1.0) ; + screenUV.y = clamp(sin(screenUV.y * 1.0),0.0,1.0) ; + // screenUV.y = cos(ORI_VertexVarying.fragPosition.y/7.15); + + let frameMap = textureSample(splitTexture_Map,splitTexture_MapSampler,screenUV); + // let noesMap = textureSample(noes_Map,noes_MapSampler,screenUV); + + ORI_ShadingInput.BaseColor = vec4( frameMap.rgb , 1.0) ; + UnLit(); + } +` + diff --git a/src/assets/shader/materials/GlassShader.wgsl b/src/assets/shader/materials/GlassShader.wgsl deleted file mode 100644 index 19e5b95d..00000000 --- a/src/assets/shader/materials/GlassShader.wgsl +++ /dev/null @@ -1,36 +0,0 @@ - - #include "Common_vert" - #include "Common_frag" - #include "UnLit_frag" - #include "UnLitMaterialUniform_frag" - - // @group(1) @binding(auto) - // var noes_MapSampler: sampler; - // @group(1) @binding(auto) - // var noes_Map: texture_2d; - - @group(1) @binding(auto) - var splitTexture_MapSampler: sampler; - @group(1) @binding(auto) - var splitTexture_Map: texture_2d; - - fn vert(inputData:VertexAttributes) -> VertexOutput { - ORI_Vert(inputData) ; - return ORI_VertexOut ; - } - - fn frag(){ - var screenUV = ORI_VertexVarying.fragPosition.xy / ORI_VertexVarying.fragPosition.w; - screenUV = (screenUV.xy + 1.0) * 0.5; - screenUV.y = 1.0 - screenUV.y; - - screenUV.x = clamp(sin(screenUV.x * 1.0),0.0,1.0) ; - screenUV.y = clamp(sin(screenUV.y * 1.0),0.0,1.0) ; - // screenUV.y = cos(ORI_VertexVarying.fragPosition.y/7.15); - - let frameMap = textureSample(splitTexture_Map,splitTexture_MapSampler,screenUV); - // let noesMap = textureSample(noes_Map,noes_MapSampler,screenUV); - - ORI_ShadingInput.BaseColor = vec4( frameMap.rgb , 1.0) ; - UnLit(); - } diff --git a/src/assets/shader/materials/LitShader.ts b/src/assets/shader/materials/LitShader.ts new file mode 100644 index 00000000..4dae19b4 --- /dev/null +++ b/src/assets/shader/materials/LitShader.ts @@ -0,0 +1,23 @@ +export let LitShader: string = /*wgsl*/ ` + #include "Common_vert" + #include "Common_frag" + #include "BxDF_frag" + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + ORI_ShadingInput.BaseColor = materialUniform.baseColor ; + ORI_ShadingInput.Roughness = materialUniform.roughness ; + ORI_ShadingInput.Metallic = materialUniform.metallic ; + ORI_ShadingInput.Specular = 0.5 ; + ORI_ShadingInput.AmbientOcclusion = materialUniform.ao ; + ORI_ShadingInput.EmissiveColor = vec4(0.0); + + ORI_ShadingInput.Normal = ORI_VertexVarying.vWorldNormal.rgb ; + + BxDFShading(); + } +` diff --git a/src/assets/shader/materials/LitShader.wgsl b/src/assets/shader/materials/LitShader.wgsl deleted file mode 100644 index 7e9aad9c..00000000 --- a/src/assets/shader/materials/LitShader.wgsl +++ /dev/null @@ -1,22 +0,0 @@ - - #include "Common_vert" - #include "Common_frag" - #include "BxDF_frag" - - fn vert(inputData:VertexAttributes) -> VertexOutput { - ORI_Vert(inputData) ; - return ORI_VertexOut ; - } - - fn frag(){ - ORI_ShadingInput.BaseColor = materialUniform.baseColor ; - ORI_ShadingInput.Roughness = materialUniform.roughness ; - ORI_ShadingInput.Metallic = materialUniform.metallic ; - ORI_ShadingInput.Specular = 0.5 ; - ORI_ShadingInput.AmbientOcclusion = materialUniform.ao ; - ORI_ShadingInput.EmissiveColor = vec4(0.0); - - ORI_ShadingInput.Normal = ORI_VertexVarying.vWorldNormal.rgb ; - - BxDFShading(); - } diff --git a/src/assets/shader/materials/OutlinePass.ts b/src/assets/shader/materials/OutlinePass.ts new file mode 100644 index 00000000..44689a12 --- /dev/null +++ b/src/assets/shader/materials/OutlinePass.ts @@ -0,0 +1,83 @@ +export let OutlinePass: string = /*wgsl*/ ` + #include "Common_vert" + #include "Common_frag" + #include "UnLit_frag" + + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d; + + + struct MaterialUniform { + baseColor:vec4, + lineWeight:f32 + }; + + @group(2) @binding(0) + var materialUniform: MaterialUniform; + + fn vert(vertex:VertexAttributes) -> VertexOutput { + var vertexPosition = vertex.position; + var vertexNormal = vertex.normal; + + #if USE_MORPHTARGETS + vertexPosition = vertexPosition * morphTargetData.morphBaseInfluence + vertex.a_morphPositions_0 * morphTargetData.morphInfluence0; + #if USE_MORPHNORMALS + vertexNormal = vertexNormal * morphTargetData.morphBaseInfluence + vertex.a_morphNormals_0 * morphTargetData.morphInfluence0; + #endif + #endif + + #if USE_SKELETON + #if USE_JOINT_VEC8 + let skeletonNormal = getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); + ORI_MATRIX_M *= skeletonNormal ; + // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; + #else + let skeletonNormal = getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); + ORI_MATRIX_M *= skeletonNormal ; + // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; + #endif + #endif + + + #if USE_TANGENT + ORI_VertexOut.varying_Tangent = vertex.TANGENT ; + #endif + + ORI_NORMALMATRIX = transpose(inverse( mat3x3(ORI_MATRIX_M[0].xyz,ORI_MATRIX_M[1].xyz,ORI_MATRIX_M[2].xyz) )); + + let worldNormal = normalize(ORI_NORMALMATRIX * vertexNormal.xyz) ; + + vertexPosition = vertexPosition + worldNormal * materialUniform.lineWeight ; + + var worldPos = (ORI_MATRIX_M * vec4(vertexPosition.xyz, 1.0)); + var viewPosition = ORI_MATRIX_V * worldPos; + var clipPosition = ORI_MATRIX_P * viewPosition ; + + ORI_VertexOut.varying_UV0 = vertex.uv.xy ; + ORI_VertexOut.varying_UV1 = vertex.TEXCOORD_1.xy; + ORI_VertexOut.varying_ViewPos = viewPosition / viewPosition.w; + ORI_VertexOut.varying_Clip = clipPosition ; + ORI_VertexOut.varying_WPos = worldPos ; + ORI_VertexOut.varying_WPos.w = f32(vertex.index); + ORI_VertexOut.varying_WNormal = worldNormal ; + ORI_VertexOut.member = clipPosition ; + + + return ORI_VertexOut ; + } + + fn frag(){ + let color = textureSample(baseMap,baseMapSampler,ORI_VertexVarying.fragUV0) ; + ORI_ShadingInput.BaseColor = color * materialUniform.baseColor ; + ORI_ShadingInput.Roughness = 0.5 ; + ORI_ShadingInput.Metallic = 0.5 ; + ORI_ShadingInput.Specular = 0.5 ; + ORI_ShadingInput.AmbientOcclusion = 1.0 ; + ORI_ShadingInput.EmissiveColor = vec4(0.0); + ORI_ShadingInput.Normal = ORI_VertexVarying.vWorldNormal.rgb ; + UnLit(); + } +` + diff --git a/src/assets/shader/materials/OutlinePass.wgsl b/src/assets/shader/materials/OutlinePass.wgsl deleted file mode 100644 index 028cc2c4..00000000 --- a/src/assets/shader/materials/OutlinePass.wgsl +++ /dev/null @@ -1,80 +0,0 @@ - #include "Common_vert" - #include "Common_frag" - #include "UnLit_frag" - - @group(1) @binding(0) - var baseMapSampler: sampler; - @group(1) @binding(1) - var baseMap: texture_2d; - - -struct MaterialUniform { - baseColor:vec4, - lineWeight:f32 -}; - -@group(2) @binding(0) -var materialUniform: MaterialUniform; - - fn vert(vertex:VertexAttributes) -> VertexOutput { - var vertexPosition = vertex.position; - var vertexNormal = vertex.normal; - - #if USE_MORPHTARGETS - vertexPosition = vertexPosition * morphTargetData.morphBaseInfluence + vertex.a_morphPositions_0 * morphTargetData.morphInfluence0; - #if USE_MORPHNORMALS - vertexNormal = vertexNormal * morphTargetData.morphBaseInfluence + vertex.a_morphNormals_0 * morphTargetData.morphInfluence0; - #endif - #endif - - #if USE_SKELETON - #if USE_JOINT_VEC8 - let skeletonNormal = getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); - ORI_MATRIX_M *= skeletonNormal ; - // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; - #else - let skeletonNormal = getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); - ORI_MATRIX_M *= skeletonNormal ; - // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; - #endif - #endif - - - #if USE_TANGENT - ORI_VertexOut.varying_Tangent = vertex.TANGENT ; - #endif - - ORI_NORMALMATRIX = transpose(inverse( mat3x3(ORI_MATRIX_M[0].xyz,ORI_MATRIX_M[1].xyz,ORI_MATRIX_M[2].xyz) )); - - let worldNormal = normalize(ORI_NORMALMATRIX * vertexNormal.xyz) ; - - vertexPosition = vertexPosition + worldNormal * materialUniform.lineWeight ; - - var worldPos = (ORI_MATRIX_M * vec4(vertexPosition.xyz, 1.0)); - var viewPosition = ORI_MATRIX_V * worldPos; - var clipPosition = ORI_MATRIX_P * viewPosition ; - - ORI_VertexOut.varying_UV0 = vertex.uv.xy ; - ORI_VertexOut.varying_UV1 = vertex.TEXCOORD_1.xy; - ORI_VertexOut.varying_ViewPos = viewPosition / viewPosition.w; - ORI_VertexOut.varying_Clip = clipPosition ; - ORI_VertexOut.varying_WPos = worldPos ; - ORI_VertexOut.varying_WPos.w = f32(vertex.index); - ORI_VertexOut.varying_WNormal = worldNormal ; - ORI_VertexOut.member = clipPosition ; - - - return ORI_VertexOut ; - } - - fn frag(){ - let color = textureSample(baseMap,baseMapSampler,ORI_VertexVarying.fragUV0) ; - ORI_ShadingInput.BaseColor = color * materialUniform.baseColor ; - ORI_ShadingInput.Roughness = 0.5 ; - ORI_ShadingInput.Metallic = 0.5 ; - ORI_ShadingInput.Specular = 0.5 ; - ORI_ShadingInput.AmbientOcclusion = 1.0 ; - ORI_ShadingInput.EmissiveColor = vec4(0.0); - ORI_ShadingInput.Normal = ORI_VertexVarying.vWorldNormal.rgb ; - UnLit(); - } \ No newline at end of file diff --git a/src/assets/shader/materials/PBRLItShader.ts b/src/assets/shader/materials/PBRLItShader.ts new file mode 100644 index 00000000..b8ac6ae1 --- /dev/null +++ b/src/assets/shader/materials/PBRLItShader.ts @@ -0,0 +1,105 @@ +export let PBRLItShader: string = /*wgsl*/ ` + #include "Common_vert" + #include "Common_frag" + #include "BxDF_frag" + + @group(1) @binding(auto) + var baseMapSampler: sampler; + @group(1) @binding(auto) + var baseMap: texture_2d; + + @group(1) @binding(auto) + var normalMapSampler: sampler; + @group(1) @binding(auto) + var normalMap: texture_2d; + + #if USE_ARMC + @group(1) @binding(auto) + var maskMapSampler: sampler; + @group(1) @binding(auto) + var maskMap: texture_2d; + #endif + + #if USE_AOTEX + @group(1) @binding(auto) + var aoMapSampler: sampler; + @group(1) @binding(auto) + var aomapMap: texture_2d; + #endif + + @group(1) @binding(auto) + var emissiveMapSampler: sampler; + @group(1) @binding(auto) + var emissiveMap: texture_2d; + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + var transformUV1 = materialUniform.transformUV1; + var transformUV2 = materialUniform.transformUV2; + + var uv = transformUV1.zw * ORI_VertexVarying.fragUV0 + transformUV1.xy; + + ORI_ShadingInput.BaseColor = textureSample(baseMap, baseMapSampler, uv ) * materialUniform.baseColor ; + + // #if USE_ALPHACUT + // ORI_ShadingInput.BaseColor.a = clamp(ORI_ShadingInput.BaseColor.a, 0.001 , 1.0 ); + if( (ORI_ShadingInput.BaseColor.a - materialUniform.alphaCutoff) <= 0.0 ){ + ORI_FragmentOutput.color = vec4(0.0,0.0,0.0,1.0); + ORI_FragmentOutput.worldPos = vec4(0.0,0.0,0.0,1.0); + ORI_FragmentOutput.worldNormal = vec4(0.0,0.0,0.0,1.0); + ORI_FragmentOutput.material = vec4(0.0,0.0,0.0,1.0); + discard; + } + // #endif + + #if USE_SHADOWMAPING + directShadowMaping(globalUniform.shadowBias); + pointShadowMapCompare(globalUniform.pointShadowBias); + #endif + + + // ORI_ShadingInput.BaseColor = vec4(sRGBToLinear(ORI_ShadingInput.BaseColor.xyz),ORI_ShadingInput.BaseColor.w); + + #if USE_ARMC + var maskTex = textureSample(maskMap, maskMapSampler, uv ) ; + + ORI_ShadingInput.AmbientOcclusion = maskTex.r * materialUniform.ao ; + + #if USE_AOTEX + var aoMap = textureSample(aomapMap, aoMapSampler, uv ); + ORI_ShadingInput.AmbientOcclusion = mix(0.0,aoMap.r,materialUniform.ao) ; + #endif + + ORI_ShadingInput.Roughness = maskTex.g * materialUniform.roughness ; + ORI_ShadingInput.Metallic = maskTex.b * materialUniform.metallic ; + + #else + ORI_ShadingInput.Roughness = materialUniform.roughness ; + ORI_ShadingInput.Metallic = materialUniform.metallic ; + ORI_ShadingInput.AmbientOcclusion = materialUniform.ao ; + #if USE_AOTEX + var aoMap = textureSample(aomapMap, aoMapSampler, ORI_VertexVarying.fragUV0.xy ); + ORI_ShadingInput.AmbientOcclusion = mix(0.0,aoMap.r,materialUniform.ao) ; + #endif + #endif + + ORI_ShadingInput.Roughness = clamp(ORI_ShadingInput.Roughness,0.084,1.0); + ORI_ShadingInput.Specular = 0.5 ; + + var emissiveColor = textureSample(emissiveMap, emissiveMapSampler , ORI_VertexVarying.fragUV0.xy) ; + ORI_ShadingInput.EmissiveColor = vec4(materialUniform.emissiveColor.rgb * emissiveColor.rgb * materialUniform.emissiveIntensity,1.0); + + var Normal = textureSample(normalMap,normalMapSampler,ORI_VertexVarying.fragUV0).rgb ; + // Normal.y = 1.0 - Normal.y ; + // let normal = unPackNormal(Normal,1.0,materialUniform.normalScale) ; + let normal = unPackNormal(Normal,materialUniform.normalScale) ; + ORI_ShadingInput.Normal = normal ; + + BxDFShading(); + } +` + diff --git a/src/assets/shader/materials/PBRLItShader.wgsl b/src/assets/shader/materials/PBRLItShader.wgsl deleted file mode 100644 index 228dac62..00000000 --- a/src/assets/shader/materials/PBRLItShader.wgsl +++ /dev/null @@ -1,106 +0,0 @@ - - #include "Common_vert" - #include "Common_frag" - #include "BxDF_frag" - - @group(1) @binding(auto) - var baseMapSampler: sampler; - @group(1) @binding(auto) - var baseMap: texture_2d; - - @group(1) @binding(auto) - var normalMapSampler: sampler; - @group(1) @binding(auto) - var normalMap: texture_2d; - - #if USE_ARMC - @group(1) @binding(auto) - var maskMapSampler: sampler; - @group(1) @binding(auto) - var maskMap: texture_2d; - #endif - - #if USE_AOTEX - @group(1) @binding(auto) - var aoMapSampler: sampler; - @group(1) @binding(auto) - var aomapMap: texture_2d; - #endif - - @group(1) @binding(auto) - var emissiveMapSampler: sampler; - @group(1) @binding(auto) - var emissiveMap: texture_2d; - - fn vert(inputData:VertexAttributes) -> VertexOutput { - ORI_Vert(inputData) ; - return ORI_VertexOut ; - } - - fn frag(){ - var transformUV1 = materialUniform.transformUV1; - var transformUV2 = materialUniform.transformUV2; - - var uv = transformUV1.zw * ORI_VertexVarying.fragUV0 + transformUV1.xy; - - ORI_ShadingInput.BaseColor = textureSample(baseMap, baseMapSampler, uv ) * materialUniform.baseColor ; - - // #if USE_ALPHACUT - // ORI_ShadingInput.BaseColor.a = clamp(ORI_ShadingInput.BaseColor.a, 0.001 , 1.0 ); - if( (ORI_ShadingInput.BaseColor.a - materialUniform.alphaCutoff) <= 0.0 ){ - ORI_FragmentOutput.color = vec4(0.0,0.0,0.0,1.0); - ORI_FragmentOutput.worldPos = vec4(0.0,0.0,0.0,1.0); - ORI_FragmentOutput.worldNormal = vec4(0.0,0.0,0.0,1.0); - ORI_FragmentOutput.material = vec4(0.0,0.0,0.0,1.0); - discard; - } - // #endif - - #if USE_SHADOWMAPING - directShadowMaping(globalUniform.shadowBias); - pointShadowMapCompare(globalUniform.pointShadowBias); - #endif - - - // ORI_ShadingInput.BaseColor = vec4(sRGBToLinear(ORI_ShadingInput.BaseColor.xyz),ORI_ShadingInput.BaseColor.w); - - #if USE_ARMC - var maskTex = textureSample(maskMap, maskMapSampler, uv ) ; - - ORI_ShadingInput.AmbientOcclusion = maskTex.r * materialUniform.ao ; - - #if USE_AOTEX - var aoMap = textureSample(aomapMap, aoMapSampler, uv ); - ORI_ShadingInput.AmbientOcclusion = mix(0.0,aoMap.r,materialUniform.ao) ; - #endif - - ORI_ShadingInput.Roughness = maskTex.g * materialUniform.roughness ; - ORI_ShadingInput.Metallic = maskTex.b * materialUniform.metallic ; - - #else - ORI_ShadingInput.Roughness = materialUniform.roughness ; - ORI_ShadingInput.Metallic = materialUniform.metallic ; - ORI_ShadingInput.AmbientOcclusion = materialUniform.ao ; - #if USE_AOTEX - var aoMap = textureSample(aomapMap, aoMapSampler, ORI_VertexVarying.fragUV0.xy ); - ORI_ShadingInput.AmbientOcclusion = mix(0.0,aoMap.r,materialUniform.ao) ; - #endif - #endif - - ORI_ShadingInput.Roughness = clamp(ORI_ShadingInput.Roughness,0.084,1.0); - ORI_ShadingInput.Specular = 0.5 ; - - var emissiveColor = textureSample(emissiveMap, emissiveMapSampler , ORI_VertexVarying.fragUV0.xy) ; - ORI_ShadingInput.EmissiveColor = vec4(materialUniform.emissiveColor.rgb * emissiveColor.rgb * materialUniform.emissiveIntensity,1.0); - - var Normal = textureSample(normalMap,normalMapSampler,ORI_VertexVarying.fragUV0).rgb ; - // Normal.y = 1.0 - Normal.y ; - // let normal = unPackNormal(Normal,1.0,materialUniform.normalScale) ; - let normal = unPackNormal(Normal,materialUniform.normalScale) ; - ORI_ShadingInput.Normal = normal ; - - BxDFShading(); - - - - } diff --git a/src/assets/shader/materials/UnLit.wgsl b/src/assets/shader/materials/UnLit.ts similarity index 94% rename from src/assets/shader/materials/UnLit.wgsl rename to src/assets/shader/materials/UnLit.ts index 0c31f8b2..4e8e439b 100644 --- a/src/assets/shader/materials/UnLit.wgsl +++ b/src/assets/shader/materials/UnLit.ts @@ -1,3 +1,4 @@ +export let UnLit: string = /*wgsl*/ ` #include "Common_vert" #include "Common_frag" #include "UnLit_frag" @@ -25,4 +26,6 @@ ORI_ShadingInput.BaseColor = color * materialUniform.baseColor ; UnLit(); - } \ No newline at end of file + } +` + diff --git a/src/assets/shader/materials/compute/ErpImage2CubeMapCreateCube_compute.wgsl b/src/assets/shader/materials/compute/ErpImage2CubeMapCreateCube_compute.wgsl deleted file mode 100644 index f765bfd8..00000000 --- a/src/assets/shader/materials/compute/ErpImage2CubeMapCreateCube_compute.wgsl +++ /dev/null @@ -1,65 +0,0 @@ -struct ImageSize { - srcWidth : i32, - srcHeight : i32, - dstWidth : i32, - dstHeight : i32 -}; - -@group(0) @binding(0) var size : ImageSize; -@group(0) @binding(1) var faceRotation: array>; -@group(0) @binding(2) var inputTexSampler : sampler; -@group(0) @binding(3) var inputTex : texture_2d; - -@group(1) @binding(0) var outputBuffer0 : texture_storage_2d_array; - -fn SampleSphericalMap(v: vec3) -> vec2 { - var uv:vec2 = vec2(atan2(v.z, v.x), asin(v.y)); - //uv = (uv * (vec2(0.1590999960899353, 0.3183000087738037) + vec2(0.0010000000474974513))); - uv = uv * vec2(0.1590999960899353, 0.3183000087738037); - uv = uv + vec2(0.5); - uv = clamp(uv, vec2(0.0), vec2(1.0)); - return uv; -} - - -fn applyQuaternion(position:vec3, q:vec4) -> vec3{ - let x:f32 = position.x; - let y:f32 = position.y; - let z:f32 = position.z; - - let qx:f32 = q.x; - let qy:f32 = q.y; - let qz:f32 = q.z; - let qw:f32 = q.w; - - let ix:f32 = qw * x + qy * z - qz * y; - let iy:f32 = qw * y + qz * x - qx * z; - let iz:f32 = qw * z + qx * y - qy * x; - let iw:f32 = -qx * x - qy * y - qz * z; - - var ret: vec3; - ret.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; - ret.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; - ret.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; - - return ret; -} - -fn convertIdToDir3(uv_i32:vec2, quaternion:vec4) -> vec3{ - var uv_f32:vec2 = vec2(uv_i32.xy); - var halfSize:f32 = f32(size.dstWidth / 2); - var worldDirection:vec3 = vec3(uv_f32.x - halfSize, uv_f32.y - halfSize, -halfSize); - worldDirection = normalize(worldDirection); - worldDirection = applyQuaternion(worldDirection, quaternion); - return worldDirection; -} - -@compute @workgroup_size(8, 8, 1) -fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { - let coord = vec2(GlobalInvocationID.xy); - let quaternion = faceRotation[GlobalInvocationID.z]; - var worldDirection:vec3 = convertIdToDir3(coord, quaternion); - let uv_f32:vec2 = SampleSphericalMap(worldDirection); - let oc = textureSampleLevel(inputTex, inputTexSampler, uv_f32 , 0.0); - textureStore(outputBuffer0, coord, i32(GlobalInvocationID.z), oc); -} \ No newline at end of file diff --git a/src/assets/shader/materials/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl b/src/assets/shader/materials/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl deleted file mode 100644 index aece1023..00000000 --- a/src/assets/shader/materials/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl +++ /dev/null @@ -1,32 +0,0 @@ -struct ImageSize { - srcWidth : i32, - srcHeight : i32, - dstWidth : i32, - dstHeight : i32 -}; - -@group(0) @binding(0) var size : ImageSize; -@group(0) @binding(1) var tex_in: array>; -@group(0) @binding(2) var outputBuffer : texture_storage_2d; - -@compute @workgroup_size(8, 8, 1) -fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { - let fragCoord = vec2(i32(GlobalInvocationID.x), i32(GlobalInvocationID.y)); - var oc:vec4 = tex_in[fragCoord.y * size.srcWidth + fragCoord.x] / 256.0; - var e = pow(2.0, oc.w * 255.0 - 128.0); - oc = oc * e; - oc = scaleByThreshold(oc, 40.0); - textureStore(outputBuffer, fragCoord , vec4(oc.xyz, 1.0) ); -} - -fn scaleByThreshold(color:vec4, threshold:f32) -> vec4{ - var oc = color; - let brightness = length(vec3(oc.xyz)); - var scale = brightness / threshold; - if(scale > 1.0){ - scale = 1.0 / pow(scale, 0.7); - oc = oc * scale; - } - oc.a = 1.0; - return oc; -} \ No newline at end of file diff --git a/src/assets/shader/materials/compute/GTAOCs.wgsl b/src/assets/shader/materials/compute/GTAOCs.wgsl deleted file mode 100644 index 74210c98..00000000 --- a/src/assets/shader/materials/compute/GTAOCs.wgsl +++ /dev/null @@ -1,133 +0,0 @@ -#include "GlobalUniform" - - struct GTAO{ - maxDistance: f32, - maxPixel: f32, - darkFactor: f32, - rayMarchSegment: f32, - cameraNear: f32, - cameraFar: f32, - viewPortWidth: f32, - viewPortHeight: f32, - multiBounce: f32, - blendColor: f32, - slot1: f32, - slot2: f32, - } - - @group(0) @binding(0) var standUniform: GlobalUniform; - @group(0) @binding(1) var gtaoData: GTAO; - @group(0) @binding(2) var directions : array>; - @group(0) @binding(3) var aoBuffer : array; - - @group(0) @binding(4) var posTex : texture_2d; - @group(0) @binding(5) var normalTex : texture_2d; - @group(0) @binding(6) var inTex : texture_2d; - @group(0) @binding(7) var outTex : texture_storage_2d; - - var texSize: vec2; - var fragCoord: vec2; - var wPosition: vec3; - var wNormal: vec4; - var maxPixelScaled: f32; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - texSize = textureDimensions(inTex).xy; - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - wNormal = textureLoad(normalTex, fragCoord, 0); - wNormal = vec4(wNormal.rgb,wNormal.w) ; - var oc = textureLoad(inTex, fragCoord, 0); - let index = fragCoord.x + fragCoord.y * i32(texSize.x); - let lastFactor = aoBuffer[index]; - var newFactor = 0.0; - if(wNormal.w < 0.5){//sky - - }else{ - wPosition = textureLoad(posTex, fragCoord, 0).xyz; - let ndc = standUniform.projMat * standUniform.viewMat * vec4(wPosition, 1.0); - let ndcZ = ndc.z / ndc.w; - maxPixelScaled = calcPixelByNDC(ndcZ); - newFactor = rayMarch(); - } - - var factor:f32 = mix(lastFactor, newFactor, 0.6); - aoBuffer[index] = factor; - factor = blurFactor(factor); - factor = 1.0 - factor * gtaoData.darkFactor; - var gtao = vec3(factor); - if(gtaoData.multiBounce > 0.5){ - gtao = MultiBounce(factor, oc.xyz); - } - - var outColor = gtao; - if(gtaoData.blendColor > 0.5){ - outColor = oc.xyz * gtao; - } - textureStore(outTex, fragCoord , vec4(outColor, oc.w)); - } - - fn MultiBounce(AO:f32, Albedo:vec3) -> vec3 - { - var A = 2 * Albedo - 0.33; - var B = -4.8 * Albedo + 0.64; - var C = 2.75 * Albedo + 0.69; - return max(vec3(AO), ((AO * A + B) * AO + C) * AO); - } - - fn calcPixelByNDC(ndcZ:f32) -> f32{ - let nearAspect = gtaoData.cameraNear / (gtaoData.cameraFar - gtaoData.cameraNear); - let aspect = (1.0 + nearAspect) / (ndcZ + nearAspect); - var viewPortMax = max(gtaoData.viewPortWidth, gtaoData.viewPortHeight); - var maxPixel = min(viewPortMax, gtaoData.maxPixel * aspect); - maxPixel = max(0.1, maxPixel); - return maxPixel; - } - - fn blurFactor(centerFactor:f32) -> f32{ - var coord0 = clamp(fragCoord + vec2(1, 0) , vec2(0), vec2(texSize - 1)); - var coord1 = clamp(fragCoord + vec2(-1, 0), vec2(0), vec2(texSize - 1)); - var coord2 = clamp(fragCoord + vec2(0, 1) , vec2(0), vec2(texSize - 1)); - var coord3 = clamp(fragCoord + vec2(0, -1), vec2(0), vec2(texSize - 1)); - var index0 = coord0.x + coord0.y * i32(texSize.x); - var index1 = coord1.x + coord1.y * i32(texSize.x); - var index2 = coord2.x + coord2.y * i32(texSize.x); - var index3 = coord3.x + coord3.y * i32(texSize.x); - let factor0:f32 = aoBuffer[index0]; - let factor1:f32 = aoBuffer[index1]; - let factor2:f32 = aoBuffer[index2]; - let factor3:f32 = aoBuffer[index3]; - var factor = 0.25 * (factor0 + factor1 + factor2 + factor3); - factor = mix(factor, centerFactor, 0.8); - return factor; - } - - fn rayMarch() -> f32{ - let originNormal = normalize(vec3(wNormal.xyz) * 2.0 - 1.0); - let stepPixel = maxPixelScaled / gtaoData.rayMarchSegment; - var totalWeight:f32 = 0.001; - var darkWeight:f32 = 0.0; - for(var i:i32 = 0; i < 8; i += 1){ - let dirVec2 = directions[i]; - for(var j:f32 = 1.1; j < maxPixelScaled; j += stepPixel){ - var sampleCoord = vec2(dirVec2 * j) + fragCoord; - sampleCoord = clamp(sampleCoord, vec2(0), vec2(texSize - 1)); - let samplePosition = textureLoad(posTex, sampleCoord, 0).xyz; - let distanceVec2 = samplePosition - wPosition; - let distance = length(distanceVec2); - if(distance < gtaoData.maxDistance){ - let sampleDir = normalize(distanceVec2); - var factor = max(0.0, dot(sampleDir, originNormal) - 0.1); - factor *= 1.0 - distance / gtaoData.maxDistance; - darkWeight += factor; - totalWeight += 1.0; - } - } - } - - return darkWeight/totalWeight ; - } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/IBLEnvMapCreator_compute.wgsl b/src/assets/shader/materials/compute/IBLEnvMapCreator_compute.wgsl deleted file mode 100644 index 4ab1a1ef..00000000 --- a/src/assets/shader/materials/compute/IBLEnvMapCreator_compute.wgsl +++ /dev/null @@ -1,174 +0,0 @@ -struct ImageSize { - srcWidth : i32, - srcHeight : i32, - dstWidth : i32, - dstHeight : i32 -}; - -@group(0) @binding(0) var size : ImageSize; -@group(0) @binding(1) var faceRotation: array>; -@group(0) @binding(2) var inputTexSampler : sampler; -@group(0) @binding(3) var inputTex : texture_2d; - -@group(1) @binding(0) var blurSetting : vec4; -@group(1) @binding(1) var outputBuffer0 : texture_storage_2d_array; - -var PI: f32 = 3.14159265359; - -fn applyQuaternion(position:vec3, q:vec4) -> vec3{ - let x:f32 = position.x; - let y:f32 = position.y; - let z:f32 = position.z; - - let qx:f32 = q.x; - let qy:f32 = q.y; - let qz:f32 = q.z; - let qw:f32 = q.w; - - let ix:f32 = qw * x + qy * z - qz * y; - let iy:f32 = qw * y + qz * x - qx * z; - let iz:f32 = qw * z + qx * y - qy * x; - let iw:f32 = -qx * x - qy * y - qz * z; - - var ret: vec3; - ret.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; - ret.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; - ret.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; - - return ret; -} - -fn convertIdToDir3(uv_i32:vec2, quaternion:vec4) -> vec3{ - var uv_f32:vec2 = vec2(uv_i32.xy); - var halfSize:f32 = f32(size.dstWidth / 2); - var worldDirection:vec3 = vec3(uv_f32.x - halfSize, uv_f32.y - halfSize, -halfSize); - worldDirection = normalize(worldDirection); - worldDirection = applyQuaternion(worldDirection, quaternion); - return worldDirection; -} - -fn VanDerCorpus(n0:u32, base0:u32) -> f32 -{ - var n = n0; - var base = base0; - var invBase:f32 = 1.0 / f32(base); - var denom:f32 = 1.0; - var result:f32 = 0.0; - - for(var i:u32 = 0u; i < 32u; i = i + 1u) - { - if(n > 0u) - { - denom = f32(n) % 2.0; - result = result + denom * invBase; - invBase = invBase / 2.0; - n = u32(f32(n) / 2.0); - } - } - - return result; -} - -fn HammersleyNoBitOps(i:u32, N:u32) -> vec2 -{ - return vec2(f32(i)/f32(N), VanDerCorpus(i, 2u)); -} - -fn hammersley( i : u32 , N : u32 ) -> vec2 -{ - // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html - var bits = (i << 16u) | (i >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - var rdi = f32(bits) * 2.3283064365386963e-10; - return vec2(f32(i) /f32(N), rdi); -} - -fn ImportanceSampleGGX( Xi:vec2, N:vec3, roughness:f32) ->vec3 -{ - var a = roughness*roughness; - - var phi = 2.0 * PI * Xi.x; - var cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); - var sinTheta = sqrt(1.0 - cosTheta*cosTheta); - - // from spherical coordinates to cartesian coordinates - var H:vec3; - H.x = cos(phi) * sinTheta; - H.y = sin(phi) * sinTheta; - H.z = cosTheta; - - // from tangent-space vector to world-space sample vector - var up:vec3; - if(abs(N.z) < 0.999) - { - up = vec3(0.0, 0.0, 1.0); - } - else - { - up = vec3(1.0, 0.0, 0.0); - } - var tangent:vec3 = normalize(cross(up, N)); - var bitangent:vec3 = cross(N, tangent); - var sampleVec:vec3 = tangent * H.x + bitangent * H.y + N * H.z; - return normalize(sampleVec); -} - -fn multiSample(localPos:vec3, roughness:f32) -> vec4 -{ - var N: vec3 = normalize(localPos); - var R: vec3 = N; - var V: vec3 = R; - - let SAMPLE_COUNT:u32 = 1024u; - var totalWeight:f32 = 0.0; - var prefilteredColor:vec3 = vec3(0.0, 0.0, 0.0); - for(var i:u32 = 0u; i < SAMPLE_COUNT; i = i + 1u) - { - var Xi:vec2 = hammersley(i, SAMPLE_COUNT); - var H :vec3 = ImportanceSampleGGX(Xi, N, roughness); - var L :vec3 = normalize(2.0 * dot(V, H) * H - V); - - var NdotL:f32 = max(dot(N, L), 0.0); - if(NdotL > 0.0) - { - var att = 1.0 ;//( f32(SAMPLE_COUNT - i) / f32(SAMPLE_COUNT)) ; - - prefilteredColor = prefilteredColor + sampleColor(L).rgb * NdotL; - prefilteredColor = prefilteredColor * att ; - totalWeight = totalWeight + NdotL; - } - } - prefilteredColor = prefilteredColor / totalWeight; - - return vec4(prefilteredColor, 1.0); -} - -fn SampleSphericalMap(v: vec3) -> vec2 { - var uv:vec2 = vec2(atan2(v.z, v.x), asin(v.y)); - //uv = (uv * (vec2(0.1590999960899353, 0.3183000087738037) + vec2(0.0010000000474974513))); - uv = uv * vec2(0.1590999960899353, 0.3183000087738037); - uv = uv + vec2(0.5); - uv = clamp(uv, vec2(0.0), vec2(1.0)); - return uv; -} - -fn sampleColor(d:vec3) -> vec4 -{ - let uv_f32:vec2 = SampleSphericalMap(d); - let oc = textureSampleLevel(inputTex, inputTexSampler, uv_f32 , 0.0); - //let dir = vec3(-d.x, -d.y, d.z); - //var oc:vec4 = textureSampleLevel(cubeMap, cubeMapSampler, dir, 0.0); - return oc; -} - -@compute @workgroup_size(8, 8, 1) -fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { - let coord = vec2(GlobalInvocationID.xy); - let quaternion = faceRotation[GlobalInvocationID.z]; - var worldDirection:vec3 = convertIdToDir3(coord, quaternion); - var oc:vec4 = multiSample(worldDirection, blurSetting.x); - textureStore(outputBuffer0, coord, i32(GlobalInvocationID.z), oc); -} diff --git a/src/assets/shader/materials/compute/MergeRGBA_Cs.wgsl b/src/assets/shader/materials/compute/MergeRGBA_Cs.wgsl deleted file mode 100644 index c4ad1034..00000000 --- a/src/assets/shader/materials/compute/MergeRGBA_Cs.wgsl +++ /dev/null @@ -1,29 +0,0 @@ - -@group(0) @binding(0) var textureR : texture_2d; -@group(0) @binding(1) var textureG : texture_2d; -@group(0) @binding(2) var textureB : texture_2d; -@group(0) @binding(3) var textureA : texture_2d; -@group(0) @binding(4) var outTex : texture_storage_2d; - -@compute @workgroup_size(8, 8, 1) -fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) { - let size = textureDimensions(outTex); - let fragCoord : vec2 = vec2(GlobalInvocationID.xy); - var uv:vec2; - uv.x = f32(fragCoord.x)/f32(size.x); - uv.y = f32(fragCoord.y)/f32(size.y); - var oc:vec4 = textureSampleLevel(atlasTexture, atlasTextureSampler, targetUV, 0.0); - - let sizeR = textureDimensions(textureR); - let sizeG = textureDimensions(textureG); - let sizeB = textureDimensions(textureB); - let sizeA = textureDimensions(textureA); - - var tr = textureLoad(textureR, vec2(uv * sizeR) , 0 ) ; - var tg = textureLoad(textureG, vec2(uv * sizeG) , 0 ) ; - var tb = textureLoad(textureB, vec2(uv * sizeB) , 0 ) ; - var ta = textureLoad(textureA, vec2(uv * sizeA) , 0 ) ; - - let color = vec4(tr,tg,tb,ta); - textureStore(outTex, fragCoord , vec4(color)); -} diff --git a/src/assets/shader/materials/compute/MultiBouncePass_Shader.wgsl b/src/assets/shader/materials/compute/MultiBouncePass_Shader.wgsl deleted file mode 100644 index a5eb8983..00000000 --- a/src/assets/shader/materials/compute/MultiBouncePass_Shader.wgsl +++ /dev/null @@ -1,185 +0,0 @@ - - #include "MathShader" - #include "IrradianceVolumeData_frag" - - -struct IrradianceField { - probeStartPosition: vec4, - probeCounts:vec4, - probeStep:f32, - irradianceTextureWidth:f32, - irradianceTextureHeight:f32, - irradianceProbeSideLength:f32, -}; - - @group(0) @binding(0) var outputBuffer : texture_storage_2d; - @group(0) @binding(1) var uniformData : IrradianceVolumeData ; - - @group(1) @binding(0) var normalMapSampler : sampler; - @group(1) @binding(1) var normalMap : texture_2d; - - @group(1) @binding(2) var colorMapSampler : sampler; - @group(1) @binding(3) var colorMap : texture_2d; - - @group(1) @binding(4) var litMapSampler : sampler; - @group(1) @binding(5) var litMap : texture_2d; - - @group(1) @binding(6) var irradianceMapSampler : sampler; - @group(1) @binding(7) var irradianceMap : texture_2d; - - var wsn:vec3; - var ulitColor:vec4; - var litColor:vec4; - var irradianceFieldSurface : IrradianceField ; - var probeID:u32; - - var quaternion:vec4 = vec4(0.0, -0.7071067811865475, 0.7071067811865475, 0.0); - -fn getIrradianceFieldSurface() -> IrradianceField{ - let data = uniformData; - irradianceFieldSurface.probeStartPosition = vec4(data.startX, data.startY, data.startZ, 0.0); - irradianceFieldSurface.probeCounts = vec4(data.gridXCount, data.gridYCount, data.gridZCount, 0.0); - irradianceFieldSurface.probeStep = data.ProbeSpace; - irradianceFieldSurface.irradianceTextureWidth = data.OctRTMaxSize; - irradianceFieldSurface.irradianceTextureHeight = data.OctRTMaxSize; - irradianceFieldSurface.irradianceProbeSideLength = data.OctRTSideSize; - return irradianceFieldSurface; -} - - fn rotateDir(n:vec3) -> vec3{ - return normalize(applyQuaternion(-n, quaternion)); - } - - fn sampleLitColor(uv:vec2) -> vec4 - { - var oc1:vec4 = textureSampleLevel(litMap, litMapSampler, vec2(0.0), 0.0); - var oc:vec4 = textureLoad(litMap, uv, 0); - return oc; - } - - fn sampleNormal(uv:vec2) -> vec4 - { - var oc1:vec4 = textureSampleLevel(normalMap, normalMapSampler, vec2(0.0), 0.0); - var oc:vec4 = textureLoad(normalMap, uv, 0); - return oc; - } - - fn sampleColor(uv:vec2) -> vec4 - { - var oc1:vec4 = textureSampleLevel(colorMap, colorMapSampler, vec2(0.0), 0.0); - var oc:vec4 = textureLoad(colorMap, uv, 0); - return oc; - } - - fn sampleProbe(fragCoord:vec2){ - var uv = vec2(i32(fragCoord.x), i32(fragCoord.y)) ; - - litColor = sampleLitColor(uv); - - var normalMap = sampleNormal(uv); - wsn = normalMap.xyz * 2.0 - 1.0; - - ulitColor = sampleColor(uv); - } - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain(@builtin(global_invocation_id) globalInvocation_id : vec3) - { - getIrradianceFieldSurface(); - var fragCoord = vec2( globalInvocation_id.x, globalInvocation_id.y); - probeID = globalInvocation_id.z; - fragCoord = fragCoord + getCoordOffset(probeID); - - sampleProbe(fragCoord); - - let irradiance = getIrradianceColor(); - let result = blendIrradianceColor(irradiance); - textureStore(outputBuffer, vec2(fragCoord), result); - } - - fn blendIrradianceColor(irradiance:vec4) -> vec4{ - var bounceColor = irradiance * ulitColor; - let bounceIntensity = getBounceIntensity(uniformData.bounceIntensity); - let conservation1 = 1.0 / sqrt((1.0 + bounceIntensity * 0.55)); - let conservation2 = 1.0 / sqrt((1.0 + bounceIntensity)); - var result = litColor * conservation2 + bounceColor * sqrt(bounceIntensity) * conservation1; - return vec4(result.xyz, litColor.w); - } - - fn getBounceIntensity(intensity:f32) -> f32 { - var value = clamp(intensity, 0.0, 1.0) * 10.0; - return value; - } - - fn getCoordOffset(id:u32) -> vec2{ - var fullCol = u32(uniformData.ProbeSourceTextureSize / uniformData.ProbeSize); - var offsetSampleUv = vec2( (id / fullCol) * 6u , id % fullCol) * u32(uniformData.ProbeSize); - return offsetSampleUv; - } - - fn getIrradianceColor() -> vec4{ - var probeIrradiance: vec4 = vec4(0.0); - if(length(wsn) > 0.01){ - probeIrradiance = getIrrdiaceIndex(i32(probeID), wsn); - } - return probeIrradiance; - } - - fn getIrrdiaceIndex(index:i32, wsn:vec3) -> vec4{ - var wsN = rotateDir(wsn.xyz); - var texCoord:vec2 = textureCoordFromDirection(wsN, - index, - irradianceFieldSurface.irradianceTextureWidth, - irradianceFieldSurface.irradianceTextureHeight, - irradianceFieldSurface.irradianceProbeSideLength); - - var probeIrradiance: vec3 = textureSampleLevel(irradianceMap, irradianceMapSampler, texCoord, 0.0).xyz; - return vec4(probeIrradiance, 1.0); - } - - fn textureCoordFromDirection(dir:vec3, probeIndex:i32, width:f32, height:f32, sideLength:f32) -> vec2 - { - var uv = getWriteOctUVByID(dir, u32(probeIndex), sideLength) ; - uv.x = uv.x / irradianceFieldSurface.irradianceTextureWidth; - uv.y = uv.y / irradianceFieldSurface.irradianceTextureHeight; - return uv ; - } - - fn getWriteOctUVByID(dir:vec3 , probeID:u32, size: f32) -> vec2 - { - var blockCount = u32(irradianceFieldSurface.probeCounts.x * irradianceFieldSurface.probeCounts.z) ; - var offsetX = (probeID % blockCount) % u32(irradianceFieldSurface.probeCounts.x) ; - var offsetY = u32(irradianceFieldSurface.probeCounts.z - 1.0) - (probeID % blockCount) / u32(irradianceFieldSurface.probeCounts.x) ; - var offsetZ = probeID / blockCount ; - - var pixelCoord = (( octEncode(dir) + 1.0 ) * 0.5) * vec2(size,size) ; - - var blockOffset = vec2(0.0); - blockOffset.x = f32(offsetX) * size; - blockOffset.y = f32(offsetY) * size + f32(offsetZ) * f32(irradianceFieldSurface.probeCounts.z) * size; - - let mapHeight = u32(irradianceFieldSurface.irradianceTextureHeight); - var probeCounts:vec3 = vec3(irradianceFieldSurface.probeCounts.xyz); - - var gridOffsetFrom = vec2(blockOffset) + 1; - var gridOffsetTo = offsetByCol(gridOffsetFrom, size, mapHeight, probeCounts); - - pixelCoord = pixelCoord + vec2(gridOffsetTo - 1) + vec2(vec2(vec2(gridOffsetTo) / size) * 2); - - return pixelCoord + 1.0 ; - } - - fn offsetByCol(pixelCoord0:vec2, octSideSize:f32, mapHeight:u32, counts:vec3) -> vec2 - { - var pixelCoord = pixelCoord0; - let blockSize:vec2 = vec2(i32(octSideSize * counts.x), i32(octSideSize * counts.z)); - let blockSizeYBorder:i32 = i32((octSideSize + 2.0) * counts.z); - let blockMaxRowBorder:i32 = i32(mapHeight) / blockSizeYBorder; - let pixelCountYMax:i32 = blockMaxRowBorder * i32(octSideSize * counts.z); - let col:i32 = pixelCoord.y / pixelCountYMax; - - pixelCoord.x = col * i32(octSideSize * counts.x) + pixelCoord.x; - pixelCoord.y = pixelCoord.y % pixelCountYMax; - - return pixelCoord; - } diff --git a/src/assets/shader/materials/compute/OutLineBlendColor.wgsl b/src/assets/shader/materials/compute/OutLineBlendColor.wgsl deleted file mode 100644 index 70779dba..00000000 --- a/src/assets/shader/materials/compute/OutLineBlendColor.wgsl +++ /dev/null @@ -1,40 +0,0 @@ -struct OutlineSettingData{ - strength: f32, - useAddMode: f32, - outlinePixel: f32, - fadeOutlinePixel: f32, - lowTexWidth: f32, - lowTexHeight: f32, - slot0: f32, - slot1: f32, - } - - @group(0) @binding(0) var outlineSetting: OutlineSettingData; - @group(0) @binding(1) var inTex : texture_2d; - @group(0) @binding(2) var lowTexSampler : sampler; - @group(0) @binding(3) var lowTex : texture_2d; - @group(0) @binding(4) var outlineTex : texture_storage_2d; - - var texSize: vec2; - var fragCoord: vec2; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - texSize = textureDimensions(outlineTex).xy; - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - - let uv01 = vec2(fragCoord) / (vec2(texSize) - 1.0); - let outLineColor = textureSampleLevel(lowTex, lowTexSampler, uv01, 0.0) * outlineSetting.strength; - var newOC = textureLoad(inTex, fragCoord, 0); - var blendColor:vec3 = vec3(0.0); - if(outlineSetting.useAddMode > 0.5){ - blendColor = vec3(newOC.xyz) + vec3(outLineColor.xyz) * outLineColor.w; - }else{ - blendColor = mix(vec3(newOC.xyz), vec3(outLineColor.xyz), outLineColor.w); - } - textureStore(outlineTex, fragCoord , vec4(blendColor, newOC.w)); - } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/OutlineCalcOutline.wgsl b/src/assets/shader/materials/compute/OutlineCalcOutline.wgsl deleted file mode 100644 index 792dc1c1..00000000 --- a/src/assets/shader/materials/compute/OutlineCalcOutline.wgsl +++ /dev/null @@ -1,86 +0,0 @@ -struct OutlineSettingData{ - strength: f32, - useAddMode: f32, - outlinePixel: f32, - fadeOutlinePixel: f32, - lowTexWidth: f32, - lowTexHeight: f32, - slot0: f32, - slot1: f32, - } - - struct OutlineSlotData{ - color: vec3, - count: f32, - } - - struct OutlineWeightData{ - slotIndex:f32, - outerSlotIndex:f32, - entityIndex:f32, - weight:f32 - } - - struct OutlineEntities{ - list: array, - } - - @group(0) @binding(0) var outlineSetting: OutlineSettingData; - @group(0) @binding(1) var slotsBuffer : array; - @group(0) @binding(2) var weightBuffer : array; - @group(0) @binding(3) var entitiesBuffer : array; - @group(0) @binding(4) var indexTexture : texture_2d; - - var texSize: vec2; - var lowSize: vec2; - var fragCoord: vec2; - var fragCoordLow: vec2; - var coordIndex: i32; - - var fragOutline: OutlineWeightData; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoordLow = vec2( globalInvocation_id.xy ); - fragCoord = fragCoordLow * 2; - texSize = textureDimensions(indexTexture).xy; - lowSize = vec2(i32(outlineSetting.lowTexWidth), i32(outlineSetting.lowTexHeight)); - - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - if(fragCoordLow.x >= lowSize.x || fragCoordLow.y >= lowSize.y){ - return; - } - - coordIndex = fragCoordLow.x + fragCoordLow.y * lowSize.x; - fragOutline = weightBuffer[coordIndex]; - var wPos = textureLoad(indexTexture, fragCoord, 0 ) ; - - fragOutline.entityIndex = round(wPos.w); - fragOutline.slotIndex = -1.0; - fragOutline.outerSlotIndex = -1.0; - fragOutline.weight = 0.0; - - if(fragOutline.entityIndex >= 0.0){ - fragOutline.slotIndex = f32(matchOutlineSlot()); - } - weightBuffer[coordIndex] = fragOutline; - } - - fn matchOutlineSlot() -> i32 - { - for(var i:i32 = 0; i < 8; i ++){ - var slotData:OutlineSlotData = slotsBuffer[i]; - var entities:array = entitiesBuffer[i].list; - let count:i32 = i32(slotData.count); - for(var j:i32 = 0; j < count; j ++){ - var outlineIndex = entities[j]; - if(abs(fragOutline.entityIndex - outlineIndex) < 0.1){ - return i; - } - } - } - return -1; - } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/OutlineCs.wgsl b/src/assets/shader/materials/compute/OutlineCs.wgsl deleted file mode 100644 index fd288996..00000000 --- a/src/assets/shader/materials/compute/OutlineCs.wgsl +++ /dev/null @@ -1,120 +0,0 @@ -struct OutlineSettingData{ - strength: f32, - useAddMode: f32, - outlinePixel: f32, - fadeOutlinePixel: f32, - lowTexWidth: f32, - lowTexHeight: f32, - slot0: f32, - slot1: f32, - } - - struct OutlineSlotData{ - color: vec3, - count: f32, - } - - struct OutlineWeightData{ - slotIndex:f32, - outerSlotIndex:f32, - entityIndex:f32, - weight:f32 - } - - @group(0) @binding(0) var outlineSetting: OutlineSettingData; - @group(0) @binding(1) var slotsBuffer : array; - @group(0) @binding(2) var weightBuffer : array; - @group(0) @binding(3) var oldOutlineColor : array>; - @group(0) @binding(4) var lowTex : texture_storage_2d; - - var texSize: vec2; - var fragCoord: vec2; - var coordIndex: i32; - var fragOutline: OutlineWeightData; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - texSize = textureDimensions(lowTex).xy; - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - - coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); - fragOutline = weightBuffer[coordIndex]; - - var blendColor = vec3(0.0); - var newOC = vec4(0.0); - - calcOutline(); - let outerSlotIndex:i32 = i32(round(fragOutline.outerSlotIndex)); - if(outerSlotIndex >= 0){ - let outLineColor = slotsBuffer[outerSlotIndex].color; - newOC = vec4(outLineColor, fragOutline.weight); - } - - let coordIndex0 = fragCoord.x + 1 + (fragCoord.y - 1) * i32(texSize.x); - let coordIndex1 = fragCoord.x - 1 + (fragCoord.y - 1) * i32(texSize.x); - let coordIndex2 = fragCoord.x + (fragCoord.y + 1) * i32(texSize.x); - - let oldOC = oldOutlineColor[coordIndex]; - let oldOC0 = oldOutlineColor[coordIndex0]; - let oldOC1 = oldOutlineColor[coordIndex1]; - let oldOC2 = oldOutlineColor[coordIndex2]; - - newOC = mix((oldOC + oldOC0 + oldOC1 + oldOC2) * 0.25, newOC, 0.4); - - oldOutlineColor[coordIndex] = newOC; - textureStore(lowTex, fragCoord, newOC); - } - - fn calcOutline() - { - let outlinePixel = outlineSetting.outlinePixel; - let fadeOutlinePixel = outlineSetting.fadeOutlinePixel; - let pixelRadius = outlinePixel + fadeOutlinePixel; - let minX = max(0.0, f32(fragCoord.x) - pixelRadius); - let maxX = min(f32(texSize.x), f32(fragCoord.x) + pixelRadius); - let minY = max(0.0, f32(fragCoord.y) - pixelRadius); - let maxY = min(f32(texSize.y), f32(fragCoord.y) + pixelRadius); - var coordTemp_f32 = vec2(0.0); - var coordCurrent_f32 = vec2(fragCoord); - var tempCoordIndex = 0; - var tempWeightData: OutlineWeightData; - for(var x:f32 = minX; x < maxX; x += 1.0){ - for(var y:f32 = minY; y < maxY; y += 1.0){ - coordTemp_f32.x = x; - coordTemp_f32.y = y; - let distanceToOuter = length(coordTemp_f32 - coordCurrent_f32); - if(distanceToOuter < pixelRadius){ - var coord_i32 = vec2(coordTemp_f32); - tempCoordIndex = coord_i32.x + coord_i32.y * i32(texSize.x); - tempWeightData = weightBuffer[tempCoordIndex]; - let outlineGap = abs(tempWeightData.slotIndex - fragOutline.slotIndex); - if(outlineGap > 0.1){ - if(tempWeightData.slotIndex > fragOutline.slotIndex){ - if(abs(tempWeightData.slotIndex - fragOutline.outerSlotIndex) < 0.1){ - fragOutline.weight = max(fragOutline.weight, calcWeight(pixelRadius, distanceToOuter, outlinePixel)); - fragOutline.outerSlotIndex = tempWeightData.slotIndex; - weightBuffer[tempCoordIndex] = tempWeightData; - }else if(tempWeightData.slotIndex > fragOutline.outerSlotIndex){ - fragOutline.weight = calcWeight(pixelRadius, distanceToOuter, outlinePixel); - fragOutline.outerSlotIndex = tempWeightData.slotIndex; - weightBuffer[tempCoordIndex] = tempWeightData; - } - } - } - } - } - } - } - - fn calcWeight(radius:f32, distance0:f32, outlinePixel:f32) -> f32{ - let distance = distance0 - outlinePixel; - if(distance < 0.0){ - return 1.0; - } - var ret = 1.0 - distance / (radius - outlinePixel); - return ret; - } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/Picker_CsShader.wgsl b/src/assets/shader/materials/compute/Picker_CsShader.wgsl deleted file mode 100644 index b6257e13..00000000 --- a/src/assets/shader/materials/compute/Picker_CsShader.wgsl +++ /dev/null @@ -1,65 +0,0 @@ -struct GlobalUniform { - projMat: mat4x4, - viewMat: mat4x4, - cameraWorldMatrix: mat4x4, - pvMatrixInv : mat4x4, - shadowMatrix: array,8>, - CameraPos: vec3, - - frame: f32, - time: f32, - delta: f32, - shadowBias: f32, - skyExposure: f32, - renderPassState:f32, - quadScale: f32, - hdrExposure: f32, - - renderState_left: i32, - renderState_right: i32, - renderState_split: f32, - - mouseX: f32, - mouseY: f32, - windowWidth: f32, - windowHeight: f32, - - near: f32, - far: f32, - - pointShadowBias: f32, - shadowMapSize: f32, - shadowSoft: f32, - }; - -struct PickResult{ - pick_meshID:f32, - pick_meshID2:f32, - pick_UV:vec2, - pick_Position:vec4, - pick_Normal:vec4, - pick_Tangent:vec4, -} - -@group(0) @binding(0) var standUniform: GlobalUniform; -@group(0) @binding(1) var outBuffer: PickResult; -@group(0) @binding(2) var visibleMap : texture_2d; - -@compute @workgroup_size( 1 ) -fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) -{ - var result:PickResult ; - // result.pick_meshID - let texSize = textureDimensions(visibleMap).xy; - let screenPoint = vec2(standUniform.mouseX/standUniform.windowWidth,standUniform.mouseY/standUniform.windowHeight); - - let mouseUV = screenPoint * vec2(texSize.xy); - let info = textureLoad(visibleMap, vec2(mouseUV) , 0); - - outBuffer.pick_meshID = f32(info.w) ; - outBuffer.pick_meshID2 = f32(info.w) ; - outBuffer.pick_Tangent = vec4(2.0,2.0,2.0,2.0) ; - outBuffer.pick_UV = vec2(standUniform.mouseX,standUniform.mouseY) ; - outBuffer.pick_Position = vec4(info.xyzw) ; - outBuffer.pick_Normal = vec4(info.xyzw) ; -} \ No newline at end of file diff --git a/src/assets/shader/materials/compute/SSAO_CsShader.wgsl b/src/assets/shader/materials/compute/SSAO_CsShader.wgsl deleted file mode 100644 index da8b0ac8..00000000 --- a/src/assets/shader/materials/compute/SSAO_CsShader.wgsl +++ /dev/null @@ -1,99 +0,0 @@ - - - #include "GlobalUniform" - - struct UniformData { - radius: f32 , - bias: f32, - aoPower: f32 , - blurSize: f32 , - }; - - @group(0) @binding(0) var standUniform: GlobalUniform; - @group(0) @binding(1) var uniformData: UniformData; - @group(0) @binding(2) var sampleData: array>; - - // @group(0) @binding(3) var colorMap : texture_2d; - @group(0) @binding(3) var positionMap : texture_2d; - @group(0) @binding(4) var normalMap : texture_2d; - - @group(0) @binding(5) var noiseMapSampler: sampler; - @group(0) @binding(6) var noiseMap : texture_2d; - - @group(0) @binding(7) var outTex : texture_storage_2d; - - var kernelSize: i32 = 32 ; - - @compute @workgroup_size( 8 , 8 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - var fragCoord = vec2( globalInvocation_id.xy ); - - var texSize = textureDimensions(positionMap).xy; - var texCoord = vec2(fragCoord) / vec2(texSize); - - var fragColor = vec4(1.0); - - var viewMat = standUniform.viewMat ; - // var color = textureLoad(colorMap, fragCoord , 0 ) ; - var wPos = textureLoad(positionMap, fragCoord , 0 ) ; - - var fragPosition = viewMat * vec4(wPos.xyz,1.0); - fragPosition = vec4(fragPosition.xyz / fragPosition.w,1.0) ; - - var texNormal = textureLoad(normalMap, fragCoord , 0 ) ; - var sampleNormal = texNormal.xyz ; - sampleNormal = sampleNormal * 2.0 - 1.0; - var fragNormal = viewMat * vec4((sampleNormal.xyz),0.0); - - var pes = vec2(texSize.xy) / 4.0 ; - var noiseTex:vec4 = textureSampleLevel(noiseMap, noiseMapSampler, texCoord * pes , 0.0); - var randomVec = (viewMat * vec4(normalize(noiseTex.xyz),0.0)).xyz; - - var tangent = normalize(randomVec - fragNormal.xyz * dot(randomVec , fragNormal.xyz)); - var bTangent = cross(fragNormal.xyz, tangent) + 0.0001 ; - var tbn = mat3x3(tangent, bTangent, fragNormal.xyz); - - var offset:vec4; - var samplePos :vec3; - var offsetPosition:f32; - var sample_depth_v:vec4; - var occlusion:f32 = 0.0; - var rangeCheck:f32 = 0.0 ; - var radius:f32 = uniformData.radius * 32.0 * fragPosition.z ; - - for(var i:i32 = 0; i < 32 ; i = i + 1 ){ - samplePos = (tbn * sampleData[i].xyz ) ; - samplePos = fragPosition.xyz + samplePos * radius ; - - offset = vec4(samplePos, 1.0); - offset = standUniform.projMat * offset; - - var off = offset.xyz / offset.w; - off = (off.xyz * 0.5 ) + 0.5 ; - off.y = 1.0 - off.y ; - var offsetUV = vec2(off.xy * vec2(texSize.xy)); - - sample_depth_v = textureLoad(positionMap, offsetUV.xy , 0 ) ; - sample_depth_v = vec4((viewMat * vec4(sample_depth_v.xyz,1.0)).xyz,1.0); - offsetPosition = sample_depth_v.z / sample_depth_v.w ; - - rangeCheck = smoothstep(0.0, 1.0, radius / abs(offsetPosition - fragPosition.z )); - // rangeCheck = smoothstep(0.0, 1.0, radius / uniformData.bias); - - var a = 1.0 ; - if(offsetPosition >= (samplePos.z + uniformData.bias)){ - a = 0.0 ; - } - a = a * rangeCheck ; - occlusion = occlusion + a ; - } - - occlusion = 1.0 - ( occlusion / f32(kernelSize) * texNormal.w ); - occlusion = pow(occlusion, uniformData.aoPower) ; - - // color = color * occlusion ; - - textureStore(outTex, fragCoord , vec4(occlusion)); - } - diff --git a/src/assets/shader/materials/compute/SSR_BlendColor_Shader.wgsl b/src/assets/shader/materials/compute/SSR_BlendColor_Shader.wgsl deleted file mode 100644 index e6d6e3df..00000000 --- a/src/assets/shader/materials/compute/SSR_BlendColor_Shader.wgsl +++ /dev/null @@ -1,45 +0,0 @@ - - - @group(0) @binding(0) var rayTraceBuffer : array; - @group(0) @binding(1) var colorMap : texture_2d; - @group(0) @binding(2) var ssrMapSampler : sampler; - @group(0) @binding(3) var ssrMap : texture_2d; - @group(0) @binding(4) var outTex : texture_storage_2d; - - var colorTexSize: vec2; - var ssrTexSize: vec2; - var fragCoord: vec2; - var ssrCoord: vec2; - - struct RayTraceRetData{ - skyColor:vec3, - roughness:f32, - - hitCoord:vec2, - alpha:f32, - fresnel:f32, - } - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - colorTexSize = textureDimensions(colorMap).xy; - ssrTexSize = textureDimensions(ssrMap).xy; - if(fragCoord.x >= i32(colorTexSize.x) || fragCoord.y >= i32(colorTexSize.y)){ - return; - } - let scale:f32 = f32(ssrTexSize.x) / f32(colorTexSize.x); - ssrCoord = vec2(vec2(fragCoord.xy) * scale); - let index = ssrCoord.x + ssrCoord.y * i32(ssrTexSize.x); - let hitData = rayTraceBuffer[index]; - var color = textureLoad(colorMap, fragCoord , 0); - var uv01 = vec2(f32(fragCoord.x), f32(fragCoord.y)); - uv01 = uv01 / vec2(colorTexSize - 1); - - var ssrColor = textureSampleLevel(ssrMap, ssrMapSampler, uv01, 0.0); - var tc = mix(color, ssrColor, hitData.fresnel) ; - var outColor = tc ; - outColor.a = color.a ; - textureStore(outTex, fragCoord , outColor ); - } diff --git a/src/assets/shader/materials/compute/TAACopyTex.wgsl b/src/assets/shader/materials/compute/TAACopyTex.wgsl deleted file mode 100644 index 4993fda2..00000000 --- a/src/assets/shader/materials/compute/TAACopyTex.wgsl +++ /dev/null @@ -1,18 +0,0 @@ - @group(0) @binding(0) var preColor : array>; - @group(0) @binding(1) var preColorTex : texture_storage_2d; - - var texSize: vec2; - var fragCoord: vec2; - var coordIndex: i32; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - texSize = textureDimensions(preColorTex).xy; - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); - textureStore(preColorTex, fragCoord , preColor[coordIndex]); - } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/TAASharpTex.wgsl b/src/assets/shader/materials/compute/TAASharpTex.wgsl deleted file mode 100644 index e57576c8..00000000 --- a/src/assets/shader/materials/compute/TAASharpTex.wgsl +++ /dev/null @@ -1,41 +0,0 @@ - - struct TAAData{ - preProjMatrix: mat4x4, - preViewMatrix: mat4x4, - jitterFrameIndex: f32, - blendFactor: f32, - sharpFactor: f32, - sharpPreBlurFactor: f32, - jitterX: f32, - jitterY: f32, - slot0: f32, - slot1: f32, - } - @group(0) @binding(0) var taaData: TAAData; - @group(0) @binding(1) var inTex : texture_2d; - @group(0) @binding(2) var outTex : texture_storage_2d; - - var texSize: vec2; - var fragCoord: vec2; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - texSize = textureDimensions(outTex).xy; - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - - let c0 = textureLoad(inTex, vec2(fragCoord.x, fragCoord.y - 1), 0); - let c1 = textureLoad(inTex, vec2(fragCoord.x, fragCoord.y + 1), 0); - let c2 = textureLoad(inTex, vec2(fragCoord.x - 1, fragCoord.y), 0); - let c3 = textureLoad(inTex, vec2(fragCoord.x + 1, fragCoord.y), 0); - - var roundColor = (c0 + c1 + c2 + c3) * 0.25; - let originColor = textureLoad(inTex, fragCoord, 0); - let blurColor = mix(roundColor, originColor, taaData.sharpPreBlurFactor); - var oc = (originColor - blurColor * taaData.sharpFactor) / (1.0 - taaData.sharpFactor); - oc = clamp(oc, vec4(0.0), oc); - textureStore(outTex, fragCoord , oc); - } \ No newline at end of file diff --git a/src/assets/shader/materials/compute/TAAcs.wgsl b/src/assets/shader/materials/compute/TAAcs.wgsl deleted file mode 100644 index 6c82bc0a..00000000 --- a/src/assets/shader/materials/compute/TAAcs.wgsl +++ /dev/null @@ -1,155 +0,0 @@ - - #include "GlobalUniform" - - struct TAAData{ - preProjMatrix: mat4x4, - preViewMatrix: mat4x4, - jitterFrameIndex: f32, - blendFactor: f32, - sharpFactor: f32, - sharpPreBlurFactor: f32, - jitterX: f32, - jitterY: f32, - slot0: f32, - slot1: f32, - } - - @group(0) @binding(0) var standUniform: GlobalUniform; - @group(0) @binding(1) var taaData: TAAData; - @group(0) @binding(2) var preColorBuffer : array>; - - @group(0) @binding(3) var preColorTexSampler : sampler; - @group(0) @binding(4) var preColorTex : texture_2d; - @group(0) @binding(5) var posTex : texture_2d; - @group(0) @binding(6) var inTexSampler : sampler; - @group(0) @binding(7) var inTex : texture_2d; - @group(0) @binding(8) var outTex : texture_storage_2d; - - var texSize: vec2; - var fragCoord: vec2; - var coordIndex: i32; - var color_min: vec4; - var color_max: vec4; - var color_avg: vec4; - var re_proj_uv01: vec2; - var FLT_EPS:f32 = 5.960464478e-8; // 2^-24, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f) - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2( globalInvocation_id.xy ); - texSize = textureDimensions(inTex).xy; - if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){ - return; - } - let frame = standUniform.frame; - coordIndex = fragCoord.x + fragCoord.y * i32(texSize.x); - - let oc = blendColor(); - preColorBuffer[coordIndex] = oc; - textureStore(outTex, fragCoord , oc); - } - - fn blendColor() -> vec4 - { - var preCoord = fragCoord; - var mixWeight = 1.0; - re_proj_uv01 = vec2(0.0); - var reProjectionCoord:vec2 = vec2(fragCoord); - //var jitterUVOffset = 0.5 * vec2(taaData.jitterX, -taaData.jitterY); - if(taaData.jitterFrameIndex > 0.5){ - var wPos = textureLoad(posTex, fragCoord, 0); - let ndc = taaData.preProjMatrix * (taaData.preViewMatrix * vec4(wPos.xyz, 1.0)); - re_proj_uv01 = vec2(ndc.x, -ndc.y) / ndc.w; - re_proj_uv01 = (re_proj_uv01 + 1.0) * 0.5; - - if(re_proj_uv01.x >= 0.0 && re_proj_uv01.x <= 1.0 && re_proj_uv01.y >= 0.0 && re_proj_uv01.y <= 1.0){ - mixWeight = taaData.blendFactor; - //reProjectionCoord = re_proj_uv01 + jitterUVOffset; - reProjectionCoord.x = re_proj_uv01.x * f32(texSize.x - 1); - reProjectionCoord.y = re_proj_uv01.y * f32(texSize.y - 1); - preCoord = vec2(reProjectionCoord); - }else{ - //outside of screen - mixWeight = 1.0; - } - } - - var curUV01 = vec2(fragCoord) / vec2(texSize - 1); - //curUV01 += jitterUVOffset; - - let curColor = textureSampleLevel(inTex, inTexSampler, curUV01, 0.0); - - let preIndex = preCoord.x + preCoord.y * i32(texSize.x); - var preColor = textureSampleLevel(preColorTex, preColorTexSampler, re_proj_uv01, 0.0); - - //minmax9(fragCoord); - minmax4(fragCoord); - - preColor = clip_aabb(color_min.xyz, color_max.xyz, color_avg, preColor); - var outColor = mix(preColor, curColor, mixWeight); - - return outColor; - } - - fn clampCoord(coord0:vec2) -> vec2{ - return clamp(coord0, vec2(0), vec2(texSize - 1)); - } - - fn minmax4(coord:vec2) { - let uv0 = clampCoord(vec2(coord.x - 1, coord.y)); - let uv1 = clampCoord(vec2(coord.x, coord.y - 1)); - let uv2 = clampCoord(vec2(coord.x, coord.y + 1)); - let uv3 = clampCoord(vec2(coord.x + 1, coord.y)); - - let c0 = textureLoad(inTex, uv0, 0); - let c1 = textureLoad(inTex, uv1, 0); - let c2 = textureLoad(inTex, uv2, 0); - let c3 = textureLoad(inTex, uv3, 0); - - color_min = min(c0, min(c1, min(c2, c3))); - color_max = max(c0, max(c1, max(c2, c3))); - color_avg = (c0 + c1 + c2 + c3) * 0.25; - } - - fn minmax9(coord:vec2) { - let uv0 = clampCoord(vec2(coord.x - 1, coord.y - 1)); - let uv1 = clampCoord(vec2(coord.x - 1, coord.y)); - let uv2 = clampCoord(vec2(coord.x - 1, coord.y + 1)); - let uv3 = clampCoord(vec2(coord.x, coord.y - 1)); - let uv4 = clampCoord(vec2(coord.x, coord.y)); - let uv5 = clampCoord(vec2(coord.x, coord.y + 1)); - let uv6 = clampCoord(vec2(coord.x + 1, coord.y - 1)); - let uv7 = clampCoord(vec2(coord.x + 1, coord.y)); - let uv8 = clampCoord(vec2(coord.x + 1, coord.y + 1)); - - let ctl = textureLoad(inTex, uv0, 0); - let ctc = textureLoad(inTex, uv1, 0); - let ctr = textureLoad(inTex, uv2, 0); - let cml = textureLoad(inTex, uv3, 0); - let cmc = textureLoad(inTex, uv4, 0); - let cmr = textureLoad(inTex, uv5, 0); - let cbl = textureLoad(inTex, uv6, 0); - let cbc = textureLoad(inTex, uv7, 0); - let cbr = textureLoad(inTex, uv8, 0); - - color_min = min(ctl, min(ctc, min(ctr, min(cml, min(cmc, min(cmr, min(cbl, min(cbc, cbr)))))))); - color_max = max(ctl, max(ctc, max(ctr, max(cml, max(cmc, max(cmr, max(cbl, max(cbc, cbr)))))))); - color_avg = (ctl + ctc + ctr + cml + cmc + cmr + cbl + cbc + cbr) / 9.0; - } - - fn clip_aabb(aabb_max:vec3, aabb_min:vec3, color_avg:vec4, input_texel:vec4) -> vec4 - { - var p_clip:vec3 = 0.5 * (aabb_max + aabb_min); - var e_clip:vec3 = 0.5 * (aabb_max - aabb_min) + FLT_EPS; - var v_clip:vec4 = input_texel - vec4(p_clip, color_avg.w); - var v_unit:vec3 = v_clip.xyz / e_clip; - var a_unit:vec3 = abs(v_unit); - var ma_unit:f32 = max(a_unit.x, max(a_unit.y, a_unit.z)); - - if (ma_unit > 1.0){ - return vec4(p_clip, color_avg.w) + v_clip / ma_unit; - }else{ - return input_texel; - } - } \ No newline at end of file diff --git a/src/assets/shader/materials/core/base/Common_frag.wgsl b/src/assets/shader/materials/core/base/Common_frag.wgsl deleted file mode 100644 index cf46db9c..00000000 --- a/src/assets/shader/materials/core/base/Common_frag.wgsl +++ /dev/null @@ -1,26 +0,0 @@ -#include "GlobalUniform" -#include "FragmentVarying" -#include "ColorPassFragmentOutput" -#include "ShadingInput" - -var ORI_FragmentOutput: FragmentOutput; -var ORI_VertexVarying: FragmentVarying; -var ORI_ShadingInput: ShadingInput; -@fragment -fn FragMain( vertex_varying:FragmentVarying ) -> FragmentOutput { - ORI_VertexVarying = vertex_varying; - ORI_FragmentOutput.color = vec4(1.0, 0.0, 0.0, 1.0); - #if USE_WORLDPOS - ORI_FragmentOutput.worldPos = ORI_VertexVarying.vWorldPos; - #endif - #if USEGBUFFER - ORI_FragmentOutput.worldNormal = vec4(ORI_ShadingInput.Normal.rgb ,1.0); - ORI_FragmentOutput.material = vec4(0.0,1.0,0.0,0.0); - #endif - frag(); - #if USE_DEBUG - debugFragmentOut(); - #endif - - return ORI_FragmentOutput ; -} diff --git a/src/assets/shader/materials/core/base/Common_vert.wgsl b/src/assets/shader/materials/core/base/Common_vert.wgsl deleted file mode 100644 index e5b674ae..00000000 --- a/src/assets/shader/materials/core/base/Common_vert.wgsl +++ /dev/null @@ -1,11 +0,0 @@ -#include "WorldMatrixUniform" -#include "VertexAttributes_vert" -#include "GlobalUniform" -#include "Inline_vert" -@vertex -fn VertMain( vertex:VertexAttributes ) -> VertexOutput { - vertex_inline(vertex); - vert(vertex); - return ORI_VertexOut ; -} - diff --git a/src/assets/shader/materials/core/common/BrdfLut_frag.wgsl b/src/assets/shader/materials/core/common/BrdfLut_frag.wgsl deleted file mode 100644 index 6a10ea79..00000000 --- a/src/assets/shader/materials/core/common/BrdfLut_frag.wgsl +++ /dev/null @@ -1,4 +0,0 @@ -@group(1) @binding(auto) -var brdflutMapSampler: sampler; -@group(1) @binding(auto) -var brdflutMap: texture_2d; \ No newline at end of file diff --git a/src/assets/shader/materials/core/common/EnvMap_frag.wgsl b/src/assets/shader/materials/core/common/EnvMap_frag.wgsl deleted file mode 100644 index a26b3e5e..00000000 --- a/src/assets/shader/materials/core/common/EnvMap_frag.wgsl +++ /dev/null @@ -1,9 +0,0 @@ - -@group(1) @binding(auto) -var prefilterMapSampler: sampler; -@group(1) @binding(auto) -var prefilterMap: texture_cube; -@group(1) @binding(auto) -var envMapSampler: sampler; -@group(1) @binding(auto) -var envMap: texture_cube; \ No newline at end of file diff --git a/src/assets/shader/materials/core/common/GlobalUniform.wgsl b/src/assets/shader/materials/core/common/GlobalUniform.wgsl deleted file mode 100644 index 8cd5e057..00000000 --- a/src/assets/shader/materials/core/common/GlobalUniform.wgsl +++ /dev/null @@ -1,37 +0,0 @@ - - struct GlobalUniform { - projMat: mat4x4, - viewMat: mat4x4, - cameraWorldMatrix: mat4x4, - pvMatrixInv : mat4x4, - shadowMatrix: array,8>, - CameraPos: vec3, - - frame: f32, - time: f32, - delta: f32, - shadowBias: f32, - skyExposure: f32, - renderPassState:f32, - quadScale: f32, - hdrExposure: f32, - - renderState_left: i32, - renderState_right: i32, - renderState_split: f32, - - mouseX: f32, - mouseY: f32, - windowWidth: f32, - windowHeight: f32, - - near: f32, - far: f32, - - pointShadowBias: f32, - shadowMapSize: f32, - shadowSoft: f32, - }; - - @group(0) @binding(0) - var globalUniform: GlobalUniform; diff --git a/src/assets/shader/materials/core/common/InstanceUniform.wgsl b/src/assets/shader/materials/core/common/InstanceUniform.wgsl deleted file mode 100644 index b3b943e4..00000000 --- a/src/assets/shader/materials/core/common/InstanceUniform.wgsl +++ /dev/null @@ -1,7 +0,0 @@ -#if USE_INSTANCEDRAW - struct InstanceUniform { - matrixIDs : array - }; - @group(2) @binding(7) - var instanceDrawID : InstanceUniform; -#endif \ No newline at end of file diff --git a/src/assets/shader/materials/core/inline/Inline_vert.wgsl b/src/assets/shader/materials/core/inline/Inline_vert.wgsl deleted file mode 100644 index d3ce06cf..00000000 --- a/src/assets/shader/materials/core/inline/Inline_vert.wgsl +++ /dev/null @@ -1,49 +0,0 @@ - - #include "MathShader" - #include "FastMathShader" - #include "InstanceUniform" - - var ORI_MATRIX_P: mat4x4; - var ORI_MATRIX_V: mat4x4; - var ORI_MATRIX_M: mat4x4; - var ORI_MATRIX_PV: mat4x4; - var ORI_MATRIX_PVInv: mat4x4; - var ORI_MATRIX_World: mat4x4; - var ORI_CAMERAMATRIX: mat4x4; - var ORI_NORMALMATRIX: mat3x3; - var ORI_CameraWorldDir: vec3; - - var TIME: vec4; - var MOUSE: vec4; - var SCREEN: vec4; - - var ProjectionParams: vec4; - - fn vertex_inline(vertex:VertexAttributes){ - TIME.x = globalUniform.frame; - TIME.y = globalUniform.time; - TIME.z = globalUniform.delta; - - MOUSE.x = globalUniform.mouseX; - MOUSE.y = globalUniform.mouseY; - - SCREEN.x = globalUniform.windowWidth; - SCREEN.y = globalUniform.windowHeight; - - ProjectionParams.x = globalUniform.near; - ProjectionParams.y = globalUniform.far; - ProjectionParams.z = 1.0 + 1.0 / globalUniform.far; - - ORI_MATRIX_P = globalUniform.projMat ; - ORI_MATRIX_V = globalUniform.viewMat ; - ORI_MATRIX_PV = ORI_MATRIX_P * ORI_MATRIX_V ; - ORI_MATRIX_PVInv = globalUniform.pvMatrixInv ; - ORI_CAMERAMATRIX = globalUniform.cameraWorldMatrix ; - - ORI_MATRIX_M = models.matrix[u32(vertex.index)]; - - #if USE_INSTANCEDRAW - let modelID = instanceDrawID.matrixIDs[vertex.index]; - ORI_MATRIX_M = models.matrix[modelID]; - #endif - } \ No newline at end of file diff --git a/src/assets/shader/materials/graphic/Graphic3DShader_fs.wgsl b/src/assets/shader/materials/graphic/Graphic3DShader_fs.wgsl deleted file mode 100644 index f0b039eb..00000000 --- a/src/assets/shader/materials/graphic/Graphic3DShader_fs.wgsl +++ /dev/null @@ -1,30 +0,0 @@ -struct FragmentOutput { - @location(0) color: vec4, - // #if USE_WORLDPOS - @location(1) worldPos: vec4, - // #endif - // #if USEGBUFFER - @location(2) worldNormal: vec4, - @location(3) material: vec4 - // #endif -}; - -@fragment -fn main( - @location(0) vWorldPos: vec4, - @location(1) varying_Color: vec4, -) -> FragmentOutput { - var result: FragmentOutput; - - // #if USE_WORLDPOS - result.worldPos = vWorldPos; - // #endif - - // #if USEGBUFFER - // result.worldNormal = vec4(0.0, 0.0, 0.0, 1.0); - result.material = vec4(0.0, 1.0, 0.0, 0.0); - // #endif - - result.color = varying_Color; - return result; -} diff --git a/src/assets/shader/materials/graphic/Graphic3DShader_vs.wgsl b/src/assets/shader/materials/graphic/Graphic3DShader_vs.wgsl deleted file mode 100644 index 336abcde..00000000 --- a/src/assets/shader/materials/graphic/Graphic3DShader_vs.wgsl +++ /dev/null @@ -1,27 +0,0 @@ -#include "WorldMatrixUniform" -#include "GlobalUniform" - -struct VertexAttributes { - @location(0) position: vec4, - @location(1) color: vec4, -} - -struct VertexOutput { - @location(0) varying_WPos: vec4, - @location(1) varying_Color: vec4, - @builtin(position) member: vec4 -}; - -@vertex -fn main( vertex:VertexAttributes ) -> VertexOutput { - var worldMatrix = models.matrix[u32(vertex.position.w)]; - var worldPos = (worldMatrix * vec4(vertex.position.xyz, 1.0)); - var viewPosition = ((globalUniform.viewMat) * worldPos); - var clipPosition = globalUniform.projMat * viewPosition; - - var ORI_VertexOut: VertexOutput; - ORI_VertexOut.varying_WPos = worldPos; - ORI_VertexOut.varying_Color = vertex.color; - ORI_VertexOut.member = clipPosition; - return ORI_VertexOut; -} diff --git a/src/assets/shader/materials/materials/GlassShader.wgsl b/src/assets/shader/materials/materials/GlassShader.wgsl deleted file mode 100644 index 19e5b95d..00000000 --- a/src/assets/shader/materials/materials/GlassShader.wgsl +++ /dev/null @@ -1,36 +0,0 @@ - - #include "Common_vert" - #include "Common_frag" - #include "UnLit_frag" - #include "UnLitMaterialUniform_frag" - - // @group(1) @binding(auto) - // var noes_MapSampler: sampler; - // @group(1) @binding(auto) - // var noes_Map: texture_2d; - - @group(1) @binding(auto) - var splitTexture_MapSampler: sampler; - @group(1) @binding(auto) - var splitTexture_Map: texture_2d; - - fn vert(inputData:VertexAttributes) -> VertexOutput { - ORI_Vert(inputData) ; - return ORI_VertexOut ; - } - - fn frag(){ - var screenUV = ORI_VertexVarying.fragPosition.xy / ORI_VertexVarying.fragPosition.w; - screenUV = (screenUV.xy + 1.0) * 0.5; - screenUV.y = 1.0 - screenUV.y; - - screenUV.x = clamp(sin(screenUV.x * 1.0),0.0,1.0) ; - screenUV.y = clamp(sin(screenUV.y * 1.0),0.0,1.0) ; - // screenUV.y = cos(ORI_VertexVarying.fragPosition.y/7.15); - - let frameMap = textureSample(splitTexture_Map,splitTexture_MapSampler,screenUV); - // let noesMap = textureSample(noes_Map,noes_MapSampler,screenUV); - - ORI_ShadingInput.BaseColor = vec4( frameMap.rgb , 1.0) ; - UnLit(); - } diff --git a/src/assets/shader/materials/materials/LitShader.wgsl b/src/assets/shader/materials/materials/LitShader.wgsl deleted file mode 100644 index 7e9aad9c..00000000 --- a/src/assets/shader/materials/materials/LitShader.wgsl +++ /dev/null @@ -1,22 +0,0 @@ - - #include "Common_vert" - #include "Common_frag" - #include "BxDF_frag" - - fn vert(inputData:VertexAttributes) -> VertexOutput { - ORI_Vert(inputData) ; - return ORI_VertexOut ; - } - - fn frag(){ - ORI_ShadingInput.BaseColor = materialUniform.baseColor ; - ORI_ShadingInput.Roughness = materialUniform.roughness ; - ORI_ShadingInput.Metallic = materialUniform.metallic ; - ORI_ShadingInput.Specular = 0.5 ; - ORI_ShadingInput.AmbientOcclusion = materialUniform.ao ; - ORI_ShadingInput.EmissiveColor = vec4(0.0); - - ORI_ShadingInput.Normal = ORI_VertexVarying.vWorldNormal.rgb ; - - BxDFShading(); - } diff --git a/src/assets/shader/materials/materials/OutlinePass.wgsl b/src/assets/shader/materials/materials/OutlinePass.wgsl deleted file mode 100644 index 028cc2c4..00000000 --- a/src/assets/shader/materials/materials/OutlinePass.wgsl +++ /dev/null @@ -1,80 +0,0 @@ - #include "Common_vert" - #include "Common_frag" - #include "UnLit_frag" - - @group(1) @binding(0) - var baseMapSampler: sampler; - @group(1) @binding(1) - var baseMap: texture_2d; - - -struct MaterialUniform { - baseColor:vec4, - lineWeight:f32 -}; - -@group(2) @binding(0) -var materialUniform: MaterialUniform; - - fn vert(vertex:VertexAttributes) -> VertexOutput { - var vertexPosition = vertex.position; - var vertexNormal = vertex.normal; - - #if USE_MORPHTARGETS - vertexPosition = vertexPosition * morphTargetData.morphBaseInfluence + vertex.a_morphPositions_0 * morphTargetData.morphInfluence0; - #if USE_MORPHNORMALS - vertexNormal = vertexNormal * morphTargetData.morphBaseInfluence + vertex.a_morphNormals_0 * morphTargetData.morphInfluence0; - #endif - #endif - - #if USE_SKELETON - #if USE_JOINT_VEC8 - let skeletonNormal = getSkeletonWorldMatrix_8(vertex.joints0, vertex.weights0, vertex.joints1, vertex.weights1); - ORI_MATRIX_M *= skeletonNormal ; - // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; - #else - let skeletonNormal = getSkeletonWorldMatrix_4(vertex.joints0, vertex.weights0); - ORI_MATRIX_M *= skeletonNormal ; - // vertexNormal = vec4(vec4(vertexNormal,0.0) * skeletonNormal).xyz; - #endif - #endif - - - #if USE_TANGENT - ORI_VertexOut.varying_Tangent = vertex.TANGENT ; - #endif - - ORI_NORMALMATRIX = transpose(inverse( mat3x3(ORI_MATRIX_M[0].xyz,ORI_MATRIX_M[1].xyz,ORI_MATRIX_M[2].xyz) )); - - let worldNormal = normalize(ORI_NORMALMATRIX * vertexNormal.xyz) ; - - vertexPosition = vertexPosition + worldNormal * materialUniform.lineWeight ; - - var worldPos = (ORI_MATRIX_M * vec4(vertexPosition.xyz, 1.0)); - var viewPosition = ORI_MATRIX_V * worldPos; - var clipPosition = ORI_MATRIX_P * viewPosition ; - - ORI_VertexOut.varying_UV0 = vertex.uv.xy ; - ORI_VertexOut.varying_UV1 = vertex.TEXCOORD_1.xy; - ORI_VertexOut.varying_ViewPos = viewPosition / viewPosition.w; - ORI_VertexOut.varying_Clip = clipPosition ; - ORI_VertexOut.varying_WPos = worldPos ; - ORI_VertexOut.varying_WPos.w = f32(vertex.index); - ORI_VertexOut.varying_WNormal = worldNormal ; - ORI_VertexOut.member = clipPosition ; - - - return ORI_VertexOut ; - } - - fn frag(){ - let color = textureSample(baseMap,baseMapSampler,ORI_VertexVarying.fragUV0) ; - ORI_ShadingInput.BaseColor = color * materialUniform.baseColor ; - ORI_ShadingInput.Roughness = 0.5 ; - ORI_ShadingInput.Metallic = 0.5 ; - ORI_ShadingInput.Specular = 0.5 ; - ORI_ShadingInput.AmbientOcclusion = 1.0 ; - ORI_ShadingInput.EmissiveColor = vec4(0.0); - ORI_ShadingInput.Normal = ORI_VertexVarying.vWorldNormal.rgb ; - UnLit(); - } \ No newline at end of file diff --git a/src/assets/shader/materials/materials/PBRLItShader.wgsl b/src/assets/shader/materials/materials/PBRLItShader.wgsl deleted file mode 100644 index 228dac62..00000000 --- a/src/assets/shader/materials/materials/PBRLItShader.wgsl +++ /dev/null @@ -1,106 +0,0 @@ - - #include "Common_vert" - #include "Common_frag" - #include "BxDF_frag" - - @group(1) @binding(auto) - var baseMapSampler: sampler; - @group(1) @binding(auto) - var baseMap: texture_2d; - - @group(1) @binding(auto) - var normalMapSampler: sampler; - @group(1) @binding(auto) - var normalMap: texture_2d; - - #if USE_ARMC - @group(1) @binding(auto) - var maskMapSampler: sampler; - @group(1) @binding(auto) - var maskMap: texture_2d; - #endif - - #if USE_AOTEX - @group(1) @binding(auto) - var aoMapSampler: sampler; - @group(1) @binding(auto) - var aomapMap: texture_2d; - #endif - - @group(1) @binding(auto) - var emissiveMapSampler: sampler; - @group(1) @binding(auto) - var emissiveMap: texture_2d; - - fn vert(inputData:VertexAttributes) -> VertexOutput { - ORI_Vert(inputData) ; - return ORI_VertexOut ; - } - - fn frag(){ - var transformUV1 = materialUniform.transformUV1; - var transformUV2 = materialUniform.transformUV2; - - var uv = transformUV1.zw * ORI_VertexVarying.fragUV0 + transformUV1.xy; - - ORI_ShadingInput.BaseColor = textureSample(baseMap, baseMapSampler, uv ) * materialUniform.baseColor ; - - // #if USE_ALPHACUT - // ORI_ShadingInput.BaseColor.a = clamp(ORI_ShadingInput.BaseColor.a, 0.001 , 1.0 ); - if( (ORI_ShadingInput.BaseColor.a - materialUniform.alphaCutoff) <= 0.0 ){ - ORI_FragmentOutput.color = vec4(0.0,0.0,0.0,1.0); - ORI_FragmentOutput.worldPos = vec4(0.0,0.0,0.0,1.0); - ORI_FragmentOutput.worldNormal = vec4(0.0,0.0,0.0,1.0); - ORI_FragmentOutput.material = vec4(0.0,0.0,0.0,1.0); - discard; - } - // #endif - - #if USE_SHADOWMAPING - directShadowMaping(globalUniform.shadowBias); - pointShadowMapCompare(globalUniform.pointShadowBias); - #endif - - - // ORI_ShadingInput.BaseColor = vec4(sRGBToLinear(ORI_ShadingInput.BaseColor.xyz),ORI_ShadingInput.BaseColor.w); - - #if USE_ARMC - var maskTex = textureSample(maskMap, maskMapSampler, uv ) ; - - ORI_ShadingInput.AmbientOcclusion = maskTex.r * materialUniform.ao ; - - #if USE_AOTEX - var aoMap = textureSample(aomapMap, aoMapSampler, uv ); - ORI_ShadingInput.AmbientOcclusion = mix(0.0,aoMap.r,materialUniform.ao) ; - #endif - - ORI_ShadingInput.Roughness = maskTex.g * materialUniform.roughness ; - ORI_ShadingInput.Metallic = maskTex.b * materialUniform.metallic ; - - #else - ORI_ShadingInput.Roughness = materialUniform.roughness ; - ORI_ShadingInput.Metallic = materialUniform.metallic ; - ORI_ShadingInput.AmbientOcclusion = materialUniform.ao ; - #if USE_AOTEX - var aoMap = textureSample(aomapMap, aoMapSampler, ORI_VertexVarying.fragUV0.xy ); - ORI_ShadingInput.AmbientOcclusion = mix(0.0,aoMap.r,materialUniform.ao) ; - #endif - #endif - - ORI_ShadingInput.Roughness = clamp(ORI_ShadingInput.Roughness,0.084,1.0); - ORI_ShadingInput.Specular = 0.5 ; - - var emissiveColor = textureSample(emissiveMap, emissiveMapSampler , ORI_VertexVarying.fragUV0.xy) ; - ORI_ShadingInput.EmissiveColor = vec4(materialUniform.emissiveColor.rgb * emissiveColor.rgb * materialUniform.emissiveIntensity,1.0); - - var Normal = textureSample(normalMap,normalMapSampler,ORI_VertexVarying.fragUV0).rgb ; - // Normal.y = 1.0 - Normal.y ; - // let normal = unPackNormal(Normal,1.0,materialUniform.normalScale) ; - let normal = unPackNormal(Normal,materialUniform.normalScale) ; - ORI_ShadingInput.Normal = normal ; - - BxDFShading(); - - - - } diff --git a/src/assets/shader/materials/materials/UnLit.wgsl b/src/assets/shader/materials/materials/UnLit.wgsl deleted file mode 100644 index 0c31f8b2..00000000 --- a/src/assets/shader/materials/materials/UnLit.wgsl +++ /dev/null @@ -1,28 +0,0 @@ - #include "Common_vert" - #include "Common_frag" - #include "UnLit_frag" - #include "UnLitMaterialUniform_frag" - - @group(1) @binding(0) - var baseMapSampler: sampler; - @group(1) @binding(1) - var baseMap: texture_2d; - - fn vert(inputData:VertexAttributes) -> VertexOutput { - ORI_Vert(inputData) ; - return ORI_VertexOut ; - } - - fn frag(){ - var transformUV1 = materialUniform.transformUV1; - var transformUV2 = materialUniform.transformUV2; - - var uv = transformUV1.zw * ORI_VertexVarying.fragUV0 + transformUV1.xy; - let color = textureSample(baseMap,baseMapSampler,uv) ; - if(color.w < 0.5){ - discard ; - } - - ORI_ShadingInput.BaseColor = color * materialUniform.baseColor ; - UnLit(); - } \ No newline at end of file diff --git a/src/assets/shader/materials/math/FastMathShader.wgsl b/src/assets/shader/materials/math/FastMathShader.wgsl deleted file mode 100644 index d10eaf7c..00000000 --- a/src/assets/shader/materials/math/FastMathShader.wgsl +++ /dev/null @@ -1,31 +0,0 @@ -fn Pow3( x : f32 ) -> f32 -{ - var xx = x*x; - return x * xx; -} - -fn Pow4( x : f32 ) -> f32 -{ - var xx = x*x; - return xx * xx; -} - -fn pow5(x: f32) -> f32 { - var x2 = x * x; - return x2 * x2 * x; -} - -fn rcp( x:f32 ) -> f32 -{ - return 1.0 / x; -} - -fn rsqrt3( a : vec3 ) -> vec3 -{ - return pow(a, vec3(-0.5)); -} - -fn rsqrt( a : f32 ) -> f32 -{ - return pow(a, -0.5); -} diff --git a/src/assets/shader/materials/post/FSAAShader.wgsl b/src/assets/shader/materials/post/FSAAShader.wgsl deleted file mode 100644 index 67ba238e..00000000 --- a/src/assets/shader/materials/post/FSAAShader.wgsl +++ /dev/null @@ -1,76 +0,0 @@ -struct FragmentOutput { - @location(0) o_Target: vec4 -}; - -var varying_uv: vec2; -@group(1) @binding(0) -var baseMapSampler: sampler; -@group(1) @binding(1) -var baseMap: texture_2d; - -struct MaterialUniform{ - u_texel: vec2, - u_strength: f32, -} - - @group(2) @binding(0) - var materialUniform: MaterialUniform; - - -fn LinearToGammaSpace(linRGB0: vec3) -> vec3 { - var linRGB = max(linRGB0, vec3(0.0, 0.0, 0.0)); - linRGB.r = pow(linRGB.r,0.416666667); - linRGB.g = pow(linRGB.g,0.416666667); - linRGB.b = pow(linRGB.b,0.416666667); - return max(1.055 * linRGB - 0.055, vec3(0.0, 0.0, 0.0)); -} - -fn texture2D( uv:vec2 , offset:vec2 ) -> vec4 { - return textureSample(baseMap, baseMapSampler, uv.xy + offset ).rgba ; -} - -@fragment -fn main(@location(0) fragUV: vec2) -> FragmentOutput { - var v_vTexcoord = fragUV ; - // v_vTexcoord.x = 1.0 - v_vTexcoord.x ; - v_vTexcoord.y = 1.0 - v_vTexcoord.y ; - - var reducemul = 1.0 / 8.0; - var reducemin = 1.0 / 128.0; - - var basecol = texture2D(v_vTexcoord , vec2(0.0)).rgba; - var baseNW = texture2D(v_vTexcoord , -materialUniform.u_texel).rgb; - var baseNE = texture2D(v_vTexcoord , vec2(materialUniform.u_texel.x, -materialUniform.u_texel.y)).rgb; - var baseSW = texture2D(v_vTexcoord , vec2(-materialUniform.u_texel.x, materialUniform.u_texel.y)).rgb; - var baseSE = texture2D(v_vTexcoord , materialUniform.u_texel ).rgb; - - // var gray = vec3(0.299, 0.587, 0.114); - var gray = vec3(0.213, 0.715, 0.072); - var monocol = dot(basecol.rgb, gray); - var monoNW = dot(baseNW, gray); - var monoNE = dot(baseNE, gray); - var monoSW = dot(baseSW, gray); - var monoSE = dot(baseSE, gray); - - var monomin = min(monocol, min(min(monoNW, monoNE), min(monoSW, monoSE))); - var monomax = max(monocol, max(max(monoNW, monoNE), max(monoSW, monoSE))); - - var dir = vec2(-((monoNW + monoNE) - (monoSW + monoSE)), ((monoNW + monoSW) - (monoNE + monoSE))); - var dirreduce = max((monoNW + monoNE + monoSW + monoSE) * reducemul * 0.25, reducemin); - var dirmin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirreduce); - dir = min(vec2(materialUniform.u_strength), max(vec2(-materialUniform.u_strength), dir * dirmin)) * materialUniform.u_texel; - - var resultA = 0.5 * (texture2D(v_vTexcoord , dir * -0.166667).rgb + - texture2D(v_vTexcoord , dir * 0.166667).rgb); - var resultB = resultA * 0.5 + 0.25 * (texture2D( v_vTexcoord , dir * -0.5).rgb + - texture2D( v_vTexcoord , dir * 0.5).rgb); - var monoB = dot(resultB.rgb, gray); - - var color:vec3 ; - if(monoB < monomin || monoB > monomax) { - color = resultA ;//* v_vColour; - } else { - color = resultB ;//* v_vColour; - } - return FragmentOutput(vec4(color.rgb,basecol.a)); -} \ No newline at end of file diff --git a/src/assets/shader/materials/program/BxdfDebug_frag.wgsl b/src/assets/shader/materials/program/BxdfDebug_frag.ts similarity index 98% rename from src/assets/shader/materials/program/BxdfDebug_frag.wgsl rename to src/assets/shader/materials/program/BxdfDebug_frag.ts index ee337854..2e36276b 100644 --- a/src/assets/shader/materials/program/BxdfDebug_frag.wgsl +++ b/src/assets/shader/materials/program/BxdfDebug_frag.ts @@ -1,5 +1,5 @@ - - #include "ClusterDebug_frag" +export let BxdfDebug_frag: string = /*wgsl*/ ` +#include "ClusterDebug_frag" fn debugPosition(){ ORI_FragmentOutput.color = vec4(ORI_VertexVarying.vWorldPos.xyz,1.0); @@ -172,4 +172,5 @@ } } } - } \ No newline at end of file + } +` diff --git a/src/assets/shader/materials/program/Clearcoat_frag.ts b/src/assets/shader/materials/program/Clearcoat_frag.ts new file mode 100644 index 00000000..ee478d64 --- /dev/null +++ b/src/assets/shader/materials/program/Clearcoat_frag.ts @@ -0,0 +1,21 @@ + + + + +export let Clearcoat_frag: string = /*wgsl*/ ` + #if USE_CLEARCOAT_ROUGHNESS + @group(1) @binding(auto) + var clearCoatRoughnessMapSampler: sampler; + @group(1) @binding(auto) + var clearCoatRoughnessMap: texture_2d; + + fn getClearcoatRoughnees() -> f32{ + let clearcoatRoughness = textureSample(clearCoatRoughnessMap, clearCoatRoughnessMapSampler, ORI_VertexVarying.fragUV0.xy).r; + return clearcoatRoughness; + } + #else + fn getClearcoatRoughnees() -> f32{ + return 0.0; + } + #endif +` \ No newline at end of file diff --git a/src/assets/shader/materials/program/Clearcoat_frag.wgsl b/src/assets/shader/materials/program/Clearcoat_frag.wgsl deleted file mode 100644 index 3081ebb8..00000000 --- a/src/assets/shader/materials/program/Clearcoat_frag.wgsl +++ /dev/null @@ -1,16 +0,0 @@ - - #if USE_CLEARCOAT_ROUGHNESS - @group(1) @binding(auto) - var clearCoatRoughnessMapSampler: sampler; - @group(1) @binding(auto) - var clearCoatRoughnessMap: texture_2d; - - fn getClearcoatRoughnees() -> f32{ - let clearcoatRoughness = textureSample(clearCoatRoughnessMap, clearCoatRoughnessMapSampler , ORI_VertexVarying.fragUV0.xy).r ; - return clearcoatRoughness ; - } - #else - fn getClearcoatRoughnees() -> f32{ - return 0.0 ; - } - #endif \ No newline at end of file diff --git a/src/assets/shader/materials/program/NormalMap_frag.wgsl b/src/assets/shader/materials/program/NormalMap_frag.ts similarity index 96% rename from src/assets/shader/materials/program/NormalMap_frag.wgsl rename to src/assets/shader/materials/program/NormalMap_frag.ts index d3f023dd..8af8cb5e 100644 --- a/src/assets/shader/materials/program/NormalMap_frag.wgsl +++ b/src/assets/shader/materials/program/NormalMap_frag.ts @@ -1,4 +1,4 @@ - +export let NormalMap_frag: string = /*wgsl*/ ` fn perturbNormal( worldPos:vec3, surf_norm:vec3, mapN:vec3 , normalScale:f32 , face:f32 ) -> vec3 { var q0 = vec3( dpdx( worldPos.x ), dpdx( worldPos.y ), dpdx( worldPos.z ) ); var q1 = vec3( dpdy( worldPos.x ), dpdy( worldPos.y ), dpdy( worldPos.z ) ); @@ -38,7 +38,7 @@ #else var n = normal ; #if USE_NORMALFILPY - n.y = 1.0 - n.y ; + n.y = 1.0 - n.y ; #endif var mapNormal: vec3 = unpackNormalMap(n) ; @@ -55,3 +55,5 @@ var outN = perturbNormal(ORI_VertexVarying.vWorldPos.xyz,ORI_VertexVarying.vWorldNormal,mapNormal,1.0,face) ; return outN ; } +` + diff --git a/src/assets/shader/materials/program/ShadowMapping_frag.ts b/src/assets/shader/materials/program/ShadowMapping_frag.ts new file mode 100644 index 00000000..6103f5ef --- /dev/null +++ b/src/assets/shader/materials/program/ShadowMapping_frag.ts @@ -0,0 +1,142 @@ +export let ShadowMapping_frag: string = /*wgsl*/ ` + #if USE_SHADOWMAPING + @group(1) @binding(auto) var shadowMapSampler: sampler_comparison; + @group(1) @binding(auto) var shadowMap: texture_depth_2d_array; + #endif + + @group(1) @binding(auto) var pointShadowMapSampler: sampler; + @group(1) @binding(auto) var pointShadowMap: texture_depth_cube_array; + + struct ShadowStruct{ + directShadowVisibility: array, + pointShadows: array, + } + + varshadowStrut: ShadowStruct; + + fn directShadowMaping(shadowBias: f32) { + for (var i: i32 = i32(0); i < i32(clustersUniform.numLights); i = i + 1) { + var light = lightBuffer[i]; + var shadowIndex = i32(light.castShadow); + shadowStrut.directShadowVisibility[shadowIndex] = 1.0; + #if USE_SHADOWMAPING + + + if (shadowIndex < 0 && light.lightType != DirectLightType) { + continue; + } + + var shadowPosTmp = globalUniform.shadowMatrix[shadowIndex] * vec4(ORI_VertexVarying.vWorldPos.xyz, 1.0); + var shadowPos = shadowPosTmp.xyz / shadowPosTmp.w; + var varying_shadowUV = shadowPos.xy * vec2(0.5, -0.5) + vec2(0.5, 0.5); + var bias = max(shadowBias * (1.0 - dot(ORI_ShadingInput.Normal, light.direction)), 0.000005); + + // if(varying_shadowUV.y>=1.0) { + // shadowStrut.directShadowVisibility[shadowIndex] = 2.0 ; + // continue; + // } + if (varying_shadowUV.x <= 1.0 && varying_shadowUV.x >= 0.0 && varying_shadowUV.y <= 1.0 && varying_shadowUV.y >= 0.0 && shadowPosTmp.z <= 1.0) { + var texelSize = 1.0 / vec2(globalUniform.shadowMapSize); + var oneOverShadowDepthTextureSize = texelSize; + var size = 1; + var sizeBlock = size * 2 + 1; + var sizeBlockA = sizeBlock * sizeBlock; + var visibility = 0.0; + for (var y = -size; y <= size; y++) { + for (var x = -size; x <= size; x++) { + var offset = vec2(f32(x), f32(y)) * oneOverShadowDepthTextureSize / f32(sizeBlock); + visibility += textureSampleCompare( + shadowMap, + shadowMapSampler, + varying_shadowUV + offset, + shadowIndex, + shadowPos.z - bias + ); + } + } + visibility /= f32(sizeBlockA); + shadowStrut.directShadowVisibility[shadowIndex] = visibility + 0.001; + } + #endif + } + } + + fn pointShadowMapCompare(shadowBias: f32){ + let worldPos = ORI_VertexVarying.vWorldPos.xyz; + let offset = 0.1; + let lightIndex = getCluster(ORI_VertexVarying.fragCoord); + let start = max(lightIndex.start, 0.0); + let count = max(lightIndex.count, 0.0); + let end = max(start + count, 0.0); + for (var i: i32 = i32(start); i < i32(end); i = i + 1) { + let light = getLight(i); + shadowStrut.pointShadows[light.castShadow] = 1.0; + + #if USE_SHADOWMAPING + if (light.castShadow < 0 || light.lightType == DirectLightType) { + continue; + } + let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; + var shadow = 0.0; + let frgToLight = worldPos - lightPos.xyz; + var dir: vec3 = normalize(frgToLight); + var len = length(frgToLight); + var bias = max(shadowBias * globalUniform.far * (1.0 - dot(ORI_ShadingInput.Normal, dir)), 0.005); + + #if USE_PCF_SHADOW + let samples = 4.0; + for (var x: f32 = -offset; x < offset; x += offset / (samples * 0.5)) { + for (var y: f32 = -offset; y < offset; y += offset / (samples * 0.5)) { + for (var z: f32 = -offset; z < offset; z += offset / (samples * 0.5)) { + let offsetDir = normalize(dir.xyz + vec3(x, y, z)); + var depth = textureSampleLevel(pointShadowMap, pointShadowMapSampler, offsetDir, light.castShadow, 0); + depth *= globalUniform.far; + if ((len - bias) > depth) { + shadow += 1.0 * dot(offsetDir, dir.xyz); + } + } + } + } + shadow = min(max(shadow / (samples * samples * samples), 0.0), 1.0); + #endif + + #if USE_SOFT_SHADOW + let vDis = length(globalUniform.CameraPos.xyz - worldPos.xyz); + let sampleRadies = globalUniform.shadowSoft; + let samples = 20; + for (var j: i32 = 0; j < samples; j += 1) { + let offsetDir = normalize(dir.xyz + sampleOffetDir[j] * sampleRadies); + var depth = textureSampleLevel(pointShadowMap, pointShadowMapSampler, offsetDir, light.castShadow, 0); + depth *= globalUniform.far; + if ((len - bias) > depth) { + shadow += 1.0 * dot(offsetDir, dir.xyz); + } + } + shadow = min(max(shadow / f32(samples), 0.0), 1.0); + #endif + + #if USE_HARD_SHADOW + var depth = textureSampleLevel(pointShadowMap, pointShadowMapSampler, dir.xyz, light.castShadow, 0); + depth *= globalUniform.far; + if ((len - bias) > depth) { + shadow = 1.0; + } + #endif + + shadowStrut.pointShadows[light.castShadow] = 1.0 - shadow; + #endif + } + } + + #if USE_SOFT_SHADOW + varsampleOffetDir : array, 20> = array, 20>( + vec3(1.0, 1.0, 1.0), vec3(1.0, -1.0, 1.0), vec3(-1.0, -1.0, 1.0), vec3(-1.0, 1.0, 1.0), + vec3(1.0, 1.0, -1.0), vec3(1.0, -1.0, -1.0), vec3(-1.0, -1.0, -1.0), vec3(-1.0, 1.0, -1.0), + vec3(1.0, 1.0, 0.0), vec3(1.0, -1.0, 0.0), vec3(-1.0, -1.0, 0.0), vec3(-1.0, 1.0, 0.0), + vec3(1.0, 0.0, 1.0), vec3(-1.0, 0.0, 1.0), vec3(1.0, 0.0, -1.0), vec3(-1.0, 0.0, -1.0), + vec3(0.0, 1.0, 1.0), vec3(0.0, -1.0, 1.0), vec3(0.0, -1.0, -1.0), vec3(0.0, 1.0, -1.0), + ); + #endif +` + + diff --git a/src/assets/shader/materials/program/ShadowMapping_frag.wgsl b/src/assets/shader/materials/program/ShadowMapping_frag.wgsl deleted file mode 100644 index e67a6717..00000000 --- a/src/assets/shader/materials/program/ShadowMapping_frag.wgsl +++ /dev/null @@ -1,142 +0,0 @@ - - - #if USE_SHADOWMAPING - @group(1) @binding(auto) var shadowMapSampler: sampler_comparison; - @group(1) @binding(auto) var shadowMap: texture_depth_2d_array ; - #endif - - @group(1) @binding(auto) var pointShadowMapSampler: sampler; - @group(1) @binding(auto) var pointShadowMap: texture_depth_cube_array ; - - struct ShadowStruct{ - directShadowVisibility:array, - pointShadows:array , - } - - var shadowStrut: ShadowStruct ; - - fn directShadowMaping(shadowBias:f32) { - for(var i:i32 = i32(0) ; i < i32(clustersUniform.numLights) ; i = i + 1 ) - { - var light = lightBuffer[i] ; - var shadowIndex = i32(light.castShadow) ; - shadowStrut.directShadowVisibility[shadowIndex] = 1.0 ; - #if USE_SHADOWMAPING - - - if(shadowIndex < 0 && light.lightType != DirectLightType){ - continue ; - } - - var shadowPosTmp = globalUniform.shadowMatrix[shadowIndex] * vec4(ORI_VertexVarying.vWorldPos.xyz,1.0) ; - var shadowPos = shadowPosTmp.xyz / shadowPosTmp.w ; - var varying_shadowUV = shadowPos.xy * vec2(0.5, -0.5) + vec2(0.5, 0.5) ; - var bias = max(shadowBias * (1.0 - dot(ORI_ShadingInput.Normal, light.direction)) , 0.000005); - - // if(varying_shadowUV.y>=1.0) { - // shadowStrut.directShadowVisibility[shadowIndex] = 2.0 ; - // continue; - // } - if(varying_shadowUV.x <= 1.0 && varying_shadowUV.x >= 0.0 && varying_shadowUV.y <= 1.0 && varying_shadowUV.y >= 0.0 && shadowPosTmp.z <= 1.0 ){ - var texelSize = 1.0 / vec2(globalUniform.shadowMapSize); - var oneOverShadowDepthTextureSize = texelSize ; - var size = 1 ; - var sizeBlock = size * 2 + 1; - var sizeBlockA = sizeBlock * sizeBlock ; - var visibility = 0.0 ; - for (var y = -size; y <= size; y++) { - for (var x = -size; x <= size; x++) { - var offset = vec2(f32(x),f32(y)) * oneOverShadowDepthTextureSize / f32(sizeBlock) ; - visibility += textureSampleCompare( - shadowMap, - shadowMapSampler, - varying_shadowUV + offset, - shadowIndex, - shadowPos.z - bias - ); - } - } - visibility /= f32(sizeBlockA) ; - shadowStrut.directShadowVisibility[shadowIndex] = visibility + 0.001 ; - } - #endif - } - } - - fn pointShadowMapCompare(shadowBias:f32){ - let worldPos = ORI_VertexVarying.vWorldPos.xyz ; - let offset = 0.1 ; - let lightIndex = getCluster(ORI_VertexVarying.fragCoord); - let start = max(lightIndex.start, 0.0); - let count = max(lightIndex.count, 0.0); - let end = max(start + count , 0.0); - for(var i:i32 = i32(start) ; i < i32(end) ; i = i + 1 ) - { - let light = getLight(i); - shadowStrut.pointShadows[light.castShadow] = 1.0 ; - - #if USE_SHADOWMAPING - if(light.castShadow < 0 || light.lightType == DirectLightType){ - continue ; - } - let lightPos = models.matrix[u32(light.lightMatrixIndex)][3].xyz; - var shadow = 0.0 ; - let frgToLight = worldPos - lightPos.xyz; - var dir:vec3 = normalize(frgToLight) ; - var len = length(frgToLight) ; - var bias = max(shadowBias * globalUniform.far * (1.0 - dot(ORI_ShadingInput.Normal, dir)) , 0.005); - - #if USE_PCF_SHADOW - let samples = 4.0 ; - for (var x : f32 = -offset ; x < offset ; x += offset / (samples * 0.5) ) { - for (var y : f32 = -offset ; y < offset ; y += offset / (samples * 0.5) ) { - for (var z : f32 = -offset ; z < offset ; z += offset / (samples * 0.5) ) { - let offsetDir = normalize(dir.xyz + vec3(x,y,z)) ; - var depth = textureSampleLevel(pointShadowMap,pointShadowMapSampler,offsetDir,light.castShadow,0); - depth *= globalUniform.far ; - if((len - bias ) > depth){ - shadow += 1.0 * dot(offsetDir,dir.xyz); - } - } - } - } - shadow = min(max(shadow / (samples*samples*samples),0.0),1.0) ; - #endif - - #if USE_SOFT_SHADOW - let vDis = length( globalUniform.CameraPos.xyz - worldPos.xyz ); - let sampleRadies = globalUniform.shadowSoft ; - let samples = 20 ; - for (var j : i32 = 0 ; j < samples ; j += 1 ) { - let offsetDir = normalize(dir.xyz + sampleOffetDir[j] * sampleRadies) ; - var depth = textureSampleLevel(pointShadowMap,pointShadowMapSampler,offsetDir,light.castShadow,0); - depth *= globalUniform.far ; - if((len - bias) > depth){ - shadow += 1.0 * dot(offsetDir,dir.xyz); - } - } - shadow = min(max(shadow / f32(samples) ,0.0),1.0) ; - #endif - - #if USE_HARD_SHADOW - var depth = textureSampleLevel(pointShadowMap,pointShadowMapSampler,dir.xyz,light.castShadow,0); - depth *= globalUniform.far ; - if((len - bias) > depth){ - shadow = 1.0 ; - } - #endif - - shadowStrut.pointShadows[light.castShadow] = 1.0 - shadow ; - #endif - } - } - - #if USE_SOFT_SHADOW - var sampleOffetDir : array,20> = array,20>( - vec3(1.0,1.0,1.0),vec3(1.0,-1.0,1.0),vec3(-1.0,-1.0,1.0),vec3(-1.0,1.0,1.0), - vec3(1.0,1.0,-1.0),vec3(1.0,-1.0,-1.0),vec3(-1.0,-1.0,-1.0),vec3(-1.0,1.0,-1.0), - vec3(1.0,1.0,0.0),vec3(1.0,-1.0,0.0),vec3(-1.0,-1.0,0.0),vec3(-1.0,1.0,0.0), - vec3(1.0,0.0,1.0),vec3(-1.0,0.0,1.0),vec3(1.0,0.0,-1.0),vec3(-1.0,0.0,-1.0), - vec3(0.0,1.0,1.0),vec3(0.0,-1.0,1.0),vec3(0.0,-1.0,-1.0),vec3(0.0,1.0,-1.0), - ); - #endif diff --git a/src/assets/shader/materials/sky/AtmosphericScatteringSky_shader.ts b/src/assets/shader/materials/sky/AtmosphericScatteringSky_shader.ts deleted file mode 100644 index 278c3d3a..00000000 --- a/src/assets/shader/materials/sky/AtmosphericScatteringSky_shader.ts +++ /dev/null @@ -1,311 +0,0 @@ -/** - * @internal - */ -export class AtmosphericScatteringSky_shader { - public static cs: string = /* wgsl */ ` - struct UniformData { - width: f32, - height: f32, - sunU: f32, - sunV: f32, - eyePos: f32, - sunRadius: f32, // = 500.0; - sunRadiance: f32, // = 20.0; - mieG: f32, // = 0.76; - mieHeight: f32, // = 1200; - sunBrightness: f32, // = 1.0; - displaySun: f32, // > 0.5: true - }; - - @group(0) @binding(0) var uniformBuffer: UniformData; - @group(0) @binding(1) var outTexture : texture_storage_2d; - - var uv01: vec2; - var fragCoord: vec2; - var texSizeF32: vec2; - - var PI:f32 = 3.1415926535; - var PI_2:f32 = 0.0; - var EPSILON:f32 = 0.00001; - var SAMPLES_NUMS:i32 = 16; - - var transmittance:vec3; - var insctrMie:vec3; - var insctrRayleigh:vec3; - - @compute @workgroup_size( 8 , 8 , 1 ) - fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(global_invocation_id) globalInvocation_id : vec3) - { - fragCoord = vec2(globalInvocation_id.xy); - texSizeF32 = vec2( uniformBuffer.width, uniformBuffer.height); - uv01 = vec2(globalInvocation_id.xy) / texSizeF32; - uv01.y = 1.0 - uv01.y - EPSILON; - PI_2 = PI * 2.0; - textureStore(outTexture, fragCoord , mainImage(uv01));//vec4(uv01, 0.0, 1.0)); - } - - struct ScatteringParams - { - sunRadius:f32, - sunRadiance:f32, - - mieG:f32, - mieHeight:f32, - - rayleighHeight:f32, - - waveLambdaMie:vec3, - waveLambdaOzone:vec3, - waveLambdaRayleigh:vec3, - - earthRadius:f32, - earthAtmTopRadius:f32, - earthCenter:vec3, - } - - fn ComputeSphereNormal(coord:vec2, phiStart:f32, phiLength:f32, thetaStart:f32, thetaLength:f32) -> vec3 - { - var normal:vec3; - normal.x = -sin(thetaStart + coord.y * thetaLength) * sin(phiStart + coord.x * phiLength); - normal.y = -cos(thetaStart + coord.y * thetaLength); - normal.z = -sin(thetaStart + coord.y * thetaLength) * cos(phiStart + coord.x * phiLength); - return normalize(normal); - } - - fn ComputeRaySphereIntersection(position:vec3, dir:vec3, center:vec3, radius:f32) -> vec2 - { - var origin:vec3 = position - center; - var B = dot(origin, dir); - var C = dot(origin, origin) - radius * radius; - var D = B * B - C; - - var minimaxIntersections:vec2; - if (D < 0.0) - { - minimaxIntersections = vec2(-1.0, -1.0); - } - else - { - D = sqrt(D); - minimaxIntersections = vec2(-B - D, -B + D); - } - - return minimaxIntersections; - } - - fn ComputeWaveLambdaRayleigh(lambda: vec3) -> vec3 - { - var n:f32 = 1.0003; - var N:f32 = 2.545E25; - var pn:f32 = 0.035; - var n2:f32 = n * n; - var pi3:f32 = PI * PI * PI; - var rayleighConst:f32 = (8.0 * pi3 * pow(n2 - 1.0,2.0)) / (3.0 * N) * ((6.0 + 3.0 * pn) / (6.0 - 7.0 * pn)); - return vec3(rayleighConst) / (lambda * lambda * lambda * lambda); - } - - fn ComputePhaseMie(theta: f32, g:f32) -> f32 - { - var g2 = g * g; - return (1.0 - g2) / pow(1.0 + g2 - 2.0 * g * saturate(theta), 1.5) / (4.0 * PI); - } - - fn ComputePhaseRayleigh(theta: f32) -> f32 - { - var theta2 = theta * theta; - return (theta2 * 0.75 + 0.75) / (4.0 * PI); - } - - fn ChapmanApproximation(X: f32, h: f32, cosZenith: f32) -> f32 - { - var c = sqrt(X + h); - var c_exp_h = c * exp(-h); - - if (cosZenith >= 0.0) - { - return c_exp_h / (c * cosZenith + 1.0); - } - else - { - var x0 = sqrt(1.0 - cosZenith * cosZenith) * (X + h); - var c0 = sqrt(x0); - - return 2.0 * c0 * exp(X - x0) - c_exp_h / (1.0 - c * cosZenith); - } - } - - fn GetOpticalDepthSchueler(h: f32, H: f32, earthRadius: f32, cosZenith: f32) -> f32 - { - return H * ChapmanApproximation(earthRadius / H, h / H, cosZenith); - } - - fn GetTransmittance(setting: ScatteringParams, L:vec3, V: vec3) -> vec3 - { - var ch = GetOpticalDepthSchueler(L.y, setting.rayleighHeight, setting.earthRadius, V.y); - return exp(-(setting.waveLambdaMie + setting.waveLambdaRayleigh) * ch); - } - - fn ComputeOpticalDepth(setting: ScatteringParams, samplePoint: vec3, V: vec3, L: vec3, neg: f32) -> vec2 - { - var rl = length(samplePoint); - var h = rl - setting.earthRadius; - var r: vec3 = samplePoint / rl; - - var cos_chi_sun = dot(r, L); - var cos_chi_ray = dot(r, V * neg); - - var opticalDepthSun = GetOpticalDepthSchueler(h, setting.rayleighHeight, setting.earthRadius, cos_chi_sun); - var opticalDepthCamera = GetOpticalDepthSchueler(h, setting.rayleighHeight, setting.earthRadius, cos_chi_ray) * neg; - - return vec2(opticalDepthSun, opticalDepthCamera); - } - - fn AerialPerspective(setting:ScatteringParams, start: vec3, end: vec3, V: vec3, L: vec3, infinite:i32) - { - var inf_neg:f32 = 1.0; - if( infinite == 0){ - inf_neg = -1.0; - } - - var sampleStep: vec3 = (end - start) / f32(SAMPLES_NUMS); - var samplePoint: vec3 = end - sampleStep; - var sampleLambda: vec3 = setting.waveLambdaMie + setting.waveLambdaRayleigh + setting.waveLambdaOzone; - - var sampleLength:f32 = length(sampleStep); - - var scattering:vec3 = vec3(0.0); - var lastOpticalDepth:vec2 = ComputeOpticalDepth(setting, end, V, L, inf_neg); - - for (var i:i32 = 1; i < SAMPLES_NUMS; i = i + 1) - { - var opticalDepth: vec2 = ComputeOpticalDepth(setting, samplePoint, V, L, inf_neg); - - var segment_s: vec3 = exp(-sampleLambda * (opticalDepth.x + lastOpticalDepth.x)); - var segment_t: vec3 = exp(-sampleLambda * (opticalDepth.y - lastOpticalDepth.y)); - - transmittance *= segment_t; - - scattering = scattering * segment_t; - scattering += exp(-(length(samplePoint) - setting.earthRadius) / setting.rayleighHeight) * segment_s; - - lastOpticalDepth = opticalDepth; - samplePoint = samplePoint - sampleStep; - } - - insctrMie = scattering * setting.waveLambdaMie * sampleLength; - insctrRayleigh = scattering * setting.waveLambdaRayleigh * sampleLength; - } - - fn ComputeSkyboxChapman(setting: ScatteringParams, eye:vec3, V:vec3, L:vec3) -> f32 - { - var neg:i32 = 1; - var outerIntersections: vec2 = ComputeRaySphereIntersection(eye, V, setting.earthCenter, setting.earthAtmTopRadius); - if (outerIntersections.y < 0.0){ - return 0.0; - } - var innerIntersections: vec2 = ComputeRaySphereIntersection(eye, V, setting.earthCenter, setting.earthRadius); - if (innerIntersections.x > 0.0) - { - neg = 0; - outerIntersections.y = innerIntersections.x; - } - - let eye0 = eye - setting.earthCenter; - - var start : vec3 = eye0 + V * max(0.0, outerIntersections.x); - var end : vec3= eye0 + V * outerIntersections.y; - - AerialPerspective(setting, start, end, V, L, neg); - - //bool intersectionTest = innerIntersections.x < 0.0 && innerIntersections.y < 0.0; - //return intersectionTest ? 1.0 : 0.0; - - if(innerIntersections.x < 0.0 && innerIntersections.y < 0.0){ - return 1.0; - } - return 0.0; - } - - fn ComputeSkyInscattering(setting: ScatteringParams, eye: vec3, V: vec3, L: vec3) -> vec4 - { - transmittance = vec3(1.0); - insctrMie = vec3(0.0); - insctrRayleigh = vec3(0.0); - var intersectionTest:f32 = ComputeSkyboxChapman(setting, eye, V, L); - - var phaseTheta = dot(V, L); - var phaseMie = ComputePhaseMie(phaseTheta, setting.mieG); - var phaseRayleigh = ComputePhaseRayleigh(phaseTheta); - var phaseNight = 1.0 - saturate(transmittance.x * EPSILON); - - var insctrTotalMie: vec3 = insctrMie * phaseMie; - var insctrTotalRayleigh: vec3 = insctrRayleigh * phaseRayleigh; - - var sky: vec3 = (insctrTotalMie + insctrTotalRayleigh) * setting.sunRadiance; - if(uniformBuffer.displaySun > 0.5){ - var angle:f32 = saturate((1.0 - phaseTheta) * setting.sunRadius); - var cosAngle:f32 = cos(angle * PI * 0.5); - var edge:f32 = 0.0; - if(angle >= 0.9){ - edge = smoothstep(0.9, 1.0, angle); - } - - var limbDarkening: vec3 = GetTransmittance(setting, -L, V); - limbDarkening *= pow(vec3(cosAngle), vec3(0.420, 0.503, 0.652)) * mix(vec3(1.0), vec3(1.2,0.9,0.5), edge) * intersectionTest; - sky += limbDarkening * uniformBuffer.sunBrightness; - } - return vec4(sky, phaseNight * intersectionTest); - } - - fn TonemapACES(x: vec3) -> vec3 - { - var A:f32 = 2.51f; - var B:f32 = 0.03f; - var C:f32 = 2.43f; - var D:f32 = 0.59f; - var E:f32 = 0.14f; - return (x * (A * x + B)) / (x * (C * x + D) + E); - } - - fn noise(uv:vec2) -> f32 - { - return fract(dot(sin(vec3(uv.xyx) * vec3(uv.xyy) * 1024.0), vec3(341896.483, 891618.637, 602649.7031))); - } - - fn mainImage( uv:vec2 ) -> vec4 - { - let eyePosition = uniformBuffer.eyePos; - var sun = vec2(uniformBuffer.sunU, uniformBuffer.sunV); - var V: vec3 = ComputeSphereNormal(uv, 0.0, PI_2, 0.0, PI); - var L: vec3 = ComputeSphereNormal(vec2(sun.x, sun.y), 0.0, PI_2, 0.0, PI); - - var setting: ScatteringParams; - setting.sunRadius = uniformBuffer.sunRadius;//500.0; - setting.sunRadiance = uniformBuffer.sunRadiance;//20.0; - setting.mieG = uniformBuffer.mieG;//0.76; - setting.mieHeight = uniformBuffer.mieHeight;// 1200.0; - setting.rayleighHeight = 8000.0; - setting.earthRadius = 6360000.0; - setting.earthAtmTopRadius = 6420000.0; - setting.earthCenter = vec3(0, -setting.earthRadius, 0); - setting.waveLambdaMie = vec3(0.0000002); - - // wavelength with 680nm, 550nm, 450nm - setting.waveLambdaRayleigh = ComputeWaveLambdaRayleigh(vec3(0.000000680, 0.000000550, 0.000000450)); - - // see https://www.shadertoy.com/view/MllBR2 - setting.waveLambdaOzone = vec3(1.36820899679147, 3.31405330400124, 0.13601728252538) * 0.0000006 * 2.504; - - var eye:vec3 = vec3(0,eyePosition,0); - var sky0:vec4 = ComputeSkyInscattering(setting, eye, V, L); - var sky = vec3(sky0.rgb); - - // sky = TonemapACES(sky.rgb * 2.0); - // sky = pow(sky.rgb, vec3(2.4)); // gamma - // sky.rgb += noise(uv*iTime) / 255.0; // dither - - var fragColor:vec4 = vec4(sky, 1.0); - return fragColor; - } - `; -} diff --git a/src/assets/shader/materials/sky/CubeSky_Shader.ts b/src/assets/shader/materials/sky/CubeSky_Shader.ts deleted file mode 100644 index dca45731..00000000 --- a/src/assets/shader/materials/sky/CubeSky_Shader.ts +++ /dev/null @@ -1,98 +0,0 @@ -export class CubeSky_Shader { - public static sky_vs_frag_wgsl: string = /* wgsl */ ` - #include "WorldMatrixUniform" - #include "GlobalUniform" - - struct VertexOutput { - @location(0) fragUV: vec2, - @location(1) vWorldPos: vec4, - @location(2) vWorldNormal: vec3, - @builtin(position) member: vec4 - }; - - var ORI_VertexOut: VertexOutput ; - - @vertex - fn main( - @builtin(instance_index) index : u32, - @location(0) position: vec3, - @location(1) normal: vec3, - @location(2) uv: vec2 - ) -> VertexOutput { - ORI_VertexOut.fragUV = uv; - let modelMat = models.matrix[u32(index)]; - let vm = globalUniform.viewMat * modelMat; - let normalMatrix = mat3x3(vm[0].xyz,vm[1].xyz,vm[2].xyz); - ORI_VertexOut.vWorldNormal = normalize( normalMatrix * normal ); - ORI_VertexOut.vWorldPos = modelMat * vec4(position.xyz,1.0) ; - - var fixProjMat = globalUniform.projMat ; - fixProjMat[2].z = 1.0 ;//99999.0 / (99999.0 - 1.0) ; - fixProjMat[3].z = -1.0 ;//(-1.0 * 99999.0) / (99999.0 - 1.0) ; - - var fixViewMat = globalUniform.viewMat ; - fixViewMat[3].x = 0.0 ; - fixViewMat[3].y = 0.0 ; - fixViewMat[3].z = 0.0 ; - - var clipPos = fixProjMat * fixViewMat * ORI_VertexOut.vWorldPos; - ORI_VertexOut.member = clipPos; - return ORI_VertexOut; - } - ` - - public static sky_fs_frag_wgsl: string = /* wgsl */ ` - #include "GlobalUniform" - - struct uniformData { - exposure: f32, - roughness: f32 - }; - - struct FragmentOutput { - @location(0) o_Target: vec4, - #if USE_WORLDPOS - @location(1) o_Position: vec4, - #endif - #if USEGBUFFER - @location(2) o_Normal: vec4, - @location(3) o_Material: vec4 - #endif - }; - - @group(1) @binding(0) - var baseMapSampler: sampler; - @group(1) @binding(1) - var baseMap: texture_cube; - - @group(2) @binding(0) - var global: uniformData; - - fn LinearToGammaSpace(linRGB: vec3) -> vec3 { - var linRGB1 = max(linRGB, vec3(0.0)); - linRGB1 = pow(linRGB1, vec3(0.4166666567325592)); - return max(((1.0549999475479126 * linRGB1) - vec3(0.054999999701976776)), vec3(0.0)); - } - - @fragment - fn main(@location(0) fragUV: vec2, @location(1) vWorldPos: vec4, @location(2) vWorldNormal: vec3) -> FragmentOutput { - let maxLevel: u32 = textureNumLevels(baseMap); - let textureColor:vec3 = textureSampleLevel(baseMap, baseMapSampler, normalize(vWorldPos.xyz), global.roughness * f32(maxLevel) ).xyz; - let o_Target: vec4 = vec4(LinearToGammaSpace(textureColor),1.0) * globalUniform.skyExposure ; - var normal_rgba8unorm = (vWorldNormal + 1.0) * 0.5; - normal_rgba8unorm = clamp(normal_rgba8unorm, vec3(0.0), vec3(1.0)); - - return FragmentOutput( - o_Target, - #if USE_WORLDPOS - vWorldPos, - #endif - #if USEGBUFFER - vec4(normal_rgba8unorm,0.0), - vec4(0.0,1.0,0.0,0.0) - #endif - ); - } - `; - -} \ No newline at end of file diff --git a/src/assets/shader/materials/utils/BRDFLUT.wgsl b/src/assets/shader/materials/utils/BRDFLUT.wgsl deleted file mode 100644 index 4a898192..00000000 --- a/src/assets/shader/materials/utils/BRDFLUT.wgsl +++ /dev/null @@ -1,112 +0,0 @@ - var PI:f32 = 3.141592653589793 ; - - // fn saturate( x : f32 ) -> f32 { - // return clamp(x, 0.0, 1.0); - // } - - fn hammersley( i : u32 , N : u32 ) -> vec2 - { - // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html - var bits = (i << 16u) | (i >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - var rdi = f32(bits) * 2.3283064365386963e-10; - return vec2(f32(i) /f32(N), rdi); - } - - fn G_Smith( NoV:f32 , NoL : f32 , roughness : f32 ) -> f32 - { - var k = (roughness * roughness) / 2.0; - var GGXL = NoL / (NoL * (1.0 - k) + k); - var GGXV = NoV / (NoV * (1.0 - k) + k); - return GGXL * GGXV; - } - - fn V_SmithGGXCorrelated( NoV:f32 , NoL : f32 , roughness : f32 ) -> f32 - { - var a2 = pow(roughness, 4.0); - var GGXV = NoL * sqrt(NoV * NoV * (1.0 - a2) + a2); - var GGXL = NoV * sqrt(NoL * NoL * (1.0 - a2) + a2); - return 0.5 / (GGXV + GGXL); - } - - - // Based on Karis 2014 - fn importanceSampleGGX( Xi:vec2, roughness:f32 , N:vec3 ) -> vec3 - { - var a = roughness * roughness; - // Sample in spherical coordinates - var Phi = 2.0 * PI * Xi.x; - var CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); - var SinTheta = sqrt(1.0 - CosTheta * CosTheta); - // Construct tangent space vector - var H:vec3; - H.x = SinTheta * cos(Phi); - H.y = SinTheta * sin(Phi); - H.z = CosTheta; - - // Tangent to world space - var UpVector = vec3(1.0,0.0,0.0); - if(abs(N.z) < 0.999){ - UpVector = vec3(0.0,0.0,1.0) ; - } - var TangentX = normalize(cross(UpVector, N)); - var TangentY = cross(N, TangentX); - return TangentX * H.x + TangentY * H.y + N * H.z; - } - - - // Karis 2014 - fn integrateBRDF( roughness:f32 , NoV: f32) -> vec2 - { - var V : vec3 ; - V.x = sqrt(1.0 - NoV * NoV); // sin - V.y = 0.0; - V.z = NoV; // cos - - // N points straight upwards for this integration - var N = vec3(0.0, 0.0, 1.0); - - var A = 0.0; - var B = 0.0; - var numSamples = 1024u; - - for (var i = 0u; i < numSamples; i+=1u) { - var Xi = hammersley(i, numSamples); - // Sample microfacet direction - var H = importanceSampleGGX(Xi, roughness, N); - - // Get the light direction - var L = 2.0 * dot(V, H) * H - V; - - var NoL = saturate(dot(N, L)); - var NoH = saturate(dot(N, H)); - var VoH = saturate(dot(V, H)); - - if(NoL > 0.0) { - var V_pdf = V_SmithGGXCorrelated(NoV, NoL, roughness) * VoH * NoL / NoH; - var Fc = pow(1.0 - VoH, 5.0); - A += (1.0 - Fc) * V_pdf; - B += Fc * V_pdf; - } - } - - return 4.0 * vec2(A, B) / f32(numSamples); - } - - @group(0) @binding(0) var brdflutTexture : texture_storage_2d; - - @compute @workgroup_size(8,8,1) - // fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(local_invocation_id) local_invocation_id : vec3 ){ - fn CsMain( @builtin(global_invocation_id) global_invocation_id : vec3){ - var fragCoord = vec2( global_invocation_id.x, global_invocation_id.y); - - var fragColor = vec4(0.0) ; - // Output to screen - var res = integrateBRDF( f32(fragCoord.y+1u) / 256.0 , f32(fragCoord.x+1u) / 256.0 ); - fragColor = vec4(res.x, res.y, 0.0, 1.0) ; - - textureStore(brdflutTexture, vec2(fragCoord.xy), fragColor ); - } diff --git a/src/assets/shader/materials/utils/ColorUtil.wgsl b/src/assets/shader/materials/utils/ColorUtil.wgsl deleted file mode 100644 index 5db84e7a..00000000 --- a/src/assets/shader/materials/utils/ColorUtil.wgsl +++ /dev/null @@ -1,99 +0,0 @@ - - - fn getHDRColor(color:vec3,exposure:f32)-> vec3{ - // var newColor = color * ( 1.0 / 255.0 ) ; - return color * pow(2.4 , exposure) ; - } - - fn lambda2rgb( lambda : f32 ) -> vec3 { - let ultraviolet = 400.0; - let infrared = 700.0; - - var a = (lambda - ultraviolet)/(infrared - ultraviolet); - let c = 10.0; - var b = vec3(a) - vec3(0.75,0.5,0.25); - return max((1.0 - c*b*b), vec3(0.0) ); - } - - fn CEToneMapping( color:vec3, adapted_lum:f32)-> vec3 - { - return 1.0 - exp(-adapted_lum * color); - } - - fn ACESToneMapping( color:vec3, adapted_lum:f32 )-> vec3 - { - let A = 2.51; - let B = 0.03; - let C = 2.43; - let D = 0.59; - let E = 0.14; - - var color2 = color * adapted_lum; - color2 = (color2 * (A * color2 + B)) / (color2 * (C * color2 + D) + E); - return color2 ; - } - - fn gammaToLiner(color:vec4) -> vec4 { - let gammaCorrect = 2.4; - var color2 = pow(color, vec4(gammaCorrect)); - return color2 ; - } - - fn linerToGamma4(color:vec4) -> vec4 { - let gammaCorrect = 1.0 / 2.4; - var color2 = pow(color, vec4(gammaCorrect)); - return color2 ; - } - - fn linerToGamma3(color:vec3) -> vec3 { - let gammaCorrect = 1.0 / 2.4; - var color2 = pow(color, vec3(gammaCorrect)); - return color2 ; - } - - fn LinearToGammaSpace(linRGB0: vec3) -> vec3 { - var linRGB = max(linRGB0, vec3(0.0, 0.0, 0.0)); - linRGB.r = pow(linRGB.r,0.416666667); - linRGB.g = pow(linRGB.g,0.416666667); - linRGB.b = pow(linRGB.b,0.416666667); - return max(1.055 * linRGB - 0.055, vec3(0.0, 0.0, 0.0)); - } - - var sRGB_2_LMS_MAT:mat3x3 = mat3x3( - 17.8824, 43.5161, 4.1193, - 3.4557, 27.1554, 3.8671, - 0.02996, 0.18431, 1.4670, - ) ; - - var LMS_2_sRGB_MAT:mat3x3 = mat3x3( - 0.0809, -0.1305, 0.1167, - -0.0102, 0.0540, -0.1136, - -0.0003, -0.0041, 0.6935, - ); - - fn sRGB_2_LMS( RGB:vec3 ) -> vec3 - { - return sRGB_2_LMS_MAT * RGB ; - } - - fn LMS_2_sRGB( LMS:vec3 ) -> vec3 - { - return LMS_2_sRGB_MAT * LMS; - } - - fn LinearToSrgbBranchless( lin:vec3 ) -> vec3 - { - var lin2 = max(vec3(6.10352e-5), lin); - return min(lin2 * 12.92, pow(max(lin2, vec3(0.00313067)), vec3(1.0/2.4)) * vec3(1.055) - vec3(0.055)); - } - - fn sRGBToLinear( color : vec3 ) -> vec3 - { - let color2 = max(vec3(6.10352e-5), color); - let c = 0.04045 ; - if(color2.r > c && color2.g > c && color2.b > c){ - return pow( color2 * (1.0 / 1.055) + 0.0521327, vec3(2.4) ) ; - }else{ - return color2 * (1.0 / 12.92); - } - } diff --git a/src/assets/shader/materials/utils/GenerayRandomDir.wgsl b/src/assets/shader/materials/utils/GenerayRandomDir.wgsl deleted file mode 100644 index 74a72796..00000000 --- a/src/assets/shader/materials/utils/GenerayRandomDir.wgsl +++ /dev/null @@ -1,23 +0,0 @@ - -fn madfrac(A:f32, B:f32)-> f32 { - return A*B-floor(A*B) ; -} - -fn sampleRandomDir(count:u32,SAMPLE_COUNT:u32) -> vec3{ - var ray_dir = sphericalFibonacci(f32((count)), f32(SAMPLE_COUNT) ); - return normalize(ray_dir) ; -} - -fn sphericalFibonacci( i : f32 , n : f32 ) -> vec3{ - const PHI = sqrt(5.0) * 0.5 + 0.5; - let phi = 2.0 * PI * madfrac(i, PHI - 1); - let cosTheta = 1.0 - (2.0 * i + 1.0) * (1.0 / n); - let sinTheta = sqrt(saturate(1.0 - cosTheta*cosTheta)); - - return vec3( - cos(phi) * sinTheta, - sin(phi) * sinTheta, - cosTheta); - -} - diff --git a/src/assets/shader/math/FastMathShader.ts b/src/assets/shader/math/FastMathShader.ts new file mode 100644 index 00000000..4a4eb495 --- /dev/null +++ b/src/assets/shader/math/FastMathShader.ts @@ -0,0 +1,34 @@ +export let FastMathShader: string = /*wgsl*/ ` + fn Pow3( x : f32 ) -> f32 + { + var xx = x*x; + return x * xx; + } + + fn Pow4( x : f32 ) -> f32 + { + var xx = x*x; + return xx * xx; + } + + fn pow5(x: f32) -> f32 { + var x2 = x * x; + return x2 * x2 * x; + } + + fn rcp( x:f32 ) -> f32 + { + return 1.0 / x; + } + + fn rsqrt3( a : vec3 ) -> vec3 + { + return pow(a, vec3(-0.5)); + } + + fn rsqrt( a : f32 ) -> f32 + { + return pow(a, -0.5); + } +` + diff --git a/src/assets/shader/math/FastMathShader.wgsl b/src/assets/shader/math/FastMathShader.wgsl deleted file mode 100644 index d10eaf7c..00000000 --- a/src/assets/shader/math/FastMathShader.wgsl +++ /dev/null @@ -1,31 +0,0 @@ -fn Pow3( x : f32 ) -> f32 -{ - var xx = x*x; - return x * xx; -} - -fn Pow4( x : f32 ) -> f32 -{ - var xx = x*x; - return xx * xx; -} - -fn pow5(x: f32) -> f32 { - var x2 = x * x; - return x2 * x2 * x; -} - -fn rcp( x:f32 ) -> f32 -{ - return 1.0 / x; -} - -fn rsqrt3( a : vec3 ) -> vec3 -{ - return pow(a, vec3(-0.5)); -} - -fn rsqrt( a : f32 ) -> f32 -{ - return pow(a, -0.5); -} diff --git a/src/assets/shader/post/FSAAShader.wgsl b/src/assets/shader/post/FSAAShader.wgsl deleted file mode 100644 index 67ba238e..00000000 --- a/src/assets/shader/post/FSAAShader.wgsl +++ /dev/null @@ -1,76 +0,0 @@ -struct FragmentOutput { - @location(0) o_Target: vec4 -}; - -var varying_uv: vec2; -@group(1) @binding(0) -var baseMapSampler: sampler; -@group(1) @binding(1) -var baseMap: texture_2d; - -struct MaterialUniform{ - u_texel: vec2, - u_strength: f32, -} - - @group(2) @binding(0) - var materialUniform: MaterialUniform; - - -fn LinearToGammaSpace(linRGB0: vec3) -> vec3 { - var linRGB = max(linRGB0, vec3(0.0, 0.0, 0.0)); - linRGB.r = pow(linRGB.r,0.416666667); - linRGB.g = pow(linRGB.g,0.416666667); - linRGB.b = pow(linRGB.b,0.416666667); - return max(1.055 * linRGB - 0.055, vec3(0.0, 0.0, 0.0)); -} - -fn texture2D( uv:vec2 , offset:vec2 ) -> vec4 { - return textureSample(baseMap, baseMapSampler, uv.xy + offset ).rgba ; -} - -@fragment -fn main(@location(0) fragUV: vec2) -> FragmentOutput { - var v_vTexcoord = fragUV ; - // v_vTexcoord.x = 1.0 - v_vTexcoord.x ; - v_vTexcoord.y = 1.0 - v_vTexcoord.y ; - - var reducemul = 1.0 / 8.0; - var reducemin = 1.0 / 128.0; - - var basecol = texture2D(v_vTexcoord , vec2(0.0)).rgba; - var baseNW = texture2D(v_vTexcoord , -materialUniform.u_texel).rgb; - var baseNE = texture2D(v_vTexcoord , vec2(materialUniform.u_texel.x, -materialUniform.u_texel.y)).rgb; - var baseSW = texture2D(v_vTexcoord , vec2(-materialUniform.u_texel.x, materialUniform.u_texel.y)).rgb; - var baseSE = texture2D(v_vTexcoord , materialUniform.u_texel ).rgb; - - // var gray = vec3(0.299, 0.587, 0.114); - var gray = vec3(0.213, 0.715, 0.072); - var monocol = dot(basecol.rgb, gray); - var monoNW = dot(baseNW, gray); - var monoNE = dot(baseNE, gray); - var monoSW = dot(baseSW, gray); - var monoSE = dot(baseSE, gray); - - var monomin = min(monocol, min(min(monoNW, monoNE), min(monoSW, monoSE))); - var monomax = max(monocol, max(max(monoNW, monoNE), max(monoSW, monoSE))); - - var dir = vec2(-((monoNW + monoNE) - (monoSW + monoSE)), ((monoNW + monoSW) - (monoNE + monoSE))); - var dirreduce = max((monoNW + monoNE + monoSW + monoSE) * reducemul * 0.25, reducemin); - var dirmin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirreduce); - dir = min(vec2(materialUniform.u_strength), max(vec2(-materialUniform.u_strength), dir * dirmin)) * materialUniform.u_texel; - - var resultA = 0.5 * (texture2D(v_vTexcoord , dir * -0.166667).rgb + - texture2D(v_vTexcoord , dir * 0.166667).rgb); - var resultB = resultA * 0.5 + 0.25 * (texture2D( v_vTexcoord , dir * -0.5).rgb + - texture2D( v_vTexcoord , dir * 0.5).rgb); - var monoB = dot(resultB.rgb, gray); - - var color:vec3 ; - if(monoB < monomin || monoB > monomax) { - color = resultA ;//* v_vColour; - } else { - color = resultB ;//* v_vColour; - } - return FragmentOutput(vec4(color.rgb,basecol.a)); -} \ No newline at end of file diff --git a/src/assets/shader/post/FXAAShader.ts b/src/assets/shader/post/FXAAShader.ts new file mode 100644 index 00000000..ac915d1b --- /dev/null +++ b/src/assets/shader/post/FXAAShader.ts @@ -0,0 +1,79 @@ +export let FXAAShader: string = /*wgsl*/ ` + struct FragmentOutput { + @location(0) o_Target: vec4 + }; + + var varying_uv: vec2; + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d; + + struct MaterialUniform{ + u_texel: vec2, + u_strength: f32, + } + + @group(2) @binding(0) + var materialUniform: MaterialUniform; + + + fn LinearToGammaSpace(linRGB0: vec3) -> vec3 { + var linRGB = max(linRGB0, vec3(0.0, 0.0, 0.0)); + linRGB.r = pow(linRGB.r,0.416666667); + linRGB.g = pow(linRGB.g,0.416666667); + linRGB.b = pow(linRGB.b,0.416666667); + return max(1.055 * linRGB - 0.055, vec3(0.0, 0.0, 0.0)); + } + + fn texture2D( uv:vec2 , offset:vec2 ) -> vec4 { + return textureSample(baseMap, baseMapSampler, uv.xy + offset ).rgba ; + } + + @fragment + fn main(@location(0) fragUV: vec2) -> FragmentOutput { + var v_vTexcoord = fragUV ; + // v_vTexcoord.x = 1.0 - v_vTexcoord.x ; + v_vTexcoord.y = 1.0 - v_vTexcoord.y ; + + var reducemul = 1.0 / 8.0; + var reducemin = 1.0 / 128.0; + + var basecol = texture2D(v_vTexcoord , vec2(0.0)).rgba; + var baseNW = texture2D(v_vTexcoord , -materialUniform.u_texel).rgb; + var baseNE = texture2D(v_vTexcoord , vec2(materialUniform.u_texel.x, -materialUniform.u_texel.y)).rgb; + var baseSW = texture2D(v_vTexcoord , vec2(-materialUniform.u_texel.x, materialUniform.u_texel.y)).rgb; + var baseSE = texture2D(v_vTexcoord , materialUniform.u_texel ).rgb; + + // var gray = vec3(0.299, 0.587, 0.114); + var gray = vec3(0.213, 0.715, 0.072); + var monocol = dot(basecol.rgb, gray); + var monoNW = dot(baseNW, gray); + var monoNE = dot(baseNE, gray); + var monoSW = dot(baseSW, gray); + var monoSE = dot(baseSE, gray); + + var monomin = min(monocol, min(min(monoNW, monoNE), min(monoSW, monoSE))); + var monomax = max(monocol, max(max(monoNW, monoNE), max(monoSW, monoSE))); + + var dir = vec2(-((monoNW + monoNE) - (monoSW + monoSE)), ((monoNW + monoSW) - (monoNE + monoSE))); + var dirreduce = max((monoNW + monoNE + monoSW + monoSE) * reducemul * 0.25, reducemin); + var dirmin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirreduce); + dir = min(vec2(materialUniform.u_strength), max(vec2(-materialUniform.u_strength), dir * dirmin)) * materialUniform.u_texel; + + var resultA = 0.5 * (texture2D(v_vTexcoord , dir * -0.166667).rgb + + texture2D(v_vTexcoord , dir * 0.166667).rgb); + var resultB = resultA * 0.5 + 0.25 * (texture2D( v_vTexcoord , dir * -0.5).rgb + + texture2D( v_vTexcoord , dir * 0.5).rgb); + var monoB = dot(resultB.rgb, gray); + + var color:vec3 ; + if(monoB < monomin || monoB > monomax) { + color = resultA ;//* v_vColour; + } else { + color = resultB ;//* v_vColour; + } + return FragmentOutput(vec4(color.rgb,basecol.a)); + } +` + diff --git a/src/assets/shader/post/GlobalFog_shader.ts b/src/assets/shader/post/GlobalFog_shader.ts index f6b7c018..7f6fd075 100644 --- a/src/assets/shader/post/GlobalFog_shader.ts +++ b/src/assets/shader/post/GlobalFog_shader.ts @@ -1,4 +1,4 @@ -import GlobalUniform from "../core/common/GlobalUniform.wgsl?raw"; +import { GlobalUniform } from "../core/common/GlobalUniform"; /** * @internal diff --git a/src/assets/shader/quad/Quad_shader.ts b/src/assets/shader/quad/Quad_shader.ts index 2e1775c1..92c4af37 100644 --- a/src/assets/shader/quad/Quad_shader.ts +++ b/src/assets/shader/quad/Quad_shader.ts @@ -1,57 +1,39 @@ -export class Quad_shader { - - public static FullQuad_vert_wgsl: string = /* wgsl */ ` - #include "WorldMatrixUniform" - #include "GlobalUniform" - - struct MaterialUniform { - x:f32, - y:f32, - width:f32, - height:f32, - }; - - struct VertexOutput { - @location(0) fragUV: vec2, - @builtin(position) position: vec4 - }; - - @vertex - fn main(@builtin(vertex_index) vertexIndex : u32, @builtin(instance_index) index : u32 ) -> VertexOutput { - const pos = array( - vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), - vec2(-1.0, 1.0), vec2(1.0, -1.0), vec2(1.0, 1.0), - ); - const uv = array( - vec2(1.0, 0.0), vec2(1.0, 1.0), vec2(0.0, 1.0), - vec2(1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, 0.0), - ); - - // var uvPos = position.xy ; - - let id = u32(index) ; - - // let worldMatrix = models.matrix[id]; - - // let windowSize = vec2(globalUniform.windowWidth,globalUniform.windowHeight) ; - - // let size = vec2(worldMatrix[0].x,worldMatrix[1].y) / (windowSize ) ; - - // var pos = (worldMatrix[3].xy / windowSize) * vec2(1.0,-1.0) ; - - // uvPos = uvPos * size; +export let FullQuad_vert_wgsl: string = /*wgsl*/ ` + #include "WorldMatrixUniform" + #include "GlobalUniform" + + struct MaterialUniform { + x:f32, + y:f32, + width:f32, + height:f32, + }; - // let screenPos = vec2(((uvPos * 2.0) - vec2(1.0))) ; + struct VertexOutput { + @location(0) fragUV: vec2, + @builtin(position) position: vec4 + }; - var output : VertexOutput; - output.fragUV = uv[vertexIndex] ; - output.position = vec4(pos[vertexIndex] , 0.0, 1.0) ; - return output ; - } - `; + @vertex + fn main(@builtin(vertex_index) vertexIndex : u32, @builtin(instance_index) index : u32 ) -> VertexOutput { + const pos = array( + vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), + vec2(-1.0, 1.0), vec2(1.0, -1.0), vec2(1.0, 1.0), + ); + const uv = array( + vec2(1.0, 0.0), vec2(1.0, 1.0), vec2(0.0, 1.0), + vec2(1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, 0.0), + ); + let id = u32(index) ; + var output : VertexOutput; + output.fragUV = uv[vertexIndex] ; + output.position = vec4(pos[vertexIndex] , 0.0, 1.0) ; + return output ; + } +` - public static Quad_vert_wgsl: string = /* wgsl */ ` - #include "WorldMatrixUniform" +export let Quad_vert_wgsl: string = /*wgsl*/ ` +#include "WorldMatrixUniform" #include "GlobalUniform" struct MaterialUniform { @@ -77,133 +59,125 @@ export class Quad_shader { let size = vec2(worldMatrix[0].x,worldMatrix[1].y) / windowSize ; - // let offset = (size) / windowSize * 0.5 + pos / windowSize ; - let uv = vec2(((TEXCOORD_1.xy * 2.0) - vec2(1.0))) ;// / windowSize * size - offset ; - // let suv = worldMatrix * vec4(uv, 0.0, 1.0) ; return VertexOutput(TEXCOORD_1, vec4(uv, 0.0, 1.0)); } - `; - - - public static Quad_frag_wgsl: string = /* wgsl */ ` - struct FragmentOutput { - @location(0) o_Target: vec4 - }; - - var fragUV1: vec2; - var o_Target: vec4; - @group(1) @binding(0) - var baseMapSampler: sampler; - @group(1) @binding(1) - var baseMap: texture_2d; - - @fragment - fn main(@location(0) fragUV: vec2) -> FragmentOutput { - var uv = fragUV ; - uv.y = 1.0 - uv.y ; - var color: vec4 = textureSample(baseMap, baseMapSampler, uv ); - - //test - // if(color.r <= 0.001 && color.g <= 0.001 && color.b <= 0.001 ){ - // discard ; - // } - return FragmentOutput(color); - } - `; +` + +export let Quad_frag_wgsl: string = /*wgsl*/ ` + struct FragmentOutput { + @location(0) o_Target: vec4 + }; + + var fragUV1: vec2; + var o_Target: vec4; + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d; + + @fragment + fn main(@location(0) fragUV: vec2) -> FragmentOutput { + var uv = fragUV ; + uv.y = 1.0 - uv.y ; + var color: vec4 = textureSample(baseMap, baseMapSampler, uv ); - public static Quad_depth2d_frag_wgsl: string = /* wgsl */ ` - struct FragmentOutput { - @location(0) o_Target: vec4 - }; + return FragmentOutput(color); + } +` + +export let Quad_depth2d_frag_wgsl: string = /*wgsl*/ ` + struct FragmentOutput { + @location(0) o_Target: vec4 + }; - var fragUV1: vec2; - var o_Target: vec4; + var fragUV1: vec2; + var o_Target: vec4; - @group(1) @binding(0) - var baseMapSampler: sampler; - @group(1) @binding(1) - var baseMap: texture_depth_2d ; + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_depth_2d ; + + fn Linear01Depth( z : f32 ) -> f32 + { + return 1.0 / (1.0 * z + 5000.0); + } - fn Linear01Depth( z : f32 ) -> f32 - { - return 1.0 / (1.0 * z + 5000.0); + @fragment + fn main(@location(0) fragUV: vec2) -> FragmentOutput { + var uv = fragUV ; + uv.y = 1.0 - uv.y ; + var depth = textureSample(baseMap, baseMapSampler, uv , vec2(0) ) ; + return FragmentOutput(vec4(depth,0.0,0.0,1.0)); + } +` + +export let Quad_depthCube_frag_wgsl: string = /*wgsl*/ ` + struct FragmentOutput { + @location(0) o_Target: vec4 + }; + + var fragUV1: vec2; + var o_Target: vec4; + + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_depth_cube ; + + fn uvToXYZ( face : i32 , uv : vec2 ) -> vec3 + { + var out : vec3 ; + if(face == 0){ + out = vec3( 1.0, uv.y, -uv.x); + }else if(face == 1){ + out = vec3( -1.0, uv.y, uv.x); + }else if(face == 2){ + out = vec3( uv.x, -1.0, uv.y); + }else if(face == 3){ + out = vec3( uv.x, 1.0, -uv.y); + }else if(face == 4){ + out = vec3( uv.x, uv.y, 1.0); + }else{ + out = vec3( -uv.x, uv.y, -1.0); } + return out ; + } - @fragment - fn main(@location(0) fragUV: vec2) -> FragmentOutput { - var uv = fragUV ; - uv.y = 1.0 - uv.y ; - var depth = textureSample(baseMap, baseMapSampler, uv , vec2(0) ) ; - return FragmentOutput(vec4(depth,0.0,0.0,1.0)); + @fragment + fn main(@location(0) fragUV: vec2) -> FragmentOutput { + var uv = fragUV ; + uv.y = 1.0 - uv.y ; + var ii = 0.16 ; + var ouv = vec3(0.0); + if(uv.x < ii * 6.0){ + ouv = uvToXYZ(5,uv/ii); } - `; - - public static Quad_depthCube_frag_wgsl: string = /* wgsl */ ` - struct FragmentOutput { - @location(0) o_Target: vec4 - }; - - var fragUV1: vec2; - var o_Target: vec4; - - @group(1) @binding(0) - var baseMapSampler: sampler; - @group(1) @binding(1) - var baseMap: texture_depth_cube ; - - fn uvToXYZ( face : i32 , uv : vec2 ) -> vec3 - { - var out : vec3 ; - if(face == 0){ - out = vec3( 1.0, uv.y, -uv.x); - }else if(face == 1){ - out = vec3( -1.0, uv.y, uv.x); - }else if(face == 2){ - out = vec3( uv.x, -1.0, uv.y); - }else if(face == 3){ - out = vec3( uv.x, 1.0, -uv.y); - }else if(face == 4){ - out = vec3( uv.x, uv.y, 1.0); - }else{ - out = vec3( -uv.x, uv.y, -1.0); - } - return out ; + if(uv.x < ii * 5.0){ + ouv = uvToXYZ(4,uv/ii); } - - @fragment - fn main(@location(0) fragUV: vec2) -> FragmentOutput { - var uv = fragUV ; - uv.y = 1.0 - uv.y ; - var ii = 0.16 ; - var ouv = vec3(0.0); - if(uv.x < ii * 6.0){ - ouv = uvToXYZ(5,uv/ii); - } - if(uv.x < ii * 5.0){ - ouv = uvToXYZ(4,uv/ii); - } - if(uv.x < ii * 4.0){ - ouv = uvToXYZ(3,uv/ii); - } - if(uv.x < ii * 3.0){ - ouv = uvToXYZ(2,uv/ii); - } - if(uv.x < ii * 2.0){ - ouv = uvToXYZ(1,uv/ii); - } - if(uv.x < ii * 1.0){ - ouv = uvToXYZ(0,uv/ii); - } - var depth = textureSample(baseMap, baseMapSampler, ouv ) ; - depth = 1.0 - depth; - - return FragmentOutput(vec4(depth,0.0,0.0,1.0)); + if(uv.x < ii * 4.0){ + ouv = uvToXYZ(3,uv/ii); + } + if(uv.x < ii * 3.0){ + ouv = uvToXYZ(2,uv/ii); + } + if(uv.x < ii * 2.0){ + ouv = uvToXYZ(1,uv/ii); + } + if(uv.x < ii * 1.0){ + ouv = uvToXYZ(0,uv/ii); } - `; + var depth = textureSample(baseMap, baseMapSampler, ouv ) ; + depth = 1.0 - depth; + + return FragmentOutput(vec4(depth,0.0,0.0,1.0)); + } +` - public static Quad_depth2dArray_frag_wgsl: string = /* wgsl */ ` +export let Quad_depth2dArray_frag_wgsl: string = /*wgsl*/ ` struct FragmentOutput { @location(0) o_Target: vec4 }; @@ -224,11 +198,10 @@ export class Quad_shader { fn main(@location(0) fragUV: vec2) -> FragmentOutput { var uv = fragUV ; uv.y = 1.0 - uv.y ; - + var depth = textureSample(baseMap, baseMapSampler, ouv ) ; depth = 1.0 - depth; return FragmentOutput(vec4(depth,0.0,0.0,1.0)); } -`; -} \ No newline at end of file +` \ No newline at end of file diff --git a/src/assets/shader/materials/materials/sky/AtmosphericScatteringSky_shader.ts b/src/assets/shader/sky/AtmosphericScatteringSky_shader.ts similarity index 100% rename from src/assets/shader/materials/materials/sky/AtmosphericScatteringSky_shader.ts rename to src/assets/shader/sky/AtmosphericScatteringSky_shader.ts diff --git a/src/assets/shader/materials/materials/sky/CubeSky_Shader.ts b/src/assets/shader/sky/CubeSky_Shader.ts similarity index 100% rename from src/assets/shader/materials/materials/sky/CubeSky_Shader.ts rename to src/assets/shader/sky/CubeSky_Shader.ts diff --git a/src/assets/shader/utils/BRDFLUT.ts b/src/assets/shader/utils/BRDFLUT.ts new file mode 100644 index 00000000..e40760bc --- /dev/null +++ b/src/assets/shader/utils/BRDFLUT.ts @@ -0,0 +1,115 @@ + +export let BRDFLUT: string = /*wgsl*/ ` +varPI: f32 = 3.141592653589793; + +// fn saturate( x : f32 ) -> f32 { +// return clamp(x, 0.0, 1.0); +// } + +fn hammersley(i : u32, N : u32) -> vec2 +{ + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + var bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + var rdi = f32(bits) * 2.3283064365386963e-10; + return vec2(f32(i) / f32(N), rdi); +} + +fn G_Smith(NoV: f32, NoL : f32, roughness : f32) -> f32 +{ + var k = (roughness * roughness) / 2.0; + var GGXL = NoL / (NoL * (1.0 - k) + k); + var GGXV = NoV / (NoV * (1.0 - k) + k); + return GGXL * GGXV; +} + +fn V_SmithGGXCorrelated(NoV: f32, NoL : f32, roughness : f32) -> f32 +{ + var a2 = pow(roughness, 4.0); + var GGXV = NoL * sqrt(NoV * NoV * (1.0 - a2) + a2); + var GGXL = NoV * sqrt(NoL * NoL * (1.0 - a2) + a2); + return 0.5 / (GGXV + GGXL); +} + + +// Based on Karis 2014 +fn importanceSampleGGX(Xi: vec2, roughness: f32, N: vec3) -> vec3 +{ + var a = roughness * roughness; + // Sample in spherical coordinates + var Phi = 2.0 * PI * Xi.x; + var CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y)); + var SinTheta = sqrt(1.0 - CosTheta * CosTheta); + // Construct tangent space vector + var H: vec3; + H.x = SinTheta * cos(Phi); + H.y = SinTheta * sin(Phi); + H.z = CosTheta; + + // Tangent to world space + var UpVector = vec3(1.0, 0.0, 0.0); + if (abs(N.z) < 0.999) { + UpVector = vec3(0.0, 0.0, 1.0); + } + var TangentX = normalize(cross(UpVector, N)); + var TangentY = cross(N, TangentX); + return TangentX * H.x + TangentY * H.y + N * H.z; +} + + +// Karis 2014 +fn integrateBRDF(roughness: f32, NoV: f32) -> vec2 +{ + var V: vec3; + V.x = sqrt(1.0 - NoV * NoV); // sin + V.y = 0.0; + V.z = NoV; // cos + + // N points straight upwards for this integration + var N = vec3(0.0, 0.0, 1.0); + + var A = 0.0; + var B = 0.0; + var numSamples = 1024u; + + for (var i = 0u; i < numSamples; i += 1u) { + var Xi = hammersley(i, numSamples); + // Sample microfacet direction + var H = importanceSampleGGX(Xi, roughness, N); + + // Get the light direction + var L = 2.0 * dot(V, H) * H - V; + + var NoL = saturate(dot(N, L)); + var NoH = saturate(dot(N, H)); + var VoH = saturate(dot(V, H)); + + if (NoL > 0.0) { + var V_pdf = V_SmithGGXCorrelated(NoV, NoL, roughness) * VoH * NoL / NoH; + var Fc = pow(1.0 - VoH, 5.0); + A += (1.0 - Fc) * V_pdf; + B += Fc * V_pdf; + } + } + + return 4.0 * vec2(A, B) / f32(numSamples); +} + +@group(0) @binding(0) var brdflutTexture: texture_storage_2d; +@compute @workgroup_size(8, 8, 1) +// fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(local_invocation_id) local_invocation_id : vec3 ){ +fn CsMain(@builtin(global_invocation_id) global_invocation_id : vec3){ + var fragCoord = vec2(global_invocation_id.x, global_invocation_id.y); + + var fragColor = vec4(0.0); + // Output to screen + var res = integrateBRDF(f32(fragCoord.y + 1u) / 256.0, f32(fragCoord.x + 1u) / 256.0); + fragColor = vec4(res.x, res.y, 0.0, 1.0); + + textureStore(brdflutTexture, vec2(fragCoord.xy), fragColor); +} +` + diff --git a/src/assets/shader/utils/BRDFLUT.wgsl b/src/assets/shader/utils/BRDFLUT.wgsl deleted file mode 100644 index 4a898192..00000000 --- a/src/assets/shader/utils/BRDFLUT.wgsl +++ /dev/null @@ -1,112 +0,0 @@ - var PI:f32 = 3.141592653589793 ; - - // fn saturate( x : f32 ) -> f32 { - // return clamp(x, 0.0, 1.0); - // } - - fn hammersley( i : u32 , N : u32 ) -> vec2 - { - // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html - var bits = (i << 16u) | (i >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - var rdi = f32(bits) * 2.3283064365386963e-10; - return vec2(f32(i) /f32(N), rdi); - } - - fn G_Smith( NoV:f32 , NoL : f32 , roughness : f32 ) -> f32 - { - var k = (roughness * roughness) / 2.0; - var GGXL = NoL / (NoL * (1.0 - k) + k); - var GGXV = NoV / (NoV * (1.0 - k) + k); - return GGXL * GGXV; - } - - fn V_SmithGGXCorrelated( NoV:f32 , NoL : f32 , roughness : f32 ) -> f32 - { - var a2 = pow(roughness, 4.0); - var GGXV = NoL * sqrt(NoV * NoV * (1.0 - a2) + a2); - var GGXL = NoV * sqrt(NoL * NoL * (1.0 - a2) + a2); - return 0.5 / (GGXV + GGXL); - } - - - // Based on Karis 2014 - fn importanceSampleGGX( Xi:vec2, roughness:f32 , N:vec3 ) -> vec3 - { - var a = roughness * roughness; - // Sample in spherical coordinates - var Phi = 2.0 * PI * Xi.x; - var CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); - var SinTheta = sqrt(1.0 - CosTheta * CosTheta); - // Construct tangent space vector - var H:vec3; - H.x = SinTheta * cos(Phi); - H.y = SinTheta * sin(Phi); - H.z = CosTheta; - - // Tangent to world space - var UpVector = vec3(1.0,0.0,0.0); - if(abs(N.z) < 0.999){ - UpVector = vec3(0.0,0.0,1.0) ; - } - var TangentX = normalize(cross(UpVector, N)); - var TangentY = cross(N, TangentX); - return TangentX * H.x + TangentY * H.y + N * H.z; - } - - - // Karis 2014 - fn integrateBRDF( roughness:f32 , NoV: f32) -> vec2 - { - var V : vec3 ; - V.x = sqrt(1.0 - NoV * NoV); // sin - V.y = 0.0; - V.z = NoV; // cos - - // N points straight upwards for this integration - var N = vec3(0.0, 0.0, 1.0); - - var A = 0.0; - var B = 0.0; - var numSamples = 1024u; - - for (var i = 0u; i < numSamples; i+=1u) { - var Xi = hammersley(i, numSamples); - // Sample microfacet direction - var H = importanceSampleGGX(Xi, roughness, N); - - // Get the light direction - var L = 2.0 * dot(V, H) * H - V; - - var NoL = saturate(dot(N, L)); - var NoH = saturate(dot(N, H)); - var VoH = saturate(dot(V, H)); - - if(NoL > 0.0) { - var V_pdf = V_SmithGGXCorrelated(NoV, NoL, roughness) * VoH * NoL / NoH; - var Fc = pow(1.0 - VoH, 5.0); - A += (1.0 - Fc) * V_pdf; - B += Fc * V_pdf; - } - } - - return 4.0 * vec2(A, B) / f32(numSamples); - } - - @group(0) @binding(0) var brdflutTexture : texture_storage_2d; - - @compute @workgroup_size(8,8,1) - // fn CsMain( @builtin(workgroup_id) workgroup_id : vec3 , @builtin(local_invocation_id) local_invocation_id : vec3 ){ - fn CsMain( @builtin(global_invocation_id) global_invocation_id : vec3){ - var fragCoord = vec2( global_invocation_id.x, global_invocation_id.y); - - var fragColor = vec4(0.0) ; - // Output to screen - var res = integrateBRDF( f32(fragCoord.y+1u) / 256.0 , f32(fragCoord.x+1u) / 256.0 ); - fragColor = vec4(res.x, res.y, 0.0, 1.0) ; - - textureStore(brdflutTexture, vec2(fragCoord.xy), fragColor ); - } diff --git a/src/assets/shader/utils/ColorUtil.ts b/src/assets/shader/utils/ColorUtil.ts new file mode 100644 index 00000000..9b2636c3 --- /dev/null +++ b/src/assets/shader/utils/ColorUtil.ts @@ -0,0 +1,99 @@ +export let ColorUtil: string = /*wgsl*/ ` + fn getHDRColor(color: vec3, exposure: f32) -> vec3 < f32 > { + // var newColor = color * ( 1.0 / 255.0 ) ; + return color * pow(2.4, exposure) ; + } + + fn lambda2rgb(lambda : f32) -> vec3 < f32 > { + let ultraviolet = 400.0; + let infrared = 700.0; + + var a = (lambda - ultraviolet) / (infrared - ultraviolet); + let c = 10.0; + var b = vec3(a) - vec3(0.75, 0.5, 0.25); + return max((1.0 - c * b * b), vec3(0.0)); + } + + fn CEToneMapping(color: vec3, adapted_lum: f32) -> vec3 + { + return 1.0 - exp(-adapted_lum * color); + } + + fn ACESToneMapping(color: vec3, adapted_lum: f32) -> vec3 + { + let A = 2.51; + let B = 0.03; + let C = 2.43; + let D = 0.59; + let E = 0.14; + + var color2 = color * adapted_lum; + color2 = (color2 * (A * color2 + B)) / (color2 * (C * color2 + D) + E); + return color2; + } + + fn gammaToLiner(color: vec4) -> vec4 < f32 > { + let gammaCorrect = 2.4; + var color2 = pow(color, vec4(gammaCorrect)); + return color2 ; + } + + fn linerToGamma4(color: vec4) -> vec4 < f32 > { + let gammaCorrect = 1.0 / 2.4; + var color2 = pow(color, vec4(gammaCorrect)); + return color2 ; + } + + fn linerToGamma3(color: vec3) -> vec3 < f32 > { + let gammaCorrect = 1.0 / 2.4; + var color2 = pow(color, vec3(gammaCorrect)); + return color2 ; + } + + fn LinearToGammaSpace(linRGB0: vec3) -> vec3 < f32 > { + var linRGB = max(linRGB0, vec3(0.0, 0.0, 0.0)); + linRGB.r = pow(linRGB.r, 0.416666667); + linRGB.g = pow(linRGB.g, 0.416666667); + linRGB.b = pow(linRGB.b, 0.416666667); + return max(1.055 * linRGB - 0.055, vec3(0.0, 0.0, 0.0)); + } + + varsRGB_2_LMS_MAT: mat3x3 = mat3x3( + 17.8824, 43.5161, 4.1193, + 3.4557, 27.1554, 3.8671, + 0.02996, 0.18431, 1.4670, + ); + + varLMS_2_sRGB_MAT: mat3x3 = mat3x3( + 0.0809, -0.1305, 0.1167, + -0.0102, 0.0540, -0.1136, + -0.0003, -0.0041, 0.6935, + ); + + fn sRGB_2_LMS(RGB: vec3) -> vec3 + { + return sRGB_2_LMS_MAT * RGB; + } + + fn LMS_2_sRGB(LMS: vec3) -> vec3 + { + return LMS_2_sRGB_MAT * LMS; + } + + fn LinearToSrgbBranchless(lin: vec3) -> vec3 + { + var lin2 = max(vec3(6.10352e-5), lin); + return min(lin2 * 12.92, pow(max(lin2, vec3(0.00313067)), vec3(1.0 / 2.4)) * vec3(1.055) - vec3(0.055)); + } + + fn sRGBToLinear(color : vec3) -> vec3 + { + let color2 = max(vec3(6.10352e-5), color); + let c = 0.04045; + if (color2.r > c && color2.g > c && color2.b > c) { + return pow(color2 * (1.0 / 1.055) + 0.0521327, vec3(2.4)); + } else { + return color2 * (1.0 / 12.92); + } + } +` diff --git a/src/assets/shader/utils/ColorUtil.wgsl b/src/assets/shader/utils/ColorUtil.wgsl deleted file mode 100644 index 5db84e7a..00000000 --- a/src/assets/shader/utils/ColorUtil.wgsl +++ /dev/null @@ -1,99 +0,0 @@ - - - fn getHDRColor(color:vec3,exposure:f32)-> vec3{ - // var newColor = color * ( 1.0 / 255.0 ) ; - return color * pow(2.4 , exposure) ; - } - - fn lambda2rgb( lambda : f32 ) -> vec3 { - let ultraviolet = 400.0; - let infrared = 700.0; - - var a = (lambda - ultraviolet)/(infrared - ultraviolet); - let c = 10.0; - var b = vec3(a) - vec3(0.75,0.5,0.25); - return max((1.0 - c*b*b), vec3(0.0) ); - } - - fn CEToneMapping( color:vec3, adapted_lum:f32)-> vec3 - { - return 1.0 - exp(-adapted_lum * color); - } - - fn ACESToneMapping( color:vec3, adapted_lum:f32 )-> vec3 - { - let A = 2.51; - let B = 0.03; - let C = 2.43; - let D = 0.59; - let E = 0.14; - - var color2 = color * adapted_lum; - color2 = (color2 * (A * color2 + B)) / (color2 * (C * color2 + D) + E); - return color2 ; - } - - fn gammaToLiner(color:vec4) -> vec4 { - let gammaCorrect = 2.4; - var color2 = pow(color, vec4(gammaCorrect)); - return color2 ; - } - - fn linerToGamma4(color:vec4) -> vec4 { - let gammaCorrect = 1.0 / 2.4; - var color2 = pow(color, vec4(gammaCorrect)); - return color2 ; - } - - fn linerToGamma3(color:vec3) -> vec3 { - let gammaCorrect = 1.0 / 2.4; - var color2 = pow(color, vec3(gammaCorrect)); - return color2 ; - } - - fn LinearToGammaSpace(linRGB0: vec3) -> vec3 { - var linRGB = max(linRGB0, vec3(0.0, 0.0, 0.0)); - linRGB.r = pow(linRGB.r,0.416666667); - linRGB.g = pow(linRGB.g,0.416666667); - linRGB.b = pow(linRGB.b,0.416666667); - return max(1.055 * linRGB - 0.055, vec3(0.0, 0.0, 0.0)); - } - - var sRGB_2_LMS_MAT:mat3x3 = mat3x3( - 17.8824, 43.5161, 4.1193, - 3.4557, 27.1554, 3.8671, - 0.02996, 0.18431, 1.4670, - ) ; - - var LMS_2_sRGB_MAT:mat3x3 = mat3x3( - 0.0809, -0.1305, 0.1167, - -0.0102, 0.0540, -0.1136, - -0.0003, -0.0041, 0.6935, - ); - - fn sRGB_2_LMS( RGB:vec3 ) -> vec3 - { - return sRGB_2_LMS_MAT * RGB ; - } - - fn LMS_2_sRGB( LMS:vec3 ) -> vec3 - { - return LMS_2_sRGB_MAT * LMS; - } - - fn LinearToSrgbBranchless( lin:vec3 ) -> vec3 - { - var lin2 = max(vec3(6.10352e-5), lin); - return min(lin2 * 12.92, pow(max(lin2, vec3(0.00313067)), vec3(1.0/2.4)) * vec3(1.055) - vec3(0.055)); - } - - fn sRGBToLinear( color : vec3 ) -> vec3 - { - let color2 = max(vec3(6.10352e-5), color); - let c = 0.04045 ; - if(color2.r > c && color2.g > c && color2.b > c){ - return pow( color2 * (1.0 / 1.055) + 0.0521327, vec3(2.4) ) ; - }else{ - return color2 * (1.0 / 12.92); - } - } diff --git a/src/assets/shader/utils/GenerayRandomDir.ts b/src/assets/shader/utils/GenerayRandomDir.ts new file mode 100644 index 00000000..6e1c9971 --- /dev/null +++ b/src/assets/shader/utils/GenerayRandomDir.ts @@ -0,0 +1,25 @@ + + +export let GenerayRandomDir: string = /*wgsl*/ ` + fn madfrac(A:f32, B:f32)-> f32 { + return A*B-floor(A*B) ; + } + + fn sampleRandomDir(count:u32,SAMPLE_COUNT:u32) -> vec3{ + var ray_dir = sphericalFibonacci(f32((count)), f32(SAMPLE_COUNT) ); + return normalize(ray_dir) ; + } + + fn sphericalFibonacci( i : f32 , n : f32 ) -> vec3{ + const PHI = sqrt(5.0) * 0.5 + 0.5; + let phi = 2.0 * PI * madfrac(i, PHI - 1); + let cosTheta = 1.0 - (2.0 * i + 1.0) * (1.0 / n); + let sinTheta = sqrt(saturate(1.0 - cosTheta*cosTheta)); + + return vec3( + cos(phi) * sinTheta, + sin(phi) * sinTheta, + cosTheta); + + } +` \ No newline at end of file diff --git a/src/assets/shader/utils/GenerayRandomDir.wgsl b/src/assets/shader/utils/GenerayRandomDir.wgsl deleted file mode 100644 index 74a72796..00000000 --- a/src/assets/shader/utils/GenerayRandomDir.wgsl +++ /dev/null @@ -1,23 +0,0 @@ - -fn madfrac(A:f32, B:f32)-> f32 { - return A*B-floor(A*B) ; -} - -fn sampleRandomDir(count:u32,SAMPLE_COUNT:u32) -> vec3{ - var ray_dir = sphericalFibonacci(f32((count)), f32(SAMPLE_COUNT) ); - return normalize(ray_dir) ; -} - -fn sphericalFibonacci( i : f32 , n : f32 ) -> vec3{ - const PHI = sqrt(5.0) * 0.5 + 0.5; - let phi = 2.0 * PI * madfrac(i, PHI - 1); - let cosTheta = 1.0 - (2.0 * i + 1.0) * (1.0 / n); - let sinTheta = sqrt(saturate(1.0 - cosTheta*cosTheta)); - - return vec3( - cos(phi) * sinTheta, - sin(phi) * sinTheta, - cosTheta); - -} - diff --git a/src/gfx/generate/BrdfLUTGenerate.ts b/src/gfx/generate/BrdfLUTGenerate.ts index d93c5651..80b2d2a0 100644 --- a/src/gfx/generate/BrdfLUTGenerate.ts +++ b/src/gfx/generate/BrdfLUTGenerate.ts @@ -1,4 +1,4 @@ -import BRDFLUT from '../../assets/shader/utils/BRDFLUT.wgsl?raw'; +import { BRDFLUT } from '../../assets/shader/utils/BRDFLUT'; import { VirtualTexture } from '../../textures/VirtualTexture'; import { ComputeShader } from '../graphics/webGpu/shader/ComputeShader'; import { GPUTextureFormat } from '../graphics/webGpu/WebGPUConst'; diff --git a/src/gfx/generate/convert/BlurEffectCreator.ts b/src/gfx/generate/convert/BlurEffectCreator.ts index 2135dad6..e3a7a438 100644 --- a/src/gfx/generate/convert/BlurEffectCreator.ts +++ b/src/gfx/generate/convert/BlurEffectCreator.ts @@ -1,4 +1,4 @@ -import { BlurEffectCreator_compute } from '../../../assets/shader/compute/BlurEffectCreator_compute'; +import { BlurEffectCreatorBlur_cs, BlurEffectCreatorSample_cs } from '../../../assets/shader/compute/BlurEffectCreator_cs'; import { webGPUContext } from '../../graphics/webGpu/Context3D'; import { GPUContext } from '../../renderJob/GPUContext'; /** @@ -9,7 +9,7 @@ export class BlurTexture2DBufferCreator { //Image is the texture of converting from rgba8unorm to rgba8unorm public static blurImageFromTexture(image: { width: number; height: number; gpuTexture: GPUTexture }, dstWidth: number, dstHeight: number, blur: boolean): GPUTexture { const device = webGPUContext.device; - let code: string = blur ? BlurEffectCreator_compute.blur_rgba8unorm : BlurEffectCreator_compute.sample_rgba8unorm; + let code: string = blur ? BlurEffectCreatorBlur_cs : BlurEffectCreatorSample_cs; const computePipeline = device.createComputePipeline({ layout: `auto`, compute: { diff --git a/src/gfx/generate/convert/ErpImage2CubeMap.ts b/src/gfx/generate/convert/ErpImage2CubeMap.ts index a7d1e4b0..d6b246f4 100644 --- a/src/gfx/generate/convert/ErpImage2CubeMap.ts +++ b/src/gfx/generate/convert/ErpImage2CubeMap.ts @@ -1,10 +1,10 @@ -import ErpImage2CubeMapCreateCube_compute from '../../../assets/shader/compute/ErpImage2CubeMapCreateCube_compute.wgsl?raw'; -import ErpImage2CubeMapRgbe2rgba_compute from '../../../assets/shader/compute/ErpImage2CubeMapRgbe2rgba_compute.wgsl?raw'; import { VirtualTexture } from '../../../textures/VirtualTexture'; import { Texture } from '../../graphics/webGpu/core/texture/Texture'; import { webGPUContext } from '../../graphics/webGpu/Context3D'; import { TextureCubeUtils } from './TextureCubeUtils'; import { GPUContext } from '../../renderJob/GPUContext'; +import { ErpImage2CubeMapCreateCube_cs } from '../../../assets/shader/compute/ErpImage2CubeMapCreateCube_cs'; +import { ErpImage2CubeMapRgbe2rgba_cs } from '../../../assets/shader/compute/ErpImage2CubeMapRgbe2rgba_cs'; /** * @internal * @group GFX @@ -16,7 +16,7 @@ export class ErpImage2CubeMap { layout: `auto`, compute: { module: device.createShaderModule({ - code: ErpImage2CubeMapRgbe2rgba_compute, + code: ErpImage2CubeMapRgbe2rgba_cs, }), entryPoint: 'main', }, @@ -87,7 +87,7 @@ export class ErpImage2CubeMap { layout: `auto`, compute: { module: device.createShaderModule({ - code: ErpImage2CubeMapCreateCube_compute, + code: ErpImage2CubeMapCreateCube_cs, }), entryPoint: 'main', }, diff --git a/src/gfx/generate/convert/IBLEnvMapCreator.ts b/src/gfx/generate/convert/IBLEnvMapCreator.ts index 9477a05b..36711793 100644 --- a/src/gfx/generate/convert/IBLEnvMapCreator.ts +++ b/src/gfx/generate/convert/IBLEnvMapCreator.ts @@ -1,8 +1,9 @@ import { Texture } from '../../graphics/webGpu/core/texture/Texture'; import { webGPUContext } from '../../graphics/webGpu/Context3D'; -import IBLEnvMapCreator_compute from '../../../assets/shader/compute/IBLEnvMapCreator_compute.wgsl?raw'; + import { TextureCubeUtils } from './TextureCubeUtils'; import { GPUContext } from '../../renderJob/GPUContext'; +import { IBLEnvMapCreator_cs } from '../../../assets/shader/compute/IBLEnvMapCreator_cs'; /** * @internal @@ -21,7 +22,7 @@ export class IBLEnvMapCreator { layout: `auto`, compute: { module: device.createShaderModule({ - code: IBLEnvMapCreator_compute, + code: IBLEnvMapCreator_cs, }), entryPoint: 'main', }, diff --git a/src/gfx/generate/convert/MergeRGBACreator.ts b/src/gfx/generate/convert/MergeRGBACreator.ts index 142ecd1c..b53d7c88 100644 --- a/src/gfx/generate/convert/MergeRGBACreator.ts +++ b/src/gfx/generate/convert/MergeRGBACreator.ts @@ -1,4 +1,4 @@ -import MergeRGBA_Cs from '../../../assets/shader/compute/MergeRGBA_Cs.wgsl?raw'; +import { MergeRGBA_cs } from '../../../assets/shader/compute/MergeRGBA_cs'; import { VirtualTexture } from '../../../textures/VirtualTexture'; import { Texture } from '../../graphics/webGpu/core/texture/Texture'; import { ComputeShader } from '../../graphics/webGpu/shader/ComputeShader'; @@ -23,7 +23,7 @@ export class MergeRGBACreator { h = Math.max(textureA.height, h); let outTex = new VirtualTexture(w, h, GPUTextureFormat.rgba8unorm); - let compute = new ComputeShader(MergeRGBA_Cs); + let compute = new ComputeShader(MergeRGBA_cs); compute.setSamplerTexture('textureR', textureR); compute.setSamplerTexture('textureG', textureG); compute.setSamplerTexture('textureB', textureB); diff --git a/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts b/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts index b3269c3b..bd5b125e 100644 --- a/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts +++ b/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts @@ -11,8 +11,6 @@ import { Struct } from "../../../../../util/struct/Struct"; import { webGPUContext } from "../../Context3D"; import { MemoryDO } from "../../../../../core/pool/memory/MemoryDO"; import { MemoryInfo } from "../../../../../core/pool/memory/MemoryInfo"; -import { GPUContext } from "../../../../renderJob/GPUContext"; - /** * @internal @@ -360,17 +358,17 @@ export class GPUBufferBase { } private async read() { - // this._readFlag = true; - - // let command = context.beginCommandEncoder(); - // command.copyBufferToBuffer(this.buffer, 0, this._readBuffer, 0, this.memory.shareDataBuffer.byteLength); - // GPUContext.endCommandEncoder(command); - - // await this._readBuffer.mapAsync(GPUMapMode.READ); - // const copyArrayBuffer = this._readBuffer.getMappedRange(); - // this.outFloat32Array.set(new Float32Array(copyArrayBuffer), 0); - // // this.memory.shareDataBuffer.set(new Float32Array(copyArrayBuffer), 0); - // this._readBuffer.unmap(); - // this._readFlag = false; + this._readFlag = true; + + let command = webGPUContext.device.createCommandEncoder();; + command.copyBufferToBuffer(this.buffer, 0, this._readBuffer, 0, this.memory.shareDataBuffer.byteLength); + webGPUContext.device.queue.submit([command.finish()]); + + await this._readBuffer.mapAsync(GPUMapMode.READ); + const copyArrayBuffer = this._readBuffer.getMappedRange(); + this.outFloat32Array.set(new Float32Array(copyArrayBuffer), 0); + // this.memory.shareDataBuffer.set(new Float32Array(copyArrayBuffer), 0); + this._readBuffer.unmap(); + this._readFlag = false; } } diff --git a/src/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts b/src/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts index 9f91c364..81902203 100644 --- a/src/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts +++ b/src/gfx/renderJob/passRenderer/cluster/ClusterLightingRender.ts @@ -1,6 +1,3 @@ -import ClusterBoundsSource_cs from '../../../../assets/shader/cluster/ClusterBoundsSource_cs.wgsl?raw'; -import ClusterLighting_cs from '../../../../assets/shader/cluster/ClusterLighting_cs.wgsl?raw'; - import { View3D } from '../../../../core/View3D'; import { GlobalBindGroup } from '../../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; import { ComputeShader } from '../../../graphics/webGpu/shader/ComputeShader'; @@ -12,6 +9,8 @@ import { RendererBase } from '../RendererBase'; import { RendererType } from '../state/RendererType'; import { ILight } from '../../../../components/lights/ILight'; import { ClusterLightingBuffer } from './ClusterLightingBuffer'; +import { ClusterBoundsSource_cs } from '../../../../assets/shader/cluster/ClusterBoundsSource_cs'; +import { ClusterLighting_cs } from '../../../../assets/shader/cluster/ClusterLighting_cs'; /** * @internal * @group Post diff --git a/src/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts b/src/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts index 28b75fcb..5bf9204e 100644 --- a/src/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts +++ b/src/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts @@ -3,11 +3,11 @@ import { GlobalBindGroupLayout } from "../../../graphics/webGpu/core/bindGroups/ import { GPUCullMode, GPUCompareFunction } from "../../../graphics/webGpu/WebGPUConst"; import { webGPUContext } from "../../../graphics/webGpu/Context3D"; import { Graphics3DShape } from "./Graphics3DShape"; -import Graphic3DShader_vs from "../../../../assets/shader/graphic/Graphic3DShader_vs.wgsl?raw" -import Graphic3DShader_fs from "../../../../assets/shader/graphic/Graphic3DShader_fs.wgsl?raw" import { Preprocessor } from "../../../graphics/webGpu/shader/util/Preprocessor"; import { GPUContext } from "../../GPUContext"; import { RendererPassState } from "../state/RendererPassState"; +import { Graphic3DShader_vs } from "../../../../assets/shader/graphic/Graphic3DShader_vs"; +import { Graphic3DShader_fs } from "../../../../assets/shader/graphic/Graphic3DShader_fs"; /** * @internal diff --git a/src/gfx/renderJob/passRenderer/post/PostRenderer.ts b/src/gfx/renderJob/passRenderer/post/PostRenderer.ts index 275a61f1..8d4bec11 100644 --- a/src/gfx/renderJob/passRenderer/post/PostRenderer.ts +++ b/src/gfx/renderJob/passRenderer/post/PostRenderer.ts @@ -1,6 +1,6 @@ import { Engine3D } from "../../../../Engine3D"; import { ShaderLib } from "../../../../assets/shader/ShaderLib"; -import { Quad_shader } from "../../../../assets/shader/quad/Quad_shader"; +import { FullQuad_vert_wgsl } from "../../../../assets/shader/quad/Quad_shader"; import { View3D } from "../../../../core/View3D"; import { ViewQuad } from "../../../../core/ViewQuad"; import { GPUContext } from "../../GPUContext"; @@ -28,7 +28,7 @@ export class PostRenderer extends RendererBase { } public initRenderer() { - ShaderLib.register("FullQuad_vert_wgsl", Quad_shader.FullQuad_vert_wgsl); + ShaderLib.register("FullQuad_vert_wgsl", FullQuad_vert_wgsl); this.finalQuadView = new ViewQuad(`Quad_vert_wgsl`, `Quad_frag_wgsl`, new RTFrame([], []), null, null, false); } diff --git a/src/gfx/renderJob/passRenderer/preDepth/ZCullingCompute.ts b/src/gfx/renderJob/passRenderer/preDepth/ZCullingCompute.ts index 978ed9cf..86733c32 100644 --- a/src/gfx/renderJob/passRenderer/preDepth/ZCullingCompute.ts +++ b/src/gfx/renderJob/passRenderer/preDepth/ZCullingCompute.ts @@ -1,5 +1,5 @@ -import ZPassShader_cs from '../../../../assets/shader/core/pass/ZPassShader_cs.wgsl?raw'; +import { ZPassShader_cs } from '../../../../assets/shader/core/pass/ZPassShader_cs'; import { Scene3D } from '../../../../core/Scene3D'; import { ComputeGPUBuffer } from '../../../graphics/webGpu/core/buffer/ComputeGPUBuffer'; import { Texture } from '../../../graphics/webGpu/core/texture/Texture'; diff --git a/src/gfx/renderJob/post/DepthOfFieldPost.ts b/src/gfx/renderJob/post/DepthOfFieldPost.ts index 068e7605..79177990 100644 --- a/src/gfx/renderJob/post/DepthOfFieldPost.ts +++ b/src/gfx/renderJob/post/DepthOfFieldPost.ts @@ -1,4 +1,3 @@ -import DepthOfView_CsShader from '../../../assets/shader/compute/DepthOfView_CsShader.wgsl?raw'; import { VirtualTexture } from '../../../textures/VirtualTexture'; import { GlobalBindGroup } from '../../graphics/webGpu/core/bindGroups/GlobalBindGroup'; import { StorageGPUBuffer } from '../../graphics/webGpu/core/buffer/StorageGPUBuffer'; @@ -17,6 +16,7 @@ import { RTDescriptor } from '../../graphics/webGpu/descriptor/RTDescriptor'; import { RTResourceConfig } from '../config/RTResourceConfig'; import { GBufferFrame } from '../frame/GBufferFrame'; import { RTFrame } from '../frame/RTFrame'; +import { DepthOfView_cs } from '../../../assets/shader/compute/DepthOfView_cs'; /** * depth of field effect. * A common post-processing effect that simulates the focusing characteristics of a camera lens. @@ -122,7 +122,7 @@ export class DepthOfFieldPost extends PostBase { for (let i = 0; i < cfg.iterationCount; i++) { let blurSetting: UniformGPUBuffer = new UniformGPUBuffer(4); - let blurCompute = new ComputeShader(DepthOfView_CsShader); + let blurCompute = new ComputeShader(DepthOfView_cs); this.blurComputes.push(blurCompute); this.blurSettings.push(blurSetting); diff --git a/src/gfx/renderJob/post/FXAAPost.ts b/src/gfx/renderJob/post/FXAAPost.ts index 2d8a7482..fe2ed8bc 100644 --- a/src/gfx/renderJob/post/FXAAPost.ts +++ b/src/gfx/renderJob/post/FXAAPost.ts @@ -1,4 +1,3 @@ -import FSAA_Shader from '../../../assets/shader/post/FSAAShader.wgsl?raw'; import { ShaderLib } from '../../../assets/shader/ShaderLib'; import { Engine3D } from '../../../Engine3D'; import { Vector2 } from '../../../math/Vector2'; @@ -9,6 +8,7 @@ import { RTResourceConfig } from '../config/RTResourceConfig'; import { RTResourceMap } from '../frame/RTResourceMap'; import { PostBase } from './PostBase'; import { View3D } from '../../../core/View3D'; +import { FXAAShader } from '../../..'; /** * FXAA(fast approximate antialiasing) * A deformation anti-aliasing method that pays more attention to performance. @@ -23,7 +23,7 @@ export class FXAAPost extends PostBase { let presentationSize = webGPUContext.presentationSize; RTResourceMap.createRTTexture(RTResourceConfig.colorBufferTex_NAME, presentationSize[0], presentationSize[1], GPUTextureFormat.rgba16float, false); - ShaderLib.register("FXAA_Shader", FSAA_Shader); + ShaderLib.register("FXAA_Shader", FXAAShader); let shaderUniforms = { u_texel: new UniformNode(new Vector2(1.0 / presentationSize[0], 1.0 / presentationSize[1])), diff --git a/src/gfx/renderJob/post/GTAOPost.ts b/src/gfx/renderJob/post/GTAOPost.ts index cf995f35..c0f6dc24 100644 --- a/src/gfx/renderJob/post/GTAOPost.ts +++ b/src/gfx/renderJob/post/GTAOPost.ts @@ -10,26 +10,20 @@ import { GPUContext } from '../GPUContext'; import { RendererPassState } from '../passRenderer/state/RendererPassState'; import { PostBase } from './PostBase'; import { Engine3D } from '../../../Engine3D'; -import GTAOCs from '../../../assets/shader/compute/GTAOCs.wgsl?raw'; import { Time } from '../../../util/Time'; import { clamp } from '../../../math/MathUtil'; import { View3D } from '../../../core/View3D'; import { RTDescriptor } from '../../graphics/webGpu/descriptor/RTDescriptor'; import { GBufferFrame } from '../frame/GBufferFrame'; import { RTFrame } from '../frame/RTFrame'; +import { GTAO_cs } from '../../../assets/shader/compute/GTAO_cs'; /** * Ground base Ambient Occlusion * Let the intersection of the object and the object imitate the effect of the light being cross-occluded * ``` - * //gtao setting - * let cfg = {@link Engine3D.setting.render.postProcessing.gtao}; - * let view = new View3D(); - view.scene = this.scene; - view.camera = mainCamera; - - * - * Engine3D.startRender(renderJob); + * gtao setting + * let cfg = {@link Engine3D.setting.render.postProcessing.gtao}; *``` * @group Post Effects */ @@ -170,7 +164,7 @@ export class GTAOPost extends PostBase { private createCompute() { let setting = Engine3D.setting.render.postProcessing.gtao; - this.gtaoCompute = new ComputeShader(GTAOCs); + this.gtaoCompute = new ComputeShader(GTAO_cs); let gtaoSetting: UniformGPUBuffer = new UniformGPUBuffer(4 * 3); //vector4 * 2 this.gtaoCompute.setUniformBuffer('gtaoData', gtaoSetting); diff --git a/src/gfx/renderJob/post/GlobalFog.ts b/src/gfx/renderJob/post/GlobalFog.ts index 63d4024e..25db5eb5 100644 --- a/src/gfx/renderJob/post/GlobalFog.ts +++ b/src/gfx/renderJob/post/GlobalFog.ts @@ -7,7 +7,6 @@ import { VirtualTexture } from '../../../textures/VirtualTexture'; import { UniformNode } from '../../graphics/webGpu/core/uniforms/UniformNode'; import { GPUTextureFormat } from '../../graphics/webGpu/WebGPUConst'; import { webGPUContext } from '../../graphics/webGpu/Context3D'; -import { GPUContext } from '../GPUContext'; import { PostBase } from './PostBase'; import { View3D } from '../../../core/View3D'; import { GBufferFrame } from '../frame/GBufferFrame'; diff --git a/src/gfx/renderJob/post/OutlinePost.ts b/src/gfx/renderJob/post/OutlinePost.ts index 95e3aaa3..c2dd09f4 100644 --- a/src/gfx/renderJob/post/OutlinePost.ts +++ b/src/gfx/renderJob/post/OutlinePost.ts @@ -12,14 +12,14 @@ import { PostBase } from './PostBase'; import { Engine3D } from '../../../Engine3D'; import { clamp } from '../../../math/MathUtil'; import { Color } from '../../../math/Color'; -import OutLineBlendColor from '../../../assets/shader/compute/OutLineBlendColor.wgsl?raw'; -import OutlineCalcOutline from '../../../assets/shader/compute/OutlineCalcOutline.wgsl?raw'; -import OutlineCs from '../../../assets/shader/compute/OutlineCs.wgsl?raw'; import { Vector2 } from '../../../math/Vector2'; import { RTDescriptor } from '../../graphics/webGpu/descriptor/RTDescriptor'; import { GBufferFrame } from '../frame/GBufferFrame'; import { RTFrame } from '../frame/RTFrame'; import { View3D } from '../../../core/View3D'; +import { OutlineCalcOutline_cs } from '../../../assets/shader/compute/OutlineCalcOutline_cs'; +import { Outline_cs } from '../../../assets/shader/compute/Outline_cs'; +import { OutLineBlendColor_cs } from '../../../assets/shader/compute/OutLineBlendColor_cs'; export class OutlinePostSlot { public indexList: Float32Array; @@ -210,7 +210,7 @@ export class OutlinePost extends PostBase { let rtFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer"); let visibleMap = rtFrame.getPositionMap();// RTResourceMap.getTexture(RTResourceConfig.zBufferTexture_NAME); - this.calcWeightCompute = new ComputeShader(OutlineCalcOutline); + this.calcWeightCompute = new ComputeShader(OutlineCalcOutline_cs); this.calcWeightCompute.setStorageBuffer('outlineSetting', this.outlineSetting); this.calcWeightCompute.setStorageBuffer('slotsBuffer', this.slotsBuffer); this.calcWeightCompute.setStorageBuffer(`weightBuffer`, this.weightBuffer); @@ -222,7 +222,7 @@ export class OutlinePost extends PostBase { this.calcWeightCompute.workerSizeZ = 1; //outline - this.outlineCompute = new ComputeShader(OutlineCs); + this.outlineCompute = new ComputeShader(Outline_cs); this.outlineCompute.setStorageBuffer('outlineSetting', this.outlineSetting); this.outlineCompute.setStorageBuffer('slotsBuffer', this.slotsBuffer); this.outlineCompute.setStorageBuffer(`weightBuffer`, this.weightBuffer); @@ -234,7 +234,7 @@ export class OutlinePost extends PostBase { this.outlineCompute.workerSizeZ = 1; //blend - this.blendCompute = new ComputeShader(OutLineBlendColor); + this.blendCompute = new ComputeShader(OutLineBlendColor_cs); this.blendCompute.setStorageBuffer('outlineSetting', this.outlineSetting); this.autoSetColorTexture('inTex', this.blendCompute); this.blendCompute.setSamplerTexture(`lowTex`, this.lowTex); diff --git a/src/gfx/renderJob/post/SSRPost.ts b/src/gfx/renderJob/post/SSRPost.ts index af4e84ac..5fedce16 100644 --- a/src/gfx/renderJob/post/SSRPost.ts +++ b/src/gfx/renderJob/post/SSRPost.ts @@ -1,6 +1,3 @@ -import SSR_BlendColor_Shader from '../../../assets/shader/compute/SSR_BlendColor_Shader.wgsl?raw'; -import SSR_IS_Shader from '../../../assets/shader/compute/SSR_IS_Shader.wgsl?raw'; -import SSR_RayTrace_Shader from '../../../assets/shader/compute/SSR_RayTrace_Shader.wgsl?raw'; import { Engine3D } from '../../../Engine3D'; import { Vector3 } from '../../../math/Vector3'; import { VirtualTexture } from '../../../textures/VirtualTexture'; @@ -24,6 +21,9 @@ import { GBufferFrame } from '../frame/GBufferFrame'; import { SSRSetting } from '../../../setting/post/SSRSetting'; import { View3D } from '../../../core/View3D'; import { SkyRenderer } from '../../../components/renderer/SkyRenderer'; +import { SSR_RayTrace_cs } from '../../../assets/shader/compute/SSR_RayTrace_cs'; +import { SSR_IS_cs } from '../../../assets/shader/compute/SSR_IS_cs'; +import { SSR_BlendColor_cs } from '../../../assets/shader/compute/SSR_BlendColor_cs'; /** * Screen space reflection * ``` @@ -162,7 +162,7 @@ export class SSRPost extends PostBase { } private createRayTraceShader() { - this.SSR_RayTraceCompute = new ComputeShader(SSR_RayTrace_Shader); + this.SSR_RayTraceCompute = new ComputeShader(SSR_RayTrace_cs); this.SSR_RayTraceCompute.setStorageBuffer('ssrUniform', this.ssrUniformBuffer); this.SSR_RayTraceCompute.setStorageBuffer(`rayTraceBuffer`, this.rayTraceData); this.SSR_RayTraceCompute.setStorageBuffer(`historyPosition`, this.historyPosition); @@ -181,7 +181,7 @@ export class SSRPost extends PostBase { } private createISShader() { - this.SSR_IS_Compute = new ComputeShader(SSR_IS_Shader); + this.SSR_IS_Compute = new ComputeShader(SSR_IS_cs); this.SSR_IS_Compute.setStorageBuffer('ssrUniform', this.ssrUniformBuffer); this.SSR_IS_Compute.setStorageBuffer(`rayTraceBuffer`, this.rayTraceData); @@ -197,7 +197,7 @@ export class SSRPost extends PostBase { } private createBlendShader(input: VirtualTexture): void { - this.SSR_Blend_Compute = new ComputeShader(SSR_BlendColor_Shader); + this.SSR_Blend_Compute = new ComputeShader(SSR_BlendColor_cs); this.SSR_Blend_Compute.setStorageBuffer(`rayTraceBuffer`, this.rayTraceData); this.autoSetColorTexture('colorMap', this.SSR_Blend_Compute); diff --git a/src/gfx/renderJob/post/TAAPost.ts b/src/gfx/renderJob/post/TAAPost.ts index 87f69970..e395351b 100644 --- a/src/gfx/renderJob/post/TAAPost.ts +++ b/src/gfx/renderJob/post/TAAPost.ts @@ -14,11 +14,11 @@ import { Matrix4 } from '../../../math/Matrix4'; import { clamp } from '../../../math/MathUtil'; import { RTDescriptor } from '../../graphics/webGpu/descriptor/RTDescriptor'; import { RTFrame } from '../frame/RTFrame'; -import TAAcs from '../../../assets/shader/compute/TAAcs.wgsl?raw'; -import TAACopyTex from '../../../assets/shader/compute/TAACopyTex.wgsl?raw'; -import TAASharpTex from '../../../assets/shader/compute/TAASharpTex.wgsl?raw'; import { GBufferFrame } from '../frame/GBufferFrame'; import { View3D } from '../../../core/View3D'; +import { TAA_cs } from '../../../assets/shader/compute/TAA_cs'; +import { TAACopyTex_cs } from '../../../assets/shader/compute/TAACopyTex_cs'; +import { TAASharpTex_cs } from '../../../assets/shader/compute/TAASharpTex_cs'; /** * Temporal AA @@ -148,7 +148,7 @@ export class TAAPost extends PostBase { } private createCompute(view: View3D) { - let computeShader = new ComputeShader(TAAcs); + let computeShader = new ComputeShader(TAA_cs); let cfg = Engine3D.setting.render.postProcessing.taa; let taaSetting: UniformGPUBuffer = new UniformGPUBuffer(16 * 2 + 4 * 3); //matrix + 3 * vector4 @@ -172,7 +172,7 @@ export class TAAPost extends PostBase { this.taaSetting = taaSetting; //copy - this.copyTexCompute = new ComputeShader(TAACopyTex); + this.copyTexCompute = new ComputeShader(TAACopyTex_cs); this.copyTexCompute.setStorageBuffer(`preColor`, this.preColorBuffer); this.copyTexCompute.setStorageTexture(`preColorTex`, this.preColorTex); this.copyTexCompute.workerSizeX = Math.ceil(this.taaTexture.width / 8); @@ -180,7 +180,7 @@ export class TAAPost extends PostBase { this.copyTexCompute.workerSizeZ = 1; //sharp - this.sharpCompute = new ComputeShader(TAASharpTex); + this.sharpCompute = new ComputeShader(TAASharpTex_cs); this.sharpCompute.setUniformBuffer('taaData', taaSetting); this.sharpCompute.setSamplerTexture(`inTex`, this.taaTexture); this.sharpCompute.setStorageTexture(`outTex`, this.outTexture); diff --git a/src/index.ts b/src/index.ts index 48dd772f..63db0c2f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,387 +1,444 @@ -export * from "./Engine3D" -export * from "./assets/Res" -export * from "./assets/shader/ShaderLib" -export * from "./assets/shader/anim/SkeletonAnimation_shader" -export * from "./assets/shader/compute/BlurEffectCreator_compute" -export * from "./assets/shader/core/pass/CastShadowPass_wgsl" -export * from "./assets/shader/core/pass/ZPassShader_vs" -export * from "./assets/shader/core/struct/LightStructFrag" -export * from "./assets/shader/core/struct/VertexAttributes" -export * from "./assets/shader/glsl/Quad_glsl" -export * from "./assets/shader/glsl/Sky_glsl" -export * from "./assets/shader/glsl/post/LUT_glsl" -export * from "./assets/shader/lighting/IrradianceVolumeData_frag" -export * from "./assets/shader/lighting/LightingFunction_frag" -export * from "./assets/shader/lighting/UnLit_frag" -export * from "./assets/shader/materials/ColorLitShader" -export * from "./assets/shader/materials/Lambert_shader" -export * from "./assets/shader/materials/PavementShader" -export * from "./assets/shader/materials/PointShadowDebug" -export * from "./assets/shader/materials/materials/sky/AtmosphericScatteringSky_shader" -export * from "./assets/shader/materials/materials/sky/CubeSky_Shader" -export * from "./assets/shader/materials/program/ClusterDebug_frag" -export * from "./assets/shader/materials/sky/AtmosphericScatteringSky_shader" -export * from "./assets/shader/materials/sky/CubeSky_Shader" -export * from "./assets/shader/materials/uniforms/MaterialUniform" -export * from "./assets/shader/materials/uniforms/PhysicMaterialUniform_frag" -export * from "./assets/shader/materials/uniforms/UnLitMaterialUniform_frag" -export * from "./assets/shader/materials/uniforms/VideoUniform_frag" -export * from "./assets/shader/math/MathShader" -export * from "./assets/shader/post/Bloom_shader" -export * from "./assets/shader/post/GlobalFog_shader" -export * from "./assets/shader/quad/Quad_shader" -export * from "./components/AtmosphericComponent" -export * from "./components/BillboardComponent" -export * from "./components/ColliderComponent" -export * from "./components/ComponentBase" -export * from "./components/IComponent" -export * from "./components/SkeletonAnimationComponent" -export * from "./components/Transform" -export * from "./components/anim/OAnimationEvent" -export * from "./components/anim/curveAnim/curveAnim/AnimationMonitor" -export * from "./components/anim/curveAnim/curveAnim/AttributeAnimCurve" -export * from "./components/anim/curveAnim/curveAnim/PropertyAnimClip" -export * from "./components/anim/curveAnim/curveAnim/PropertyAnimation" -export * from "./components/anim/curveAnim/curveAnim/PropertyAnimationEvent" -export * from "./components/anim/curveAnim/curveAnim/PropertyHelp" -export * from "./components/anim/morphAnim/MorphTargetBlender" -export * from "./components/anim/morphAnim/MorphTargetData" -export * from "./components/anim/morphAnim/MorphTargetFrame" -export * from "./components/anim/morphAnim/MorphTargetKey" -export * from "./components/anim/morphAnim/MorphTarget_shader" -export * from "./components/anim/skeletonAnim/Joint" -export * from "./components/anim/skeletonAnim/JointPose" -export * from "./components/anim/skeletonAnim/Skeleton" -export * from "./components/anim/skeletonAnim/SkeletonAnimationClip" -export * from "./components/anim/skeletonAnim/SkeletonAnimationClipState" -export * from "./components/anim/skeletonAnim/SkeletonAnimationCompute" -export * from "./components/anim/skeletonAnim/SkeletonPose" -export * from "./components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs" -export * from "./components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs" -export * from "./components/anim/skeletonAnim/shader/compute_skeleton_blend" -export * from "./components/anim/skeletonAnim/shader/compute_skeleton_transform" -export * from "./components/audio/AudioListener" -export * from "./components/audio/PositionAudio" -export * from "./components/audio/StaticAudio" -export * from "./components/controller/CameraControllerBase" -export * from "./components/controller/FirstPersonCameraController" -export * from "./components/controller/FlyCameraController" -export * from "./components/controller/HoverCameraController" -export * from "./components/controller/OrbitController" -export * from "./components/controller/ThirdPersonCameraController" -export * from "./components/lights/DirectLight" -export * from "./components/lights/GILighting" -export * from "./components/lights/IESProfiles" -export * from "./components/lights/ILight" -export * from "./components/lights/LightBase" -export * from "./components/lights/LightData" -export * from "./components/lights/PointLight" -export * from "./components/lights/SpotLight" -export * from "./components/post/PostProcessingComponent" -export * from "./components/renderer/InstanceDrawComponent" -export * from "./components/renderer/MaterialComponent" -export * from "./components/renderer/MeshComponent" -export * from "./components/renderer/MeshRenderer" -export * from "./components/renderer/RenderNode" -export * from "./components/renderer/SkinnedMeshRenderer" -export * from "./components/renderer/SkyRenderer" -export * from "./components/shape/BoxColliderShape" -export * from "./components/shape/CapsuleColliderShape" -export * from "./components/shape/ColliderShape" -export * from "./components/shape/MeshColliderShape" -export * from "./components/shape/SphereColliderShape" -export * from "./core/Camera3D" -export * from "./core/CameraType" -export * from "./core/CubeCamera" -export * from "./core/PointShadowCubeCamera" -export * from "./core/Scene3D" -export * from "./core/View3D" -export * from "./core/ViewQuad" -export * from "./core/bound/BoundingBox" -export * from "./core/bound/BoundingSphere" -export * from "./core/bound/Frustum" -export * from "./core/bound/IBound" -export * from "./core/entities/Entity" -export * from "./core/entities/InstancedMesh" -export * from "./core/entities/Object3D" -export * from "./core/geometry/GeometryBase" -export * from "./core/geometry/GeometryIndicesBuffer" -export * from "./core/geometry/GeometryVertexBuffer" -export * from "./core/geometry/GeometryVertexType" -export * from "./core/geometry/VertexAttribute" -export * from "./core/geometry/VertexAttributeData" -export * from "./core/geometry/VertexAttributeName" -export * from "./core/geometry/VertexAttributeSize" -export * from "./core/geometry/VertexAttributeStride" -export * from "./core/geometry/VertexFormat" -export * from "./core/pool/ObjectPool" -export * from "./core/pool/memory/MatrixDO" -export * from "./core/pool/memory/MemoryDO" -export * from "./core/pool/memory/MemoryInfo" -export * from "./core/tree/kdTree/IKDTreeUserData" -export * from "./core/tree/kdTree/KDTreeEntity" -export * from "./core/tree/kdTree/KDTreeNode" -export * from "./core/tree/kdTree/KDTreeSpace" -export * from "./event/CEvent" -export * from "./event/CEventDispatcher" -export * from "./event/CEventListener" -export * from "./event/CResizeEvent" -export * from "./event/KeyCode" -export * from "./event/MouseCode" -export * from "./event/eventConst/KeyEvent" -export * from "./event/eventConst/LoaderEvent" -export * from "./event/eventConst/Object3DEvent" -export * from "./event/eventConst/PointerEvent3D" -export * from "./event/eventConst/UIEvent" -export * from "./gfx/data/IrradianceVolume" -export * from "./gfx/generate/BrdfLUTGenerate" -export * from "./gfx/generate/PassGenerate" -export * from "./gfx/generate/convert/BlurEffectCreator" -export * from "./gfx/generate/convert/ErpImage2CubeMap" -export * from "./gfx/generate/convert/IBLEnvMapCreator" -export * from "./gfx/generate/convert/MergeRGBACreator" -export * from "./gfx/generate/convert/TextureCubeStdCreator" -export * from "./gfx/generate/convert/TextureCubeUtils" -export * from "./gfx/graphics/webGpu/CanvasConfig" -export * from "./gfx/graphics/webGpu/Context3D" -export * from "./gfx/graphics/webGpu/WebGPUConst" -export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup" -export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout" -export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup" -export * from "./gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup" -export * from "./gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup" -export * from "./gfx/graphics/webGpu/core/bindGroups/groups/LightEntries" -export * from "./gfx/graphics/webGpu/core/buffer/ArrayBufferData" -export * from "./gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferBase" -export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferType" -export * from "./gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/StorageGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/UniformGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/VertexGPUBuffer" -export * from "./gfx/graphics/webGpu/core/texture/ITexture" -export * from "./gfx/graphics/webGpu/core/texture/Texture" -export * from "./gfx/graphics/webGpu/core/texture/TextureCube" -export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapCompute" -export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapGenerator" -export * from "./gfx/graphics/webGpu/core/uniforms/UniformNode" -export * from "./gfx/graphics/webGpu/descriptor/RTDescriptor" -export * from "./gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator" -export * from "./gfx/graphics/webGpu/shader/ComputeShader" -export * from "./gfx/graphics/webGpu/shader/RenderShader" -export * from "./gfx/graphics/webGpu/shader/ShaderBase" -export * from "./gfx/graphics/webGpu/shader/ShaderStage" -export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexer" -export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexerToken" -export * from "./gfx/graphics/webGpu/shader/converter/GLSLPreprocessor" -export * from "./gfx/graphics/webGpu/shader/converter/GLSLSyntax" -export * from "./gfx/graphics/webGpu/shader/converter/Reader" -export * from "./gfx/graphics/webGpu/shader/converter/ShaderConverter" -export * from "./gfx/graphics/webGpu/shader/converter/StatementNode" -export * from "./gfx/graphics/webGpu/shader/converter/WGSLTranslator" -export * from "./gfx/graphics/webGpu/shader/util/MorePassParser" -export * from "./gfx/graphics/webGpu/shader/util/Preprocessor" -export * from "./gfx/graphics/webGpu/shader/util/ShaderUtil" -export * from "./gfx/graphics/webGpu/shader/value/ConstValue" -export * from "./gfx/graphics/webGpu/shader/value/DefineValue" -export * from "./gfx/graphics/webGpu/shader/value/ShaderReflectionInfo" -export * from "./gfx/graphics/webGpu/shader/value/ShaderState" -export * from "./gfx/graphics/webGpu/shader/value/ShaderValue" -export * from "./gfx/graphics/webGpu/shader/value/UniformValue" -export * from "./gfx/renderJob/GPUContext" -export * from "./gfx/renderJob/collect/CollectInfo" -export * from "./gfx/renderJob/collect/ComponentCollect" -export * from "./gfx/renderJob/collect/EntityBatchCollect" -export * from "./gfx/renderJob/collect/EntityCollect" -export * from "./gfx/renderJob/collect/RenderGroup" -export * from "./gfx/renderJob/collect/ShadowLightsCollect" -export * from "./gfx/renderJob/config/RTResourceConfig" -export * from "./gfx/renderJob/config/RenderLayer" -export * from "./gfx/renderJob/frame/GBufferFrame" -export * from "./gfx/renderJob/frame/ProbeGBufferFrame" -export * from "./gfx/renderJob/frame/RTFrame" -export * from "./gfx/renderJob/frame/RTResourceMap" -export * from "./gfx/renderJob/jobs/ForwardRenderJob" -export * from "./gfx/renderJob/jobs/RenderMap" -export * from "./gfx/renderJob/jobs/RendererJob" -export * from "./gfx/renderJob/occlusion/OcclusionSystem" -export * from "./gfx/renderJob/passRenderer/RenderContext" -export * from "./gfx/renderJob/passRenderer/RendererBase" -export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer" -export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingRender" -export * from "./gfx/renderJob/passRenderer/color/ColorPassRenderer" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DRender" -export * from "./gfx/renderJob/passRenderer/graphic/GraphicConfig" -export * from "./gfx/renderJob/passRenderer/graphic/Graphics3DShape" -export * from "./gfx/renderJob/passRenderer/post/PostRenderer" -export * from "./gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer" -export * from "./gfx/renderJob/passRenderer/preDepth/ZCullingCompute" -export * from "./gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer" -export * from "./gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer" -export * from "./gfx/renderJob/passRenderer/state/RendererMask" -export * from "./gfx/renderJob/passRenderer/state/RendererPassState" -export * from "./gfx/renderJob/passRenderer/state/RendererType" -export * from "./gfx/renderJob/post/DepthOfFieldPost" -export * from "./gfx/renderJob/post/FXAAPost" -export * from "./gfx/renderJob/post/GTAOPost" -export * from "./gfx/renderJob/post/GlobalFog" -export * from "./gfx/renderJob/post/HDRBloomPost" -export * from "./gfx/renderJob/post/OutlinePost" -export * from "./gfx/renderJob/post/PostBase" -export * from "./gfx/renderJob/post/SSRPost" -export * from "./gfx/renderJob/post/TAAPost" -export * from "./io/InputSystem" -export * from "./io/PickFire" -export * from "./io/PickResult" -export * from "./io/RayCastMeshDetail" -export * from "./io/TouchData" -export * from "./io/picker/PickCompute" -export * from "./loader/FileLoader" -export * from "./loader/LoaderBase" -export * from "./loader/LoaderData" -export * from "./loader/LoaderFunctions" -export * from "./loader/LoaderManager" -export * from "./loader/parser/B3DMParser" -export * from "./loader/parser/I3DMParser" -export * from "./loader/parser/OBJParser" -export * from "./loader/parser/ParserBase" -export * from "./loader/parser/RGBEParser" -export * from "./loader/parser/b3dm/B3DMLoader" -export * from "./loader/parser/b3dm/B3DMLoaderBase" -export * from "./loader/parser/b3dm/FeatureTable" -export * from "./loader/parser/b3dm/arrayToString" -export * from "./loader/parser/b3dm/readMagicBytes" -export * from "./loader/parser/gltf/GLBParser" -export * from "./loader/parser/gltf/GLTFInfo" -export * from "./loader/parser/gltf/GLTFParser" -export * from "./loader/parser/gltf/GLTFSubParser" -export * from "./loader/parser/gltf/GLTFSubParserCamera" -export * from "./loader/parser/gltf/GLTFSubParserConverter" -export * from "./loader/parser/gltf/GLTFSubParserMaterial" -export * from "./loader/parser/gltf/GLTFSubParserMesh" -export * from "./loader/parser/gltf/GLTFSubParserSkeleton" -export * from "./loader/parser/gltf/GLTFSubParserSkin" -export * from "./loader/parser/gltf/GLTFType" -export * from "./loader/parser/gltf/TypeArray" -export * from "./loader/parser/gltf/extends/KHR_draco_mesh_compression" -export * from "./loader/parser/gltf/extends/KHR_lights_punctual" -export * from "./loader/parser/gltf/extends/KHR_materials_clearcoat" -export * from "./loader/parser/gltf/extends/KHR_materials_emissive_strength" -export * from "./loader/parser/gltf/extends/KHR_materials_ior" -export * from "./loader/parser/gltf/extends/KHR_materials_sheen" -export * from "./loader/parser/gltf/extends/KHR_materials_specular" -export * from "./loader/parser/gltf/extends/KHR_materials_transmission" -export * from "./loader/parser/gltf/extends/KHR_materials_unlit" -export * from "./loader/parser/gltf/extends/KHR_materials_variants" -export * from "./loader/parser/gltf/extends/KHR_materials_volume" -export * from "./loader/parser/gltf/extends/KHR_mesh_quantization" -export * from "./loader/parser/gltf/extends/KHR_texture_basisu" -export * from "./loader/parser/gltf/extends/KHR_texture_transform" -export * from "./loader/parser/i3dm/I3DMLoader" -export * from "./loader/parser/i3dm/I3DMLoaderBase" -export * from "./loader/parser/tileRenderer/TileSet" -export * from "./loader/parser/tileRenderer/TilesRenderer" -export * from "./materials/BlendMode" -export * from "./materials/ColorLitMaterial" -export * from "./materials/GlassMaterial" -export * from "./materials/LambertMaterial" -export * from "./materials/LitMaterial" -export * from "./materials/MaterialBase" -export * from "./materials/MaterialPass" -export * from "./materials/MaterialRegister" -export * from "./materials/PavementMaterial" -export * from "./materials/PhysicMaterial" -export * from "./materials/PointMaterial" -export * from "./materials/SkyMaterial" -export * from "./materials/UnLitMaterial" -export * from "./materials/effectPass/OutLinePass" -export * from "./materials/multiPass/CastPointShadowMaterialPass" -export * from "./materials/multiPass/CastShadowMaterialPass" -export * from "./materials/multiPass/DepthMaterialPass" -export * from "./materials/multiPass/GBufferPass" -export * from "./materials/multiPass/SkyGBufferPass" -export * from "./math/AnimationCurve" -export * from "./math/Bezier2D" -export * from "./math/Bezier3D" -export * from "./math/Color" -export * from "./math/HaltonSeq" -export * from "./math/Line" -export * from "./math/MathUtil" -export * from "./math/Matrix3" -export * from "./math/Matrix4" -export * from "./math/Orientation3D" -export * from "./math/ParticleMath" -export * from "./math/ParticleSystemCurves" -export * from "./math/Plane" -export * from "./math/PolynomialCurve" -export * from "./math/Polynomials" -export * from "./math/Quaternion" -export * from "./math/Rand" -export * from "./math/Random" -export * from "./math/Ray" -export * from "./math/Rect" -export * from "./math/TimeInterpolator" -export * from "./math/Triangle" -export * from "./math/UV" -export * from "./math/Vector2" -export * from "./math/Vector3" -export * from "./math/Vector4" -export * from "./setting/EngineSetting" -export * from "./setting/GlobalIlluminationSetting" -export * from "./setting/LightSetting" -export * from "./setting/MaterialSetting" -export * from "./setting/OcclusionQuerySetting" -export * from "./setting/PickSetting" -export * from "./setting/RenderSetting" -export * from "./setting/ShadowSetting" -export * from "./setting/SkySetting" -export * from "./setting/post/BloomSetting" -export * from "./setting/post/DepthOfViewSetting" -export * from "./setting/post/GTAOSetting" -export * from "./setting/post/GlobalFogSetting" -export * from "./setting/post/OutlineSetting" -export * from "./setting/post/SSRSetting" -export * from "./setting/post/TAASetting" -export * from "./shape/BoxGeometry" -export * from "./shape/CylinderGeometry" -export * from "./shape/PlaneGeometry" -export * from "./shape/SphereGeometry" -export * from "./shape/TorusGeometry" -export * from "./textures/AtmosphericScatteringSky" -export * from "./textures/BitmapTexture2D" -export * from "./textures/BitmapTexture2DArray" -export * from "./textures/BitmapTextureCube" -export * from "./textures/Depth2DTextureArray" -export * from "./textures/DepthCubeArrayTexture" -export * from "./textures/DepthCubeTexture" -export * from "./textures/Float16ArrayTexture" -export * from "./textures/Float32ArrayTexture" -export * from "./textures/HDRTexture" -export * from "./textures/HDRTextureCube" -export * from "./textures/LDRTextureCube" -export * from "./textures/SolidColorSky" -export * from "./textures/Uint16Texture" -export * from "./textures/Uint8ArrayTexture" -export * from "./textures/VirtualTexture" -export * from "./util/AxisObject" -export * from "./util/BytesStream" -export * from "./util/CameraUtil" -export * from "./util/Convert" -export * from "./util/GeometryUtil" -export * from "./util/Global" -export * from "./util/KelvinUtil" -export * from "./util/Object3DUtil" -export * from "./util/ProfilerUtil" -export * from "./util/StringUtil" -export * from "./util/Time" -export * from "./util/Vector3Ex" -export * from "./util/ZSorterUtil" -export * from "./util/struct/Struct" -export * from "./util/struct/StructValue" -export * from "./util/struct/Vector3Struct" +export * from "./assets/Res" +export * from "./assets/shader/anim/SkeletonAnimation_shader" +export * from "./assets/shader/cluster/ClusterBoundsSource_cs" +export * from "./assets/shader/cluster/ClusterLighting_cs" +export * from "./assets/shader/compute/BlurEffectCreator_cs" +export * from "./assets/shader/compute/BLUR_CsShader" +export * from "./assets/shader/compute/DepthOfView_cs" +export * from "./assets/shader/compute/ErpImage2CubeMapCreateCube_cs" +export * from "./assets/shader/compute/ErpImage2CubeMapRgbe2rgba_cs" +export * from "./assets/shader/compute/GTAO_cs" +export * from "./assets/shader/compute/IBLEnvMapCreator_cs" +export * from "./assets/shader/compute/MergeRGBA_cs" +export * from "./assets/shader/compute/MultiBouncePass_cs" +export * from "./assets/shader/compute/OutLineBlendColor_cs" +export * from "./assets/shader/compute/OutlineCalcOutline_cs" +export * from "./assets/shader/compute/Outline_cs" +export * from "./assets/shader/compute/Picker_cs" +export * from "./assets/shader/compute/SSAO_cs" +export * from "./assets/shader/compute/SSR_BlendColor_cs" +export * from "./assets/shader/compute/SSR_IS_cs" +export * from "./assets/shader/compute/SSR_RayTrace_cs" +export * from "./assets/shader/compute/TAACopyTex_cs" +export * from "./assets/shader/compute/TAASharpTex_cs" +export * from "./assets/shader/compute/TAA_cs" +export * from "./assets/shader/core/base/Common_frag" +export * from "./assets/shader/core/base/Common_vert" +export * from "./assets/shader/core/common/BrdfLut_frag" +export * from "./assets/shader/core/common/EnvMap_frag" +export * from "./assets/shader/core/common/GlobalUniform" +export * from "./assets/shader/core/common/InstanceUniform" +export * from "./assets/shader/core/common/WorldMatrixUniform" +export * from "./assets/shader/core/inline/Inline_vert" +export * from "./assets/shader/core/pass/CastShadow_pass" +export * from "./assets/shader/core/pass/FrustumCulling_cs" +export * from "./assets/shader/core/pass/GBuffer_pass" +export * from "./assets/shader/core/pass/SkyGBuffer_pass" +export * from "./assets/shader/core/pass/ZPassShader_cs" +export * from "./assets/shader/core/pass/ZPassShader_fs" +export * from "./assets/shader/core/pass/ZPassShader_vs" +export * from "./assets/shader/core/struct/ColorPassFragmentOutput" +export * from "./assets/shader/core/struct/EmptyFrag_CommonFragment" +export * from "./assets/shader/core/struct/EmptyFrag_FragmentOutput" +export * from "./assets/shader/core/struct/FragmentVarying" +export * from "./assets/shader/core/struct/LightStruct" +export * from "./assets/shader/core/struct/LightStructFrag" +export * from "./assets/shader/core/struct/ShadingInput" +export * from "./assets/shader/core/struct/VertexAttributes" +export * from "./assets/shader/glsl/post/LUT_glsl" +export * from "./assets/shader/glsl/Quad_glsl" +export * from "./assets/shader/glsl/Sky_glsl" +export * from "./assets/shader/graphic/Graphic3DShader_fs" +export * from "./assets/shader/graphic/Graphic3DShader_vs" +export * from "./assets/shader/lighting/BRDF_frag" +export * from "./assets/shader/lighting/BxDF_frag" +export * from "./assets/shader/lighting/IESProfiles_frag" +export * from "./assets/shader/lighting/IrradianceVolumeData_frag" +export * from "./assets/shader/lighting/Irradiance_frag" +export * from "./assets/shader/lighting/LightingFunction_frag" +export * from "./assets/shader/lighting/UnLit_frag" +export * from "./assets/shader/materials/ColorLitShader" +export * from "./assets/shader/materials/GlassShader" +export * from "./assets/shader/materials/Lambert_shader" +export * from "./assets/shader/materials/LitShader" +export * from "./assets/shader/materials/OutlinePass" +export * from "./assets/shader/materials/PavementShader" +export * from "./assets/shader/materials/PBRLItShader" +export * from "./assets/shader/materials/PointShadowDebug" +export * from "./assets/shader/materials/program/BxdfDebug_frag" +export * from "./assets/shader/materials/program/Clearcoat_frag" +export * from "./assets/shader/materials/program/ClusterDebug_frag" +export * from "./assets/shader/materials/program/NormalMap_frag" +export * from "./assets/shader/materials/program/ShadowMapping_frag" +export * from "./assets/shader/materials/uniforms/MaterialUniform" +export * from "./assets/shader/materials/uniforms/PhysicMaterialUniform_frag" +export * from "./assets/shader/materials/uniforms/UnLitMaterialUniform_frag" +export * from "./assets/shader/materials/uniforms/VideoUniform_frag" +export * from "./assets/shader/materials/UnLit" +export * from "./assets/shader/math/FastMathShader" +export * from "./assets/shader/math/MathShader" +export * from "./assets/shader/post/Bloom_shader" +export * from "./assets/shader/post/FXAAShader" +export * from "./assets/shader/post/GlobalFog_shader" +export * from "./assets/shader/quad/Quad_shader" +export * from "./assets/shader/ShaderLib" +export * from "./assets/shader/sky/AtmosphericScatteringSky_shader" +export * from "./assets/shader/sky/CubeSky_Shader" +export * from "./assets/shader/utils/BRDFLUT" +export * from "./assets/shader/utils/ColorUtil" +export * from "./assets/shader/utils/GenerayRandomDir" +export * from "./components/anim/curveAnim/curveAnim/AnimationMonitor" +export * from "./components/anim/curveAnim/curveAnim/AttributeAnimCurve" +export * from "./components/anim/curveAnim/curveAnim/PropertyAnimation" +export * from "./components/anim/curveAnim/curveAnim/PropertyAnimationEvent" +export * from "./components/anim/curveAnim/curveAnim/PropertyAnimClip" +export * from "./components/anim/curveAnim/curveAnim/PropertyHelp" +export * from "./components/anim/morphAnim/MorphTargetBlender" +export * from "./components/anim/morphAnim/MorphTargetData" +export * from "./components/anim/morphAnim/MorphTargetFrame" +export * from "./components/anim/morphAnim/MorphTargetKey" +export * from "./components/anim/morphAnim/MorphTarget_shader" +export * from "./components/anim/OAnimationEvent" +export * from "./components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs" +export * from "./components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs" +export * from "./components/anim/skeletonAnim/Joint" +export * from "./components/anim/skeletonAnim/JointPose" +export * from "./components/anim/skeletonAnim/shader/compute_skeleton_blend" +export * from "./components/anim/skeletonAnim/shader/compute_skeleton_transform" +export * from "./components/anim/skeletonAnim/Skeleton" +export * from "./components/anim/skeletonAnim/SkeletonAnimationClip" +export * from "./components/anim/skeletonAnim/SkeletonAnimationClipState" +export * from "./components/anim/skeletonAnim/SkeletonAnimationCompute" +export * from "./components/anim/skeletonAnim/SkeletonPose" +export * from "./components/AtmosphericComponent" +export * from "./components/audio/AudioListener" +export * from "./components/audio/PositionAudio" +export * from "./components/audio/StaticAudio" +export * from "./components/BillboardComponent" +export * from "./components/ColliderComponent" +export * from "./components/ComponentBase" +export * from "./components/controller/CameraControllerBase" +export * from "./components/controller/FirstPersonCameraController" +export * from "./components/controller/FlyCameraController" +export * from "./components/controller/HoverCameraController" +export * from "./components/controller/OrbitController" +export * from "./components/controller/ThirdPersonCameraController" +export * from "./components/IComponent" +export * from "./components/lights/DirectLight" +export * from "./components/lights/GILighting" +export * from "./components/lights/IESProfiles" +export * from "./components/lights/ILight" +export * from "./components/lights/LightBase" +export * from "./components/lights/LightData" +export * from "./components/lights/PointLight" +export * from "./components/lights/SpotLight" +export * from "./components/post/PostProcessingComponent" +export * from "./components/renderer/InstanceDrawComponent" +export * from "./components/renderer/MaterialComponent" +export * from "./components/renderer/MeshComponent" +export * from "./components/renderer/MeshRenderer" +export * from "./components/renderer/RenderNode" +export * from "./components/renderer/SkinnedMeshRenderer" +export * from "./components/renderer/SkyRenderer" +export * from "./components/shape/BoxColliderShape" +export * from "./components/shape/CapsuleColliderShape" +export * from "./components/shape/ColliderShape" +export * from "./components/shape/MeshColliderShape" +export * from "./components/shape/SphereColliderShape" +export * from "./components/SkeletonAnimationComponent" +export * from "./components/Transform" +export * from "./core/bound/BoundingBox" +export * from "./core/bound/BoundingSphere" +export * from "./core/bound/Frustum" +export * from "./core/bound/IBound" +export * from "./core/Camera3D" +export * from "./core/CameraType" +export * from "./core/CubeCamera" +export * from "./core/entities/Entity" +export * from "./core/entities/InstancedMesh" +export * from "./core/entities/Object3D" +export * from "./core/geometry/GeometryBase" +export * from "./core/geometry/GeometryIndicesBuffer" +export * from "./core/geometry/GeometryVertexBuffer" +export * from "./core/geometry/GeometryVertexType" +export * from "./core/geometry/VertexAttribute" +export * from "./core/geometry/VertexAttributeData" +export * from "./core/geometry/VertexAttributeName" +export * from "./core/geometry/VertexAttributeSize" +export * from "./core/geometry/VertexAttributeStride" +export * from "./core/geometry/VertexFormat" +export * from "./core/PointShadowCubeCamera" +export * from "./core/pool/memory/MatrixDO" +export * from "./core/pool/memory/MemoryDO" +export * from "./core/pool/memory/MemoryInfo" +export * from "./core/pool/ObjectPool" +export * from "./core/Scene3D" +export * from "./core/tree/kdTree/IKDTreeUserData" +export * from "./core/tree/kdTree/KDTreeEntity" +export * from "./core/tree/kdTree/KDTreeNode" +export * from "./core/tree/kdTree/KDTreeSpace" +export * from "./core/View3D" +export * from "./core/ViewQuad" +export * from "./Engine3D" +export * from "./event/CEvent" +export * from "./event/CEventDispatcher" +export * from "./event/CEventListener" +export * from "./event/CResizeEvent" +export * from "./event/eventConst/KeyEvent" +export * from "./event/eventConst/LoaderEvent" +export * from "./event/eventConst/Object3DEvent" +export * from "./event/eventConst/PointerEvent3D" +export * from "./event/eventConst/UIEvent" +export * from "./event/KeyCode" +export * from "./event/MouseCode" +export * from "./gfx/data/IrradianceVolume" +export * from "./gfx/generate/BrdfLUTGenerate" +export * from "./gfx/generate/convert/BlurEffectCreator" +export * from "./gfx/generate/convert/ErpImage2CubeMap" +export * from "./gfx/generate/convert/IBLEnvMapCreator" +export * from "./gfx/generate/convert/MergeRGBACreator" +export * from "./gfx/generate/convert/TextureCubeStdCreator" +export * from "./gfx/generate/convert/TextureCubeUtils" +export * from "./gfx/generate/PassGenerate" +export * from "./gfx/graphics/webGpu/CanvasConfig" +export * from "./gfx/graphics/webGpu/Context3D" +export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout" +export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/groups/LightEntries" +export * from "./gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup" +export * from "./gfx/graphics/webGpu/core/buffer/ArrayBufferData" +export * from "./gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferBase" +export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferType" +export * from "./gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/StorageGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/UniformGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/VertexGPUBuffer" +export * from "./gfx/graphics/webGpu/core/texture/ITexture" +export * from "./gfx/graphics/webGpu/core/texture/Texture" +export * from "./gfx/graphics/webGpu/core/texture/TextureCube" +export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapCompute" +export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapGenerator" +export * from "./gfx/graphics/webGpu/core/uniforms/UniformNode" +export * from "./gfx/graphics/webGpu/descriptor/RTDescriptor" +export * from "./gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator" +export * from "./gfx/graphics/webGpu/shader/ComputeShader" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexer" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexerToken" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLPreprocessor" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLSyntax" +export * from "./gfx/graphics/webGpu/shader/converter/Reader" +export * from "./gfx/graphics/webGpu/shader/converter/ShaderConverter" +export * from "./gfx/graphics/webGpu/shader/converter/StatementNode" +export * from "./gfx/graphics/webGpu/shader/converter/WGSLTranslator" +export * from "./gfx/graphics/webGpu/shader/RenderShader" +export * from "./gfx/graphics/webGpu/shader/ShaderBase" +export * from "./gfx/graphics/webGpu/shader/ShaderStage" +export * from "./gfx/graphics/webGpu/shader/util/MorePassParser" +export * from "./gfx/graphics/webGpu/shader/util/Preprocessor" +export * from "./gfx/graphics/webGpu/shader/util/ShaderUtil" +export * from "./gfx/graphics/webGpu/shader/value/ConstValue" +export * from "./gfx/graphics/webGpu/shader/value/DefineValue" +export * from "./gfx/graphics/webGpu/shader/value/ShaderReflectionInfo" +export * from "./gfx/graphics/webGpu/shader/value/ShaderState" +export * from "./gfx/graphics/webGpu/shader/value/ShaderValue" +export * from "./gfx/graphics/webGpu/shader/value/UniformValue" +export * from "./gfx/graphics/webGpu/WebGPUConst" +export * from "./gfx/renderJob/collect/CollectInfo" +export * from "./gfx/renderJob/collect/ComponentCollect" +export * from "./gfx/renderJob/collect/EntityBatchCollect" +export * from "./gfx/renderJob/collect/EntityCollect" +export * from "./gfx/renderJob/collect/RenderGroup" +export * from "./gfx/renderJob/collect/ShadowLightsCollect" +export * from "./gfx/renderJob/config/RenderLayer" +export * from "./gfx/renderJob/config/RTResourceConfig" +export * from "./gfx/renderJob/frame/GBufferFrame" +export * from "./gfx/renderJob/frame/ProbeGBufferFrame" +export * from "./gfx/renderJob/frame/RTFrame" +export * from "./gfx/renderJob/frame/RTResourceMap" +export * from "./gfx/renderJob/GPUContext" +export * from "./gfx/renderJob/jobs/ForwardRenderJob" +export * from "./gfx/renderJob/jobs/RendererJob" +export * from "./gfx/renderJob/jobs/RenderMap" +export * from "./gfx/renderJob/occlusion/OcclusionSystem" +export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer" +export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingRender" +export * from "./gfx/renderJob/passRenderer/color/ColorPassRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DRender" +export * from "./gfx/renderJob/passRenderer/graphic/GraphicConfig" +export * from "./gfx/renderJob/passRenderer/graphic/Graphics3DShape" +export * from "./gfx/renderJob/passRenderer/post/PostRenderer" +export * from "./gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer" +export * from "./gfx/renderJob/passRenderer/preDepth/ZCullingCompute" +export * from "./gfx/renderJob/passRenderer/RenderContext" +export * from "./gfx/renderJob/passRenderer/RendererBase" +export * from "./gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer" +export * from "./gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer" +export * from "./gfx/renderJob/passRenderer/state/RendererMask" +export * from "./gfx/renderJob/passRenderer/state/RendererPassState" +export * from "./gfx/renderJob/passRenderer/state/RendererType" +export * from "./gfx/renderJob/post/DepthOfFieldPost" +export * from "./gfx/renderJob/post/FXAAPost" +export * from "./gfx/renderJob/post/GlobalFog" +export * from "./gfx/renderJob/post/GTAOPost" +export * from "./gfx/renderJob/post/HDRBloomPost" +export * from "./gfx/renderJob/post/OutlinePost" +export * from "./gfx/renderJob/post/PostBase" +export * from "./gfx/renderJob/post/SSRPost" +export * from "./gfx/renderJob/post/TAAPost" +export * from "./io/InputSystem" +export * from "./io/picker/PickCompute" +export * from "./io/PickFire" +export * from "./io/PickResult" +export * from "./io/RayCastMeshDetail" +export * from "./io/TouchData" +export * from "./loader/FileLoader" +export * from "./loader/LoaderBase" +export * from "./loader/LoaderData" +export * from "./loader/LoaderFunctions" +export * from "./loader/LoaderManager" +export * from "./loader/parser/b3dm/arrayToString" +export * from "./loader/parser/b3dm/B3DMLoader" +export * from "./loader/parser/b3dm/B3DMLoaderBase" +export * from "./loader/parser/b3dm/FeatureTable" +export * from "./loader/parser/b3dm/readMagicBytes" +export * from "./loader/parser/B3DMParser" +export * from "./loader/parser/gltf/extends/KHR_draco_mesh_compression" +export * from "./loader/parser/gltf/extends/KHR_lights_punctual" +export * from "./loader/parser/gltf/extends/KHR_materials_clearcoat" +export * from "./loader/parser/gltf/extends/KHR_materials_emissive_strength" +export * from "./loader/parser/gltf/extends/KHR_materials_ior" +export * from "./loader/parser/gltf/extends/KHR_materials_sheen" +export * from "./loader/parser/gltf/extends/KHR_materials_specular" +export * from "./loader/parser/gltf/extends/KHR_materials_transmission" +export * from "./loader/parser/gltf/extends/KHR_materials_unlit" +export * from "./loader/parser/gltf/extends/KHR_materials_variants" +export * from "./loader/parser/gltf/extends/KHR_materials_volume" +export * from "./loader/parser/gltf/extends/KHR_mesh_quantization" +export * from "./loader/parser/gltf/extends/KHR_texture_basisu" +export * from "./loader/parser/gltf/extends/KHR_texture_transform" +export * from "./loader/parser/gltf/GLBParser" +export * from "./loader/parser/gltf/GLTFInfo" +export * from "./loader/parser/gltf/GLTFParser" +export * from "./loader/parser/gltf/GLTFSubParser" +export * from "./loader/parser/gltf/GLTFSubParserCamera" +export * from "./loader/parser/gltf/GLTFSubParserConverter" +export * from "./loader/parser/gltf/GLTFSubParserMaterial" +export * from "./loader/parser/gltf/GLTFSubParserMesh" +export * from "./loader/parser/gltf/GLTFSubParserSkeleton" +export * from "./loader/parser/gltf/GLTFSubParserSkin" +export * from "./loader/parser/gltf/GLTFType" +export * from "./loader/parser/gltf/TypeArray" +export * from "./loader/parser/i3dm/I3DMLoader" +export * from "./loader/parser/i3dm/I3DMLoaderBase" +export * from "./loader/parser/I3DMParser" +export * from "./loader/parser/OBJParser" +export * from "./loader/parser/ParserBase" +export * from "./loader/parser/RGBEParser" +export * from "./loader/parser/tileRenderer/TileSet" +export * from "./loader/parser/tileRenderer/TilesRenderer" +export * from "./materials/BlendMode" +export * from "./materials/ColorLitMaterial" +export * from "./materials/GlassMaterial" +export * from "./materials/LambertMaterial" +export * from "./materials/LitMaterial" +export * from "./materials/MaterialBase" +export * from "./materials/MaterialPass" +export * from "./materials/MaterialRegister" +export * from "./materials/multiPass/CastPointShadowMaterialPass" +export * from "./materials/multiPass/CastShadowMaterialPass" +export * from "./materials/multiPass/DepthMaterialPass" +export * from "./materials/multiPass/GBufferPass" +export * from "./materials/multiPass/SkyGBufferPass" +export * from "./materials/PavementMaterial" +export * from "./materials/PhysicMaterial" +export * from "./materials/PointMaterial" +export * from "./materials/SkyMaterial" +export * from "./materials/UnLitMaterial" +export * from "./math/AnimationCurve" +export * from "./math/Bezier2D" +export * from "./math/Bezier3D" +export * from "./math/Color" +export * from "./math/HaltonSeq" +export * from "./math/Line" +export * from "./math/MathUtil" +export * from "./math/Matrix3" +export * from "./math/Matrix4" +export * from "./math/Orientation3D" +export * from "./math/ParticleMath" +export * from "./math/ParticleSystemCurves" +export * from "./math/Plane" +export * from "./math/PolynomialCurve" +export * from "./math/Polynomials" +export * from "./math/Quaternion" +export * from "./math/Rand" +export * from "./math/Random" +export * from "./math/Ray" +export * from "./math/Rect" +export * from "./math/TimeInterpolator" +export * from "./math/Triangle" +export * from "./math/UV" +export * from "./math/Vector2" +export * from "./math/Vector3" +export * from "./math/Vector4" +export * from "./setting/EngineSetting" +export * from "./setting/GlobalIlluminationSetting" +export * from "./setting/LightSetting" +export * from "./setting/MaterialSetting" +export * from "./setting/OcclusionQuerySetting" +export * from "./setting/PickSetting" +export * from "./setting/post/BloomSetting" +export * from "./setting/post/DepthOfViewSetting" +export * from "./setting/post/GlobalFogSetting" +export * from "./setting/post/GTAOSetting" +export * from "./setting/post/OutlineSetting" +export * from "./setting/post/SSRSetting" +export * from "./setting/post/TAASetting" +export * from "./setting/RenderSetting" +export * from "./setting/ShadowSetting" +export * from "./setting/SkySetting" +export * from "./shape/BoxGeometry" +export * from "./shape/CylinderGeometry" +export * from "./shape/PlaneGeometry" +export * from "./shape/SphereGeometry" +export * from "./shape/TorusGeometry" +export * from "./textures/AtmosphericScatteringSky" +export * from "./textures/BitmapTexture2D" +export * from "./textures/BitmapTexture2DArray" +export * from "./textures/BitmapTextureCube" +export * from "./textures/Depth2DTextureArray" +export * from "./textures/DepthCubeArrayTexture" +export * from "./textures/DepthCubeTexture" +export * from "./textures/Float16ArrayTexture" +export * from "./textures/Float32ArrayTexture" +export * from "./textures/HDRTexture" +export * from "./textures/HDRTextureCube" +export * from "./textures/LDRTextureCube" +export * from "./textures/SolidColorSky" +export * from "./textures/Uint16Texture" +export * from "./textures/Uint8ArrayTexture" +export * from "./textures/VirtualTexture" +export * from "./util/AxisObject" +export * from "./util/BytesStream" +export * from "./util/CameraUtil" +export * from "./util/Convert" +export * from "./util/GeometryUtil" +export * from "./util/Global" +export * from "./util/KelvinUtil" +export * from "./util/Object3DUtil" +export * from "./util/ProfilerUtil" +export * from "./util/StringUtil" +export * from "./util/struct/Struct" +export * from "./util/struct/StructValue" +export * from "./util/struct/Vector3Struct" +export * from "./util/Time" +export * from "./util/Vector3Ex" +export * from "./util/ZSorterUtil" diff --git a/src/io/picker/PickCompute.ts b/src/io/picker/PickCompute.ts index cf489fc2..1455c1d9 100644 --- a/src/io/picker/PickCompute.ts +++ b/src/io/picker/PickCompute.ts @@ -1,4 +1,4 @@ -import Picker_CsShader from '../../assets/shader/compute/Picker_CsShader.wgsl?raw'; +import { Picker_cs } from '../../assets/shader/compute/Picker_cs'; import { Camera3D } from '../../core/Camera3D'; import { View3D } from '../../core/View3D'; import { GlobalBindGroup } from '../../gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup'; @@ -18,18 +18,12 @@ export class PickCompute { constructor() { } public init() { - let rtFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer"); - - this._computeShader = new ComputeShader(Picker_CsShader); - - + this._computeShader = new ComputeShader(Picker_cs); this._outBuffer = new ComputeGPUBuffer(32); this._computeShader.setStorageBuffer('outBuffer', this._outBuffer); this._computeShader.setSamplerTexture('visibleMap', rtFrame.getPositionMap()); - - this._outBuffer.debug(); } compute(view: View3D) { diff --git a/src/materials/GlassMaterial.ts b/src/materials/GlassMaterial.ts index d885fe48..a6a799c3 100644 --- a/src/materials/GlassMaterial.ts +++ b/src/materials/GlassMaterial.ts @@ -1,10 +1,10 @@ import { ShaderLib } from '../assets/shader/ShaderLib'; -import GlassShader from '../assets/shader/materials/GlassShader.wgsl?raw'; import { Engine3D } from '../Engine3D'; import { Vector4 } from '../math/Vector4'; import { PhysicMaterial } from './PhysicMaterial'; import { registerMaterial } from './MaterialRegister'; +import { GlassShader } from '../assets/shader/materials/GlassShader'; /** * GlassMaterial * an rendering material implemented by simulating glass surfaces diff --git a/src/materials/PointMaterial.ts b/src/materials/PointMaterial.ts index 4353148f..337a4ae5 100644 --- a/src/materials/PointMaterial.ts +++ b/src/materials/PointMaterial.ts @@ -1,7 +1,7 @@ import { Engine3D } from '../Engine3D'; import { ShaderLib } from '../assets/shader/ShaderLib'; import { PointShadowDebug } from '../assets/shader/materials/PointShadowDebug'; -import UnLit from '../assets/shader/materials/UnLit.wgsl?raw'; +import { UnLit } from '../assets/shader/materials/UnLit'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { Color } from '../math/Color'; import { Vector4 } from '../math/Vector4'; diff --git a/src/materials/UnLitMaterial.ts b/src/materials/UnLitMaterial.ts index e596040c..09271b2c 100644 --- a/src/materials/UnLitMaterial.ts +++ b/src/materials/UnLitMaterial.ts @@ -1,6 +1,6 @@ import { Engine3D } from '../Engine3D'; import { ShaderLib } from '../assets/shader/ShaderLib'; -import UnLit from '../assets/shader/materials/UnLit.wgsl?raw'; +import { UnLit } from '../assets/shader/materials/UnLit'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { Color } from '../math/Color'; import { Vector4 } from '../math/Vector4'; diff --git a/src/materials/effectPass/OutLinePass.ts b/src/materials/effectPass/OutLinePass.ts deleted file mode 100644 index 71068e6a..00000000 --- a/src/materials/effectPass/OutLinePass.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { MaterialPass } from "../MaterialPass"; - -import OutlineShaderPass from "../../assets/shader/materials/OutlinePass.wgsl?raw" -import { GPUCompareFunction } from "../../gfx/graphics/webGpu/WebGPUConst"; - -import { Color } from "../../math/Color"; -import { ShaderLib } from "../../assets/shader/ShaderLib"; -import { Engine3D } from "../../Engine3D"; - -export class OutLinePass extends MaterialPass { - constructor(lineWeight: number = 10) { - super(); - - ShaderLib.register("OutlineShaderPass", OutlineShaderPass); - - let shader = this.setShader(`OutlineShaderPass`, `OutlineShaderPass`); - shader.setShaderEntry(`VertMain`, `FragMain`) - shader.setUniformColor(`baseColor`, new Color(1.0, 0.0, 0.0)); - shader.setUniformFloat(`lineWeight`, lineWeight); - - let shaderState = shader.shaderState; - shaderState.acceptShadow = false; - shaderState.receiveEnv = false; - shaderState.acceptGI = false; - shaderState.useLight = false; - shaderState.depthWriteEnabled = false; - shaderState.depthCompare = GPUCompareFunction.always; - // shaderState.blendMode = BlendMode.ADD ; - - shader.setTexture("baseMap", Engine3D.res.whiteTexture); - } - - private _lineWeight: number = 0; - public get lineWeight(): number { - return this._lineWeight; - } - - public set lineWeight(value: number) { - this._lineWeight = value; - this.renderShader.setUniformFloat("lineWeight", value); - } - - private _baseColor: Color; - public get baseColor(): Color { - return this._baseColor; - } - public set baseColor(value: Color) { - this._baseColor = value; - this.renderShader.setUniformColor("baseColor", value); - } -} \ No newline at end of file diff --git a/src/materials/multiPass/CastPointShadowMaterialPass.ts b/src/materials/multiPass/CastPointShadowMaterialPass.ts index b93f11c0..c5061ff6 100644 --- a/src/materials/multiPass/CastPointShadowMaterialPass.ts +++ b/src/materials/multiPass/CastPointShadowMaterialPass.ts @@ -1,5 +1,5 @@ -import { CastShadow } from '../../assets/shader/core/pass/CastShadowPass_wgsl'; import { ShaderLib } from '../../assets/shader/ShaderLib'; +import { castPointShadowMap_vert, shadowCastMap_frag } from '../../assets/shader/core/pass/CastShadow_pass'; import { Vector3 } from '../../math/Vector3'; import { MaterialBase } from '../MaterialBase'; import { registerMaterial } from "../MaterialRegister"; @@ -14,10 +14,10 @@ export class CastPointShadowMaterialPass extends MaterialBase { constructor() { super(); this.isPassMaterial = true; - ShaderLib.register("castPointShadowMap_vert_wgsl", CastShadow.castPointShadowMap_vert_wgsl); - ShaderLib.register("shadowCastMap_frag_wgsl", CastShadow.shadowCastMap_frag_wgsl); + ShaderLib.register("castPointShadowMap_vert", castPointShadowMap_vert); + ShaderLib.register("shadowCastMap_frag", shadowCastMap_frag); - let shader = this.setShader(`castPointShadowMap_vert_wgsl`, `shadowCastMap_frag_wgsl`); + let shader = this.setShader(`castPointShadowMap_vert`, `shadowCastMap_frag`); shader.setShaderEntry("main", "main"); shader.setUniformFloat("cameraFar", 5000); shader.setUniformVector3("lightWorldPos", Vector3.ZERO); diff --git a/src/materials/multiPass/CastShadowMaterialPass.ts b/src/materials/multiPass/CastShadowMaterialPass.ts index 216672e8..7952e1c3 100644 --- a/src/materials/multiPass/CastShadowMaterialPass.ts +++ b/src/materials/multiPass/CastShadowMaterialPass.ts @@ -1,5 +1,5 @@ -import { CastShadow } from '../../assets/shader/core/pass/CastShadowPass_wgsl'; import { ShaderLib } from '../../assets/shader/ShaderLib'; +import { shadowCastMap_frag, shadowCastMap_vert } from '../../assets/shader/core/pass/CastShadow_pass'; import { Vector3 } from '../../math/Vector3'; import { MaterialBase } from '../MaterialBase'; import { registerMaterial } from "../MaterialRegister"; @@ -15,10 +15,10 @@ export class CastShadowMaterialPass extends MaterialBase { super(); this.isPassMaterial = true; //OutLineSubPass this.shaderState - ShaderLib.register("shadowCastMap_vert_wgsl", CastShadow.shadowCastMap_vert_wgsl); - ShaderLib.register("shadowCastMap_frag_wgsl", CastShadow.shadowCastMap_frag_wgsl); + ShaderLib.register("shadowCastMap_vert", shadowCastMap_vert); + ShaderLib.register("shadowCastMap_frag", shadowCastMap_frag); // let shader = this.setShader(`shadowCastMap_vert_wgsl`,`shadowCastMap_frag_wgsl`); - let shader = this.setShader(`shadowCastMap_vert_wgsl`, `shadowCastMap_frag_wgsl`); + let shader = this.setShader(`shadowCastMap_vert`, `shadowCastMap_frag`); shader.setShaderEntry("main"); shader.setUniformFloat("cameraFar", 5000); shader.setUniformVector3("lightWorldPos", Vector3.ZERO); diff --git a/src/materials/multiPass/DepthMaterialPass.ts b/src/materials/multiPass/DepthMaterialPass.ts index 9803b8aa..0c3e29d0 100644 --- a/src/materials/multiPass/DepthMaterialPass.ts +++ b/src/materials/multiPass/DepthMaterialPass.ts @@ -2,7 +2,7 @@ import { ShaderLib } from '../../assets/shader/ShaderLib'; import { MaterialBase } from '../MaterialBase'; import { registerMaterial } from "../MaterialRegister"; import { ZPassShader_vs } from '../../assets/shader/core/pass/ZPassShader_vs'; -import ZPassShader_fs from '../../assets/shader/core/pass/ZPassShader_fs.wgsl?raw'; +import { ZPassShader_fs } from '../../assets/shader/core/pass/ZPassShader_fs'; /** diff --git a/src/materials/multiPass/GBufferPass.ts b/src/materials/multiPass/GBufferPass.ts index 393af896..94754dc3 100644 --- a/src/materials/multiPass/GBufferPass.ts +++ b/src/materials/multiPass/GBufferPass.ts @@ -5,8 +5,8 @@ import { Color } from '../../math/Color'; import { BlendMode } from '../BlendMode'; import { MaterialBase } from '../MaterialBase'; import { registerMaterial } from "../MaterialRegister"; -import GBuffer_shader from '../../assets/shader/core/pass/GBuffer_shader.wgsl?raw'; import { Engine3D } from '../../Engine3D'; +import { GBuffer_pass } from '../..'; /** * @internal @@ -21,8 +21,8 @@ export class GBufferPass extends MaterialBase { this.isPassMaterial = true; //OutLineSubPass - ShaderLib.register("gbuffer_vs", GBuffer_shader); - ShaderLib.register("gbuffer_fs", GBuffer_shader); + ShaderLib.register("gbuffer_vs", GBuffer_pass); + ShaderLib.register("gbuffer_fs", GBuffer_pass); let shader = this.setShader(`gbuffer_vs`, `gbuffer_fs`); shader.setShaderEntry(`VertMain`, `FragMain`) diff --git a/src/materials/multiPass/SkyGBufferPass.ts b/src/materials/multiPass/SkyGBufferPass.ts index 23207c0e..1cbe5279 100644 --- a/src/materials/multiPass/SkyGBufferPass.ts +++ b/src/materials/multiPass/SkyGBufferPass.ts @@ -1,9 +1,9 @@ +import { SkyGBuffer_pass } from '../..'; import { ShaderLib } from '../../assets/shader/ShaderLib'; import { Texture } from '../../gfx/graphics/webGpu/core/texture/Texture'; import { GPUCompareFunction, GPUCullMode } from '../../gfx/graphics/webGpu/WebGPUConst'; import { MaterialBase } from '../MaterialBase'; import { registerMaterial } from "../MaterialRegister"; -import SkyGBuffer_fs from '../../assets/shader/core/pass/SkyGBuffer_fs.wgsl?raw'; /** * @internal @@ -16,7 +16,7 @@ export class SkyGBufferPass extends MaterialBase { super(); this.isPassMaterial = true; //OutLineSubPass - ShaderLib.register("SkyGBuffer_fs", SkyGBuffer_fs); + ShaderLib.register("SkyGBuffer_fs", SkyGBuffer_pass); let shader = this.setShader(`sky_vs_frag_wgsl`, `SkyGBuffer_fs`); shader.setUniformFloat(`exposure`, 1.0); diff --git a/src/textures/AtmosphericScatteringSky.ts b/src/textures/AtmosphericScatteringSky.ts index 37e3a535..93784bbd 100644 --- a/src/textures/AtmosphericScatteringSky.ts +++ b/src/textures/AtmosphericScatteringSky.ts @@ -1,4 +1,4 @@ -import { AtmosphericScatteringSky_shader } from '../assets/shader/materials/sky/AtmosphericScatteringSky_shader'; +import { AtmosphericScatteringSky_shader } from '../assets/shader/sky/AtmosphericScatteringSky_shader'; import { UniformGPUBuffer } from '../gfx/graphics/webGpu/core/buffer/UniformGPUBuffer'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { ComputeShader } from '../gfx/graphics/webGpu/shader/ComputeShader'; diff --git a/test/util.ts b/test/util.ts index ac1bfede..e7b7f958 100644 --- a/test/util.ts +++ b/test/util.ts @@ -1,3 +1,4 @@ +// @ts-ignore import { isEqual, isMatch } from 'https://unpkg.com/underscore@1.13.6/underscore-esm-min.js' let target = sessionStorage.target.split('/').pop() diff --git a/vite.config.js b/vite.config.js index 242df888..95794251 100644 --- a/vite.config.js +++ b/vite.config.js @@ -51,7 +51,7 @@ module.exports = defineConfig({ } server.httpServer.on('listening', autoIndex) server.watcher.on('change', autoIndex) - server.watcher.on('unlink', autoIndex) + server.watcher.on('unlink', autoIndex) } }], build: { From 3f9b70b673a779db61c75327df8f60137b5d1215 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Thu, 4 May 2023 19:20:40 +0800 Subject: [PATCH 078/100] fix: sort exports in index.ts --- vite.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/vite.config.js b/vite.config.js index 95794251..d23792b4 100644 --- a/vite.config.js +++ b/vite.config.js @@ -39,6 +39,7 @@ module.exports = defineConfig({ if(file && !tsFile.test(file.replace(/\\/g, '/'))) // fix windows path return let ts = await dir('./src') + ts.sort() // make sure same sort on windows and unix let improts = '', _dir = __dirname.replace(/\\/g, '/') + '/src' // fix windows path for (let path of ts) { improts += `export * from "${path.replace(_dir, '.').slice(0, -3)}"\r\n` From 6a93d0f2146857d2c8468decf7c58092ead33985 Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Thu, 4 May 2023 19:27:32 +0800 Subject: [PATCH 079/100] test: add test sample (#91) add gfx test add math test add shader test add component test unable access webgpu in github runners --- .github/workflows/ci.yml | 4 +- src/components/ComponentBase.ts | 2 +- .../DirectionLight_lighting.test.ts | 17 +++ test/components/ECS.test.ts | 44 ++++++ test/components/GTAOPostEffects.test.ts | 16 +++ test/components/GlobalFogEffects.test.ts | 15 ++ test/components/HDRBloomPostEffects.test.ts | 16 +++ test/components/PointLight_lighting.test.ts | 34 +++++ test/components/SSRPostEffects.test.ts | 16 +++ test/components/SpotLight_lighting.test.ts | 20 +++ test/components/TAAPostEffects.test.ts | 15 ++ test/components/Texture.test.ts | 49 +++++++ test/components/component.test.ts | 48 +++++++ .../components/componentLife-Camera3D.test.ts | 41 ++++++ test/components/lightingShadow.test.ts | 55 ++++++++ test/components/test/TestComponents.ts | 49 +++++++ test/components/transform.test.ts | 49 +++++++ test/gfx/ComputeGPUBuffer.test.ts | 34 +++++ test/gfx/GPUContext.test.ts | 9 ++ test/gfx/StorageGPUBuffer.test.ts | 34 +++++ test/gfx/StructGPUBuffer.test.ts | 34 +++++ test/gfx/WebgpuContext.test.ts | 39 ++++++ test/math/AnimationCurve.test.ts | 98 +++++++++++++ test/math/Bezier2DCurve.test.ts | 19 +++ test/math/Color.test.ts | 30 ++++ test/math/HaltonSeq.test.ts | 23 +++ test/math/Matrix3.test.ts | 46 ++++++ test/math/Matrix4.test.ts | 92 ++++++++++++ test/math/MatrixDO.test.ts | 26 ++++ test/math/Plane.test.ts | 30 ++++ test/math/Quaternion.test.ts | 34 +++++ test/math/Rand.test.ts | 33 +++++ test/math/Ray.test.ts | 131 ++++++++++++++++++ test/math/Rect.test.ts | 62 +++++++++ test/math/Triangle.test.ts | 68 +++++++++ test/math/UV.test.ts | 11 ++ test/math/Vector2.test.ts | 101 ++++++++++++++ test/math/Vector3.test.ts | 111 +++++++++++++++ test/math/Vector4.test.ts | 19 +++ test/shader/ComputeShader.test.ts | 49 +++++++ test/shader/RenderShader.test.ts | 65 +++++++++ test/system/EventSystem.test.ts | 28 ++++ test/util.ts | 12 ++ 43 files changed, 1725 insertions(+), 3 deletions(-) create mode 100644 test/components/DirectionLight_lighting.test.ts create mode 100644 test/components/ECS.test.ts create mode 100644 test/components/GTAOPostEffects.test.ts create mode 100644 test/components/GlobalFogEffects.test.ts create mode 100644 test/components/HDRBloomPostEffects.test.ts create mode 100644 test/components/PointLight_lighting.test.ts create mode 100644 test/components/SSRPostEffects.test.ts create mode 100644 test/components/SpotLight_lighting.test.ts create mode 100644 test/components/TAAPostEffects.test.ts create mode 100644 test/components/Texture.test.ts create mode 100644 test/components/component.test.ts create mode 100644 test/components/componentLife-Camera3D.test.ts create mode 100644 test/components/lightingShadow.test.ts create mode 100644 test/components/test/TestComponents.ts create mode 100644 test/components/transform.test.ts create mode 100644 test/gfx/ComputeGPUBuffer.test.ts create mode 100644 test/gfx/GPUContext.test.ts create mode 100644 test/gfx/StorageGPUBuffer.test.ts create mode 100644 test/gfx/StructGPUBuffer.test.ts create mode 100644 test/gfx/WebgpuContext.test.ts create mode 100644 test/math/AnimationCurve.test.ts create mode 100644 test/math/Bezier2DCurve.test.ts create mode 100644 test/math/Color.test.ts create mode 100644 test/math/HaltonSeq.test.ts create mode 100644 test/math/Matrix3.test.ts create mode 100644 test/math/Matrix4.test.ts create mode 100644 test/math/MatrixDO.test.ts create mode 100644 test/math/Plane.test.ts create mode 100644 test/math/Quaternion.test.ts create mode 100644 test/math/Rand.test.ts create mode 100644 test/math/Ray.test.ts create mode 100644 test/math/Rect.test.ts create mode 100644 test/math/Triangle.test.ts create mode 100644 test/math/UV.test.ts create mode 100644 test/math/Vector2.test.ts create mode 100644 test/math/Vector3.test.ts create mode 100644 test/math/Vector4.test.ts create mode 100644 test/shader/ComputeShader.test.ts create mode 100644 test/shader/RenderShader.test.ts create mode 100644 test/system/EventSystem.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 211bc669..7b0941b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,6 @@ jobs: - name: Test Build run: pnpm run build - - name: Test in Electron - run: pnpm run test:ci + # - name: Test in Electron + # run: pnpm run test:ci \ No newline at end of file diff --git a/src/components/ComponentBase.ts b/src/components/ComponentBase.ts index 3328b02b..e80868f8 100644 --- a/src/components/ComponentBase.ts +++ b/src/components/ComponentBase.ts @@ -48,7 +48,7 @@ export class ComponentBase implements IComponent { this._enable = value; if (this._enable) { this.onEnable(); - } else { + } else if (this.onDisable) { this.onDisable(); } } diff --git a/test/components/DirectionLight_lighting.test.ts b/test/components/DirectionLight_lighting.test.ts new file mode 100644 index 00000000..62bc0a2f --- /dev/null +++ b/test/components/DirectionLight_lighting.test.ts @@ -0,0 +1,17 @@ +import { test, end } from '../util' +import { Camera3D, CameraUtil, Color, DirectLight, Engine3D, Object3D, Scene3D, View3D } from '@orillusion/core'; + +await test('DirectionLight test', async () => { + let suc = await Engine3D.init(); + let view = new View3D(); + view.scene = new Scene3D(); + view.camera = CameraUtil.createCamera3DObject(view.scene, "camera"); + let directLight = new Object3D(); + let pl = directLight.addComponent(DirectLight); + pl.intensity = 10; + pl.lightColor = new Color(1.0, 0.0, 0.0); + view.scene.addChild(directLight); + Engine3D.startRenderViews([view]); +}) + +setTimeout(end, 500) diff --git a/test/components/ECS.test.ts b/test/components/ECS.test.ts new file mode 100644 index 00000000..74337a60 --- /dev/null +++ b/test/components/ECS.test.ts @@ -0,0 +1,44 @@ +import { test, expect, end } from '../util' +import { BoxColliderShape, Camera3D, ColliderComponent, Engine3D, LitMaterial, MeshRenderer, Object3D, PlaneGeometry, Ray, Scene3D, Vector3 } from '@orillusion/core'; + +await Engine3D.init(); + +await test('ecs remove Component', async () => { + let obj = new Object3D(); + obj.addComponent(ColliderComponent); + obj.removeComponent(ColliderComponent); + + let nullComponent = obj.hasComponent(ColliderComponent); + expect(nullComponent).toEqual(false); +}) + +await test('ecs create MeshRenderer', async () => { + let obj = new Object3D(); + let renderder = obj.addComponent(MeshRenderer); + let material = new LitMaterial(); + let geometry = new PlaneGeometry(10, 10); + renderder.material = material; + renderder.geometry = geometry; + + expect(renderder.materials[0]).toEqual(renderder.material); +}) + +await test('ecs test ColliderComponent', async () => { + let obj = new Object3D(); + let component = obj.addComponent(ColliderComponent); + let size: number = 1; + + let boxShape = new BoxColliderShape().setFromCenterAndSize(new Vector3(0, 0, 0), new Vector3(size, size, size)); + component.shape = boxShape; + component.enable = true; + + let ray = new Ray(new Vector3(0, 0, -5), new Vector3(0, 0, 1)); + + let pick = component.rayPick(ray); + let success = pick && pick.intersect; + + expect(success).toEqual(true); +}) + + +setTimeout(end, 500) diff --git a/test/components/GTAOPostEffects.test.ts b/test/components/GTAOPostEffects.test.ts new file mode 100644 index 00000000..39ea66fa --- /dev/null +++ b/test/components/GTAOPostEffects.test.ts @@ -0,0 +1,16 @@ +import { test, expect, end, delay } from '../util' +import { Camera3D, CameraUtil, Engine3D, GTAOPost, Object3D, PostProcessingComponent, Scene3D, View3D } from '@orillusion/core'; + +await test('Post GTAOPost test', async () => { + let suc = await Engine3D.init(); + let view = new View3D(); + view.scene = new Scene3D(); + view.camera = CameraUtil.createCamera3DObject(view.scene, "camera"); + Engine3D.startRenderViews([view]); + + let postProcessing = view.scene.addComponent(PostProcessingComponent); + postProcessing.addPost(GTAOPost); +}) + + +setTimeout(end, 500) diff --git a/test/components/GlobalFogEffects.test.ts b/test/components/GlobalFogEffects.test.ts new file mode 100644 index 00000000..93bb0924 --- /dev/null +++ b/test/components/GlobalFogEffects.test.ts @@ -0,0 +1,15 @@ +import { test, expect, end, delay } from '../util' +import { Camera3D, CameraUtil, Engine3D, GlobalFog, Object3D, PostProcessingComponent, Scene3D, View3D } from '@orillusion/core'; + +await test('Post GlobalFog test', async () => { + let suc = await Engine3D.init(); + let view = new View3D(); + view.scene = new Scene3D(); + view.camera = CameraUtil.createCamera3DObject(view.scene, "camera"); + Engine3D.startRenderViews([view]); + + let postProcessing = view.scene.addComponent(PostProcessingComponent); + postProcessing.addPost(GlobalFog); +}) + +setTimeout(end, 500) diff --git a/test/components/HDRBloomPostEffects.test.ts b/test/components/HDRBloomPostEffects.test.ts new file mode 100644 index 00000000..9389e3f3 --- /dev/null +++ b/test/components/HDRBloomPostEffects.test.ts @@ -0,0 +1,16 @@ +import { test, end } from '../util' +import { Camera3D, CameraUtil, Engine3D, HDRBloomPost, Object3D, PostProcessingComponent, Scene3D, View3D } from '@orillusion/core'; + +await test('Post HDRBloomPost test', async () => { + let suc = await Engine3D.init(); + let view = new View3D(); + view.scene = new Scene3D(); + view.camera = CameraUtil.createCamera3DObject(view.scene, "camera"); + Engine3D.startRenderView(view); + + let postProcessing = view.scene.addComponent(PostProcessingComponent); + postProcessing.addPost(HDRBloomPost); +}) + + +setTimeout(end, 500) diff --git a/test/components/PointLight_lighting.test.ts b/test/components/PointLight_lighting.test.ts new file mode 100644 index 00000000..fee532e4 --- /dev/null +++ b/test/components/PointLight_lighting.test.ts @@ -0,0 +1,34 @@ +import { test, end } from '../util' +import { Camera3D, CameraUtil, Color, Engine3D, Object3D, PointLight, Scene3D, View3D } from '@orillusion/core'; + +await test('PointLight test', async () => { + let suc = await Engine3D.init(); + let view = new View3D(); + view.scene = new Scene3D(); + view.camera = CameraUtil.createCamera3DObject(view.scene, "camera"); + let pointLight = new Object3D(); + let pl = pointLight.addComponent(PointLight); + pl.intensity = 10; + pl.range = 10; + pl.lightColor = new Color(1.0, 0.0, 0.0); + view.scene.addChild(pointLight); + Engine3D.startRenderViews([view]); +}) + +// await test('SpotLight test', async () => { +// let suc = await Engine3D.init(); + +// let view = new View3D(); +// view.scene = new Scene3D(); +// view.camera = CameraUtil.createCamera3DObject(view.scene, "camera"); +// let pointLight = new Object3D(); +// let pl = pointLight.addComponent(SpotLight); +// pl.intensity = 10; +// pl.range = 10; +// pl.lightColor = new Color(1.0, 0.0, 0.0); +// Engine3D.startRenderViews([view]); +// }) + + + +setTimeout(end, 500) diff --git a/test/components/SSRPostEffects.test.ts b/test/components/SSRPostEffects.test.ts new file mode 100644 index 00000000..e4d57088 --- /dev/null +++ b/test/components/SSRPostEffects.test.ts @@ -0,0 +1,16 @@ +import { test, expect, end, delay } from '../util' +import { AtmosphericComponent, Camera3D, CameraUtil, Engine3D, Object3D, PostProcessingComponent, SSRPost, Scene3D, View3D } from '@orillusion/core'; + +await test('Post SSR test', async () => { + let suc = await Engine3D.init(); + let view = new View3D(); + view.scene = new Scene3D(); + view.scene.addComponent(AtmosphericComponent); + view.camera = CameraUtil.createCamera3DObject(view.scene, "camera"); + Engine3D.startRenderViews([view]); + + let postProcessing = view.scene.addComponent(PostProcessingComponent); + postProcessing.addPost(SSRPost); +}) + +setTimeout(end, 500) diff --git a/test/components/SpotLight_lighting.test.ts b/test/components/SpotLight_lighting.test.ts new file mode 100644 index 00000000..64e606a2 --- /dev/null +++ b/test/components/SpotLight_lighting.test.ts @@ -0,0 +1,20 @@ +import { test, expect, end, delay } from '../util' +import { Camera3D, CameraUtil, Color, Engine3D, Object3D, Scene3D, SpotLight, View3D } from '@orillusion/core'; + +await test('SpotLight test', async () => { + let suc = await Engine3D.init(); + let view = new View3D(); + view.scene = new Scene3D(); + view.camera = CameraUtil.createCamera3DObject(view.scene, "camera"); + let spotLight = new Object3D(); + let pl = spotLight.addComponent(SpotLight); + pl.intensity = 10; + pl.range = 10; + pl.lightColor = new Color(1.0, 0.0, 0.0); + view.scene.addChild(spotLight); + Engine3D.startRenderViews([view]); +}) + + + +setTimeout(end, 500) diff --git a/test/components/TAAPostEffects.test.ts b/test/components/TAAPostEffects.test.ts new file mode 100644 index 00000000..b269c288 --- /dev/null +++ b/test/components/TAAPostEffects.test.ts @@ -0,0 +1,15 @@ +import { test, expect, end, delay } from '../util' +import { Camera3D, CameraUtil, Engine3D, Object3D, PostProcessingComponent, Scene3D, TAAPost, View3D } from '@orillusion/core'; + +await test('Post TAAPost test', async () => { + let suc = await Engine3D.init(); + let view = new View3D(); + view.scene = new Scene3D(); + view.camera = CameraUtil.createCamera3DObject(view.scene, "camera"); + Engine3D.startRenderViews([view]); + + let postProcessing = view.scene.addComponent(PostProcessingComponent); + postProcessing.addPost(TAAPost); +}) + +setTimeout(end, 500) diff --git a/test/components/Texture.test.ts b/test/components/Texture.test.ts new file mode 100644 index 00000000..1cc6560e --- /dev/null +++ b/test/components/Texture.test.ts @@ -0,0 +1,49 @@ +import { test, expect, end } from '../util' +import { Camera3D, Color, Engine3D, Float16ArrayTexture, Float32ArrayTexture, Object3D, Scene3D, SolidColorSky } from '@orillusion/core'; + +await test('textue2D create Uint8Texture', async () => { + await Engine3D.init(); + let texture2D = Engine3D.res.createTexture(32, 64, 255, 255, 0, 255, 'uint8Texture') + let success = (texture2D.gpuSampler && texture2D.getGPUTexture() && texture2D.getGPUView()) ? true : false; + expect(success).toEqual(true); +}) + +await test('textue2D create Float16ArrayTexture', async () => { + let texture2D = new Float16ArrayTexture(); + let color: number[] = []; + let width = 64; + let height = 64; + for (let i = 0, count = width * height; i < count; i++) { + color.push(1, 0.5, 0.0, 1); + } + texture2D.create(width, height, color, false); + let success = (texture2D.gpuSampler && texture2D.getGPUTexture() && texture2D.getGPUView()) ? true : false; + expect(success).toEqual(true); +}) + +await test('textue2D create Float32ArrayTexture', async () => { + let texture2D = new Float32ArrayTexture(); + let width = 64; + let height = 64; + let color: Float32Array = new Float32Array(width * height * 4); + + for (let i = 0, count = width * height; i < count; i++) { + color[i * 4] = 1; + color[i * 4 + 1] = 0; + color[i * 4 + 2] = 0.5; + color[i * 4 + 3] = 1; + } + texture2D.create(width, height, color, false); + let success = (texture2D.gpuSampler && texture2D.getGPUTexture() && texture2D.getGPUView()) ? true : false; + expect(success).toEqual(true); +}) + +await test('textureCube create SolidColorSky', async () => { + let color = new Color(1, 0, 1, 1); + let texture2D = new SolidColorSky(color); + let success = (texture2D.gpuSampler && texture2D.getGPUTexture() && texture2D.getGPUView()) ? true : false; + expect(success).toEqual(true); +}) + + +setTimeout(end, 500) diff --git a/test/components/component.test.ts b/test/components/component.test.ts new file mode 100644 index 00000000..9ed6e577 --- /dev/null +++ b/test/components/component.test.ts @@ -0,0 +1,48 @@ +import { test, expect, end, delay } from '../util' +import { TestComponents } from './test/TestComponents'; +import { Camera3D, Engine3D, Object3D, Scene3D } from '@orillusion/core'; + +await Engine3D.init(); + +await test('component create', async () => { + let obj = new Object3D(); + let c = obj.addComponent(Camera3D); + + expect(c.transform).toEqual(obj.transform); +}) + +await test('component enable true', async () => { + let obj = new Object3D(); + let c = obj.addComponent(Camera3D); + c.enable = true; + expect(c.enable).toEqual(true); +}) + +await test('component enable false', async () => { + let obj = new Object3D(); + let c = obj.addComponent(Camera3D); + c.enable = false; + expect(c.enable).toEqual(false); +}) + +await test('component enable false', async () => { + let scene = new Scene3D(); + let obj = new Object3D(); + let c = obj.addComponent(TestComponents); + expect(c.initState).toEqual(true); + expect(c.startState).toEqual(false); + expect(c.destroyState).toEqual(false); + + scene.addChild(obj); + scene.waitUpdate(); + + expect(c.startState).toEqual(true); + + c.enable = false; + expect(c.enableState).toEqual(false); + + c.enable = true; + expect(c.enableState).toEqual(true); +}) + +setTimeout(end, 500) diff --git a/test/components/componentLife-Camera3D.test.ts b/test/components/componentLife-Camera3D.test.ts new file mode 100644 index 00000000..2ea5d1f6 --- /dev/null +++ b/test/components/componentLife-Camera3D.test.ts @@ -0,0 +1,41 @@ +import { test, expect, end, delay } from '../util' +import { Camera3D, Engine3D, Object3D, Scene3D } from '@orillusion/core'; +import { TestComponents } from './test/TestComponents'; + +await Engine3D.init(); + +await test('component enable true', async () => { + let obj = new Object3D(); + let c = obj.addComponent(Camera3D); + c.enable = true; + expect(c.enable).toEqual(true); +}) + +await test('component enable false', async () => { + let obj = new Object3D(); + let c = obj.addComponent(Camera3D); + c.enable = false; + expect(c.enable).toEqual(false); +}) + +await test('component enable false', async () => { + let scene = new Scene3D(); + let obj = new Object3D(); + let c = obj.addComponent(TestComponents); + expect(c.initState).toEqual(true); + expect(c.startState).toEqual(false); + expect(c.destroyState).toEqual(false); + + scene.addChild(obj); + scene.waitUpdate(); + + expect(c.startState).toEqual(true); + + c.enable = false; + expect(c.enableState).toEqual(false); + + c.enable = true; + expect(c.enableState).toEqual(true); +}) + +setTimeout(end, 500) diff --git a/test/components/lightingShadow.test.ts b/test/components/lightingShadow.test.ts new file mode 100644 index 00000000..da66305f --- /dev/null +++ b/test/components/lightingShadow.test.ts @@ -0,0 +1,55 @@ +import { test, expect, end, delay } from '../util' +import { Camera3D, CameraUtil, Color, DirectLight, Engine3D, Object3D, PointLight, Scene3D, SpotLight, View3D, webGPUContext } from '@orillusion/core'; + +await Engine3D.init(); + +await test('DirectionLight Shadow test', async () => { + let suc = await webGPUContext.init(); + expect(suc).toEqual(true); + + let view = new View3D(); + view.scene = new Scene3D(); + view.camera = CameraUtil.createCamera3DObject(view.scene, "camera"); + let pointLight = new Object3D(); + let pl = pointLight.addComponent(DirectLight); + pl.intensity = 10; + pl.lightColor = new Color(1.0, 0.0, 0.0); + pl.castShadow = true; + // Engine3D.startRenderViews([view]); +}) + +await test('PointLight Shadow test', async () => { + let suc = await webGPUContext.init(); + expect(suc).toEqual(true); + + let view = new View3D(); + view.scene = new Scene3D(); + view.camera = CameraUtil.createCamera3DObject(view.scene, "camera"); + let pointLight = new Object3D(); + let pl = pointLight.addComponent(PointLight); + pl.intensity = 10; + pl.range = 10; + pl.castShadow = true; + pl.lightColor = new Color(1.0, 0.0, 0.0); + // Engine3D.startRenderViews([view]); +}) + +await test('SpotLight Shadow test', async () => { + let suc = await webGPUContext.init(); + expect(suc).toEqual(true); + + let view = new View3D(); + view.scene = new Scene3D(); + view.camera = CameraUtil.createCamera3DObject(view.scene, "camera"); + let pointLight = new Object3D(); + let pl = pointLight.addComponent(SpotLight); + pl.intensity = 10; + pl.range = 10; + pl.castShadow = true; + pl.lightColor = new Color(1.0, 0.0, 0.0); + // Engine3D.startRenderViews([view]); +}) + + + +setTimeout(end, 500) diff --git a/test/components/test/TestComponents.ts b/test/components/test/TestComponents.ts new file mode 100644 index 00000000..78f470d6 --- /dev/null +++ b/test/components/test/TestComponents.ts @@ -0,0 +1,49 @@ +import { ComponentBase } from "../../../src/components/ComponentBase"; + +export class TestComponents extends ComponentBase { + public initState: boolean = false; + public startState: boolean = false; + public stopState: boolean = false; + public destroyState: boolean = false; + public enableState: boolean = false; + public updateState: boolean = false; + public lateUpdateState: boolean = false; + public beforeUpdateState: boolean = false; + + public init(param?: any): void { + this.initState = true; + } + + public start(): void { + this.startState = true; + } + + public stop(): void { + this.stopState = true; + } + + public onEnable(): void { + this.enableState = true; + } + + public onDisable(): void { + this.enableState = false; + } + + public onUpdate(): void { + this.updateState = true; + } + + public onLateUpdate(): void { + + } + + public onBeforeUpdate(): void { + + } + + public destroy(): void { + this.destroyState = true; + super.destroy(); + } +} \ No newline at end of file diff --git a/test/components/transform.test.ts b/test/components/transform.test.ts new file mode 100644 index 00000000..ed381458 --- /dev/null +++ b/test/components/transform.test.ts @@ -0,0 +1,49 @@ +import { test, expect, end, delay } from '../util' +import { Camera3D, Engine3D, Object3D, Scene3D } from '@orillusion/core'; + +await Engine3D.init(); + +await test('Transform not repeat', async () => { + let objA = new Object3D(); + let objB = new Object3D(); + let objC = new Object3D(); + + expect(objA.transform).toEqual(objA.transform.object3D.transform) + expect(objB.transform).toEqual(objB.transform.object3D.transform) + expect(objC.transform).toEqual(objC.transform.object3D.transform) +}) + +await test('Transform parent', async () => { + let objA = new Object3D(); + let objB = new Object3D(); + let objC = new Object3D(); + + objA.addChild(objB); + objB.addChild(objC); + + expect(objB.transform.parent).toEqual(objA.transform) + expect(objC.transform.parent).toEqual(objB.transform) +}) + +await test('Transform position', async () => { + let objA = new Object3D(); + let objB = new Object3D(); + let objC = new Object3D(); + + objA.x = 100; + + objB.y = 100; + + objC.z = 100; + + objA.addChild(objB); + objB.addChild(objC); + + expect(objC.transform.worldPosition.x).toEqual(100) + expect(objC.transform.worldPosition.y).toEqual(100) + expect(objC.transform.worldPosition.z).toEqual(100) +}) + + + +setTimeout(end, 500) diff --git a/test/gfx/ComputeGPUBuffer.test.ts b/test/gfx/ComputeGPUBuffer.test.ts new file mode 100644 index 00000000..9e39085a --- /dev/null +++ b/test/gfx/ComputeGPUBuffer.test.ts @@ -0,0 +1,34 @@ +import { test, expect, end, delay } from '../util' +import { Color, ComputeGPUBuffer, Matrix4, Vector2, Vector3, Vector4, webGPUContext } from '@orillusion/core'; + +await test('ComputeGPUBuffer ', async () => { + let suc = await webGPUContext.init(); + expect(suc).toEqual(true); + + let computeGPUBuffer = new ComputeGPUBuffer(2048); + computeGPUBuffer.setMatrix("setMatrix", new Matrix4().identity()); + computeGPUBuffer.setInt32Array("setInt32Array", new Int32Array(4 * 4)); + computeGPUBuffer.setColor("setColor", new Color(1, 0, 0, 1)); + computeGPUBuffer.setInt8("setInt8", 1); + computeGPUBuffer.setBoolean("setBoolean", true); + computeGPUBuffer.setInt16("setInt16", 1); + computeGPUBuffer.setInt32("setInt32", 1); + computeGPUBuffer.setInt8("alignment", 0); + computeGPUBuffer.setFloat32Array("setFloat32Array", new Float32Array(4 * 4)); + computeGPUBuffer.setFloat("setFloat", 0.5); + computeGPUBuffer.setUint8("setUint8", 128); + computeGPUBuffer.setUint16("setUint16", 128); + computeGPUBuffer.setUint32("setUint32", 128); + computeGPUBuffer.setVector2("setVector2", new Vector2(0.5, 10.0)); + computeGPUBuffer.setVector3("setVector3", new Vector3(1.5, 11.0, 55.0)); + computeGPUBuffer.setVector4("setVector4", new Vector4(2, 5, 8, 9)); + computeGPUBuffer.setArray("setArray", [1, 2, 3, 4, 5, 6]); + computeGPUBuffer.setColorArray("setColorArray", [ + new Color(1, 0, 0, 1), + new Color(0, 1, 0, 1), + new Color(0, 0, 1, 1), + ]); +}) + + +setTimeout(end, 500) diff --git a/test/gfx/GPUContext.test.ts b/test/gfx/GPUContext.test.ts new file mode 100644 index 00000000..e9d4e7b0 --- /dev/null +++ b/test/gfx/GPUContext.test.ts @@ -0,0 +1,9 @@ +import { test, expect, end, delay } from '../util' +import { webGPUContext } from '@orillusion/core'; + +await test('GPUContext createIndexBuffer', async () => { + let suc = await webGPUContext.init(); + expect(suc).toEqual(true); +}) + +setTimeout(end, 500) diff --git a/test/gfx/StorageGPUBuffer.test.ts b/test/gfx/StorageGPUBuffer.test.ts new file mode 100644 index 00000000..1d3a8821 --- /dev/null +++ b/test/gfx/StorageGPUBuffer.test.ts @@ -0,0 +1,34 @@ +import { test, expect, end, delay } from '../util' +import { Color, Engine3D, Matrix4, StorageGPUBuffer, Vector2, Vector3, Vector4, webGPUContext } from '@orillusion/core'; + +await test('StorageGPUBuffer ', async () => { + let suc = await webGPUContext.init(); + expect(suc).toEqual(true); + + let storageBuffer = new StorageGPUBuffer(2048); + storageBuffer.setMatrix("setMatrix", new Matrix4().identity()); + storageBuffer.setInt32Array("setInt32Array", new Int32Array(4 * 4)); + storageBuffer.setColor("setColor", new Color(1, 0, 0, 1)); + storageBuffer.setBoolean("setBoolean", true); + storageBuffer.setInt8("setInt8", 1); + storageBuffer.setInt16("setInt16", 1); + storageBuffer.setInt32("setInt32", 1); + storageBuffer.setInt8("alignment", 0); + storageBuffer.setFloat32Array("setFloat32Array", new Float32Array(4 * 4)); + storageBuffer.setFloat("setFloat", 0.5); + storageBuffer.setUint8("setUint8", 128); + storageBuffer.setUint16("setUint16", 128); + storageBuffer.setUint32("setUint32", 128); + storageBuffer.setVector2("setVector2", new Vector2(0.5, 10.0)); + storageBuffer.setVector3("setVector3", new Vector3(1.5, 11.0, 55.0)); + storageBuffer.setVector4("setVector4", new Vector4(2, 5, 8, 9)); + storageBuffer.setArray("setArray", [1, 2, 3, 4, 5, 6]); + storageBuffer.setColorArray("setColorArray", [ + new Color(1, 0, 0, 1), + new Color(0, 1, 0, 1), + new Color(0, 0, 1, 1), + ]); +}) + + +setTimeout(end, 500) diff --git a/test/gfx/StructGPUBuffer.test.ts b/test/gfx/StructGPUBuffer.test.ts new file mode 100644 index 00000000..97426f8a --- /dev/null +++ b/test/gfx/StructGPUBuffer.test.ts @@ -0,0 +1,34 @@ +import { test, expect, end, delay } from '../util' +import { Color, Engine3D, Struct, StructStorageGPUBuffer, Vector3, webGPUContext } from '@orillusion/core'; + +class TestInfo extends Struct { + public index: number = 0; + public position: Vector3 = new Vector3(); + public rotation: Vector3 = new Vector3(); + public color: Color = new Color(); + constructor() { + super(); + } +} + +await test('StructGPUBuffer ', async () => { + let suc = await webGPUContext.init(); + expect(suc).toEqual(true); + + let arr_TestInfos: TestInfo[] = []; + for (let i = 0; i < 100; i++) { + const info = new TestInfo(); + info.index = i; + info.position = new Vector3(Math.random(), Math.random(), Math.random()); + info.rotation = new Vector3(Math.random(), Math.random(), Math.random()); + info.color = new Color(Math.random(), Math.random(), Math.random(), Math.random()); + arr_TestInfos.push(info); + } + + let structStorageGPUBuffer = new StructStorageGPUBuffer(TestInfo, 100); + structStorageGPUBuffer.setStruct(TestInfo, 0, new TestInfo()); + structStorageGPUBuffer.setStructArray(TestInfo, arr_TestInfos); +}) + + +setTimeout(end, 500) diff --git a/test/gfx/WebgpuContext.test.ts b/test/gfx/WebgpuContext.test.ts new file mode 100644 index 00000000..2bf36ef4 --- /dev/null +++ b/test/gfx/WebgpuContext.test.ts @@ -0,0 +1,39 @@ +import { test, expect, end, delay } from '../util' +import { Engine3D, webGPUContext } from '@orillusion/core'; + +await test('webgpu context', async () => { + let suc = await webGPUContext.init(); + expect(suc).toEqual(true); +}) + +await test('webgpu context adapter', async () => { + let suc = await webGPUContext.init(); + expect(suc).toEqual(true); + expect(webGPUContext.adapter != null).toEqual(true); + expect(webGPUContext.device != null).toEqual(true); +}) + + +await test('webgpu context pixelRatio', async () => { + let suc = await webGPUContext.init(); + expect(suc).toEqual(true); + expect(webGPUContext.pixelRatio >= 1).toEqual(true); +}) + +await test('webgpu canvas', async () => { + let suc = await webGPUContext.init(); + expect(suc).toEqual(true); + expect(webGPUContext.canvas != null).toEqual(true); +}) + +await test('webgpu size', async () => { + let suc = await webGPUContext.init(); + expect(suc).toEqual(true); + expect(webGPUContext.presentationSize[0] > 32).toEqual(true); + expect(webGPUContext.presentationSize[1] > 32).toEqual(true); + expect(webGPUContext.presentationSize[0] == webGPUContext.windowWidth).toEqual(true); + expect(webGPUContext.presentationSize[1] == webGPUContext.windowHeight).toEqual(true); +}) + + +setTimeout(end, 500) diff --git a/test/math/AnimationCurve.test.ts b/test/math/AnimationCurve.test.ts new file mode 100644 index 00000000..5636dab6 --- /dev/null +++ b/test/math/AnimationCurve.test.ts @@ -0,0 +1,98 @@ +import { test, expect, end, delay } from '../util' +import { AnimationCurve, Engine3D, Keyframe, WrapTimeMode } from '@orillusion/core'; + +await test('AnimationCurve Add Frame test', async () => { + let frame_0 = new Keyframe(0, 0); + let frame_1 = new Keyframe(1, 1); + let animationCurve = new AnimationCurve( + [ + frame_0, + frame_1, + ], + WrapTimeMode.Repeat, + WrapTimeMode.PingPong, + ); + + { + let v0 = animationCurve.getValue(0); + let v1 = animationCurve.getValue(1); + let v2 = animationCurve.getValue(0.5); + + expect(v0).toEqual(0); + expect(v1).toEqual(1); + expect(v2).toEqual(0.5); + } +}) + +await test('AnimationCurve Frame in&out test', async () => { + let frame_0 = new Keyframe(0, 0); + let frame_1 = new Keyframe(1, 1); + let animationCurve = new AnimationCurve( + [ + frame_0, + frame_1, + ], + WrapTimeMode.Repeat, + WrapTimeMode.PingPong, + ); + + { + frame_0.inSlope = 0.5; + frame_0.outSlope = 0.15; + frame_1.inSlope = 0.5; + frame_1.outSlope = 0.25; + + let v0 = animationCurve.getValue(0); + let v1 = animationCurve.getValue(1); + let v2 = animationCurve.getValue(0.5); + + expect(v0).toEqual(0); + expect(v1).toEqual(1); + expect(v2).toEqual(0.45625000000000004); + } +}) + +await test('AnimationCurve WarpTimeMode test', async () => { + let frame_0 = new Keyframe(0, 0); + let frame_1 = new Keyframe(1, 1); + let animationCurve = new AnimationCurve( + [ + frame_0, + frame_1, + ], + WrapTimeMode.Repeat, + WrapTimeMode.PingPong, + ); + + frame_0.inSlope = 0.5; + frame_0.outSlope = 0.15; + frame_1.inSlope = 0.5; + frame_1.outSlope = 0.25; + + let v0 = animationCurve.getValue(-0.5); + let v1 = animationCurve.getValue(1.5); + + expect(v0).toEqual(-8127000.075000001); + expect(v1).toEqual(0.45625000000000004); +}) + + +await test('AnimationCurve Remove test', async () => { + let frame_0 = new Keyframe(0, 0); + let frame_1 = new Keyframe(1, 1); + let animationCurve = new AnimationCurve( + [ + frame_0, + frame_1, + ], + WrapTimeMode.Repeat, + WrapTimeMode.PingPong, + ); + + { + animationCurve.removeKeyFrame(frame_1); + expect(animationCurve.getKeyCount()).toEqual(1); + } +}) + +setTimeout(end, 500) diff --git a/test/math/Bezier2DCurve.test.ts b/test/math/Bezier2DCurve.test.ts new file mode 100644 index 00000000..74a2d8d4 --- /dev/null +++ b/test/math/Bezier2DCurve.test.ts @@ -0,0 +1,19 @@ +import { test, expect, end, delay } from '../util' +import { Bezier2D, Engine3D, Vector2 } from '@orillusion/core'; + +await test('Bezier test', async () => { + let bezier2d = new Bezier2D([ + new Vector2(0.0, 0.0), + new Vector2(0.5, 0.5), + new Vector2(0.6, 1.0), + new Vector2(0.8, 1.0), + new Vector2(1.0, 1.0), + ]); + + let v = bezier2d.getValue(0.5); + + expect(v).toEqual(new Vector2(0.7, 1.0)); +}) + + +setTimeout(end, 500) diff --git a/test/math/Color.test.ts b/test/math/Color.test.ts new file mode 100644 index 00000000..b35a77e3 --- /dev/null +++ b/test/math/Color.test.ts @@ -0,0 +1,30 @@ +import { test, expect, end, delay } from '../util' +import { Color, Engine3D } from '@orillusion/core'; + +await test('Color hex test', async () => { + let color = Color.hexRGBColor(Color.WHITE); + expect(color.r).toEqual(1); + expect(color.g).toEqual(1); + expect(color.b).toEqual(1); +}) + +await test('Color hdr test', async () => { + let color = new Color(1, 0.5, 0.3, 5.0); + color.convertToHDRRGB(); + + + expect(color.r).toEqual(79.62623999999998); + expect(color.g).toEqual(39.81311999999999); + expect(color.b).toEqual(23.887871999999994); +}) + +await test('Color Copy test', async () => { + let color = new Color(1, 0.0, 0.0, 1.0); + color.copyFormArray([255, 255, 255, 255], 255); + + expect(color.r).toEqual(1); + expect(color.g).toEqual(1); + expect(color.b).toEqual(1); +}) + +setTimeout(end, 500) diff --git a/test/math/HaltonSeq.test.ts b/test/math/HaltonSeq.test.ts new file mode 100644 index 00000000..a0e9eee2 --- /dev/null +++ b/test/math/HaltonSeq.test.ts @@ -0,0 +1,23 @@ +import { test, expect, end, delay } from '../util' +import { HaltonSeq } from '@orillusion/core'; + +await test('HaltonSeq test', async () => { + let list: number[] = []; + for (let i = 0; i < 100; i++) { + let v = HaltonSeq.get(i, 100); + list.push(v); + } + + let error = false; + for (let j = 0; j < list.length; j++) { + const value = list[j]; + let index = list.indexOf(value); + if (index != j && index != -1) { + error = true; + console.log(value, j, list); + } + } + expect(error).toEqual(false); +}) + +setTimeout(end, 500) diff --git a/test/math/Matrix3.test.ts b/test/math/Matrix3.test.ts new file mode 100644 index 00000000..8e25eb84 --- /dev/null +++ b/test/math/Matrix3.test.ts @@ -0,0 +1,46 @@ +import { test, expect, end, delay } from '../util' +import { Matrix3 } from '@orillusion/core'; + +await test('Matrix3 clone', async () => { + let a = new Matrix3(); + + let b = a.clone(); + expect(a.a).toEqual(b.a); + expect(a.b).toEqual(b.b); + expect(a.c).toEqual(b.c); + expect(a.d).toEqual(b.d); + expect(a.tx).toEqual(b.tx); + expect(a.ty).toEqual(b.ty); +}) + +await test('Matrix3 identity', async () => { + let a = new Matrix3(); + a.identity(); + + expect(a.a).toEqual(1); + expect(a.b).toEqual(0); + expect(a.c).toEqual(0); + expect(a.d).toEqual(1); + expect(a.tx).toEqual(0); + expect(a.ty).toEqual(0); +}) + +await test('Matrix3 rotate', async () => { + let a = new Matrix3(); + a.rotate(90); + let result = a.transformPoint(10, 0); + + expect(result.x).toSubequal(0) + expect(result.y).toSubequal(10); +}) + +await test('Matrix3 scale', async () => { + let a = new Matrix3(); + a.scale(2, 1); + let result = a.transformPoint(10, 0); + + expect(result.x).toSubequal(20); + expect(result.y).toSubequal(0); +}) + +setTimeout(end, 500) diff --git a/test/math/Matrix4.test.ts b/test/math/Matrix4.test.ts new file mode 100644 index 00000000..428f3b53 --- /dev/null +++ b/test/math/Matrix4.test.ts @@ -0,0 +1,92 @@ +import { test, expect, end, delay } from '../util' +import { Matrix4, Vector3 } from '@orillusion/core'; + +await test('Matrix4', async () => { + let mat4 = new Matrix4(); + + expect(mat4.rawData[0]).toEqual(1.0); + expect(mat4.rawData[1]).toEqual(0.0); + expect(mat4.rawData[2]).toEqual(0.0); + expect(mat4.rawData[3]).toEqual(0.0); + + expect(mat4.rawData[4]).toEqual(0.0); + expect(mat4.rawData[5]).toEqual(1.0); + expect(mat4.rawData[6]).toEqual(0.0); + expect(mat4.rawData[7]).toEqual(0.0); + + expect(mat4.rawData[8]).toEqual(0.0); + expect(mat4.rawData[9]).toEqual(0.0); + expect(mat4.rawData[10]).toEqual(1.0); + expect(mat4.rawData[11]).toEqual(0.0); + + expect(mat4.rawData[12]).toEqual(0.0); + expect(mat4.rawData[13]).toEqual(0.0); + expect(mat4.rawData[14]).toEqual(0.0); + expect(mat4.rawData[15]).toEqual(1.0); +}) + +await test('Matrix4 lookAt', async () => { + let mat4 = new Matrix4(); + + mat4.lookAt(new Vector3(0, 0, 10), new Vector3(0, 0, 0), Vector3.Y_AXIS); +}) + +await test('Matrix4 Scale', async () => { + let a = new Matrix4(); + a.createByScale(10, 1, 1); + + let result = new Vector3(); + a.multiplyPoint3(new Vector3(10, 0, 10), result); + + expect(result.x).toSubequal(100); + expect(result.y).toSubequal(0); + expect(result.z).toSubequal(10); +}) + +await test('Matrix4 Rotation', async () => { + let a = new Matrix4(); + a.createByRotation(45, Vector3.Y_AXIS); + + let result = new Vector3(); + a.multiplyPoint3(new Vector3(10, 0, 10), result); + + expect(result.x).toSubequal(14.142135); + expect(result.y).toSubequal(0); + expect(result.z).toSubequal(0); +}) + +await test('Matrix4 Translation', async () => { + let a = new Matrix4(); + a.appendTranslation(10, 10, 0); + + let result = new Vector3(); + a.multiplyPoint3(new Vector3(10, 0, 10), result); + + expect(result.x).toSubequal(20); + expect(result.y).toSubequal(10); + expect(result.z).toSubequal(10); +}) + +await test('Matrix4 ScaleRotationTranslation', async () => { + let scaleMatrix = new Matrix4(); + scaleMatrix.createByScale(10, 10, 10); + + let rotationMatrix = new Matrix4(); + rotationMatrix.createByRotation(45, Vector3.Y_AXIS); + + let translationMatrix = new Matrix4(); + translationMatrix.appendTranslation(0, 10, 0); + + let finalMatrix = new Matrix4(); + finalMatrix.multiplyMatrices(scaleMatrix, rotationMatrix); + finalMatrix.multiplyMatrices(finalMatrix, translationMatrix); + + let result = new Vector3(); + finalMatrix.multiplyPoint3(new Vector3(10, 0, 10), result); + + expect(result.x).toSubequal(141.421356); + expect(result.y).toSubequal(100); + expect(result.z).toSubequal(0); +}) + +setTimeout(end, 500) diff --git a/test/math/MatrixDO.test.ts b/test/math/MatrixDO.test.ts new file mode 100644 index 00000000..ab5c969a --- /dev/null +++ b/test/math/MatrixDO.test.ts @@ -0,0 +1,26 @@ +import { test, expect, end, delay } from '../util' +import { Engine3D, Matrix4 } from '@orillusion/core'; + +await test('MatrixDO create test', async () => { + let mat_0 = new Matrix4(); +}) + +await test('MatrixDO create 5000 test', async () => { + for (let i = 0; i < 5000; i++) { + let mat_0 = new Matrix4(); + } +}) + +await test('MatrixDO create 5000 test', async () => { + let list: number[] = []; + for (let i = 0; i < 5000; i++) { + let mat_0 = new Matrix4(); + list.push(mat_0.index); + } + + expect(list.length).toEqual(5000); + // expect(Matrix4.globalMatrixRef.length).toEqual(10010); // about all this runtime init matrix + expect(Matrix4.matrixBytes.byteLength).toEqual(704000); +}) + +setTimeout(end, 500) diff --git a/test/math/Plane.test.ts b/test/math/Plane.test.ts new file mode 100644 index 00000000..9913cf55 --- /dev/null +++ b/test/math/Plane.test.ts @@ -0,0 +1,30 @@ +import { test, expect, end, delay } from '../util' +import { Engine3D, Plane, Ray, Vector3 } from '@orillusion/core'; + +await test('Plane intersectsLine', async () => { + let plane = new Plane(Vector3.ZERO, Vector3.X_AXIS); + + let intersection = new Vector3(); + let result = plane.intersectsLine(new Vector3(-10, 0, 0), new Vector3(10, 0, 0), intersection); + + expect(result).toEqual(true); + expect(intersection.x).toSubequal(0); + expect(intersection.y).toSubequal(0); + expect(intersection.z).toSubequal(0); +}) + +await test('Plane intersectsRay', async () => { + let plane = new Plane(Vector3.ZERO, Vector3.X_AXIS); + + let ray = new Ray(new Vector3(-10, 0, 0), new Vector3(1, 0, 0)); + + let intersection = new Vector3(); + let result = plane.intersectsRay(ray, intersection); + + expect(result).toEqual(true); + expect(intersection.x).toSubequal(0); + expect(intersection.y).toSubequal(0); + expect(intersection.z).toSubequal(0); +}) + +setTimeout(end, 500) diff --git a/test/math/Quaternion.test.ts b/test/math/Quaternion.test.ts new file mode 100644 index 00000000..fa75a1e7 --- /dev/null +++ b/test/math/Quaternion.test.ts @@ -0,0 +1,34 @@ +import { test, expect, end, delay } from '../util' +import { Engine3D, Quaternion, Vector3 } from '@orillusion/core'; + +await test('Quaternion fromEulerAngles', async () => { + let quat = new Quaternion(); + quat.fromEulerAngles(0, -90, 0); + + let result = new Vector3(); + quat.transformVector(new Vector3(10, 0, 0), result); + + expect(result.x).toSubequal(0); + expect(result.y).toSubequal(0); + expect(result.z).toSubequal(10); +}) + +await test('Quaternion multiply', async () => { + let quatA = new Quaternion(); + quatA.fromEulerAngles(0, -45, 0); + + let quatB = new Quaternion(); + quatB.fromEulerAngles(0, -45, 0); + + let finalQuat = new Quaternion(); + finalQuat.multiply(quatA, quatB); + + let result = new Vector3(); + finalQuat.transformVector(new Vector3(10, 0, 0), result); + + expect(result.x).toSubequal(0); + expect(result.y).toSubequal(0); + expect(result.z).toSubequal(10); +}) + +setTimeout(end, 500) diff --git a/test/math/Rand.test.ts b/test/math/Rand.test.ts new file mode 100644 index 00000000..190d4bc0 --- /dev/null +++ b/test/math/Rand.test.ts @@ -0,0 +1,33 @@ +import { test, expect, end, delay } from '../util' +import { Rand } from '@orillusion/core'; + +await test('Rand seed', async () => { + let rand = new Rand(2023); + expect(rand.seed).toEqual(2023); + + rand.seed = 10; + expect(rand.seed).toEqual(10); + + let rand2 = rand.clone(); + expect(rand2.seed).toEqual(rand.seed); +}) + +await test('Rand get', async () => { + let rand = new Rand(2023); + + expect(rand.get()).toRange(Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); +}) + +await test('Rand getFloat', async () => { + let rand = new Rand(2023); + + expect(rand.getFloat()).toRange(0.0, 1.0); +}) + +await test('Rand getSignedFloat', async () => { + let rand = new Rand(2023); + + expect(rand.getSignedFloat()).toRange(-1.0, 1.0); +}) + +setTimeout(end, 500) diff --git a/test/math/Ray.test.ts b/test/math/Ray.test.ts new file mode 100644 index 00000000..1e3fe03f --- /dev/null +++ b/test/math/Ray.test.ts @@ -0,0 +1,131 @@ +import { test, expect, end, delay } from '../util' +import { BoundingBox, Matrix4, Ray, Triangle, Vector3 } from '@orillusion/core'; + +await test('Ray base', async () => { + let ray = new Ray(Vector3.ZERO, Vector3.X_AXIS); + + expect(ray.origin.x).toEqual(Vector3.ZERO.x); + expect(ray.origin.y).toEqual(Vector3.ZERO.y); + expect(ray.origin.z).toEqual(Vector3.ZERO.z); + + expect(ray.direction.x).toEqual(Vector3.X_AXIS.x); + expect(ray.direction.y).toEqual(Vector3.X_AXIS.y); + expect(ray.direction.z).toEqual(Vector3.X_AXIS.z); + + let ray2 = ray.clone(); + expect(ray2.origin.x).toEqual(ray.origin.x); + expect(ray2.origin.y).toEqual(ray.origin.y); + expect(ray2.origin.z).toEqual(ray.origin.z); + + expect(ray2.direction.x).toEqual(ray.direction.x); + expect(ray2.direction.y).toEqual(ray.direction.y); + expect(ray2.direction.z).toEqual(ray.direction.z); +}) + +await test('Ray intersectsBox', async () => { + let ray = new Ray(Vector3.ZERO, Vector3.X_AXIS); + let boundBox = new BoundingBox(Vector3.ZERO, new Vector3(10, 10, 10)); + + expect(ray.intersectsBox(boundBox)).toEqual(true); +}) + +await test('Ray intersectBox', async () => { + let ray = new Ray(Vector3.ZERO, Vector3.X_AXIS); + let vec3 = new Vector3(); + let boundBox = new BoundingBox(Vector3.ZERO, new Vector3(10, 10, 10)); + + let result = ray.intersectBox(boundBox, vec3); + expect(result.x).toEqual(5); + expect(result.y).toEqual(0); + expect(result.z).toEqual(0); +}) + +await test('Ray at', async () => { + let ray = new Ray(Vector3.ZERO, Vector3.X_AXIS); + let vec3 = new Vector3(); + + let result = ray.at(10, vec3); + expect(result.x).toEqual(10); + expect(result.y).toEqual(0); + expect(result.z).toEqual(0); +}) + +await test('Ray getPoint', async () => { + let ray = new Ray(Vector3.ZERO, Vector3.X_AXIS); + + let result = ray.getPoint(10); + expect(result.x).toEqual(10); + expect(result.y).toEqual(0); + expect(result.z).toEqual(0); +}) + +await test('Ray applyMatrix', async () => { + let boundBox = new BoundingBox(Vector3.ZERO, new Vector3(10, 10, 10)); + + let rotMatrix = new Matrix4(); + rotMatrix.identity(); + rotMatrix.createByRotation(180, Vector3.Z_AXIS); + + let ray = new Ray(Vector3.ZERO, Vector3.X_AXIS); + ray.applyMatrix(rotMatrix); + + const threshold = 0.000001; + let result = ray.intersectBox(boundBox, new Vector3()); + expect(result.x).toSubequal(-5, threshold); + expect(result.y).toSubequal(0, threshold); + expect(result.z).toSubequal(0, threshold); +}) + +await test('Ray pointInTriangle', async () => { + let ray = new Ray(Vector3.ZERO, Vector3.X_AXIS); + + const p = new Vector3(0, 0, 0); + const a = new Vector3(0, 10, 0); + const b = new Vector3(-5, -5, 0); + const c = new Vector3(5, -5, 0); + + expect(ray.pointInTriangle(p, a, b, c)).toEqual(true); +}) + +await test('Ray intersectTriangle', async () => { + let ray = new Ray(Vector3.ZERO, Vector3.X_AXIS); + + let face = new Triangle( + new Vector3(20, 10, 0), + new Vector3(20, -5, -5), + new Vector3(20, -5, 5) + ); + let result = ray.intersectTriangle(ray.origin, ray.direction, face); + + expect(result.x).toEqual(20); + expect(result.y).toEqual(0); + expect(result.z).toEqual(0); +}) + +await test('Ray intersectSphere', async () => { + let ray = new Ray(new Vector3(-100, 0, 0), Vector3.X_AXIS); + + let result = ray.intersectSphere(ray.origin, ray.direction, Vector3.ZERO, 10); + + expect(result.x).toEqual(-10); + expect(result.y).toEqual(0); + expect(result.z).toEqual(0); +}) + +await test('Ray intersectionSegment', async () => { + let ray = new Ray(new Vector3(-100, 0, 0), Vector3.X_AXIS); + + let result = ray.intersectionSegment( + new Vector3(0, 0, 10), + new Vector3(0, 0, -10), + 0.1 + ); + + expect(result.out.x).toEqual(0); + expect(result.out.y).toEqual(0); + expect(result.out.z).toEqual(0); + + expect(result.length).toEqual(100); +}) + +setTimeout(end, 500) diff --git a/test/math/Rect.test.ts b/test/math/Rect.test.ts new file mode 100644 index 00000000..7f38a0d3 --- /dev/null +++ b/test/math/Rect.test.ts @@ -0,0 +1,62 @@ +import { test, expect, end, delay } from '../util' +import { Rect } from '@orillusion/core'; + +await test('Rect base', async () => { + let rect = new Rect(10, 10, 20, 10); + + let rect2 = rect.clone(); + + expect(rect.width).toEqual(20); + expect(rect.height).toEqual(10); + + expect(rect2.width).toEqual(rect.w); + expect(rect2.height).toEqual(rect.h); +}) + +await test('Rect pointInRect', async () => { + let result = Rect.pointInRect(0, 0, -10, -10, 10, 10); + + expect(result).toEqual(true); +}) + +await test('Rect inner', async () => { + let rect = new Rect(10, 10, 20, 10); + + expect(rect.inner(11, 19)).toEqual(true); +}) + +await test('Rect equal', async () => { + let rect1 = new Rect(10, 10, 20, 10); + let rect2 = new Rect(10, 10, 20, 10); + let rect3 = new Rect(0, 0, 20, 10); + + expect(rect1.equal(rect2)).toEqual(true); + expect(rect1.equal(rect3)).toEqual(false); +}) + +await test('Rect equalArea', async () => { + let rect1 = new Rect(10, 10, 20, 10); + + expect(rect1.equalArea(10, 10, 20, 10)).toEqual(true); +}) + +await test('Rect equalInnerArea', async () => { + let rect1 = new Rect(10, 10, 20, 10); + let rect2 = new Rect(12, 12, 16, 6); + + expect(rect1.equalInnerArea(rect2)).toEqual(true); +}) + +await test('Rect innerArea', async () => { + let rect1 = new Rect(10, 10, 20, 10); + let rect2 = new Rect(12, 12, 20, 10); + + let result = rect1.innerArea(rect2, new Rect()); + + expect(result.x).toEqual(12); + expect(result.y).toEqual(12); + expect(result.w).toEqual(18); + expect(result.h).toEqual(8); +}) + +setTimeout(end, 500) diff --git a/test/math/Triangle.test.ts b/test/math/Triangle.test.ts new file mode 100644 index 00000000..33889f82 --- /dev/null +++ b/test/math/Triangle.test.ts @@ -0,0 +1,68 @@ +import { test, expect, end, delay } from '../util' +import { Triangle, Vector3 } from '@orillusion/core'; + +await test('Triangle base', async () => { + let a = new Triangle( + new Vector3(0, 10, 0), + new Vector3(-5, 0, 0), + new Vector3(5, 0, 0), + ); + + expect(a.v1.x).toEqual(0); + expect(a.v1.y).toEqual(10); + expect(a.v1.z).toEqual(0); + + expect(a.v2.x).toEqual(-5); + expect(a.v2.y).toEqual(0); + expect(a.v2.z).toEqual(0); + + expect(a.v3.x).toEqual(5); + expect(a.v3.y).toEqual(0); + expect(a.v3.z).toEqual(0); +}) + +await test('Triangle getNormal', async () => { + let a = new Triangle( + new Vector3(0, 10, 0), + new Vector3(-5, 0, 0), + new Vector3(5, 0, 0), + ); + + let result = a.getNormal(); + + expect(result.x).toSubequal(0); + expect(result.y).toSubequal(0); + expect(result.z).toSubequal(-1); +}) + +await test('Triangle getCenter', async () => { + let a = new Triangle( + new Vector3(0, 10, 0), + new Vector3(-5, 0, 0), + new Vector3(5, 0, 0), + ); + + let result = a.getCenter(); + + expect(result.x).toSubequal(0); + expect(result.y).toSubequal(5); + expect(result.z).toSubequal(0); +}) + +await test('Triangle intersects', async () => { + let a = new Triangle( + new Vector3(0, 10, 0), + new Vector3(-5, 0, 0), + new Vector3(5, 0, 0), + ); + + let b = new Triangle( + new Vector3(0, 10, 0), + new Vector3(0, 0, -5), + new Vector3(0, 0, 5), + ); + + expect(a.intersects(b)).toEqual(true); +}) + +setTimeout(end, 500) diff --git a/test/math/UV.test.ts b/test/math/UV.test.ts new file mode 100644 index 00000000..58f3abcf --- /dev/null +++ b/test/math/UV.test.ts @@ -0,0 +1,11 @@ +import { test, expect, end, delay } from '../util' +import { UV } from '@orillusion/core'; + +await test('UV', async () => { + let rect = new UV(0, 0); + + expect(rect.u).toEqual(0); + expect(rect.v).toEqual(0); +}) + +setTimeout(end, 500) diff --git a/test/math/Vector2.test.ts b/test/math/Vector2.test.ts new file mode 100644 index 00000000..cec45ea4 --- /dev/null +++ b/test/math/Vector2.test.ts @@ -0,0 +1,101 @@ +import { test, expect, end, delay } from '../util' +import { RADIANS_TO_DEGREES, Vector2 } from '@orillusion/core'; + +await test('Vector2 base', async () => { + let a = new Vector2(20, 10); + + expect(a.x).toEqual(20); + expect(a.y).toEqual(10); + + let b = a.clone(); + expect(b.x).toEqual(a.x); + expect(b.y).toEqual(a.y); + + a.set(0, 0); + expect(a.x).toEqual(0); + expect(a.y).toEqual(0); +}) + +await test('Vector2 add', async () => { + let a = new Vector2(20, 10); + let b = new Vector2(10, 10); + + let result = a.add(b); + expect(result.x).toEqual(30); + expect(result.y).toEqual(20); +}) + +await test('Vector2 sub', async () => { + let a = new Vector2(20, 10); + let b = new Vector2(10, 10); + + let result = a.sub(b); + expect(result.x).toEqual(10); + expect(result.y).toEqual(0); +}) + +await test('Vector2 dot', async () => { + let a = new Vector2(20, 10); + let b = new Vector2(10, 10); + + let result = a.dot(b); + expect(result).toEqual(300); +}) + +await test('Vector2 addScalar', async () => { + let a = new Vector2(20, 10); + + let result = a.addScalar(10); + expect(result.x).toEqual(30); + expect(result.y).toEqual(20); +}) + +await test('Vector2 scale', async () => { + let a = new Vector2(20, 10); + a.scale(10); + + expect(a.x).toEqual(200); + expect(a.y).toEqual(100); +}) + +await test('Vector2 divide', async () => { + let a = new Vector2(20, 10); + + let result = a.divide(10); + + expect(result.x).toSubequal(2); + expect(result.y).toSubequal(1); +}) + +await test('Vector2 distance', async () => { + let a = new Vector2(20, 10); + let b = new Vector2(10, 10); + + let result = a.distance(b); + expect(result).toSubequal(10); +}) + +await test('Vector2 length', async () => { + let a = new Vector2(20, 10); + let result = a.length(); + + expect(result).toSubequal(22.360679774997898); +}) + +await test('Vector2 getAngle', async () => { + let a = new Vector2(20, 10); + let b = new Vector2(10, 10); + let result = a.getAngle(b); + + expect(result * RADIANS_TO_DEGREES).toSubequal(180); +}) + +await test('Vector2 normalize', async () => { + let a = new Vector2(20, 10) + a.normalize(); + + expect(a.x).toSubequal(0.89442719099); + expect(a.y).toSubequal(0.44721359549); +}) + +setTimeout(end, 500) diff --git a/test/math/Vector3.test.ts b/test/math/Vector3.test.ts new file mode 100644 index 00000000..046301ac --- /dev/null +++ b/test/math/Vector3.test.ts @@ -0,0 +1,111 @@ +import { test, expect, end, delay } from '../util' +import { Vector3 } from '@orillusion/core'; + +await test('Vector3 base', async () => { + let a = new Vector3(20, 10, 0); + + expect(a.x).toEqual(20); + expect(a.y).toEqual(10); + expect(a.z).toEqual(0); + + let b = a.clone(); + expect(b.x).toEqual(a.x); + expect(b.y).toEqual(a.y); + expect(b.z).toEqual(a.z); + + a.set(0, 0, 0); + expect(a.x).toEqual(0); + expect(a.y).toEqual(0); + expect(a.z).toEqual(0); +}) + +await test('Vector3 add', async () => { + let a = new Vector3(20, 10, 0); + let b = new Vector3(10, 10, 0); + + let result = a.add(b); + expect(result.x).toEqual(30); + expect(result.y).toEqual(20); + expect(result.z).toEqual(0); +}) + +await test('Vector3 sub', async () => { + let a = new Vector3(20, 10, 0); + let b = new Vector3(10, 10, 0); + + let result = a.subtract(b); + expect(result.x).toEqual(10); + expect(result.y).toEqual(0); + expect(result.z).toEqual(0); +}) + +await test('Vector3 dotProduct', async () => { + let a = new Vector3(20, 10, 0); + let b = new Vector3(10, 10, 0); + + let result = a.dotProduct(b); + expect(result).toEqual(300); +}) + +await test('Vector3 addScalar', async () => { + let a = new Vector3(20, 10, 0); + + let result = a.addXYZW(10, 10, 10, 0); + expect(result.x).toEqual(30); + expect(result.y).toEqual(20); + expect(result.z).toEqual(10); +}) + +await test('Vector3 scaleBy', async () => { + let a = new Vector3(20, 10, 0); + a.scaleBy(10); + + expect(a.x).toEqual(200); + expect(a.y).toEqual(100); + expect(a.z).toEqual(0); +}) + +await test('Vector3 divide', async () => { + let a = new Vector3(20, 10, 0); + + let result = a.divide(10); + + expect(result.x).toSubequal(2); + expect(result.y).toSubequal(1); + expect(result.z).toSubequal(0); +}) + +await test('Vector3 distance', async () => { + let a = new Vector3(20, 10, 0); + let b = new Vector3(10, 10, 0); + + let result = Vector3.distance(a, b) + expect(result).toSubequal(10); +}) + +await test('Vector3 length', async () => { + let a = new Vector3(20, 10, 0); + let result = a.length; + + expect(result).toSubequal(22.360679774997898); +}) + +await test('Vector3 getAngle', async () => { + let a = new Vector3(20, 10, 0); + let b = new Vector3(10, 10, 0); + + let result = Vector3.getAngle(a, b); + + expect(result).toSubequal(18.43494882292201); +}) + +await test('Vector3 normalize', async () => { + let a = new Vector3(20, 10, 0) + a.normalize(); + + expect(a.x).toSubequal(0.89442719099); + expect(a.y).toSubequal(0.44721359549); + expect(a.z).toSubequal(0); +}) + +setTimeout(end, 500) diff --git a/test/math/Vector4.test.ts b/test/math/Vector4.test.ts new file mode 100644 index 00000000..8e32cc80 --- /dev/null +++ b/test/math/Vector4.test.ts @@ -0,0 +1,19 @@ +import { test, expect, end, delay } from '../util' +import { Vector4 } from '@orillusion/core'; + +await test('Vector4 base', async () => { + let a = new Vector4(20, 10, 1, 1); + + expect(a.x).toEqual(20); + expect(a.y).toEqual(10); + expect(a.z).toEqual(1); + expect(a.w).toEqual(1); + + let b = a.clone(); + expect(b.x).toEqual(a.x); + expect(b.y).toEqual(a.y); + expect(b.z).toEqual(a.z); + expect(b.w).toEqual(a.w); +}) + +setTimeout(end, 500) diff --git a/test/shader/ComputeShader.test.ts b/test/shader/ComputeShader.test.ts new file mode 100644 index 00000000..8c2ccd5a --- /dev/null +++ b/test/shader/ComputeShader.test.ts @@ -0,0 +1,49 @@ +import { test, expect, end, delay } from '../util' +import { ComputeShader, Engine3D, UniformGPUBuffer } from '@orillusion/core'; + +await test('ComputeShader', async () => { + + await Engine3D.init(); + + let gaussianBlurShader = new ComputeShader(/* wgsl */ ` + struct GaussianBlurArgs { + radius: f32, + retain: vec3, + }; + + @group(0) @binding(0) var args: GaussianBlurArgs; + @group(0) @binding(1) var colorMap: texture_2d; + @group(0) @binding(2) var resultTex: texture_storage_2d; + + @compute @workgroup_size(8, 8) + fn CsMain( @builtin(global_invocation_id) globalInvocation_id: vec3) { + var pixelCoord = vec2(globalInvocation_id.xy); + + var value = vec4(0.0); + var count = 0.0; + let radius = i32(args.radius); + for (var i = -radius; i < radius; i += 1) { + for (var j = -radius; j < radius; j += 1) { + var offset = vec2(i, j); + value += textureLoad(colorMap, pixelCoord + offset, 0); + count += 1.0; + } + } + + let result = value / count; + textureStore(resultTex, pixelCoord, result); + } + `); + + let gaussianBlurArgs = new UniformGPUBuffer(28); + gaussianBlurArgs.setFloat('radius', 2); + gaussianBlurArgs.apply(); + + gaussianBlurShader.setUniformBuffer('args', gaussianBlurArgs); + + gaussianBlurShader.workerSizeX = 1; + gaussianBlurShader.workerSizeY = 1; + gaussianBlurShader.workerSizeZ = 1; +}) + +setTimeout(end, 500) diff --git a/test/shader/RenderShader.test.ts b/test/shader/RenderShader.test.ts new file mode 100644 index 00000000..678833d6 --- /dev/null +++ b/test/shader/RenderShader.test.ts @@ -0,0 +1,65 @@ +import { test, expect, end, delay } from '../util' +import { Engine3D, RenderShader, ShaderLib } from '@orillusion/core'; + +const a = Engine3D; + +await test('RenderShader', async () => { + const shaderCode = /* wgsl */ ` + + struct VertexInput { + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) uv: vec2, + @location(3) color: vec4, + }; + + struct FragmentInput { + @builtin(position) position: vec4, + @location(0) uv: vec4, + @location(1) color: vec4, + }; + + struct GlobalUniform { + projMatrix: mat4x4, + viewMatrix: mat4x4, + modelMatrix: mat4x4, + }; + + @group(0) @binding(0) var global: GlobalUniform; + + @vertex + fn vsMain(in: VertexInput) -> FragmentInput { + let mvpMatrix = global.projMatrix * global.viewMatrix * global.modelMatrix; + var out: FragmentInput; + out.position = mvpMatrix * vec4(in.position.xyz, 1.0); + out.uv = in.uv; + out.color = in.color; + return out; + } + + struct FragmentOutput { + @location(0) color: vec4, + }; + + @group(1) @binding(0) var baseMapSampler: sampler; + @group(1) @binding(1) var baseMap: texture_2d; + + @fragment + fn fsMain(in: FragmentInput) -> FragmentOutput { + var out: FragmentOutput; + out.color = textureSampleLevel(baseMap, baseMapSampler, in.uv, 0.0) * in.color; + return out; + } + `; + ShaderLib.register('TestShader', shaderCode); + + expect(ShaderLib.getShader('TestShader')).toEqual(shaderCode); + + let renderShader = new RenderShader('TestShader', 'TestShader'); + renderShader.setShaderEntry('vsMain', 'fsMain'); + + expect(renderShader.vsEntryPoint).toEqual('vsMain'); + expect(renderShader.fsEntryPoint).toEqual('fsMain'); +}) + +setTimeout(end, 500) diff --git a/test/system/EventSystem.test.ts b/test/system/EventSystem.test.ts new file mode 100644 index 00000000..ba2c615b --- /dev/null +++ b/test/system/EventSystem.test.ts @@ -0,0 +1,28 @@ +import { test, expect, end } from '../util' +import { CEventDispatcher, UIEvent } from '@orillusion/core'; + +await test('EventSystem register event', async () => { + let dispatcher = new CEventDispatcher(); + let callbackAction = () => { + console.log('show UI'); + } + let that = {}; + let id = dispatcher.addEventListener(UIEvent.SHOW, callbackAction, that); + + let containEvent: boolean = dispatcher.containEventListener(UIEvent.SHOW); + let hasEvent: boolean = dispatcher.hasEventListener(UIEvent.SHOW, callbackAction, that); + + dispatcher.removeEventListenerAt(id); + let removedEvent = dispatcher.containEventListener(UIEvent.SHOW); + + expect(id > 0).toEqual(true); + expect(containEvent).toEqual(true); + expect(hasEvent).toEqual(true); + expect(removedEvent).toEqual(false); +}) + +setTimeout(end, 500) + + + + diff --git a/test/util.ts b/test/util.ts index e7b7f958..28f56daa 100644 --- a/test/util.ts +++ b/test/util.ts @@ -64,6 +64,18 @@ class Compare { } } // TODO + toSubequal(obj: any, threshold: any = 0.00001) { + let min = obj - threshold; + let max = obj + threshold; + if (this.src < min || this.src > max) { + throw new Error('not subequal') + } + } + toRange(min: any, max: any) { + if (this.src < min || this.src > max) { + throw new Error('out of range') + } + } } function expect(object: any) { return new Compare(object) From 13b376dda99b061b74a2c0aa470f39f8cc703482 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Fri, 5 May 2023 13:25:03 +0800 Subject: [PATCH 080/100] test: try ci with ubuntu and swiftshader (#94) try ci with ubuntu and swiftshader --- .github/workflows/ci.yml | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b0941b0..1bf9d00b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ on: jobs: test: - runs-on: macos-latest + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -29,6 +29,6 @@ jobs: - name: Test Build run: pnpm run build - # - name: Test in Electron - # run: pnpm run test:ci + - name: Test in Electron + run: pnpm run test:ci \ No newline at end of file diff --git a/package.json b/package.json index d6f20bf5..fcf22ac0 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json", "minify:es": "uglifyjs dist/orillusion.es.js -o dist/orillusion.es.js -c -m", "test": "electron test/ci/main.js", - "test:ci": "xvfb-maybe -- electron test/ci/main.js", + "test:ci": "xvfb-maybe -- electron --enable-unsafe-webgpu --enable-features=Vulkan --use-vulkan=swiftshader --use-webgpu-adapter=swiftshader --no-sandbox test/ci/main.js", "docs": "npm run docs:core && npm run docs:physics && npm run docs:media && npm run docs:stats", "docs:typedoc": "npx typedoc --plugin typedoc-plugin-markdown --plugin ./script/typedoc-plugin-not-exported.js --tsconfig tsconfig.build.json --gitRevision main --hideBreadcrumbs true --allReflectionsHaveOwnDocument true --readme none --excludeInternal --excludePrivate --excludeProtected --sort source-order --out", "docs:core": "npm run docs:typedoc docs/api src/index.ts", From 5b0bde31e58625f52afa2652eaff4699cee77310 Mon Sep 17 00:00:00 2001 From: hellmor Date: Fri, 5 May 2023 13:36:50 +0800 Subject: [PATCH 081/100] fix(matrix4): fix multiply function (#88) fix multiply function of matrix4 --- src/math/Matrix4.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/math/Matrix4.ts b/src/math/Matrix4.ts index 4fc3dd6b..fe4ad483 100644 --- a/src/math/Matrix4.ts +++ b/src/math/Matrix4.ts @@ -390,6 +390,8 @@ export class Matrix4 { data[15] = 1; } + private static float32Array = new Float32Array(16).fill(0); + /** * matrix multiply * @param mat4 multiply target @@ -398,7 +400,7 @@ export class Matrix4 { public multiply(mat4: Matrix4): void { let a = this.rawData; let b = mat4.rawData; - let r = Matrix4.helpMatrix.rawData; + let r = Matrix4.float32Array; r[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12]; r[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13]; From 4cf778767b86b049ad3bc00e695e74ac33288e49 Mon Sep 17 00:00:00 2001 From: hellmor Date: Fri, 5 May 2023 13:38:44 +0800 Subject: [PATCH 082/100] feat(GUIHelp): add GUIHelp class (#90) Use GUIHelp class to debug sample. --- packages/debug/GUIHelp.ts | 169 ++++++++++++++++++++++++++++++++++ samples/base/Sample_Base_0.ts | 5 +- 2 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 packages/debug/GUIHelp.ts diff --git a/packages/debug/GUIHelp.ts b/packages/debug/GUIHelp.ts new file mode 100644 index 00000000..c2136dac --- /dev/null +++ b/packages/debug/GUIHelp.ts @@ -0,0 +1,169 @@ +// @ts-ignore +import { GUI } from 'https://unpkg.com/dat.gui@0.7.9/build/dat.gui.module.js' + + +/** + * @internal + */ +class _GUIHelp { + public debug: boolean = false; + public data: any; + public gui: GUI; + public bind: { [property: string]: any }; + + private _current: GUI; + private _nullBind: any = {}; + + constructor() { + this.data = {}; + this.bind = {}; + this._nullBind = {}; + this._nullBind.onChange = () => { }; + } + + init(zIndex: number = 10) { + this.debug = true; + this.gui = new GUI(); + this.gui.domElement.style.zIndex = `${zIndex}`; + this.gui.domElement.parentElement.style.zIndex = `${zIndex}`; + this.addFolder('Orillusion'); + } + + addCustom(label: string, obj, property: string, c?: number, d?: number, e?: number) { + if (!this.debug) + return this._nullBind; + let dgui = this._current ? this._current : this.gui; + + let tobj = {}; + tobj[label] = obj[property]; + dgui.add(tobj, label, c, d, e).onChange((v) => { + obj[property] = v; + }) + } + + add(a, b?, c?, d?, e?) { + if (!this.debug) + return this._nullBind; + let dgui = this._current ? this._current : this.gui; + return dgui.add(a, b, c, d, e); + } + + addLabel(label: string) { + if (!this.debug) + return this._nullBind; + GUIHelp.add({ label: label }, 'label'); + } + + addColor(target: any, key: string) { + if (!this.debug) + return this._nullBind; + let dgui = this._current ? this._current : this.gui; + // dgui.addFolder(key); + let controller = dgui.addColor(target[key], 'rgba').name(key); + controller.onChange((val) => { + console.log(val); + let node = target[key]; + node['rgba'] = val; + target[key] = node; + }); + return controller; + } + addButton(label: string, fun: Function) { + if (!this.debug) + return this._nullBind; + var controls = new (function () { + this[label] = fun; + })(); + let dgui = this._current ? this._current : this.gui; + dgui.add(controls, label); + } + + open() { + if (!this.debug) + return this._nullBind; + let dgui = this._current ? this._current : this.gui; + dgui.open(); + } + + close() { + if (!this.debug) + return this._nullBind; + let dgui = this._current ? this._current : this.gui; + dgui.close(); + } + + public folders: { [key: string]: GUI } = {}; + addFolder(label: string) { + if (!this.debug) + return this._nullBind; + let folder = this.folders[label]; + if (!folder) { + this._current = this.gui.addFolder(label); + this.folders[label] = this._current; + } else { + this._current = this.folders[label]; + } + return this._current; + } + + removeFolder(label: string) { + if (!this.debug) + return this._nullBind; + let folder = this.folders[label]; + if (folder) { + this._current = this.gui.removeFolder(folder); + delete this.folders[label]; + } + } + + endFolder() { + if (!this.debug) + return this._nullBind; + this._current = null; + } + + _creatPanel() { + let gui = new GUI(); + gui.domElement.style.zIndex = `${10}`; + gui.domElement.parentElement.style.zIndex = `${10}`; + return gui; + } + + _add(gui: GUI, a, b?, c?, d?, e?) { + return gui.add(a, b, c, d, e); + } + + _addLabel(gui: GUI, label: string) { + GUIHelp._add(gui, { label: label }, 'label'); + } + + _addButton(gui: GUI, label: string, fun: Function) { + var controls = new (function () { + this[label] = fun; + })(); + gui.add(controls, label); + } + + _addColor(gui: GUI, target: any, label: string) { + return gui.addColor(target[label], "rgb").name(label); + } + + _addFolder(gui: GUI, label: string) { + if (gui['Folder'] == null) { + gui['Folder'] = {}; + } + let folder = gui.addFolder(label); + gui['Folder'][label] = folder; + return folder; + } + + _removeFolder(gui: GUI, label: string) { + if (gui['Folder'] && gui['Folder'][label]) { + gui.removeFolder(gui['Folder'][label]); + } + } +} +/** + * @internal + */ +export let GUIHelp = new _GUIHelp(); diff --git a/samples/base/Sample_Base_0.ts b/samples/base/Sample_Base_0.ts index 11b1c64e..f8f9e219 100644 --- a/samples/base/Sample_Base_0.ts +++ b/samples/base/Sample_Base_0.ts @@ -1,6 +1,6 @@ import { AtmosphericComponent, BoxGeometry, Camera3D, DirectLight, Engine3D, HoverCameraController, KelvinUtil, LitMaterial, MeshRenderer, Object3D, Scene3D, View3D } from '@orillusion/core'; +import { GUIHelp } from '@orillusion/debug/GUIHelp'; import { Stats } from '@orillusion/stats' -import * as dat from 'https://unpkg.com/dat.gui@0.7.9/build/dat.gui.module.js' // simple base demo class Sample_Base_0 { @@ -56,7 +56,7 @@ class Sample_Base_0 { Engine3D.startRenderView(view); // debug GUI - const GUIHelp = new dat.GUI({name: 'Orillusion'}) + GUIHelp.init(); GUIHelp.addFolder('Transform'); GUIHelp.add(cubeObj.transform, 'x', -10.0, 10.0, 0.01); GUIHelp.add(cubeObj.transform, 'y', -10.0, 10.0, 0.01); @@ -67,6 +67,7 @@ class Sample_Base_0 { GUIHelp.add(cubeObj.transform, 'scaleX', 0.0, 2.0, 0.01); GUIHelp.add(cubeObj.transform, 'scaleY', 0.0, 2.0, 0.01); GUIHelp.add(cubeObj.transform, 'scaleZ', 0.0, 2.0, 0.01); + GUIHelp.open(); GUIHelp.endFolder(); } } From cbe44e59635f933eb1875aced86b50aed06b753e Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Fri, 5 May 2023 13:44:51 +0800 Subject: [PATCH 083/100] chore: move property animation file (#93) move property animation file add cubic bezier algorithm fix engine update greater than 1 , must once styler CubicBezierPath styler CubicBezierCurve --- src/Engine3D.ts | 152 +++++++-- src/components/ComponentBase.ts | 35 +-- .../{curveAnim => }/AnimationMonitor.ts | 7 +- .../{curveAnim => }/AttributeAnimCurve.ts | 2 +- .../{curveAnim => }/PropertyAnimClip.ts | 0 .../{curveAnim => }/PropertyAnimation.ts | 6 +- .../{curveAnim => }/PropertyAnimationEvent.ts | 2 +- .../curveAnim/{curveAnim => }/PropertyHelp.ts | 0 src/core/View3D.ts | 15 + src/gfx/renderJob/collect/ComponentCollect.ts | 104 ++++++- src/gfx/renderJob/jobs/RendererJob.ts | 50 +-- src/index.ts | 156 +++++----- src/math/CubicBezierCurve.ts | 113 +++++++ src/math/CubicBezierPath.ts | 293 ++++++++++++++++++ tsconfig.json | 1 + 15 files changed, 743 insertions(+), 193 deletions(-) rename src/components/anim/curveAnim/{curveAnim => }/AnimationMonitor.ts (97%) rename src/components/anim/curveAnim/{curveAnim => }/AttributeAnimCurve.ts (88%) rename src/components/anim/curveAnim/{curveAnim => }/PropertyAnimClip.ts (100%) rename src/components/anim/curveAnim/{curveAnim => }/PropertyAnimation.ts (96%) rename src/components/anim/curveAnim/{curveAnim => }/PropertyAnimationEvent.ts (92%) rename src/components/anim/curveAnim/{curveAnim => }/PropertyHelp.ts (100%) create mode 100644 src/math/CubicBezierCurve.ts create mode 100644 src/math/CubicBezierPath.ts diff --git a/src/Engine3D.ts b/src/Engine3D.ts index f789746d..23471424 100644 --- a/src/Engine3D.ts +++ b/src/Engine3D.ts @@ -19,34 +19,47 @@ import { ComponentCollect } from './gfx/renderJob/collect/ComponentCollect'; /** * Orillusion 3D Engine + * + * -- Engine3D.setting.* + * + * -- await Engine3D.init(); * @group engine3D */ export class Engine3D { + /** - * @internal - */ - // [x: string]: any; - /** - * resource manager + * resource manager in engine3d */ public static res: Res; + /** - * input system + * input system in engine3d */ public static inputSystem: InputSystem; - public static views: View3D[]; + /** + * more view in engine3d + */ + public static views: View3D[]; private static _frameRateValue: number = 0; private static _frameRate: number = 360; - private static _isRun: boolean = false; private static _frameTimeCount: number = 0; private static _deltaTime: number = 0; private static _time: number = 0; + private static _beforeRender: Function; + private static _renderLoop: Function; + private static _lateRender: Function; + /** + * set engine render frameRate 24/30/60/114/120/144/240/360 fps or other + */ public static get frameRate(): number { return this._frameRate; } + /** + * get engine render frameRate + */ public static set frameRate(value: number) { this._frameRate = value; this._frameRateValue = 1.0 / value; @@ -55,18 +68,30 @@ export class Engine3D { } } + /** + * get render window size width and height + */ public static get size(): number[] { return webGPUContext.presentationSize; } + /** + * get render window aspect + */ public static get aspect(): number { return webGPUContext.aspect; } + /** + * get render window size width + */ public static get width(): number { return webGPUContext.windowWidth; } + /** + * get render window size height + */ public static get height(): number { return webGPUContext.windowHeight; } @@ -215,16 +240,12 @@ export class Engine3D { }, }; - private static _beforeRender: Function; - private static _renderLoop: Function; - private static _lateRender: Function; + /** * @internal */ public static renderJobs: Map; - - /** * create webgpu 3d engine * @param descriptor {@link CanvasConfig} @@ -257,6 +278,11 @@ export class Engine3D { return; } + /** + * set render view and start renderer + * @param view + * @returns + */ public static startRenderView(view: View3D) { this.renderJobs ||= new Map(); this.views = [view]; @@ -268,6 +294,12 @@ export class Engine3D { return renderJob; } + + /** + * set render views and start renderer + * @param view + * @returns + */ public static startRenderViews(views: View3D[]) { this.renderJobs ||= new Map(); this.views = views; @@ -281,33 +313,50 @@ export class Engine3D { this.render(0); } + /** + * get view render job instance + * @param view + * @returns + */ public static getRenderJob(view: View3D): RendererJob { return this.renderJobs.get(view); } + /** + * Pause the engine render + */ + public static pause() { + requestAnimationFrame(null); + } + + /** + * Resume the engine render + */ + public static resume() { + requestAnimationFrame((t) => this.render(t)); + } /** + * start engine render * @internal */ - public static render(time) { - if (!this._isRun) { - this._deltaTime = time - this._time; - this._time = time; - - if (this._frameRateValue > 0) { - this._frameTimeCount += this._deltaTime * 0.001; - if (this._frameTimeCount >= this._frameRateValue * 0.95) { - this._frameTimeCount = 0; - this.updateFrame(time); - } - } else { + private static render(time) { + this._deltaTime = time - this._time; + this._time = time; + + if (this._frameRateValue > 0) { + this._frameTimeCount += this._deltaTime * 0.001; + if (this._frameTimeCount >= this._frameRateValue * 0.95) { + this._frameTimeCount = 0; this.updateFrame(time); } + } else { + this.updateFrame(time); } - requestAnimationFrame((t) => this.render(t)); + this.resume(); } - public static updateFrame(time: number) { + private static updateFrame(time: number) { Time.delta = time - Time.time; Time.time = time; Time.frame += 1; @@ -315,10 +364,57 @@ export class Engine3D { Interpolator.tick(Time.delta); if (this._beforeRender) this._beforeRender(); + /****** auto before update with component list *****/ + ComponentCollect.componentsBeforeUpdateList.forEach((v, k) => { + v.forEach((c, f) => { + if (f.enable) { + c(k); + }; + }) + }); + + let command = webGPUContext.device.createCommandEncoder();; + ComponentCollect.componentsComputeList.forEach((v, k) => { + v.forEach((c, f) => { + if (f.enable) { + c(k, command); + }; + }) + }); + webGPUContext.device.queue.submit([command.finish()]); + + /****** auto update global matrix share buffer write to gpu *****/ + let globalMatrixBindGroup = GlobalBindGroup.modelMatrixBindGroup; + globalMatrixBindGroup.writeBuffer(); + + /****** auto update with component list *****/ + ComponentCollect.componentsUpdateList.forEach((v, k) => { + v.forEach((c, f) => { + if (f.enable) { + c(k); + }; + }) + }); + + if (this._renderLoop) { + this._renderLoop(); + } + this.renderJobs.forEach((v, k) => { - v.render(this._renderLoop); + v.renderFrame(); + }); + + /****** auto late update with component list *****/ + ComponentCollect.componentsLateUpdateList.forEach((v, k) => { + v.forEach((c, f) => { + if (f.enable) { + c(k); + }; + }) }); if (this._lateRender) this._lateRender(); } + + } diff --git a/src/components/ComponentBase.ts b/src/components/ComponentBase.ts index e80868f8..689217b6 100644 --- a/src/components/ComponentBase.ts +++ b/src/components/ComponentBase.ts @@ -39,7 +39,6 @@ export class ComponentBase implements IComponent { return this.object3D.transform; } - /** * Enable/disable components. The enabled components can be updated, while the disabled components cannot be updated. */ @@ -129,9 +128,9 @@ export class ComponentBase implements IComponent { */ private _onUpdate(call: Function) { if (call != null) { - ComponentCollect.componentsUpdateList.set(this, call); + ComponentCollect.bindUpdate(this.transform.view3D, this, call); } else { - ComponentCollect.componentsUpdateList.delete(this); + ComponentCollect.unBindUpdate(this.transform.view3D, this); } } @@ -140,11 +139,10 @@ export class ComponentBase implements IComponent { * @param call callback */ private _onLateUpdate(call: Function) { - // if(!this.enable) return; if (call != null) { - ComponentCollect.componentsLateUpdateList.set(this, call); + ComponentCollect.bindLateUpdate(this.transform.view3D, this, call); } else { - ComponentCollect.componentsLateUpdateList.delete(this); + ComponentCollect.unBindLateUpdate(this.transform.view3D, this); } } @@ -153,11 +151,10 @@ export class ComponentBase implements IComponent { * @param call callback */ private _onBeforeUpdate(call: Function) { - // if(!this.enable) return; if (call != null) { - ComponentCollect.componentsBeforeUpdateList.set(this, call); + ComponentCollect.bindLateUpdate(this.transform.view3D, this, call); } else { - ComponentCollect.componentsBeforeUpdateList.delete(this); + ComponentCollect.unBindLateUpdate(this.transform.view3D, this); } } @@ -168,9 +165,9 @@ export class ComponentBase implements IComponent { */ private _onCompute(call: Function) { if (call != null) { - ComponentCollect.componentsComputeList.set(this, call); + ComponentCollect.bindCompute(this.transform.view3D, this, call); } else { - ComponentCollect.componentsComputeList.delete(this); + ComponentCollect.unBindCompute(this.transform.view3D, this); } } @@ -180,9 +177,9 @@ export class ComponentBase implements IComponent { */ private _onGraphic(call: Function) { if (call != null) { - ComponentCollect.graphicComponent.set(this, call); + ComponentCollect.bindGraphic(this.transform.view3D, this, call); } else { - ComponentCollect.graphicComponent.delete(this); + ComponentCollect.unBindGraphic(this.transform.view3D, this); } } @@ -204,16 +201,4 @@ export class ComponentBase implements IComponent { this.onCompute = null; this.onGraphic = null; } - - - - /** - * @internal - */ - static waitStartComponent: Map = new Map(); - - /** - * @internal - */ - static graphicComponent: Map = new Map(); } diff --git a/src/components/anim/curveAnim/curveAnim/AnimationMonitor.ts b/src/components/anim/curveAnim/AnimationMonitor.ts similarity index 97% rename from src/components/anim/curveAnim/curveAnim/AnimationMonitor.ts rename to src/components/anim/curveAnim/AnimationMonitor.ts index b2b7f424..39c21a5b 100644 --- a/src/components/anim/curveAnim/curveAnim/AnimationMonitor.ts +++ b/src/components/anim/curveAnim/AnimationMonitor.ts @@ -1,9 +1,10 @@ -import { Object3D } from '../../../../core/entities/Object3D'; -import { repeat, clamp } from '../../../../math/MathUtil'; -import { Matrix4 } from '../../../../math/Matrix4'; +import { Object3D } from '../../../core/entities/Object3D'; +import { repeat, clamp } from '../../../math/MathUtil'; +import { Matrix4 } from '../../../math/Matrix4'; import { PropertyAnimClip, WrapMode } from './PropertyAnimClip'; import { PropertyAnimation } from './PropertyAnimation'; import { PropertyHelp } from './PropertyHelp'; + /** * @internal * @group Animation diff --git a/src/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts b/src/components/anim/curveAnim/AttributeAnimCurve.ts similarity index 88% rename from src/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts rename to src/components/anim/curveAnim/AttributeAnimCurve.ts index 11eda502..af5db90f 100644 --- a/src/components/anim/curveAnim/curveAnim/AttributeAnimCurve.ts +++ b/src/components/anim/curveAnim/AttributeAnimCurve.ts @@ -1,4 +1,4 @@ -import { AnimationCurve } from "../../../../math/AnimationCurve"; +import { AnimationCurve } from "../../../math/AnimationCurve"; /** * @internal diff --git a/src/components/anim/curveAnim/curveAnim/PropertyAnimClip.ts b/src/components/anim/curveAnim/PropertyAnimClip.ts similarity index 100% rename from src/components/anim/curveAnim/curveAnim/PropertyAnimClip.ts rename to src/components/anim/curveAnim/PropertyAnimClip.ts diff --git a/src/components/anim/curveAnim/curveAnim/PropertyAnimation.ts b/src/components/anim/curveAnim/PropertyAnimation.ts similarity index 96% rename from src/components/anim/curveAnim/curveAnim/PropertyAnimation.ts rename to src/components/anim/curveAnim/PropertyAnimation.ts index ea97d7e1..3699124f 100644 --- a/src/components/anim/curveAnim/curveAnim/PropertyAnimation.ts +++ b/src/components/anim/curveAnim/PropertyAnimation.ts @@ -1,6 +1,6 @@ -import { Object3D } from '../../../../core/entities/Object3D'; -import { Time } from '../../../../util/Time'; -import { ComponentBase } from '../../../ComponentBase'; +import { Object3D } from '../../../core/entities/Object3D'; +import { Time } from '../../../util/Time'; +import { ComponentBase } from '../../ComponentBase'; import { AnimationMonitor } from './AnimationMonitor'; import { AnimatorEventKeyframe, PropertyAnimationEvent } from './PropertyAnimationEvent'; import { PropertyAnimClip } from './PropertyAnimClip'; diff --git a/src/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts b/src/components/anim/curveAnim/PropertyAnimationEvent.ts similarity index 92% rename from src/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts rename to src/components/anim/curveAnim/PropertyAnimationEvent.ts index 2d7f547a..672fb87a 100644 --- a/src/components/anim/curveAnim/curveAnim/PropertyAnimationEvent.ts +++ b/src/components/anim/curveAnim/PropertyAnimationEvent.ts @@ -1,4 +1,4 @@ -import { CEvent } from '../../../../event/CEvent'; +import { CEvent } from '../../../event/CEvent'; import { PropertyAnimation } from './PropertyAnimation'; /** * @internal diff --git a/src/components/anim/curveAnim/curveAnim/PropertyHelp.ts b/src/components/anim/curveAnim/PropertyHelp.ts similarity index 100% rename from src/components/anim/curveAnim/curveAnim/PropertyHelp.ts rename to src/components/anim/curveAnim/PropertyHelp.ts diff --git a/src/core/View3D.ts b/src/core/View3D.ts index b59f4bb5..88bebb66 100644 --- a/src/core/View3D.ts +++ b/src/core/View3D.ts @@ -11,6 +11,8 @@ export class View3D extends CEventListener { private _scene: Scene3D; private _viewPort: Vector4; private _enablePick: boolean = false; + private _enable: boolean = true; + public pickFire: PickFire; constructor(x: number = 0, y: number = 0, width: number = 0, height: number = 0) { @@ -19,6 +21,14 @@ export class View3D extends CEventListener { this.enablePick = true; } + public get enable(): boolean { + return this._enable; + } + + public set enable(value: boolean) { + this._enable = value; + } + public get enablePick(): boolean { return this._enablePick; } @@ -34,19 +44,24 @@ export class View3D extends CEventListener { public get scene(): Scene3D { return this._scene; } + public set scene(value: Scene3D) { this._scene = value; value.view = this; } + public get camera(): Camera3D { return this._camera; } + public set camera(value: Camera3D) { this._camera = value; } + public get viewPort(): Vector4 { return this._viewPort; } + public set viewPort(value: Vector4) { this._viewPort = value; } diff --git a/src/gfx/renderJob/collect/ComponentCollect.ts b/src/gfx/renderJob/collect/ComponentCollect.ts index b72536bb..e30e41d9 100644 --- a/src/gfx/renderJob/collect/ComponentCollect.ts +++ b/src/gfx/renderJob/collect/ComponentCollect.ts @@ -1,3 +1,4 @@ +import { View3D } from "../../.."; import { IComponent } from "../../../components/IComponent"; import { Object3D } from "../../../core/entities/Object3D"; @@ -6,39 +7,120 @@ export class ComponentCollect { /** * @internal */ - public static componentsUpdateList: Map; + public static componentsUpdateList: Map>; /** * @internal */ - public static componentsLateUpdateList: Map; + public static componentsLateUpdateList: Map>; /** * @internal */ - public static componentsBeforeUpdateList: Map; + public static componentsBeforeUpdateList: Map>; /** * @internal */ - public static componentsComputeList: Map; + public static componentsComputeList: Map>; /** * @internal */ - public static waitStartComponent: Map; + public static graphicComponent: Map>; /** * @internal */ - public static graphicComponent: Map; + public static waitStartComponent: Map; public static init() { - ComponentCollect.componentsUpdateList = new Map(); - ComponentCollect.componentsLateUpdateList = new Map(); - ComponentCollect.componentsBeforeUpdateList = new Map(); - ComponentCollect.componentsComputeList = new Map(); + ComponentCollect.componentsUpdateList = new Map>(); + ComponentCollect.componentsLateUpdateList = new Map>(); + ComponentCollect.componentsBeforeUpdateList = new Map>(); + ComponentCollect.componentsComputeList = new Map>(); + ComponentCollect.graphicComponent = new Map>(); ComponentCollect.waitStartComponent = new Map(); - ComponentCollect.graphicComponent = new Map(); + } + + public static bindUpdate(view: View3D, component: IComponent, call: Function) { + let list = ComponentCollect.componentsUpdateList.get(view); + if (!list) { + list = new Map(); + ComponentCollect.componentsUpdateList.set(view, list); + } + list.set(component, call); + } + + public static unBindUpdate(view: View3D, component: IComponent) { + let list = ComponentCollect.componentsUpdateList.get(view); + if (list) { + list.delete(component); + } + } + + public static bindLateUpdate(view: View3D, component: IComponent, call: Function) { + let list = ComponentCollect.componentsLateUpdateList.get(view); + if (!list) { + list = new Map(); + ComponentCollect.componentsLateUpdateList.set(view, list); + } + list.set(component, call); + } + + public static unBindLateUpdate(view: View3D, component: IComponent) { + let list = ComponentCollect.componentsLateUpdateList.get(view); + if (list) { + list.delete(component); + } + } + + public static bindBeforeUpdate(view: View3D, component: IComponent, call: Function) { + let list = ComponentCollect.componentsBeforeUpdateList.get(view); + if (!list) { + list = new Map(); + ComponentCollect.componentsBeforeUpdateList.set(view, list); + } + list.set(component, call); + } + + public static unBindBeforeUpdate(view: View3D, component: IComponent) { + let list = ComponentCollect.componentsBeforeUpdateList.get(view); + if (list) { + list.delete(component); + } + } + + public static bindCompute(view: View3D, component: IComponent, call: Function) { + let list = ComponentCollect.componentsComputeList.get(view); + if (!list) { + list = new Map(); + ComponentCollect.componentsComputeList.set(view, list); + } + list.set(component, call); + } + + public static unBindCompute(view: View3D, component: IComponent) { + let list = ComponentCollect.componentsComputeList.get(view); + if (list) { + list.delete(component); + } + } + + + public static bindGraphic(view: View3D, component: IComponent, call: Function) { + let list = ComponentCollect.graphicComponent.get(view); + if (!list) { + list = new Map(); + ComponentCollect.graphicComponent.set(view, list); + } + list.set(component, call); + } + + public static unBindGraphic(view: View3D, component: IComponent) { + let list = ComponentCollect.graphicComponent.get(view); + if (list) { + list.delete(component); + } } } diff --git a/src/gfx/renderJob/jobs/RendererJob.ts b/src/gfx/renderJob/jobs/RendererJob.ts index b79ba779..3fca750f 100644 --- a/src/gfx/renderJob/jobs/RendererJob.ts +++ b/src/gfx/renderJob/jobs/RendererJob.ts @@ -186,59 +186,17 @@ export class RendererJob { } /** - * @internal + * To render a frame of the scene */ - public render(renderLoop: Function) { + public renderFrame() { let view = this._view; - // let camera = this._view.camera; - // let scene = this._view.scene; this.view.scene.waitUpdate(); - /****** - * auto update component list - *****/ - ComponentCollect.componentsBeforeUpdateList.forEach((v, k) => { - if (k.enable) v(); - }); - GlobalBindGroup.getLightEntries(view.scene).update(view); - let globalMatrixBindGroup = GlobalBindGroup.modelMatrixBindGroup; - globalMatrixBindGroup.writeBuffer(); - - if (renderLoop) { - renderLoop(); - } - - ComponentCollect.componentsUpdateList.forEach((v, k) => { - if (k.enable) v(); - }); - - let command = GPUContext.beginCommandEncoder(); - ComponentCollect.componentsComputeList.forEach((v, k) => { - if (k.enable) v(view, command); - }); - GPUContext.endCommandEncoder(command); - this.occlusionSystem.update(view.camera, view.scene); - this.renderFrame(view); - if (this.postRenderer && this.postRenderer.postList.length > 0) { - this.postRenderer.render(view); - } - view.scene.envMapChange = false; - - ComponentCollect.componentsLateUpdateList.forEach((v, k) => { - if (k.enable) v(); - }); - - } - - /** - * To render a frame of the scene - */ - protected renderFrame(view: View3D) { this.clusterLightingRender.render(view, this.occlusionSystem); if (this.shadowMapPassRenderer && Engine3D.setting.shadow.enable) { this.shadowMapPassRenderer.render(view, this.occlusionSystem); @@ -261,6 +219,10 @@ export class RendererJob { renderer.render(view, this.occlusionSystem, this.clusterLightingRender.clusterLightingBuffer); renderer.lateCompute(view, this.occlusionSystem); } + + if (this.postRenderer && this.postRenderer.postList.length > 0) { + this.postRenderer.render(view); + } } public debug() { diff --git a/src/index.ts b/src/index.ts index 63db0c2f..690142d5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,11 @@ +export * from "./Engine3D" export * from "./assets/Res" +export * from "./assets/shader/ShaderLib" export * from "./assets/shader/anim/SkeletonAnimation_shader" export * from "./assets/shader/cluster/ClusterBoundsSource_cs" export * from "./assets/shader/cluster/ClusterLighting_cs" -export * from "./assets/shader/compute/BlurEffectCreator_cs" export * from "./assets/shader/compute/BLUR_CsShader" +export * from "./assets/shader/compute/BlurEffectCreator_cs" export * from "./assets/shader/compute/DepthOfView_cs" export * from "./assets/shader/compute/ErpImage2CubeMapCreateCube_cs" export * from "./assets/shader/compute/ErpImage2CubeMapRgbe2rgba_cs" @@ -45,9 +47,9 @@ export * from "./assets/shader/core/struct/LightStruct" export * from "./assets/shader/core/struct/LightStructFrag" export * from "./assets/shader/core/struct/ShadingInput" export * from "./assets/shader/core/struct/VertexAttributes" -export * from "./assets/shader/glsl/post/LUT_glsl" export * from "./assets/shader/glsl/Quad_glsl" export * from "./assets/shader/glsl/Sky_glsl" +export * from "./assets/shader/glsl/post/LUT_glsl" export * from "./assets/shader/graphic/Graphic3DShader_fs" export * from "./assets/shader/graphic/Graphic3DShader_vs" export * from "./assets/shader/lighting/BRDF_frag" @@ -62,9 +64,10 @@ export * from "./assets/shader/materials/GlassShader" export * from "./assets/shader/materials/Lambert_shader" export * from "./assets/shader/materials/LitShader" export * from "./assets/shader/materials/OutlinePass" -export * from "./assets/shader/materials/PavementShader" export * from "./assets/shader/materials/PBRLItShader" +export * from "./assets/shader/materials/PavementShader" export * from "./assets/shader/materials/PointShadowDebug" +export * from "./assets/shader/materials/UnLit" export * from "./assets/shader/materials/program/BxdfDebug_frag" export * from "./assets/shader/materials/program/Clearcoat_frag" export * from "./assets/shader/materials/program/ClusterDebug_frag" @@ -74,56 +77,56 @@ export * from "./assets/shader/materials/uniforms/MaterialUniform" export * from "./assets/shader/materials/uniforms/PhysicMaterialUniform_frag" export * from "./assets/shader/materials/uniforms/UnLitMaterialUniform_frag" export * from "./assets/shader/materials/uniforms/VideoUniform_frag" -export * from "./assets/shader/materials/UnLit" export * from "./assets/shader/math/FastMathShader" export * from "./assets/shader/math/MathShader" export * from "./assets/shader/post/Bloom_shader" export * from "./assets/shader/post/FXAAShader" export * from "./assets/shader/post/GlobalFog_shader" export * from "./assets/shader/quad/Quad_shader" -export * from "./assets/shader/ShaderLib" export * from "./assets/shader/sky/AtmosphericScatteringSky_shader" export * from "./assets/shader/sky/CubeSky_Shader" export * from "./assets/shader/utils/BRDFLUT" export * from "./assets/shader/utils/ColorUtil" export * from "./assets/shader/utils/GenerayRandomDir" -export * from "./components/anim/curveAnim/curveAnim/AnimationMonitor" -export * from "./components/anim/curveAnim/curveAnim/AttributeAnimCurve" -export * from "./components/anim/curveAnim/curveAnim/PropertyAnimation" -export * from "./components/anim/curveAnim/curveAnim/PropertyAnimationEvent" -export * from "./components/anim/curveAnim/curveAnim/PropertyAnimClip" -export * from "./components/anim/curveAnim/curveAnim/PropertyHelp" +export * from "./components/AtmosphericComponent" +export * from "./components/BillboardComponent" +export * from "./components/ColliderComponent" +export * from "./components/ComponentBase" +export * from "./components/IComponent" +export * from "./components/SkeletonAnimationComponent" +export * from "./components/Transform" +export * from "./components/anim/OAnimationEvent" +export * from "./components/anim/curveAnim/AnimationMonitor" +export * from "./components/anim/curveAnim/AttributeAnimCurve" +export * from "./components/anim/curveAnim/PropertyAnimClip" +export * from "./components/anim/curveAnim/PropertyAnimation" +export * from "./components/anim/curveAnim/PropertyAnimationEvent" +export * from "./components/anim/curveAnim/PropertyHelp" export * from "./components/anim/morphAnim/MorphTargetBlender" export * from "./components/anim/morphAnim/MorphTargetData" export * from "./components/anim/morphAnim/MorphTargetFrame" export * from "./components/anim/morphAnim/MorphTargetKey" export * from "./components/anim/morphAnim/MorphTarget_shader" -export * from "./components/anim/OAnimationEvent" -export * from "./components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs" -export * from "./components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs" export * from "./components/anim/skeletonAnim/Joint" export * from "./components/anim/skeletonAnim/JointPose" -export * from "./components/anim/skeletonAnim/shader/compute_skeleton_blend" -export * from "./components/anim/skeletonAnim/shader/compute_skeleton_transform" export * from "./components/anim/skeletonAnim/Skeleton" export * from "./components/anim/skeletonAnim/SkeletonAnimationClip" export * from "./components/anim/skeletonAnim/SkeletonAnimationClipState" export * from "./components/anim/skeletonAnim/SkeletonAnimationCompute" export * from "./components/anim/skeletonAnim/SkeletonPose" -export * from "./components/AtmosphericComponent" +export * from "./components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs" +export * from "./components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs" +export * from "./components/anim/skeletonAnim/shader/compute_skeleton_blend" +export * from "./components/anim/skeletonAnim/shader/compute_skeleton_transform" export * from "./components/audio/AudioListener" export * from "./components/audio/PositionAudio" export * from "./components/audio/StaticAudio" -export * from "./components/BillboardComponent" -export * from "./components/ColliderComponent" -export * from "./components/ComponentBase" export * from "./components/controller/CameraControllerBase" export * from "./components/controller/FirstPersonCameraController" export * from "./components/controller/FlyCameraController" export * from "./components/controller/HoverCameraController" export * from "./components/controller/OrbitController" export * from "./components/controller/ThirdPersonCameraController" -export * from "./components/IComponent" export * from "./components/lights/DirectLight" export * from "./components/lights/GILighting" export * from "./components/lights/IESProfiles" @@ -145,15 +148,17 @@ export * from "./components/shape/CapsuleColliderShape" export * from "./components/shape/ColliderShape" export * from "./components/shape/MeshColliderShape" export * from "./components/shape/SphereColliderShape" -export * from "./components/SkeletonAnimationComponent" -export * from "./components/Transform" +export * from "./core/Camera3D" +export * from "./core/CameraType" +export * from "./core/CubeCamera" +export * from "./core/PointShadowCubeCamera" +export * from "./core/Scene3D" +export * from "./core/View3D" +export * from "./core/ViewQuad" export * from "./core/bound/BoundingBox" export * from "./core/bound/BoundingSphere" export * from "./core/bound/Frustum" export * from "./core/bound/IBound" -export * from "./core/Camera3D" -export * from "./core/CameraType" -export * from "./core/CubeCamera" export * from "./core/entities/Entity" export * from "./core/entities/InstancedMesh" export * from "./core/entities/Object3D" @@ -167,47 +172,43 @@ export * from "./core/geometry/VertexAttributeName" export * from "./core/geometry/VertexAttributeSize" export * from "./core/geometry/VertexAttributeStride" export * from "./core/geometry/VertexFormat" -export * from "./core/PointShadowCubeCamera" +export * from "./core/pool/ObjectPool" export * from "./core/pool/memory/MatrixDO" export * from "./core/pool/memory/MemoryDO" export * from "./core/pool/memory/MemoryInfo" -export * from "./core/pool/ObjectPool" -export * from "./core/Scene3D" export * from "./core/tree/kdTree/IKDTreeUserData" export * from "./core/tree/kdTree/KDTreeEntity" export * from "./core/tree/kdTree/KDTreeNode" export * from "./core/tree/kdTree/KDTreeSpace" -export * from "./core/View3D" -export * from "./core/ViewQuad" -export * from "./Engine3D" export * from "./event/CEvent" export * from "./event/CEventDispatcher" export * from "./event/CEventListener" export * from "./event/CResizeEvent" +export * from "./event/KeyCode" +export * from "./event/MouseCode" export * from "./event/eventConst/KeyEvent" export * from "./event/eventConst/LoaderEvent" export * from "./event/eventConst/Object3DEvent" export * from "./event/eventConst/PointerEvent3D" export * from "./event/eventConst/UIEvent" -export * from "./event/KeyCode" -export * from "./event/MouseCode" export * from "./gfx/data/IrradianceVolume" export * from "./gfx/generate/BrdfLUTGenerate" +export * from "./gfx/generate/PassGenerate" export * from "./gfx/generate/convert/BlurEffectCreator" export * from "./gfx/generate/convert/ErpImage2CubeMap" export * from "./gfx/generate/convert/IBLEnvMapCreator" export * from "./gfx/generate/convert/MergeRGBACreator" export * from "./gfx/generate/convert/TextureCubeStdCreator" export * from "./gfx/generate/convert/TextureCubeUtils" -export * from "./gfx/generate/PassGenerate" export * from "./gfx/graphics/webGpu/CanvasConfig" export * from "./gfx/graphics/webGpu/Context3D" +export * from "./gfx/graphics/webGpu/WebGPUConst" export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup" export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout" export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup" -export * from "./gfx/graphics/webGpu/core/bindGroups/groups/LightEntries" export * from "./gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup" export * from "./gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/groups/LightEntries" export * from "./gfx/graphics/webGpu/core/buffer/ArrayBufferData" export * from "./gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer" export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferBase" @@ -227,6 +228,9 @@ export * from "./gfx/graphics/webGpu/core/uniforms/UniformNode" export * from "./gfx/graphics/webGpu/descriptor/RTDescriptor" export * from "./gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator" export * from "./gfx/graphics/webGpu/shader/ComputeShader" +export * from "./gfx/graphics/webGpu/shader/RenderShader" +export * from "./gfx/graphics/webGpu/shader/ShaderBase" +export * from "./gfx/graphics/webGpu/shader/ShaderStage" export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexer" export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexerToken" export * from "./gfx/graphics/webGpu/shader/converter/GLSLPreprocessor" @@ -235,9 +239,6 @@ export * from "./gfx/graphics/webGpu/shader/converter/Reader" export * from "./gfx/graphics/webGpu/shader/converter/ShaderConverter" export * from "./gfx/graphics/webGpu/shader/converter/StatementNode" export * from "./gfx/graphics/webGpu/shader/converter/WGSLTranslator" -export * from "./gfx/graphics/webGpu/shader/RenderShader" -export * from "./gfx/graphics/webGpu/shader/ShaderBase" -export * from "./gfx/graphics/webGpu/shader/ShaderStage" export * from "./gfx/graphics/webGpu/shader/util/MorePassParser" export * from "./gfx/graphics/webGpu/shader/util/Preprocessor" export * from "./gfx/graphics/webGpu/shader/util/ShaderUtil" @@ -247,24 +248,25 @@ export * from "./gfx/graphics/webGpu/shader/value/ShaderReflectionInfo" export * from "./gfx/graphics/webGpu/shader/value/ShaderState" export * from "./gfx/graphics/webGpu/shader/value/ShaderValue" export * from "./gfx/graphics/webGpu/shader/value/UniformValue" -export * from "./gfx/graphics/webGpu/WebGPUConst" +export * from "./gfx/renderJob/GPUContext" export * from "./gfx/renderJob/collect/CollectInfo" export * from "./gfx/renderJob/collect/ComponentCollect" export * from "./gfx/renderJob/collect/EntityBatchCollect" export * from "./gfx/renderJob/collect/EntityCollect" export * from "./gfx/renderJob/collect/RenderGroup" export * from "./gfx/renderJob/collect/ShadowLightsCollect" -export * from "./gfx/renderJob/config/RenderLayer" export * from "./gfx/renderJob/config/RTResourceConfig" +export * from "./gfx/renderJob/config/RenderLayer" export * from "./gfx/renderJob/frame/GBufferFrame" export * from "./gfx/renderJob/frame/ProbeGBufferFrame" export * from "./gfx/renderJob/frame/RTFrame" export * from "./gfx/renderJob/frame/RTResourceMap" -export * from "./gfx/renderJob/GPUContext" export * from "./gfx/renderJob/jobs/ForwardRenderJob" -export * from "./gfx/renderJob/jobs/RendererJob" export * from "./gfx/renderJob/jobs/RenderMap" +export * from "./gfx/renderJob/jobs/RendererJob" export * from "./gfx/renderJob/occlusion/OcclusionSystem" +export * from "./gfx/renderJob/passRenderer/RenderContext" +export * from "./gfx/renderJob/passRenderer/RendererBase" export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer" export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingRender" export * from "./gfx/renderJob/passRenderer/color/ColorPassRenderer" @@ -278,8 +280,6 @@ export * from "./gfx/renderJob/passRenderer/graphic/Graphics3DShape" export * from "./gfx/renderJob/passRenderer/post/PostRenderer" export * from "./gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer" export * from "./gfx/renderJob/passRenderer/preDepth/ZCullingCompute" -export * from "./gfx/renderJob/passRenderer/RenderContext" -export * from "./gfx/renderJob/passRenderer/RendererBase" export * from "./gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer" export * from "./gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer" export * from "./gfx/renderJob/passRenderer/state/RendererMask" @@ -287,30 +287,46 @@ export * from "./gfx/renderJob/passRenderer/state/RendererPassState" export * from "./gfx/renderJob/passRenderer/state/RendererType" export * from "./gfx/renderJob/post/DepthOfFieldPost" export * from "./gfx/renderJob/post/FXAAPost" -export * from "./gfx/renderJob/post/GlobalFog" export * from "./gfx/renderJob/post/GTAOPost" +export * from "./gfx/renderJob/post/GlobalFog" export * from "./gfx/renderJob/post/HDRBloomPost" export * from "./gfx/renderJob/post/OutlinePost" export * from "./gfx/renderJob/post/PostBase" export * from "./gfx/renderJob/post/SSRPost" export * from "./gfx/renderJob/post/TAAPost" export * from "./io/InputSystem" -export * from "./io/picker/PickCompute" export * from "./io/PickFire" export * from "./io/PickResult" export * from "./io/RayCastMeshDetail" export * from "./io/TouchData" +export * from "./io/picker/PickCompute" export * from "./loader/FileLoader" export * from "./loader/LoaderBase" export * from "./loader/LoaderData" export * from "./loader/LoaderFunctions" export * from "./loader/LoaderManager" -export * from "./loader/parser/b3dm/arrayToString" +export * from "./loader/parser/B3DMParser" +export * from "./loader/parser/I3DMParser" +export * from "./loader/parser/OBJParser" +export * from "./loader/parser/ParserBase" +export * from "./loader/parser/RGBEParser" export * from "./loader/parser/b3dm/B3DMLoader" export * from "./loader/parser/b3dm/B3DMLoaderBase" export * from "./loader/parser/b3dm/FeatureTable" +export * from "./loader/parser/b3dm/arrayToString" export * from "./loader/parser/b3dm/readMagicBytes" -export * from "./loader/parser/B3DMParser" +export * from "./loader/parser/gltf/GLBParser" +export * from "./loader/parser/gltf/GLTFInfo" +export * from "./loader/parser/gltf/GLTFParser" +export * from "./loader/parser/gltf/GLTFSubParser" +export * from "./loader/parser/gltf/GLTFSubParserCamera" +export * from "./loader/parser/gltf/GLTFSubParserConverter" +export * from "./loader/parser/gltf/GLTFSubParserMaterial" +export * from "./loader/parser/gltf/GLTFSubParserMesh" +export * from "./loader/parser/gltf/GLTFSubParserSkeleton" +export * from "./loader/parser/gltf/GLTFSubParserSkin" +export * from "./loader/parser/gltf/GLTFType" +export * from "./loader/parser/gltf/TypeArray" export * from "./loader/parser/gltf/extends/KHR_draco_mesh_compression" export * from "./loader/parser/gltf/extends/KHR_lights_punctual" export * from "./loader/parser/gltf/extends/KHR_materials_clearcoat" @@ -325,24 +341,8 @@ export * from "./loader/parser/gltf/extends/KHR_materials_volume" export * from "./loader/parser/gltf/extends/KHR_mesh_quantization" export * from "./loader/parser/gltf/extends/KHR_texture_basisu" export * from "./loader/parser/gltf/extends/KHR_texture_transform" -export * from "./loader/parser/gltf/GLBParser" -export * from "./loader/parser/gltf/GLTFInfo" -export * from "./loader/parser/gltf/GLTFParser" -export * from "./loader/parser/gltf/GLTFSubParser" -export * from "./loader/parser/gltf/GLTFSubParserCamera" -export * from "./loader/parser/gltf/GLTFSubParserConverter" -export * from "./loader/parser/gltf/GLTFSubParserMaterial" -export * from "./loader/parser/gltf/GLTFSubParserMesh" -export * from "./loader/parser/gltf/GLTFSubParserSkeleton" -export * from "./loader/parser/gltf/GLTFSubParserSkin" -export * from "./loader/parser/gltf/GLTFType" -export * from "./loader/parser/gltf/TypeArray" export * from "./loader/parser/i3dm/I3DMLoader" export * from "./loader/parser/i3dm/I3DMLoaderBase" -export * from "./loader/parser/I3DMParser" -export * from "./loader/parser/OBJParser" -export * from "./loader/parser/ParserBase" -export * from "./loader/parser/RGBEParser" export * from "./loader/parser/tileRenderer/TileSet" export * from "./loader/parser/tileRenderer/TilesRenderer" export * from "./materials/BlendMode" @@ -353,20 +353,22 @@ export * from "./materials/LitMaterial" export * from "./materials/MaterialBase" export * from "./materials/MaterialPass" export * from "./materials/MaterialRegister" -export * from "./materials/multiPass/CastPointShadowMaterialPass" -export * from "./materials/multiPass/CastShadowMaterialPass" -export * from "./materials/multiPass/DepthMaterialPass" -export * from "./materials/multiPass/GBufferPass" -export * from "./materials/multiPass/SkyGBufferPass" export * from "./materials/PavementMaterial" export * from "./materials/PhysicMaterial" export * from "./materials/PointMaterial" export * from "./materials/SkyMaterial" export * from "./materials/UnLitMaterial" +export * from "./materials/multiPass/CastPointShadowMaterialPass" +export * from "./materials/multiPass/CastShadowMaterialPass" +export * from "./materials/multiPass/DepthMaterialPass" +export * from "./materials/multiPass/GBufferPass" +export * from "./materials/multiPass/SkyGBufferPass" export * from "./math/AnimationCurve" export * from "./math/Bezier2D" export * from "./math/Bezier3D" export * from "./math/Color" +export * from "./math/CubicBezierCurve" +export * from "./math/CubicBezierPath" export * from "./math/HaltonSeq" export * from "./math/Line" export * from "./math/MathUtil" @@ -395,16 +397,16 @@ export * from "./setting/LightSetting" export * from "./setting/MaterialSetting" export * from "./setting/OcclusionQuerySetting" export * from "./setting/PickSetting" +export * from "./setting/RenderSetting" +export * from "./setting/ShadowSetting" +export * from "./setting/SkySetting" export * from "./setting/post/BloomSetting" export * from "./setting/post/DepthOfViewSetting" -export * from "./setting/post/GlobalFogSetting" export * from "./setting/post/GTAOSetting" +export * from "./setting/post/GlobalFogSetting" export * from "./setting/post/OutlineSetting" export * from "./setting/post/SSRSetting" export * from "./setting/post/TAASetting" -export * from "./setting/RenderSetting" -export * from "./setting/ShadowSetting" -export * from "./setting/SkySetting" export * from "./shape/BoxGeometry" export * from "./shape/CylinderGeometry" export * from "./shape/PlaneGeometry" @@ -436,9 +438,9 @@ export * from "./util/KelvinUtil" export * from "./util/Object3DUtil" export * from "./util/ProfilerUtil" export * from "./util/StringUtil" -export * from "./util/struct/Struct" -export * from "./util/struct/StructValue" -export * from "./util/struct/Vector3Struct" export * from "./util/Time" export * from "./util/Vector3Ex" export * from "./util/ZSorterUtil" +export * from "./util/struct/Struct" +export * from "./util/struct/StructValue" +export * from "./util/struct/Vector3Struct" diff --git a/src/math/CubicBezierCurve.ts b/src/math/CubicBezierCurve.ts new file mode 100644 index 00000000..22c4cfeb --- /dev/null +++ b/src/math/CubicBezierCurve.ts @@ -0,0 +1,113 @@ +import { Vector3 } from './Vector3'; + +/** + * Cubic Bezier Curve + * @group Math + */ +export class CubicBezierCurve { + private controlVertices: Vector3[]; + + /** + * @constructor + * @param cvs controller points + */ + constructor(cvs: Vector3[]) { + this.setControlVertices(cvs); + } + + /** + * update controller points + * @param cvs controller points + */ + public setControlVertices(cvs: Vector3[]) { + // Cubic Bezier curves require 4 cvs. + if (cvs.length == 4) { + this.controlVertices = cvs.concat(); + } + } + + /** + * get position by calc from curve + * @param t a position in range [0-1] + * @returns Vector3 + */ + public getPoint(t: number): Vector3 { + if (!(t >= 0.0 && t <= 1.0)) { + return Vector3.ZERO; + } + let c = 1.0 - t; + + let bb0 = c * c * c; + let bb1 = 3 * t * c * c; + let bb2 = 3 * t * t * c; + let bb3 = t * t * t; + + let point = this.controlVertices[0].mul(bb0).add(this.controlVertices[1].mul(bb1)).add(this.controlVertices[2].mul(bb2)).add(this.controlVertices[3].mul(bb3)); + + return point; + } + + /** + * get tagent by calc from curve + * @param t a position in range [0-1] + * @returns tagent direction + * See: http://bimixual.org/AnimationLibrary/beziertangents.html + */ + public getTangent(t: number): Vector3 { + if (!(t >= 0.0 && t <= 1.0)) { + return Vector3.ZERO + } + let controlVerts = this.controlVertices; + let q0 = controlVerts[0].add(controlVerts[1].add(controlVerts[0]).mul(t)); + let q1 = controlVerts[1].add(controlVerts[2].add(controlVerts[1]).mul(t)); + let q2 = controlVerts[2].add(controlVerts[3].add(controlVerts[2]).mul(t)); + + let r0 = q0.add(q1.subtract(q0).mul(t)); + let r1 = q1.add(q2.subtract(q1).mul(t)); + let tangent = r1.subtract(r0); + return tangent; + } + + /** + * get adjacent coordinates + * @param pos position + * @param paramThreshold threshold value + * @returns a position in range [0-1] + */ + public getClosestParam(pos: Vector3, paramThreshold: number = 0.000001): number { + return this.getClosestParamRec(pos, 0.0, 1.0, paramThreshold); + } + + /** + * get adjacent coordinates by given range + * @param pos position + * @param beginT range from + * @param endT range end + * @param thresholdT threshold value + * @returns + */ + public getClosestParamRec(pos: Vector3, beginT: number, endT: number, thresholdT: number): number { + let mid = (beginT + endT) / 2.0; + + if (endT - beginT < thresholdT) { + return mid + } + + let paramA = (beginT + mid) / 2.0; + let paramB = (mid + endT) / 2.0; + + let posA = this.getPoint(paramA); + let posB = this.getPoint(paramB); + let distASq = posA.subtract(pos).lengthSquared; + let distBSq = posB.subtract(pos).lengthSquared; + + if (distASq < distBSq) { + endT = mid; + } + else { + beginT = mid; + } + + return this.getClosestParamRec(pos, beginT, endT, thresholdT); + } +} diff --git a/src/math/CubicBezierPath.ts b/src/math/CubicBezierPath.ts new file mode 100644 index 00000000..7fa36611 --- /dev/null +++ b/src/math/CubicBezierPath.ts @@ -0,0 +1,293 @@ +import { CubicBezierCurve } from './CubicBezierCurve'; +import { MathUtil } from './MathUtil'; +import { Vector3 } from './Vector3'; + +/** + * cubicBezierType + * @group Math + */ +export enum CubicBezierType { + Open, + Closed, +} + +/** + * @group Math + */ +export class CubicBezierPath { + private type: CubicBezierType = CubicBezierType.Open; + private numCurveSegments = 0; + private numControlVertices = 0; + private controlVertices: Vector3[] = []; + + // The term 'knot' is another name for a point right on the path (an interpolated point). With this constructor the + // knots are supplied and interpolated. knots.length (the number of knots) must be >= 2. Interior Cvs are generated + // transparently and automatically. + constructor(controlVertices: Vector3[], t: CubicBezierType = CubicBezierType.Open) { + this.setControlVertices(controlVertices, t); + } + + public getPathType() { + return this.type; + } + + public isClosed() { + return this.type == CubicBezierType.Closed ? true : false; + } + + /** + * @returns + */ + public isValid() { + return this.numCurveSegments > 0 ? true : false; + } + + public clear() { + this.controlVertices.length = 0; + this.type = CubicBezierType.Open; + this.numCurveSegments = 0; + this.numControlVertices = 0; + } + + public computeApproxLength(): number { + if (!this.isValid()) return 0.0; + + // For a closed path this still works if you consider the last point as separate from the first. That is, a closed + // path is just like an open except the last interpolated point happens to match the first. + let numInterpolatedPoints = this.numCurveSegments + 1; + if (numInterpolatedPoints < 2) return 0.0; + + let totalDist = 0.0; + let controlVertices = this.controlVertices; + for (let n = 1; n < numInterpolatedPoints; n++) { + let a = controlVertices[(n - 1) * 3]; + let b = controlVertices[n * 3]; + totalDist += a.subtract(b).lengthSquared; + } + + if (totalDist == 0.0) return 0.0; + + return totalDist; + } + + public computeApproxParamPerUnitLength(): number { + let length = this.computeApproxLength(); + return this.numCurveSegments / length; + } + + public computeApproxNormParamPerUnitLength(): number { + let length = this.computeApproxLength(); + return 1.0 / length; + } + + public interpolatePoints(knots: Vector3[], t: CubicBezierType) { + let numKnots = knots.length; + if (numKnots < 2) console.error('point count must great 1'); + + this.clear(); + this.type = t; + let controlVertices = this.controlVertices; + switch (t) { + case CubicBezierType.Open: { + this.numCurveSegments = numKnots - 1; + this.numControlVertices = 3 * numKnots - 2; + controlVertices.length = this.numControlVertices; + + // Place the interpolated CVs. + for (let n = 0; n < numKnots; n++) controlVertices[n * 3] = knots[n]; + + // Place the first and last non-interpolated CVs. + let initialPoint = knots[1].subtract(knots[0]).mul(0.25); + + // Interpolate 1/4 away along first segment. + controlVertices[1] = knots[0].add(initialPoint); + let finalPoint = knots[numKnots - 2].subtract(knots[numKnots - 1]).mul(0.25); + + // Interpolate 1/4 backward along last segment. + controlVertices[this.numControlVertices - 2] = knots[numKnots - 1].add(finalPoint); + + // Now we'll do all the interior non-interpolated CVs. + for (let k = 1; k < this.numCurveSegments; k++) { + let a = knots[k - 1].subtract(knots[k]); + let b = knots[k + 1].subtract(knots[k]); + let aLen = a.lengthSquared; + let bLen = b.lengthSquared; + + if (aLen > 0.0 && bLen > 0.0) { + let abLen = (aLen + bLen) / 8.0; + let ab = b.div(bLen).subtract(a.div(aLen)); + ab.normalize(); + ab = ab.mul(abLen); + + controlVertices[k * 3 - 1] = knots[k].subtract(ab); + controlVertices[k * 3 + 1] = knots[k].add(ab); + } else { + controlVertices[k * 3 - 1] = knots[k]; + controlVertices[k * 3 + 1] = knots[k]; + } + } + break; + } + + case CubicBezierType.Closed: { + this.numCurveSegments = numKnots; + + // We duplicate the first point at the end so we have contiguous memory to look of the curve value. That's + // what the +1 is for. + this.numControlVertices = 3 * numKnots + 1; + controlVertices.length = this.numControlVertices; + + // First lets place the interpolated CVs and duplicate the first into the last CV slot. + for (let n = 0; n < numKnots; n++) controlVertices[n * 3] = knots[n]; + + controlVertices[this.numControlVertices - 1] = knots[0]; + + // Now we'll do all the interior non-interpolated CVs. We go to k=NumCurveSegments which will compute the + // two CVs around the zeroth knot (points[0]). + for (let k = 1; k <= this.numCurveSegments; k++) { + let modkm1 = k - 1; + let modkp1 = (k + 1) % this.numCurveSegments; + let modk = k % this.numCurveSegments; + + let a = knots[modkm1].subtract(knots[modk]); + let b = knots[modkp1].subtract(knots[modk]); + let aLen = a.lengthSquared; + let bLen = b.lengthSquared; + let mod3km1 = 3 * k - 1; + + // Need the -1 so the end point is a duplicated start point. + let mod3kp1 = (3 * k + 1) % (this.numControlVertices - 1); + if (aLen > 0.0 && bLen > 0.0) { + let abLen = (aLen + bLen) / 8.0; + let ab = b.div(bLen).subtract(a.div(aLen)); + ab.normalize(); + ab = ab.mul(abLen); + + controlVertices[mod3km1] = knots[modk].subtract(ab); + controlVertices[mod3kp1] = knots[modk].add(ab); + } else { + controlVertices[mod3km1] = knots[modk]; + controlVertices[mod3kp1] = knots[modk]; + } + } + break; + } + } + } + + // For a closed path the last CV must match the first. + public setControlVertices(cvs: Vector3[], t: CubicBezierType) { + let numCVs = cvs.length; + if (numCVs <= 0) return; + if (t == CubicBezierType.Open && (numCVs < 4)) return + if (t == CubicBezierType.Closed && (numCVs < 7)) return + if (!((numCVs - 1) % 3 == 0)) return; + this.clear(); + this.type = t; + + this.numControlVertices = numCVs; + this.numCurveSegments = (numCVs - 1) / 3; + this.controlVertices = cvs; + } + + // t E [0, numSegments]. If the type is closed, the number of segments is one more than the equivalent open path. + public getPoint(t: number): Vector3 { + // Only closed paths accept t values out of range. + if (this.type == CubicBezierType.Closed) { + while (t < 0.0) t += this.numCurveSegments; + + while (t > this.numCurveSegments) t -= this.numCurveSegments; + } else { + t = MathUtil.clampf(t, 0.0, this.numCurveSegments); + } + + if (!(t >= 0) && t <= this.numCurveSegments) return; + + // Segment 0 is for t E [0, 1). The last segment is for t E [NumCurveSegments-1, NumCurveSegments]. + // The following 'if' statement deals with the final inclusive bracket on the last segment. The cast must truncate. + let segment = Math.floor(t); + if (segment >= this.numCurveSegments) segment = this.numCurveSegments - 1; + + let curveCVs: Vector3[] = []; + let controlVerts = this.controlVertices; + curveCVs[0] = controlVerts[3 * segment + 0]; + curveCVs[1] = controlVerts[3 * segment + 1]; + curveCVs[2] = controlVerts[3 * segment + 2]; + curveCVs[3] = controlVerts[3 * segment + 3]; + + let bc: CubicBezierCurve = new CubicBezierCurve(curveCVs); + return bc.getPoint(t - segment); + } + + // Does the same as GetPoint except that t is normalized to be E [0, 1] over all segments. The beginning of the curve + // is at t = 0 and the end at t = 1. Closed paths allow a value bigger than 1 in which case they loop. + public getPointNorm(t: number): Vector3 { + return this.getPoint(t * this.numCurveSegments); + } + + // Similar to GetPoint but returns the tangent at the specified point on the path. The tangent is not normalized. + // The longer the tangent the 'more influence' it has pulling the path in that direction. + public getTangent(t: number): Vector3 { + // Only closed paths accept t values out of range. + if (this.type == CubicBezierType.Closed) { + while (t < 0.0) t += this.numCurveSegments; + + while (t > this.numCurveSegments) t -= this.numCurveSegments; + } else { + t = MathUtil.clampf(t, 0.0, this.numCurveSegments); + } + + if (!(t >= 0) && t <= this.numCurveSegments) return; + + // Segment 0 is for t E [0, 1). The last segment is for t E [NumCurveSegments-1, NumCurveSegments]. + // The following 'if' statement deals with the final inclusive bracket on the last segment. The cast must truncate. + let segment = Math.floor(t); + if (segment >= this.numCurveSegments) segment = this.numCurveSegments - 1; + + let controlVerts = this.controlVertices; + let curveCVs = []; + curveCVs[0] = controlVerts[3 * segment + 0]; + curveCVs[1] = controlVerts[3 * segment + 1]; + curveCVs[2] = controlVerts[3 * segment + 2]; + curveCVs[3] = controlVerts[3 * segment + 3]; + + let bc = new CubicBezierCurve(curveCVs); + return bc.getTangent(t - segment); + } + + public getTangentNorm(t: number): Vector3 { + return this.getTangent(t * this.numCurveSegments); + } + + // This function returns a single closest point. There may be more than one point on the path at the same distance. + // Use ComputeApproxParamPerUnitLength to determine a good paramThreshold. eg. Say you want a 15cm threshold, + // use: paramThreshold = ComputeApproxParamPerUnitLength() * 0.15f. + public computeClosestParam(pos: Vector3, paramThreshold: number): number { + let minDistSq = Number.MAX_SAFE_INTEGER; + let closestParam = 0.0; + let curveCVs: Vector3[] = []; + let curve: CubicBezierCurve = new CubicBezierCurve(curveCVs); + for (let startIndex = 0; startIndex < this.controlVertices.length - 1; startIndex += 3) { + for (let i = 0; i < 4; i++) curveCVs[i] = this.controlVertices[startIndex + i]; + + curve.setControlVertices(curveCVs); + let curveClosestParam = curve.getClosestParam(pos, paramThreshold); + + let curvePos = curve.getPoint(curveClosestParam); + let distSq = curvePos.subtract(pos).lengthSquared; + if (distSq < minDistSq) { + minDistSq = distSq; + let startParam = startIndex / 3.0; + closestParam = startParam + curveClosestParam; + } + } + + return closestParam; + } + + // Same as above but returns a t value E [0, 1]. You'll need to use a paramThreshold like + // ComputeApproxParamPerUnitLength() * 0.15f if you want a 15cm tolerance. + public computeClosestNormParam(pos: Vector3, paramThreshold: number) { + return this.computeClosestParam(pos, paramThreshold * this.numCurveSegments); + } +} diff --git a/tsconfig.json b/tsconfig.json index 5277d54a..53704d5a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,7 @@ "sourceMap": true, "resolveJsonModule": true, "esModuleInterop": true, + "declaration": true, "noEmit": true, "rootDir": "./", "baseUrl": "./", From d91d10f49ba572b3f1732399659f03a5983f9c27 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Fri, 5 May 2023 18:09:00 +0800 Subject: [PATCH 084/100] chore: skip build types & minify in CI test --- .github/workflows/ci.yml | 2 +- package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1bf9d00b..337ecf09 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: run: pnpm install - name: Test Build - run: pnpm run build + run: pnpm run build:test - name: Test in Electron run: pnpm run test:ci diff --git a/package.json b/package.json index fcf22ac0..7d68ec6d 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "scripts": { "dev": "vite", "build": "tsc --p tsconfig.build.json && vite build && npm run build:types && npm run minify:es", + "build:test": "tsc --p tsconfig.build.json && vite build", "build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json", "minify:es": "uglifyjs dist/orillusion.es.js -o dist/orillusion.es.js -c -m", "test": "electron test/ci/main.js", From 4688f069ed9d26dafece0a191bd04ac1354b112f Mon Sep 17 00:00:00 2001 From: hellmor Date: Fri, 5 May 2023 20:49:24 +0800 Subject: [PATCH 085/100] feat(sample): Sample blend mode (#98) Add samples of renderMode or renderState. Update docs of Sample_ChangeTexture --- samples/render/Sample_BlendMode.ts | 91 ++++++++++++++++++++++++++ samples/render/Sample_ChangeTexture.ts | 90 +++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 samples/render/Sample_BlendMode.ts create mode 100644 samples/render/Sample_ChangeTexture.ts diff --git a/samples/render/Sample_BlendMode.ts b/samples/render/Sample_BlendMode.ts new file mode 100644 index 00000000..e0389e48 --- /dev/null +++ b/samples/render/Sample_BlendMode.ts @@ -0,0 +1,91 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Object3D, Scene3D, HoverCameraController, Engine3D, AtmosphericComponent, webGPUContext, View3D, DirectLight, KelvinUtil, MeshRenderer, BoxGeometry, LitMaterial, Color, BlendMode, GPUCullMode, CameraUtil } from "@orillusion/core"; + +//sample of change BlendMode and CullMode +class Sample_BlendMode { + lightObj: Object3D; + scene: Scene3D; + + async run() { + + Engine3D.setting.material.materialChannelDebug = true; + await Engine3D.init({}); + + this.scene = new Scene3D(); + this.scene.addComponent(AtmosphericComponent); + + let mainCamera = CameraUtil.createCamera3DObject(this.scene, 'camera'); + mainCamera.perspective(60, webGPUContext.aspect, 1, 5000.0); + + mainCamera.object3D.addComponent(HoverCameraController).setCamera(-125, 0, 120); + + await this.initScene(this.scene); + + let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + this.initLight(); + // + Engine3D.startRenderView(view); + } + + private initLight(): void { + this.lightObj = new Object3D(); + this.lightObj.x = 0; + this.lightObj.y = 30; + this.lightObj.z = -40; + this.lightObj.rotationX = 46; + this.lightObj.rotationY = 62; + this.lightObj.rotationZ = 360; + let lc = this.lightObj.addComponent(DirectLight); + lc.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + lc.castShadow = false; + lc.intensity = 200; + lc.debug(); + this.scene.addChild(this.lightObj); + } + + async initScene(scene: Scene3D) { + + //create a box into scene + let box = new Object3D(); + scene.addChild(box); + + //register a mesh renderer + let meshRenderer = box.addComponent(MeshRenderer); + meshRenderer.geometry = new BoxGeometry(20, 20, 20); + let material = meshRenderer.material = new LitMaterial(); + material.baseColor = new Color(0.1, 0.3, 0.6, 0.5); + material.blendMode = BlendMode.ADD; + + // blend mode + let blendMode = { + NONE: BlendMode.NONE, + NORMAL: BlendMode.NORMAL, + ADD: BlendMode.ADD, + ALPHA: BlendMode.ALPHA, + } + GUIHelp.init(); + // change blend mode by click dropdown box + GUIHelp.add({ blendMode: material.blendMode }, 'blendMode', blendMode).onChange((v) => { + material.blendMode = BlendMode[BlendMode[parseInt(v)]]; + }); + + //cull mode + let cullMode = {}; + cullMode[GPUCullMode.none] = GPUCullMode.none; + cullMode[GPUCullMode.front] = GPUCullMode.front; + cullMode[GPUCullMode.back] = GPUCullMode.back; + + // change cull mode by click dropdown box + GUIHelp.add({ cullMode: GPUCullMode.none }, 'cullMode', cullMode).onChange((v) => { + material.cullMode = v; + }); + + GUIHelp.open(); + GUIHelp.endFolder(); + } +} + +new Sample_BlendMode().run(); \ No newline at end of file diff --git a/samples/render/Sample_ChangeTexture.ts b/samples/render/Sample_ChangeTexture.ts new file mode 100644 index 00000000..d0546a86 --- /dev/null +++ b/samples/render/Sample_ChangeTexture.ts @@ -0,0 +1,90 @@ +import { Object3D, Scene3D, Engine3D, AtmosphericComponent, webGPUContext, HoverCameraController, View3D, DirectLight, KelvinUtil, MeshRenderer, BoxGeometry, LitMaterial, Vector3, Color, BlendMode, CameraUtil } from "@orillusion/core"; + +class Sample_ChangeTexture { + lightObj: Object3D; + scene: Scene3D; + + async run() { + + Engine3D.setting.material.materialChannelDebug = true; + Engine3D.setting.material.materialDebug = true; + Engine3D.setting.shadow.autoUpdate = true; + Engine3D.setting.shadow.debug = true; + Engine3D.setting.shadow.shadowBound = 100 + Engine3D.setting.shadow.shadowBias = 0.00192; + await Engine3D.init({}); + + this.scene = new Scene3D(); + this.scene.addComponent(AtmosphericComponent); + + //camera + let mainCamera = CameraUtil.createCamera3DObject(this.scene, 'camera'); + mainCamera.perspective(60, webGPUContext.aspect, 1, 5000.0); + mainCamera.object3D.addComponent(HoverCameraController).setCamera(-125, -10, 10); + + await this.initScene(); + + let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + this.initLight(); + // + Engine3D.startRenderView(view); + } + + private initLight(): void { + this.lightObj = new Object3D(); + this.lightObj.x = 0; + this.lightObj.y = 30; + this.lightObj.z = -40; + this.lightObj.rotationX = 46; + this.lightObj.rotationY = 62; + this.lightObj.rotationZ = 360; + let lc = this.lightObj.addComponent(DirectLight); + lc.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + lc.castShadow = false; + lc.intensity = 20; + this.scene.addChild(this.lightObj); + } + + async initScene() { + //create first box + let box1 = new Object3D(); + this.scene.addChild(box1); + + let render1 = box1.addComponent(MeshRenderer); + render1.geometry = new BoxGeometry(2, 2, 2); + let material1 = render1.material = new LitMaterial(); + material1.maskMap = Engine3D.res.maskTexture; + + //create second box + let box2 = new Object3D(); + box2.transform.z = 4; + this.scene.addChild(box2); + + let render2 = box2.addComponent(MeshRenderer); + render2.geometry = new BoxGeometry(2, 2, 2); + let material2 = render2.material = new LitMaterial(); + material2.maskMap = Engine3D.res.maskTexture; + + //load 2 textures for switching display + let texture_0 = await Engine3D.res.loadTexture('textures/diffuse.jpg'); + let texture_1 = await Engine3D.res.loadTexture('textures/KB3D_NTT_Ads_basecolor.png'); + + //auto change texture per 2 second + let count = 0; + setInterval(() => { + if (count % 2 == 0) { + material2.baseMap = texture_0; + } else { + material2.baseMap = texture_1; + } + count++; + }, 2000); + + } + +} + +new Sample_ChangeTexture().run(); \ No newline at end of file From 9137521b7cf7d8142679d2c15dd2faee05e51fae Mon Sep 17 00:00:00 2001 From: hellmor Date: Fri, 5 May 2023 20:49:42 +0800 Subject: [PATCH 086/100] feat(sample): add sample (#95) Add sample of base feature. --- samples/base/Sample_Base_0.ts | 75 ------------------------- samples/base/Sample_InitEngine.ts | 27 +++++++++ samples/base/Sample_Transform.ts | 72 ++++++++++++++++++++++++ samples/base/Sample_UseComponent.ts | 70 +++++++++++++++++++++++ src/util/Object3DUtil.ts | 86 +++++++++++++++++++++++++++++ 5 files changed, 255 insertions(+), 75 deletions(-) delete mode 100644 samples/base/Sample_Base_0.ts create mode 100644 samples/base/Sample_InitEngine.ts create mode 100644 samples/base/Sample_Transform.ts create mode 100644 samples/base/Sample_UseComponent.ts diff --git a/samples/base/Sample_Base_0.ts b/samples/base/Sample_Base_0.ts deleted file mode 100644 index f8f9e219..00000000 --- a/samples/base/Sample_Base_0.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { AtmosphericComponent, BoxGeometry, Camera3D, DirectLight, Engine3D, HoverCameraController, KelvinUtil, LitMaterial, MeshRenderer, Object3D, Scene3D, View3D } from '@orillusion/core'; -import { GUIHelp } from '@orillusion/debug/GUIHelp'; -import { Stats } from '@orillusion/stats' - -// simple base demo -class Sample_Base_0 { - async run() { - // init engine - await Engine3D.init(); - // create new Scene - let scene = new Scene3D(); - - // add performance stats - scene.addComponent(Stats) - - // add an Atmospheric sky enviroment - let sky = scene.addComponent(AtmosphericComponent); - sky.sunY = 0.6 - - // add a camera object - let cameraObj = new Object3D(); - scene.addChild(cameraObj); - - // set main camera component with a perspective view - let mainCamera = cameraObj.addComponent(Camera3D); - mainCamera.perspective(60, Engine3D.aspect, 0.01, 5000.0); - - // add a basic camera controller - let hoverCameraController = cameraObj.addComponent(HoverCameraController); - hoverCameraController.setCamera(15, -15, 10); - - // create a basic cube - let cubeObj = new Object3D(); - let mr = cubeObj.addComponent(MeshRenderer); - mr.geometry = new BoxGeometry(); - let mat = new LitMaterial(); - mr.material = mat; - scene.addChild(cubeObj); - - // add a basic direct light - let lightObj = new Object3D(); - lightObj.rotationX = 45; - lightObj.rotationY = 60; - lightObj.rotationZ = 150; - let lc = lightObj.addComponent(DirectLight); - lc.lightColor = KelvinUtil.color_temperature_to_rgb(5355); - lc.intensity = 10; - scene.addChild(lightObj); - - // create a view with target scene and camera - let view = new View3D(); - view.scene = scene; - view.camera = mainCamera; - - // start render - Engine3D.startRenderView(view); - - // debug GUI - GUIHelp.init(); - GUIHelp.addFolder('Transform'); - GUIHelp.add(cubeObj.transform, 'x', -10.0, 10.0, 0.01); - GUIHelp.add(cubeObj.transform, 'y', -10.0, 10.0, 0.01); - GUIHelp.add(cubeObj.transform, 'z', -10.0, 10.0, 0.01); - GUIHelp.add(cubeObj.transform, 'rotationX', 0.0, 360.0, 0.01); - GUIHelp.add(cubeObj.transform, 'rotationY', 0.0, 360.0, 0.01); - GUIHelp.add(cubeObj.transform, 'rotationZ', 0.0, 360.0, 0.01); - GUIHelp.add(cubeObj.transform, 'scaleX', 0.0, 2.0, 0.01); - GUIHelp.add(cubeObj.transform, 'scaleY', 0.0, 2.0, 0.01); - GUIHelp.add(cubeObj.transform, 'scaleZ', 0.0, 2.0, 0.01); - GUIHelp.open(); - GUIHelp.endFolder(); - } -} - -new Sample_Base_0().run() \ No newline at end of file diff --git a/samples/base/Sample_InitEngine.ts b/samples/base/Sample_InitEngine.ts new file mode 100644 index 00000000..5f952e9d --- /dev/null +++ b/samples/base/Sample_InitEngine.ts @@ -0,0 +1,27 @@ +import { Engine3D, Scene3D, CameraUtil, webGPUContext, View3D, AtmosphericComponent } from "@orillusion/core"; + +// init engine +class Sample_InitEngine { + async run() { + // init engine + await Engine3D.init(); + // create new Scene + let scene = new Scene3D(); + // add atmospheric sky + scene.addComponent(AtmosphericComponent); + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, scene); + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + + // create a view with target scene and camera + let view = new View3D(); + view.scene = scene; + view.camera = mainCamera; + + // start render + Engine3D.startRenderView(view); + } +} + +new Sample_InitEngine().run(); \ No newline at end of file diff --git a/samples/base/Sample_Transform.ts b/samples/base/Sample_Transform.ts new file mode 100644 index 00000000..3d080569 --- /dev/null +++ b/samples/base/Sample_Transform.ts @@ -0,0 +1,72 @@ +import { GUIHelp } from '@orillusion/debug/GUIHelp'; +import { Stats } from '@orillusion/stats' +import { Engine3D, Scene3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, Object3D, MeshRenderer, BoxGeometry, LitMaterial, DirectLight, KelvinUtil, View3D } from '@orillusion/core'; + +// simple base demo +class Sample_Transform { + async run() { + // init engine + await Engine3D.init(); + // create new Scene + let scene = new Scene3D(); + + // add performance stats + scene.addComponent(Stats); + + // add an Atmospheric sky enviroment + let sky = scene.addComponent(AtmosphericComponent); + sky.sunY = 0.6 + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, scene); + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + + // add a basic camera controller + let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); + hoverCameraController.setCamera(15, -15, 10); + + // create a basic cube + let cubeObj = new Object3D(); + let mr = cubeObj.addComponent(MeshRenderer); + mr.geometry = new BoxGeometry(); + let mat = new LitMaterial(); + mr.material = mat; + scene.addChild(cubeObj); + + // add a basic direct light + let lightObj = new Object3D(); + lightObj.rotationX = 45; + lightObj.rotationY = 60; + lightObj.rotationZ = 150; + let dirLight = lightObj.addComponent(DirectLight); + dirLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + dirLight.intensity = 10; + scene.addChild(lightObj); + + // create a view with target scene and camera + let view = new View3D(); + view.scene = scene; + view.camera = mainCamera; + + // start render + Engine3D.startRenderView(view); + + let transform = cubeObj.transform; + // debug GUI + GUIHelp.init(); + GUIHelp.addFolder('Transform'); + GUIHelp.add(transform, 'x', -10.0, 10.0, 0.01); + GUIHelp.add(transform, 'y', -10.0, 10.0, 0.01); + GUIHelp.add(transform, 'z', -10.0, 10.0, 0.01); + GUIHelp.add(transform, 'rotationX', 0.0, 360.0, 0.01); + GUIHelp.add(transform, 'rotationY', 0.0, 360.0, 0.01); + GUIHelp.add(transform, 'rotationZ', 0.0, 360.0, 0.01); + GUIHelp.add(transform, 'scaleX', 0.0, 2.0, 0.01); + GUIHelp.add(transform, 'scaleY', 0.0, 2.0, 0.01); + GUIHelp.add(transform, 'scaleZ', 0.0, 2.0, 0.01); + GUIHelp.open(); + GUIHelp.endFolder(); + } +} + +new Sample_Transform().run() \ No newline at end of file diff --git a/samples/base/Sample_UseComponent.ts b/samples/base/Sample_UseComponent.ts new file mode 100644 index 00000000..fbe69eb1 --- /dev/null +++ b/samples/base/Sample_UseComponent.ts @@ -0,0 +1,70 @@ +import { Engine3D, Scene3D, CameraUtil, webGPUContext, View3D, AtmosphericComponent, ComponentBase, Time, AxisObject, Object3DUtil, KelvinUtil, DirectLight, Object3D, HoverCameraController } from "@orillusion/core"; +import { GUIHelp } from "@orillusion/debug/GUIHelp"; + +// sample use component +class Sample_UseComponent { + async run() { + // init engine + await Engine3D.init(); + // create new Scene + let scene = new Scene3D(); + // add atmospheric sky + scene.addComponent(AtmosphericComponent); + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, scene); + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); + hoverCameraController.setCamera(15, -30, 10); + + // create a view with target scene and camera + let view = new View3D(); + view.scene = scene; + view.camera = mainCamera; + + // start render + Engine3D.startRenderView(view); + + + // create cube + let cube = Object3DUtil.GetSingleCube(2, 4, 1, 0.7, 1, 0.5); + cube.name = 'AxisObject'; + scene.addChild(cube); + + // register a component + let component = cube.addComponent(RotateComponent); + + // gui + GUIHelp.init(); + GUIHelp.add(component, 'enable'); + GUIHelp.open(); + GUIHelp.endFolder(); + } +} + + +class RotateComponent extends ComponentBase { + public init(param?: any): void { + console.log('RotateComponent init, name : ', this.object3D.name); + + } + public start(): void { + console.log('RotateComponent start, name :', this.object3D.name); + } + + public onUpdate(): void { + this.transform.rotationY = Math.sin(Time.time * 0.01) * 90; + } + + public onEnable(view?: View3D) { + console.log('RotateComponent init, name : ', this.object3D.name); + this._enable = true; + } + public onDisable(view?: View3D) { + console.log('RotateComponent init, name : ', this.object3D.name); + this._enable = false; + } +} + + +new Sample_UseComponent().run(); \ No newline at end of file diff --git a/src/util/Object3DUtil.ts b/src/util/Object3DUtil.ts index 66162876..61dae2c5 100644 --- a/src/util/Object3DUtil.ts +++ b/src/util/Object3DUtil.ts @@ -2,11 +2,16 @@ import { BoundingBox } from '../core/bound/BoundingBox'; import { Object3D } from '../core/entities/Object3D'; import { MeshRenderer } from '../components/renderer/MeshRenderer'; +import { BoxGeometry, SphereGeometry, LitMaterial, Color, MaterialBase } from '..'; export class Object3DUtil { private static readonly genMeshMinVector = Vector3.ZERO.clone(); private static readonly genMeshMaxVector = Vector3.ZERO.clone(); private static readonly genMeshVectorList8: Vector3[] = [new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3(), new Vector3()]; + private static boxGeo: BoxGeometry; + private static sphere: SphereGeometry; + + private static mat: LitMaterial; /** * Merge the bounding boxes that have been added to the world matrix based on the mesh of the children node */ @@ -45,4 +50,85 @@ export class Object3DUtil { return bound; } + + + private static initHeap() { + if (!this.boxGeo) + this.boxGeo = new BoxGeometry(); + if (!this.sphere) + this.sphere = new SphereGeometry(1, 35, 35); + if (!this.mat) { + this.mat = new LitMaterial(); + } + } + + public static get CubeMesh() { + this.initHeap(); + return this.boxGeo; + } + + public static get SphereMesh() { + this.initHeap(); + return this.sphere; + } + + public static GetCube() { + this.initHeap(); + + let obj = new Object3D(); + let renderer = obj.addComponent(MeshRenderer); + renderer.geometry = this.boxGeo; + renderer.material = this.mat.clone(); + renderer.castShadow = true; + return obj; + } + + public static GetSingleCube(sizeX: number, sizeY: number, sizeZ: number, r: number, g: number, b: number) { + this.initHeap(); + + let mat = new LitMaterial(); + mat.baseColor = new Color(r, g, b, 1); + + let obj = new Object3D(); + let renderer = obj.addComponent(MeshRenderer); + renderer.castGI = true; + renderer.geometry = new BoxGeometry(sizeX, sizeY, sizeZ); + renderer.material = mat; + return obj; + } + + public static GetSingleSphere(radius: number, r: number, g: number, b: number) { + this.initHeap(); + + let mat = new LitMaterial(); + mat.baseColor = new Color(r, g, b, 1); + + let obj = new Object3D(); + let renderer = obj.addComponent(MeshRenderer); + renderer.castGI = true; + renderer.geometry = new SphereGeometry(radius, 20, 20); + renderer.material = mat; + return obj; + } + + public static get Sphere() { + this.initHeap(); + + let obj = new Object3D(); + let renderer = obj.addComponent(MeshRenderer); + renderer.geometry = this.sphere; + renderer.material = this.mat; + return obj; + } + + public static getSinglepCube(mat: MaterialBase, size: number = 10) { + this.initHeap(); + + let obj = new Object3D(); + let renderer = obj.addComponent(MeshRenderer); + renderer.castShadow = false; + renderer.geometry = new BoxGeometry(size, size, size); + renderer.material = mat; + return obj; + } } From 04b9f1aadac56d40e665e5a408f9b557b6202632 Mon Sep 17 00:00:00 2001 From: hellmor Date: Fri, 5 May 2023 20:50:04 +0800 Subject: [PATCH 087/100] feat(sample): add sky texture samples (#96) Add sky texture samples. --- samples/sky/Sample_AtmosphericSky.ts | 53 +++++++++++++++++++++++ samples/sky/Sample_BitmapCubeSky.ts | 58 ++++++++++++++++++++++++++ samples/sky/Sample_BitmapCubeStdSky.ts | 51 ++++++++++++++++++++++ samples/sky/Sample_HDRSky.ts | 50 ++++++++++++++++++++++ samples/sky/Sample_LDRSky.ts | 50 ++++++++++++++++++++++ samples/sky/Sample_SolidColorSky.ts | 54 ++++++++++++++++++++++++ 6 files changed, 316 insertions(+) create mode 100644 samples/sky/Sample_AtmosphericSky.ts create mode 100644 samples/sky/Sample_BitmapCubeSky.ts create mode 100644 samples/sky/Sample_BitmapCubeStdSky.ts create mode 100644 samples/sky/Sample_HDRSky.ts create mode 100644 samples/sky/Sample_LDRSky.ts create mode 100644 samples/sky/Sample_SolidColorSky.ts diff --git a/samples/sky/Sample_AtmosphericSky.ts b/samples/sky/Sample_AtmosphericSky.ts new file mode 100644 index 00000000..cd5fb22a --- /dev/null +++ b/samples/sky/Sample_AtmosphericSky.ts @@ -0,0 +1,53 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Texture, AtmosphericScatteringSky } from "@orillusion/core"; + +// sample of AtmosphericSky +class Sample_AtmosphericSky { + private _scene: Scene3D; + + async run() { + // init engine + await Engine3D.init({}); + + // init scene + this._scene = new Scene3D(); + // add atmospheric sky + let component = this._scene.addComponent(AtmosphericComponent); + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, this._scene); + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + + // camera controller + let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); + hoverCameraController.setCamera(45, -10, 10); + + // init view3D + let view = new View3D(); + view.scene = this._scene; + view.camera = mainCamera; + + // start renderer + Engine3D.startRenderView(view); + + // gui + this.debug(component); + } + + private debug(component: AtmosphericComponent) { + GUIHelp.init(); + GUIHelp.addFolder('AtmosphericSky'); + GUIHelp.add(component, 'sunX', 0, 1, 0.01); + GUIHelp.add(component, 'sunY', 0, 1, 0.01); + GUIHelp.add(component, 'eyePos', 0, 5000, 1); + GUIHelp.add(component, 'sunRadius', 0, 1000, 0.01); + GUIHelp.add(component, 'sunRadiance', 0, 100, 0.01); + GUIHelp.add(component, 'sunBrightness', 0, 10, 0.01); + GUIHelp.add(component, 'exposure', 0, 2, 0.01); + GUIHelp.add(component, 'displaySun', 0, 1, 0.01); + GUIHelp.open(); + GUIHelp.endFolder(); + } +} + +new Sample_AtmosphericSky().run(); \ No newline at end of file diff --git a/samples/sky/Sample_BitmapCubeSky.ts b/samples/sky/Sample_BitmapCubeSky.ts new file mode 100644 index 00000000..ec0f0d92 --- /dev/null +++ b/samples/sky/Sample_BitmapCubeSky.ts @@ -0,0 +1,58 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Texture } from "@orillusion/core"; + +// sample to replace sky map. (witch contains 6 faces) +class Sample_BitmapCubeSky { + private _scene: Scene3D; + private _originTexture: Texture; + private _externalTexture: Texture; + private _useExternal: boolean = false; + async run() { + // init engine + await Engine3D.init({}); + + // init scene + this._scene = new Scene3D(); + // add sky + this._scene.addComponent(AtmosphericComponent); + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, this._scene); + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + + // camera controller + let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); + hoverCameraController.setCamera(45, -10, 10); + + // init view3D + let view = new View3D(); + view.scene = this._scene; + view.camera = mainCamera; + + // start renderer + Engine3D.startRenderView(view); + + // load sky texture (nx/px/py/ny/nz/pz), a total of 6 images + let urls: string[] = []; + urls.push('textures/cubemap/skybox_nx.png'); + urls.push('textures/cubemap/skybox_px.png'); + urls.push('textures/cubemap/skybox_py.png'); + urls.push('textures/cubemap/skybox_ny.png'); + urls.push('textures/cubemap/skybox_nz.png'); + urls.push('textures/cubemap/skybox_pz.png'); + + this._externalTexture = await Engine3D.res.loadTextureCubeMaps(urls); + + // gui + GUIHelp.init(); + GUIHelp.addButton('Switch Maps', () => { + this._originTexture ||= this._scene.envMap; + this._useExternal = !this._useExternal; + this._scene.envMap = this._useExternal ? this._externalTexture : this._originTexture; + }) + GUIHelp.open(); + } + +} + +new Sample_BitmapCubeSky().run(); \ No newline at end of file diff --git a/samples/sky/Sample_BitmapCubeStdSky.ts b/samples/sky/Sample_BitmapCubeStdSky.ts new file mode 100644 index 00000000..110d3132 --- /dev/null +++ b/samples/sky/Sample_BitmapCubeStdSky.ts @@ -0,0 +1,51 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Texture } from "@orillusion/core"; + +// sample to replace standard sky map +class Sample_BitmapCubeStdSky { + private _scene: Scene3D; + private _originTexture: Texture; + private _externalTexture: Texture; + private _useExternal: boolean = false; + async run() { + // init engine + await Engine3D.init({}); + + // init scene + this._scene = new Scene3D(); + // add sky + this._scene.addComponent(AtmosphericComponent); + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, this._scene); + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + + // camera controller + let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); + hoverCameraController.setCamera(45, -10, 10); + + // init view3D + let view = new View3D(); + view.scene = this._scene; + view.camera = mainCamera; + + // start renderer + Engine3D.startRenderView(view); + + // load standard sky texture + let url = 'sky/StandardCubeMap-2.jpg'; + this._externalTexture = await Engine3D.res.loadTextureCubeStd(url); + + // gui + GUIHelp.init(); + GUIHelp.addButton('Switch Maps', () => { + this._originTexture ||= this._scene.envMap; + this._useExternal = !this._useExternal; + this._scene.envMap = this._useExternal ? this._externalTexture : this._originTexture; + }) + GUIHelp.open(); + } + +} + +new Sample_BitmapCubeStdSky().run(); \ No newline at end of file diff --git a/samples/sky/Sample_HDRSky.ts b/samples/sky/Sample_HDRSky.ts new file mode 100644 index 00000000..a641d6d9 --- /dev/null +++ b/samples/sky/Sample_HDRSky.ts @@ -0,0 +1,50 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Texture } from "@orillusion/core"; + +// sample to replace hdr sky map +class Sample_HDRSky { + private _scene: Scene3D; + private _externalTexture: Texture; + private _originTexture: Texture; + private _useExternal: boolean = false; + async run() { + // init engine + await Engine3D.init({}); + + // init scene + this._scene = new Scene3D(); + // add sky + this._scene.addComponent(AtmosphericComponent); + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, this._scene); + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + + // camera controller + let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); + hoverCameraController.setCamera(45, -10, 10); + + // init view3D + let view = new View3D(); + view.scene = this._scene; + view.camera = mainCamera; + + // start renderer + Engine3D.startRenderView(view); + + // load sky texture + this._externalTexture = await Engine3D.res.loadHDRTextureCube('hdri/sunset.hdr'); + + // gui + GUIHelp.init(); + GUIHelp.addButton('Switch Maps', () => { + this._originTexture ||= this._scene.envMap; + this._useExternal = !this._useExternal; + this._scene.envMap = this._useExternal ? this._externalTexture : this._originTexture; + }) + GUIHelp.open(); + } + +} + +new Sample_HDRSky().run(); \ No newline at end of file diff --git a/samples/sky/Sample_LDRSky.ts b/samples/sky/Sample_LDRSky.ts new file mode 100644 index 00000000..34f1e8de --- /dev/null +++ b/samples/sky/Sample_LDRSky.ts @@ -0,0 +1,50 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Texture } from "@orillusion/core"; + +// sample to replace ldr sky map +class Sample_LDRSky { + private _scene: Scene3D; + private _originTexture: Texture; + private _externalTexture: Texture; + private _useExternal: boolean = false; + async run() { + // init engine + await Engine3D.init({}); + + // init scene + this._scene = new Scene3D(); + // add sky + this._scene.addComponent(AtmosphericComponent); + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, this._scene); + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + + // camera controller + let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); + hoverCameraController.setCamera(45, -10, 10); + + // init view3D + let view = new View3D(); + view.scene = this._scene; + view.camera = mainCamera; + + // start renderer + Engine3D.startRenderView(view); + + // load LDR sky texture + this._externalTexture = await Engine3D.res.loadLDRTextureCube('sky/LDR_sky.jpg'); + + // gui + GUIHelp.init(); + GUIHelp.addButton('Switch Maps', () => { + this._originTexture ||= this._scene.envMap; + this._useExternal = !this._useExternal; + this._scene.envMap = this._useExternal ? this._externalTexture : this._originTexture; + }) + GUIHelp.open(); + } + +} + +new Sample_LDRSky().run(); \ No newline at end of file diff --git a/samples/sky/Sample_SolidColorSky.ts b/samples/sky/Sample_SolidColorSky.ts new file mode 100644 index 00000000..5c4909e1 --- /dev/null +++ b/samples/sky/Sample_SolidColorSky.ts @@ -0,0 +1,54 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Texture, Color, SolidColorSky, Object3DUtil } from "@orillusion/core"; + +// sample to display solid color sky +class HDRSkyMap { + private _scene: Scene3D; + private _externalTexture: SolidColorSky; + private _originTexture: Texture; + private _useExternal: boolean = false; + + async run() { + // init engine + await Engine3D.init({}); + + // init scene + this._scene = new Scene3D(); + // add default sky + this._scene.addComponent(AtmosphericComponent); + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, this._scene); + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + + // camera controller + let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); + hoverCameraController.setCamera(45, -10, 10); + + // init view3D + let view = new View3D(); + view.scene = this._scene; + view.camera = mainCamera; + + // start renderer + Engine3D.startRenderView(view); + + // gui + GUIHelp.init(); + GUIHelp.addButton('Switch Maps', () => { + if (!this._externalTexture) { + // init solid color sky + this._externalTexture = new SolidColorSky(new Color(0.5, 0.8, 0, 1)); + this._originTexture = this._scene.envMap; + GUIHelp.addColor(this._externalTexture, 'color'); + } + + this._useExternal = !this._useExternal; + this._scene.envMap = this._useExternal ? this._externalTexture : this._originTexture; + }) + GUIHelp.open(); + } + +} + +new HDRSkyMap().run(); \ No newline at end of file From d70bba055f3f2043616d6c323ff9076be843a42e Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Fri, 5 May 2023 22:33:37 +0800 Subject: [PATCH 088/100] fix(AtmosphericComponent): fix AtmosphericComponent Update (#99) fix AtmosphericComponent Update fix sky light color use gamma fix timeInterpolator add remove use list fix engine pause and resume --- src/Engine3D.ts | 8 ++- src/assets/shader/lighting/BxDF_frag.ts | 2 +- .../sky/AtmosphericScatteringSky_shader.ts | 13 ++-- src/components/AtmosphericComponent.ts | 67 +++++++++++++------ src/components/renderer/MeshRenderer.ts | 3 + src/core/entities/Entity.ts | 24 +++++-- src/math/TimeInterpolator.ts | 6 ++ src/textures/AtmosphericScatteringSky.ts | 4 ++ 8 files changed, 90 insertions(+), 37 deletions(-) diff --git a/src/Engine3D.ts b/src/Engine3D.ts index 23471424..6036b658 100644 --- a/src/Engine3D.ts +++ b/src/Engine3D.ts @@ -49,6 +49,7 @@ export class Engine3D { private static _beforeRender: Function; private static _renderLoop: Function; private static _lateRender: Function; + private static _requestAnimationFrameID: number = 0; /** * set engine render frameRate 24/30/60/114/120/144/240/360 fps or other @@ -326,14 +327,17 @@ export class Engine3D { * Pause the engine render */ public static pause() { - requestAnimationFrame(null); + if (this._requestAnimationFrameID != 0) { + cancelAnimationFrame(this._requestAnimationFrameID); + this._requestAnimationFrameID = 0; + } } /** * Resume the engine render */ public static resume() { - requestAnimationFrame((t) => this.render(t)); + this._requestAnimationFrameID = requestAnimationFrame((t) => this.render(t)); } /** diff --git a/src/assets/shader/lighting/BxDF_frag.ts b/src/assets/shader/lighting/BxDF_frag.ts index 838de425..a4ec2bdd 100644 --- a/src/assets/shader/lighting/BxDF_frag.ts +++ b/src/assets/shader/lighting/BxDF_frag.ts @@ -97,7 +97,7 @@ export let BxDF_frag: string = /*wgsl*/ ` #if USEGI irradiance += getIrradiance().rgb ; #else - irradiance += globalUniform.skyExposure * LinearToGammaSpace(textureSampleLevel(prefilterMap, prefilterMapSampler, fragData.N.xyz, 0.8 * (MAX_REFLECTION_LOD) ).rgb); + irradiance += LinearToGammaSpace(globalUniform.skyExposure * textureSampleLevel(prefilterMap, prefilterMapSampler, fragData.N.xyz, 0.8 * (MAX_REFLECTION_LOD) ).rgb); #endif fragData.Irradiance = irradiance; diff --git a/src/assets/shader/sky/AtmosphericScatteringSky_shader.ts b/src/assets/shader/sky/AtmosphericScatteringSky_shader.ts index 278c3d3a..eab202d7 100644 --- a/src/assets/shader/sky/AtmosphericScatteringSky_shader.ts +++ b/src/assets/shader/sky/AtmosphericScatteringSky_shader.ts @@ -2,7 +2,8 @@ * @internal */ export class AtmosphericScatteringSky_shader { - public static cs: string = /* wgsl */ ` + public static cs: string = /* wgsl */ ` + #include 'ColorUtil' struct UniformData { width: f32, height: f32, @@ -15,6 +16,7 @@ export class AtmosphericScatteringSky_shader { mieHeight: f32, // = 1200; sunBrightness: f32, // = 1.0; displaySun: f32, // > 0.5: true + skyColor: vec4, // sky color }; @group(0) @binding(0) var uniformBuffer: UniformData; @@ -252,7 +254,7 @@ export class AtmosphericScatteringSky_shader { var limbDarkening: vec3 = GetTransmittance(setting, -L, V); limbDarkening *= pow(vec3(cosAngle), vec3(0.420, 0.503, 0.652)) * mix(vec3(1.0), vec3(1.2,0.9,0.5), edge) * intersectionTest; - sky += limbDarkening * uniformBuffer.sunBrightness; + sky += limbDarkening * uniformBuffer.sunBrightness; } return vec4(sky, phaseNight * intersectionTest); } @@ -294,17 +296,16 @@ export class AtmosphericScatteringSky_shader { setting.waveLambdaRayleigh = ComputeWaveLambdaRayleigh(vec3(0.000000680, 0.000000550, 0.000000450)); // see https://www.shadertoy.com/view/MllBR2 - setting.waveLambdaOzone = vec3(1.36820899679147, 3.31405330400124, 0.13601728252538) * 0.0000006 * 2.504; + setting.waveLambdaOzone = vec3(1.36820899679147, 3.31405330400124, 0.13601728252538)* 0.0000006 * 2.504; var eye:vec3 = vec3(0,eyePosition,0); var sky0:vec4 = ComputeSkyInscattering(setting, eye, V, L); var sky = vec3(sky0.rgb); // sky = TonemapACES(sky.rgb * 2.0); - // sky = pow(sky.rgb, vec3(2.4)); // gamma - // sky.rgb += noise(uv*iTime) / 255.0; // dither + sky = pow(sky.rgb, vec3(1.0/1.2)); // gamma - var fragColor:vec4 = vec4(sky, 1.0); + var fragColor:vec4 = vec4((sky.rgb ), 1.0); return fragColor; } `; diff --git a/src/components/AtmosphericComponent.ts b/src/components/AtmosphericComponent.ts index 1749b083..43253264 100644 --- a/src/components/AtmosphericComponent.ts +++ b/src/components/AtmosphericComponent.ts @@ -1,3 +1,4 @@ +import { Color, View3D } from ".."; import { AtmosphericScatteringSky, AtmosphericScatteringSkySetting } from "../textures/AtmosphericScatteringSky"; import { SkyRenderer } from "./renderer/SkyRenderer"; @@ -9,14 +10,17 @@ import { SkyRenderer } from "./renderer/SkyRenderer"; export class AtmosphericComponent extends SkyRenderer { private _atmosphericScatteringSky: AtmosphericScatteringSky; + private _onChange: boolean = true; public get sunX() { return this._atmosphericScatteringSky.setting.sunX; } public set sunX(value) { - this._atmosphericScatteringSky.setting.sunX = value; - this._atmosphericScatteringSky.apply(); + if (this._atmosphericScatteringSky.setting.sunX != value) { + this._atmosphericScatteringSky.setting.sunX = value; + this._onChange = true; + } } public get sunY() { @@ -24,8 +28,10 @@ export class AtmosphericComponent extends SkyRenderer { } public set sunY(value) { - this._atmosphericScatteringSky.setting.sunY = value; - this._atmosphericScatteringSky.apply(); + if (this._atmosphericScatteringSky.setting.sunY != value) { + this._atmosphericScatteringSky.setting.sunY = value; + this._onChange = true; + } } public get eyePos() { @@ -33,8 +39,10 @@ export class AtmosphericComponent extends SkyRenderer { } public set eyePos(value) { - this._atmosphericScatteringSky.setting.eyePos = value; - this._atmosphericScatteringSky.apply(); + if (this._atmosphericScatteringSky.setting.eyePos != value) { + this._atmosphericScatteringSky.setting.eyePos = value; + this._onChange = true; + } } public get sunRadius() { @@ -42,8 +50,10 @@ export class AtmosphericComponent extends SkyRenderer { } public set sunRadius(value) { - this._atmosphericScatteringSky.setting.sunRadius = value; - this._atmosphericScatteringSky.apply(); + if (this._atmosphericScatteringSky.setting.sunRadius != value) { + this._atmosphericScatteringSky.setting.sunRadius = value; + this._onChange = true; + } } public get sunRadiance() { @@ -51,8 +61,10 @@ export class AtmosphericComponent extends SkyRenderer { } public set sunRadiance(value) { - this._atmosphericScatteringSky.setting.sunRadiance = value; - this._atmosphericScatteringSky.apply(); + if (this._atmosphericScatteringSky.setting.sunRadiance != value) { + this._atmosphericScatteringSky.setting.sunRadiance = value; + this._onChange = true; + } } public get sunBrightness() { @@ -60,8 +72,10 @@ export class AtmosphericComponent extends SkyRenderer { } public set sunBrightness(value) { - this._atmosphericScatteringSky.setting.sunBrightness = value; - this._atmosphericScatteringSky.apply(); + if (this._atmosphericScatteringSky.setting.sunBrightness != value) { + this._atmosphericScatteringSky.setting.sunBrightness = value; + this._onChange = true; + } } public get displaySun() { @@ -69,10 +83,21 @@ export class AtmosphericComponent extends SkyRenderer { } public set displaySun(value) { - this._atmosphericScatteringSky.setting.displaySun = value; - this._atmosphericScatteringSky.apply(); + if (this._atmosphericScatteringSky.setting.displaySun != value) { + this._atmosphericScatteringSky.setting.displaySun = value; + this._onChange = true; + } } + // public get skyColor(): Color { + // return this._atmosphericScatteringSky.setting.skyColor; + // } + + // public set skyColor(value: Color) { + // this._atmosphericScatteringSky.setting.skyColor = value; + // this._onChange = true; + // } + public init(): void { super.init(); this._atmosphericScatteringSky = new AtmosphericScatteringSky(new AtmosphericScatteringSkySetting()); @@ -85,14 +110,12 @@ export class AtmosphericComponent extends SkyRenderer { super.start(); } - public onEnable(): void { - - } - - public onDisable(): void { - - } + public onUpdate(view?: View3D) { + if (this._onChange) { + console.log("change sky"); - public debug() { + this._onChange = false; + this._atmosphericScatteringSky.apply(); + } } } diff --git a/src/components/renderer/MeshRenderer.ts b/src/components/renderer/MeshRenderer.ts index 3ec6f4ae..1a44499c 100644 --- a/src/components/renderer/MeshRenderer.ts +++ b/src/components/renderer/MeshRenderer.ts @@ -52,8 +52,11 @@ export class MeshRenderer extends RenderNode { this.addRendererMask(RendererMask.MorphTarget); } else { this.removeRendererMask(RendererMask.MorphTarget); + this.onCompute = null; } + this.object3D.bound = this._geometry.bounds; + if (this._readyPipeline) { this.initPipeline(); } diff --git a/src/core/entities/Entity.ts b/src/core/entities/Entity.ts index 737a677f..bcc9ac65 100644 --- a/src/core/entities/Entity.ts +++ b/src/core/entities/Entity.ts @@ -76,7 +76,8 @@ export class Entity extends CEventDispatcher { * * The bounding box of an object */ - public bound: IBound; + private _bound: IBound; + protected waitDisposeComponents: IComponent[]; @@ -313,20 +314,31 @@ export class Entity extends CEventDispatcher { } } + public get bound(): IBound { + if (!this._bound) { + this.genBounds(); + } + return this._bound; + } + + public set bound(value: IBound) { + this._bound = value; + } + /** * Returns a bounding box that defines the display area of the specified layer. * @returns */ public genBounds() { - if (!this.bound) { - this.bound = new BoundingBox(Vector3.ZERO.clone(), Vector3.ONE.clone()); + if (!this._bound) { + this._bound = new BoundingBox(Vector3.ZERO.clone(), Vector3.ONE.clone()); } for (const children of this.entityChildren) { - if (children.bound) { - this.bound.merge(children.bound); + if (children._bound) { + this._bound.merge(children._bound); } } - return this.bound; + return this._bound; } diff --git a/src/math/TimeInterpolator.ts b/src/math/TimeInterpolator.ts index 60d39930..9e82f7b4 100644 --- a/src/math/TimeInterpolator.ts +++ b/src/math/TimeInterpolator.ts @@ -448,6 +448,12 @@ export class Interpolator { if (dispose) interpolator.dispose(); } + public static removeList(interpolators: Interpolator[], dispose?: boolean) { + interpolators.forEach((v) => { + this.remove(v, dispose); + }) + } + /** * @internal */ diff --git a/src/textures/AtmosphericScatteringSky.ts b/src/textures/AtmosphericScatteringSky.ts index 93784bbd..b3d2683f 100644 --- a/src/textures/AtmosphericScatteringSky.ts +++ b/src/textures/AtmosphericScatteringSky.ts @@ -1,3 +1,4 @@ +import { Color } from '..'; import { AtmosphericScatteringSky_shader } from '../assets/shader/sky/AtmosphericScatteringSky_shader'; import { UniformGPUBuffer } from '../gfx/graphics/webGpu/core/buffer/UniformGPUBuffer'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; @@ -22,6 +23,7 @@ export class AtmosphericScatteringSkySetting { public displaySun: boolean = true; public defaultTextureCubeSize: number = 512; public defaultTexture2DSize: number = 1024; + public skyColor: Color = new Color(1, 1, 1, 1); } /** @@ -63,6 +65,7 @@ export class AtmosphericScatteringSky extends HDRTextureCube { return this; } + } /** @@ -100,6 +103,7 @@ class AtmosphericTexture2D extends VirtualTexture { this._uniformBuffer.setFloat('mieHeight', setting.mieHeight); this._uniformBuffer.setFloat('sunBrightness', setting.sunBrightness); this._uniformBuffer.setFloat('displaySun', setting.displaySun ? 1 : 0); + this._uniformBuffer.setColor('skyColor', setting.skyColor); this._uniformBuffer.apply(); let command = GPUContext.beginCommandEncoder(); From 2055c45a1f75e37697d5c28d5f959b5ac455d7c8 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Sat, 6 May 2023 11:15:14 +0800 Subject: [PATCH 089/100] fix(engine): engine shadow lights collect init bug (#102) fix engine shadow lights collect init bug --- src/Engine3D.ts | 3 +++ src/gfx/renderJob/jobs/RendererJob.ts | 25 ++++++++++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Engine3D.ts b/src/Engine3D.ts index 6036b658..da6717df 100644 --- a/src/Engine3D.ts +++ b/src/Engine3D.ts @@ -16,6 +16,7 @@ import { Res } from './assets/Res'; import { ShaderLib } from './assets/shader/ShaderLib'; import { ShaderUtil } from './gfx/graphics/webGpu/shader/util/ShaderUtil'; import { ComponentCollect } from './gfx/renderJob/collect/ComponentCollect'; +import { ShadowLightsCollect } from './gfx/renderJob/collect/ShadowLightsCollect'; /** * Orillusion 3D Engine @@ -269,6 +270,8 @@ export class Engine3D { RTResourceMap.init(); + ShadowLightsCollect.init(); + this.res = new Res(); this._beforeRender = descriptor.beforeRender; diff --git a/src/gfx/renderJob/jobs/RendererJob.ts b/src/gfx/renderJob/jobs/RendererJob.ts index 3fca750f..43226e9b 100644 --- a/src/gfx/renderJob/jobs/RendererJob.ts +++ b/src/gfx/renderJob/jobs/RendererJob.ts @@ -17,6 +17,8 @@ import { RendererMap } from './RenderMap'; import { PostRenderer } from '../passRenderer/post/PostRenderer'; import { PostBase } from '../post/PostBase'; import { ComponentCollect } from '../collect/ComponentCollect'; +import { RendererBase } from '../passRenderer/RendererBase'; +import { Ctor } from '../../../util/Global'; /** * render jobs @@ -85,29 +87,35 @@ export class RendererJob { constructor(view: View3D) { this._view = view; - ShadowLightsCollect.init(); - this.rendererMap = new RendererMap(); this.occlusionSystem = new OcclusionSystem(); - this.clusterLightingRender = new ClusterLightingRender(view); - this.rendererMap.addRenderer(this.clusterLightingRender); + this.clusterLightingRender = this.addRenderer(ClusterLightingRender, view); this.graphic3D = new Graphic3D(); if (view && this.graphic3D) view.scene.addChild(this.graphic3D); if (Engine3D.setting.render.zPrePass) { - this.depthPassRenderer = new PreDepthPassRenderer(); - this.rendererMap.addRenderer(this.depthPassRenderer); + this.depthPassRenderer = this.addRenderer(PreDepthPassRenderer); } - this.shadowMapPassRenderer = new ShadowMapPassRenderer(); + this.pointLightShadowRenderer = new PointLightShadowRenderer(); } + public addRenderer(c: Ctor, param?: any): T { + let renderer: RendererBase; + if (param) { + renderer = new c(param); + } else { + renderer = new c(); + } + this.rendererMap.addRenderer(renderer); + return renderer as T; + } /** * @internal @@ -153,9 +161,8 @@ export class RendererJob { * @internal */ public enablePost(gbufferFrame: GBufferFrame) { - this.postRenderer = new PostRenderer(); + this.postRenderer = this.addRenderer(PostRenderer); this.postRenderer.setRenderStates(gbufferFrame); - this.rendererMap.addRenderer(this.postRenderer); } /** From 3a10b25f51c82766074ee877f273366aafdfc32b Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Sat, 6 May 2023 13:31:46 +0800 Subject: [PATCH 090/100] fix: image&video material shader and skeleton animation event (#100) Fixed VideoMaterial shader abnormal registration Fixed ImageMaterial shader abnormal registration Fixed bug with skeleton animation event dispatch --- packages/media-extention/ImageMaterial.ts | 4 ++-- packages/media-extention/VideoMaterial.ts | 2 +- .../anim/skeletonAnim/SkeletonAnimationClipState.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/media-extention/ImageMaterial.ts b/packages/media-extention/ImageMaterial.ts index cd592259..6b916c76 100644 --- a/packages/media-extention/ImageMaterial.ts +++ b/packages/media-extention/ImageMaterial.ts @@ -14,8 +14,8 @@ export class ImageMaterial extends MaterialBase { */ constructor() { super(); - ShaderLib.register("ImageShVideoShaderader", ImageMaterialShader); - let shader = this.setShader(`ImageShader`, `ImageShader`); + ShaderLib.register("ImageMaterialShader", ImageMaterialShader); + let shader = this.setShader(`ImageMaterialShader`, `ImageMaterialShader`); shader.setShaderEntry(`VertMain`, `FragMain`) shader.setUniformVector4(`transformUV1`, new Vector4(0, 0, 1, 1)); shader.setUniformVector4(`transformUV2`, new Vector4(0, 0, 1, 1)); diff --git a/packages/media-extention/VideoMaterial.ts b/packages/media-extention/VideoMaterial.ts index 25cda244..f839099f 100644 --- a/packages/media-extention/VideoMaterial.ts +++ b/packages/media-extention/VideoMaterial.ts @@ -14,7 +14,7 @@ export class VideoMaterial extends MaterialBase { */ constructor() { super(); - ShaderLib['VideoShader'] = VideoShader; + ShaderLib.register('VideoShader', VideoShader); let shader = this.setShader(`VideoShader`, `VideoShader`); shader.setShaderEntry(`VertMain`, `FragMain`) shader.setUniformVector4(`transformUV1`, new Vector4(0, 0, 1, 1)); diff --git a/src/components/anim/skeletonAnim/SkeletonAnimationClipState.ts b/src/components/anim/skeletonAnim/SkeletonAnimationClipState.ts index 14cce854..fe7d7430 100644 --- a/src/components/anim/skeletonAnim/SkeletonAnimationClipState.ts +++ b/src/components/anim/skeletonAnim/SkeletonAnimationClipState.ts @@ -96,7 +96,7 @@ export class SkeletonAnimationClipState { triggerFrame = Math.max(triggerFrame, 0); if (triggerFrame == this.currFrame) { event.skeletonAnimation = this.animation; - this.animation.events.dispatchEvent(event); + this.animation.eventDispatcher.dispatchEvent(event); break; } } From 148bf1f8bea525e5511677757884d0209ac43776 Mon Sep 17 00:00:00 2001 From: hellmor Date: Sat, 6 May 2023 13:33:00 +0800 Subject: [PATCH 091/100] feat(sample): add light sample (#101) Add sample of directLight and other lights. Exclude files that are not samples. --- samples/index.ts | 1 + samples/lights/PointLightsScript.ts | 129 ++++++++++++++++++++++ samples/lights/Sample_DirectLight.ts | 80 ++++++++++++++ samples/lights/Sample_PointLight.ts | 90 +++++++++++++++ samples/lights/Sample_PointLightShadow.ts | 96 ++++++++++++++++ samples/lights/Sample_SpotLight.ts | 129 ++++++++++++++++++++++ src/components/ComponentBase.ts | 8 +- src/components/lights/LightBase.ts | 1 - 8 files changed, 529 insertions(+), 5 deletions(-) create mode 100644 samples/lights/PointLightsScript.ts create mode 100644 samples/lights/Sample_DirectLight.ts create mode 100644 samples/lights/Sample_PointLight.ts create mode 100644 samples/lights/Sample_PointLightShadow.ts create mode 100644 samples/lights/Sample_SpotLight.ts diff --git a/samples/index.ts b/samples/index.ts index a36e0213..69c8d7fe 100644 --- a/samples/index.ts +++ b/samples/index.ts @@ -5,6 +5,7 @@ // create menu let title = '', list = '' for (const path in modules) { + if (!path.includes('Sample_')) continue const arr = path.split('/') const _title = arr[1] const _demo = arr[2].replace(/Sample_|Sample|\.ts/g, '') diff --git a/samples/lights/PointLightsScript.ts b/samples/lights/PointLightsScript.ts new file mode 100644 index 00000000..11715b52 --- /dev/null +++ b/samples/lights/PointLightsScript.ts @@ -0,0 +1,129 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Vector3, ComponentBase, PointLight, SphereGeometry, LitMaterial, BoundingBox, Object3D, UUID, Quaternion, Time, View3D } from "@orillusion/core"; + +class PointLightItem { + public dir: Vector3 = new Vector3(); + public speed: number = 300; + public mass: number = 10; +} + +export class PointLightsScript extends ComponentBase { + private _points: PointLight[]; + private _pointLightItems: PointLightItem[]; + private _startAnim: boolean = false; + + private static geo: SphereGeometry; + private static mat: LitMaterial + private static boundBox: BoundingBox; + + private _geo: SphereGeometry; + private _mat: LitMaterial; + private _boundBox: BoundingBox; + + constructor() { + super(); + PointLightsScript.geo ||= new SphereGeometry(0.5, 6, 6); + PointLightsScript.mat ||= new LitMaterial(); + PointLightsScript.boundBox ||= new BoundingBox(new Vector3(0, 10, 0), new Vector3(500, 50, 500)); + + this._geo = PointLightsScript.geo; + this._mat = PointLightsScript.mat; + this._boundBox = PointLightsScript.boundBox; + this._points = []; + this._pointLightItems = []; + + this._startAnim = false; + + GUIHelp.addFolder('random pointLight'); + GUIHelp.addButton('append light', () => { + this.beginAnim(); + }); + GUIHelp.addButton('remove light', () => { + this.stopAnim(); + }); + GUIHelp.open(); + GUIHelp.endFolder(); + } + + public beginAnim() { + this._startAnim = true; + this.transform.enable = true; + + const count = 100; + for (let i = 0; i < count; i++) { + this.createLight(); + } + + } + + public stopAnim() { + this._startAnim = false; + this.transform.enable = false; + + for (let i = 0; i < this._points.length; i++) { + const element = this._points[i]; + this.object3D.removeChild(element.object3D); + element.destroy(); + } + this._points.length = 0; + } + + private createLight() { + let obj = new Object3D(); + let poi = obj.addComponent(PointLight); + poi.name = UUID(); + poi.transform.x = this._boundBox.center.x + this._boundBox.extents.x * Math.random(); + poi.transform.y = this._boundBox.center.y + this._boundBox.extents.y * Math.random(); + poi.transform.z = this._boundBox.center.z + this._boundBox.extents.z * Math.random(); + poi.range = 30 + poi.r = Math.random() + 0.1; + poi.g = Math.random() + 0.1; + poi.b = Math.random() + 0.1; + poi.intensity = Math.random() * 1.5 + 10; + poi.range *= Math.random() * 0.5 + 0.5; + + + this.object3D.addChild(obj); + this._points.push(poi); + + let item = new PointLightItem(); + Quaternion.HELP_0.fromEulerAngles(Math.random() * 360, Math.random() * 360, Math.random() * 360); + item.dir = Quaternion.HELP_0.transformVector(Vector3.FORWARD); + item.speed = 50 + Math.random() * 150; + item.mass = 5 + Math.random() * 5; + this._pointLightItems.push(item); + return poi; + } + + onUpdate(): void { + if (!this._startAnim) + return; + if (Time.delta > 30) + return; + for (let i = 0; i < this._points.length; i++) { + const po = this._points[i]; + const pd = this._pointLightItems[i]; + + if (po && pd) { + pd.mass -= Time.delta * 0.001; + if (pd.mass < 0) { + Quaternion.HELP_0.fromEulerAngles(Math.random() * 360, Math.random() * 360, Math.random() * 360); + pd.dir = Quaternion.HELP_0.transformVector(Vector3.FORWARD); + pd.speed = 50 + Math.random() * 150; + pd.mass = 5 + Math.random() * 5; + } + + if (!this._boundBox.containsPoint(po.transform.localPosition)) { + pd.dir = pd.dir.negate(); + } + + Vector3.HELP_0.copyFrom(pd.dir); + Vector3.HELP_0.scaleBy(Time.delta * 0.001 * pd.speed * 0.1); + + po.transform.x += Vector3.HELP_0.x; + po.transform.y += Vector3.HELP_0.y; + po.transform.z += Vector3.HELP_0.z; + } + } + } +} diff --git a/samples/lights/Sample_DirectLight.ts b/samples/lights/Sample_DirectLight.ts new file mode 100644 index 00000000..ac9e909e --- /dev/null +++ b/samples/lights/Sample_DirectLight.ts @@ -0,0 +1,80 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Scene3D, HoverCameraController, Engine3D, AtmosphericComponent, Object3D, Camera3D, webGPUContext, Vector3, View3D, DirectLight, KelvinUtil, LitMaterial, MeshRenderer, BoxGeometry, CameraUtil } from "@orillusion/core"; + +//sample of direction light +class Sample_DirectLight { + scene: Scene3D; + lightObj3D: any; + + async run() { + await Engine3D.init({}); + + GUIHelp.init(); + + this.scene = new Scene3D(); + this.scene.addComponent(AtmosphericComponent); + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, this.scene); + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + //set camera data + mainCamera.object3D.addComponent(HoverCameraController).setCamera(0, -25, 1000); + + await this.initScene(); + + let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + this.initLight(); + Engine3D.startRenderView(view); + + } + + // create direction light + private initLight() { + this.lightObj3D = new Object3D(); + this.lightObj3D.x = 0; + this.lightObj3D.y = 30; + this.lightObj3D.z = -40; + this.lightObj3D.rotationX = 46; + this.lightObj3D.rotationY = 62; + this.lightObj3D.rotationZ = 360; + let directLight = this.lightObj3D.addComponent(DirectLight); + + //Convert color temperature to color object + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = false; + directLight.intensity = 20; + this.showLightGUI(directLight); + this.scene.addChild(this.lightObj3D); + } + + // show gui + // control light direction/color/intensity/indirect + private showLightGUI(light: DirectLight): void { + GUIHelp.addFolder('DirectLight'); + GUIHelp.add(light.transform, 'rotationX', 0.0, 360.0, 0.01); + GUIHelp.add(light.transform, 'rotationY', 0.0, 360.0, 0.01); + GUIHelp.add(light.transform, 'rotationZ', 0.0, 360.0, 0.01); + GUIHelp.addColor(light, 'lightColor'); + GUIHelp.add(light, 'intensity', 0.0, 160.0, 0.01); + GUIHelp.add(light, 'indirect', 0.0, 10.0, 0.01); + GUIHelp.open(); + GUIHelp.endFolder(); + } + + initScene() { + let mat = new LitMaterial(); + mat.baseMap = Engine3D.res.grayTexture; + mat.roughness = 0.4; + mat.metallic = 0.6; + let floor = new Object3D(); + let render = floor.addComponent(MeshRenderer); + render.geometry = new BoxGeometry(1000, 1, 1000); + render.material = mat; + this.scene.addChild(floor); + } +} + +new Sample_DirectLight().run(); \ No newline at end of file diff --git a/samples/lights/Sample_PointLight.ts b/samples/lights/Sample_PointLight.ts new file mode 100644 index 00000000..5c6f01b7 --- /dev/null +++ b/samples/lights/Sample_PointLight.ts @@ -0,0 +1,90 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { AtmosphericComponent, BoxGeometry, CameraUtil, Engine3D, HoverCameraController, LitMaterial, MeshRenderer, Object3D, Object3DUtil, PointLight, Scene3D, SphereGeometry, View3D, webGPUContext, } from "@orillusion/core"; +import { PointLightsScript } from "./PointLightsScript"; + +class Sample_PointLight { + scene: Scene3D; + hoverCameraController: HoverCameraController; + lightObj: any; + constructor() { } + + async run() { + + await Engine3D.init({}); + + GUIHelp.init(); + + this.scene = new Scene3D(); + this.scene.addComponent(AtmosphericComponent); + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, this.scene); + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + //set camera data + mainCamera.object3D.addComponent(HoverCameraController).setCamera(0, -25, 500); + + await this.initScene(this.scene); + + let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + Engine3D.startRenderViews([view]); + } + + public debug(light: PointLight) { + GUIHelp.addFolder('PointLight' + light.name); + GUIHelp.addColor(light, 'lightColor'); + GUIHelp.add(light.transform, 'x', -1000, 1000.0, 0.01); + GUIHelp.add(light.transform, 'y', -1000, 1000.0, 0.01); + GUIHelp.add(light.transform, 'z', -1000, 1000.0, 0.01); + + GUIHelp.add(light, 'r', 0.0, 1.0, 0.001); + GUIHelp.add(light, 'g', 0.0, 1.0, 0.001); + GUIHelp.add(light, 'b', 0.0, 1.0, 0.001); + GUIHelp.add(light, 'intensity', 0.0, 1500.0, 0.001); + GUIHelp.add(light, 'at', 0.0, 1600.0, 0.001); + GUIHelp.add(light, 'radius', 0.0, 1000.0, 0.001); + GUIHelp.add(light, 'range', 0.0, 1000.0, 0.001); + GUIHelp.add(light, 'quadratic', 0.0, 2.0, 0.001); + GUIHelp.endFolder(); + } + + + initScene(scene: Scene3D) { + let lightObj3D = new Object3D(); + let render = lightObj3D.addComponent(MeshRenderer); + render.geometry = new SphereGeometry(5, 30, 30); + render.material = new LitMaterial(); + + scene.addChild(lightObj3D); + + let pointlights = new Object3D(); + let script = pointlights.addComponent(PointLightsScript); + script.beginAnim(); + scene.addChild(pointlights); + + let cube = new BoxGeometry(10, 10, 10); + let mat = new LitMaterial(); + + // make 20 box + for (let i = 0; i < 20; i++) { + for (let j = 0; j < 10; j++) { + let box = new Object3D(); + let mr2 = box.addComponent(MeshRenderer); + mr2.geometry = cube; + mr2.material = mat; + scene.addChild(box); + + box.transform.x = i * 40 - 200; + box.transform.y = 5; + box.transform.z = j * 40 - 200; + } + } + + //create floor + let floor = Object3DUtil.GetSingleCube(2000, 1, 2000, 0.5, 0.5, 0.5); + this.scene.addChild(floor); + } +} + +new Sample_PointLight().run(); \ No newline at end of file diff --git a/samples/lights/Sample_PointLightShadow.ts b/samples/lights/Sample_PointLightShadow.ts new file mode 100644 index 00000000..56d38d3a --- /dev/null +++ b/samples/lights/Sample_PointLightShadow.ts @@ -0,0 +1,96 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, Vector3, View3D, SphereGeometry, Object3D, MeshRenderer, LitMaterial, PointLight, BoxGeometry, Object3DUtil } from "@orillusion/core"; + +// sample of point light shadow +class Sample_PointLightShadow { + scene: Scene3D; + + async run() { + + Engine3D.setting.shadow.enable = true; + Engine3D.setting.shadow.debug = true; + Engine3D.setting.material.materialChannelDebug = true; + Engine3D.setting.material.materialDebug = true; + + await Engine3D.init({}); + + this.scene = new Scene3D(); + this.scene.addComponent(AtmosphericComponent); + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, this.scene); + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + //set camera data + mainCamera.object3D.addComponent(HoverCameraController).setCamera(0, -45, 500); + + await this.initScene(this.scene); + + let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + Engine3D.startRenderView(view); + } + + //show point light gui controller + private showLightGUI(light: PointLight) { + GUIHelp.init(); + GUIHelp.addFolder('PointLight'); + GUIHelp.addColor(light, 'lightColor'); + GUIHelp.add(light.transform, 'x', -1000, 1000.0, 0.01); + GUIHelp.add(light.transform, 'y', -1000, 1000.0, 0.01); + GUIHelp.add(light.transform, 'z', -1000, 1000.0, 0.01); + + GUIHelp.add(light, 'r', 0.0, 1.0, 0.001); + GUIHelp.add(light, 'g', 0.0, 1.0, 0.001); + GUIHelp.add(light, 'b', 0.0, 1.0, 0.001); + GUIHelp.add(light, 'intensity', 0.0, 1500.0, 0.001); + GUIHelp.add(light, 'at', 0.0, 1600.0, 0.001); + GUIHelp.add(light, 'radius', 0.0, 1000.0, 0.001); + GUIHelp.add(light, 'range', 0.0, 1000.0, 0.001); + GUIHelp.add(light, 'quadratic', 0.0, 2.0, 0.001); + + GUIHelp.open(); + GUIHelp.endFolder(); + } + + async initScene(scene: Scene3D) { + let lightObj3D = new Object3D(); + lightObj3D.y = 25; + + //make point light + let pointLight = lightObj3D.addComponent(PointLight); + pointLight.range = 100; + pointLight.intensity = 5; + pointLight.castShadow = true; + scene.addChild(lightObj3D); + + //show gui + this.showLightGUI(pointLight); + + let cubeGeometry = new BoxGeometry(10, 10, 10); + let litMaterial = new LitMaterial(); + + //make 20 box to receive light and cast shadow + for (let i = 0; i < 20; i++) { + for (let j = 0; j < 10; j++) { + let box = new Object3D(); + let renderer = box.addComponent(MeshRenderer); + renderer.geometry = cubeGeometry; + renderer.material = litMaterial; + renderer.castShadow = true; + scene.addChild(box); + + box.transform.x = i * 40 - 200; + box.transform.y = 5; + box.transform.z = j * 40 - 200; + } + } + + //create floor + let floor = Object3DUtil.GetSingleCube(2000, 1, 2000, 0.5, 0.5, 0.5); + this.scene.addChild(floor); + } +} + +new Sample_PointLightShadow().run(); \ No newline at end of file diff --git a/samples/lights/Sample_SpotLight.ts b/samples/lights/Sample_SpotLight.ts new file mode 100644 index 00000000..0ee635f1 --- /dev/null +++ b/samples/lights/Sample_SpotLight.ts @@ -0,0 +1,129 @@ +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, SphereGeometry, Object3D, MeshRenderer, LitMaterial, SpotLight, BoxGeometry, Vector3 } from "@orillusion/core"; +import { GUIHelp } from "@orillusion/debug/GUIHelp"; + +// sample of SpotLight +class Sample_SpotLight { + scene: Scene3D; + + async run() { + Engine3D.setting.occlusionQuery.enable = false; + Engine3D.setting.shadow.enable = true; + Engine3D.setting.shadow.pointShadowBias = 0.075; + await Engine3D.init({}); + + GUIHelp.init(); + + this.scene = new Scene3D(); + this.scene.addComponent(AtmosphericComponent); + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, this.scene); + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + //set camera data + mainCamera.object3D.addComponent(HoverCameraController).setCamera(0, -25, 1000); + + await this.initScene(); + + let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + Engine3D.startRenderView(view); + } + + initScene() { + this.makeLight(); + this.buildScene(); + } + + private makeLight(): void { + let lightObj3D = new Object3D(); + + let renderer = lightObj3D.addComponent(MeshRenderer); + renderer.geometry = new SphereGeometry(5, 30, 30); + renderer.material = new LitMaterial(); + this.scene.addChild(lightObj3D); + + let spotLight = lightObj3D.addComponent(SpotLight); + lightObj3D.x = -86; + lightObj3D.y = 130; + lightObj3D.z = -395; + lightObj3D.transform.rotationX = 342; + lightObj3D.transform.rotationY = 360; + lightObj3D.transform.rotationZ = 199; + spotLight.lightColor.r = 255 / 255; + spotLight.lightColor.g = 157 / 255; + spotLight.lightColor.b = 5 / 255; + spotLight.intensity = 80; + spotLight.radius = 1; + spotLight.range = 787; + spotLight.outerAngle = 96; + spotLight.innerAngle = 0; + spotLight.castShadow = true; + + this.showSpotLightGUI(spotLight); + } + + // show gui + // control light direction/position/color/intensity/range and so on + private showSpotLightGUI(light: SpotLight) { + GUIHelp.addFolder('SpotLight'); + GUIHelp.add(light.transform, 'x', -1000, 1000.0, 0.01); + GUIHelp.add(light.transform, 'y', -1000, 1000.0, 0.01); + GUIHelp.add(light.transform, 'z', -1000, 1000.0, 0.01); + + GUIHelp.add(light.transform, 'rotationX', -360, 360.0, 0.01); + GUIHelp.add(light.transform, 'rotationY', -360, 360.0, 0.01); + GUIHelp.add(light.transform, 'rotationZ', -360, 360.0, 0.01); + + GUIHelp.addColor(light, 'lightColor'); + GUIHelp.add(light, 'intensity', 0.0, 1600.0, 0.001); + GUIHelp.add(light, 'at', 0.0, 1600.0, 0.001); + GUIHelp.add(light, 'radius', 0.0, 1000.0, 0.001); + GUIHelp.add(light, 'range', 0.0, 1000.0, 0.001); + GUIHelp.add(light, 'outerAngle', 0.0, 180.0, 0.001); + GUIHelp.add(light, 'innerAngle', 0.0, 100.0, 0.001); + + GUIHelp.open(); + GUIHelp.endFolder(); + } + + // Build a slightly complex scene + private buildScene(): void { + let mat = new LitMaterial(); + mat.baseMap = Engine3D.res.grayTexture; + + let floor = new Object3D(); + let mr = floor.addComponent(MeshRenderer); + mr.geometry = new BoxGeometry(2000, 1, 2000); + mr.material = mat; + this.scene.addChild(floor); + + let box = new BoxGeometry(1, 1, 1); + let wall_w = new Object3D(); + wall_w.localScale = new Vector3(500, 100, 10); + wall_w.localPosition = new Vector3(0, 50, 0); + let mrw = wall_w.addComponent(MeshRenderer); + mrw.geometry = box; + mrw.material = mat; + this.scene.addChild(wall_w); + + let wall_a = new Object3D(); + wall_a.localScale = new Vector3(10, 100, 500); + wall_a.localPosition = new Vector3(250, 50, 0); + let mra = wall_a.addComponent(MeshRenderer); + mra.geometry = box; + mra.material = mat; + this.scene.addChild(wall_a); + + let wall_d = new Object3D(); + wall_d.localScale = new Vector3(10, 100, 500); + wall_d.localPosition = new Vector3(-250, 50, 0); + let mrd = wall_d.addComponent(MeshRenderer); + mrd.geometry = box; + mrd.material = mat; + this.scene.addChild(wall_d); + } +} + +new Sample_SpotLight().run(); \ No newline at end of file diff --git a/src/components/ComponentBase.ts b/src/components/ComponentBase.ts index 689217b6..dd6a15d5 100644 --- a/src/components/ComponentBase.ts +++ b/src/components/ComponentBase.ts @@ -46,9 +46,9 @@ export class ComponentBase implements IComponent { if (this._enable != value) { this._enable = value; if (this._enable) { - this.onEnable(); - } else if (this.onDisable) { - this.onDisable(); + this.onEnable && this.onEnable(); + } else { + this.onDisable && this.onDisable(); } } } @@ -92,7 +92,7 @@ export class ComponentBase implements IComponent { private __stop() { if (this.transform && this.transform.scene3D) { - this.onDisable(); + this.onDisable && this.onDisable(); } this._onUpdate(null); this._onLateUpdate(null); diff --git a/src/components/lights/LightBase.ts b/src/components/lights/LightBase.ts index a03f15da..e58b46f5 100644 --- a/src/components/lights/LightBase.ts +++ b/src/components/lights/LightBase.ts @@ -242,7 +242,6 @@ export class LightBase extends ComponentBase implements ILight { } public destroy(): void { - this.lightData = null; this.bindOnChange = null; this.transform.eventDispatcher.removeEventListener(Transform.ROTATION_ONCHANGE, this.onRotChange, this); this.transform.eventDispatcher.removeEventListener(Transform.SCALE_ONCHANGE, this.onScaleChange, this); From 0fd810d646e4eb2c271166c9ea5e34b01c3f6fe4 Mon Sep 17 00:00:00 2001 From: hellmor Date: Sat, 6 May 2023 13:35:20 +0800 Subject: [PATCH 092/100] feat(outline): add outlineManager (#97) add outline manager to support control of outline effects The outline effect cannot display properly and has been fixed. --- src/gfx/renderJob/post/OutlinePost.ts | 93 +++------------------------ src/io/OutlineManager.ts | 68 ++++++++++++++++++++ src/io/OutlinePostData.ts | 67 +++++++++++++++++++ 3 files changed, 143 insertions(+), 85 deletions(-) create mode 100644 src/io/OutlineManager.ts create mode 100644 src/io/OutlinePostData.ts diff --git a/src/gfx/renderJob/post/OutlinePost.ts b/src/gfx/renderJob/post/OutlinePost.ts index c2dd09f4..c591d195 100644 --- a/src/gfx/renderJob/post/OutlinePost.ts +++ b/src/gfx/renderJob/post/OutlinePost.ts @@ -1,4 +1,3 @@ - import { VirtualTexture } from '../../../textures/VirtualTexture'; import { StorageGPUBuffer } from '../../graphics/webGpu/core/buffer/StorageGPUBuffer'; import { UniformGPUBuffer } from '../../graphics/webGpu/core/buffer/UniformGPUBuffer'; @@ -11,7 +10,6 @@ import { RendererPassState } from '../passRenderer/state/RendererPassState'; import { PostBase } from './PostBase'; import { Engine3D } from '../../../Engine3D'; import { clamp } from '../../../math/MathUtil'; -import { Color } from '../../../math/Color'; import { Vector2 } from '../../../math/Vector2'; import { RTDescriptor } from '../../graphics/webGpu/descriptor/RTDescriptor'; import { GBufferFrame } from '../frame/GBufferFrame'; @@ -20,69 +18,8 @@ import { View3D } from '../../../core/View3D'; import { OutlineCalcOutline_cs } from '../../../assets/shader/compute/OutlineCalcOutline_cs'; import { Outline_cs } from '../../../assets/shader/compute/Outline_cs'; import { OutLineBlendColor_cs } from '../../../assets/shader/compute/OutLineBlendColor_cs'; +import { OutlinePostSlot, outlinePostData } from '../../../io/OutlinePostData'; -export class OutlinePostSlot { - public indexList: Float32Array; - public color: Color; - public count: number; -} - -export class OutlinePostData { - //max to 8 groups of different colors can be selected - public readonly SlotCount: number = 8; - public readonly MaxEntities: number = 16; - public readonly defaultColor: Color = new Color(0.2, 1, 1, 1); - private readonly slots: OutlinePostSlot[] = []; - - private dataDirty: boolean = true; - - constructor() { - let groupCount = Engine3D.setting.render.postProcessing.outline.groupCount; - this.SlotCount = Math.max(1, Math.min(groupCount, this.SlotCount)); - for (let i = 0; i < this.SlotCount; i++) { - let slot: OutlinePostSlot = (this.slots[i] = new OutlinePostSlot()); - slot.indexList = new Float32Array(this.MaxEntities); - slot.color = this.defaultColor.clone(); - slot.count = 0; - } - } - - public clear(): void { - for (let i = 0; i < this.SlotCount; i++) { - this.clearAt(i); - } - } - - public clearAt(slotIndex: number): this { - this.dataDirty = true; - let slot: OutlinePostSlot = this.slots[slotIndex]; - slot.color.copyForm(this.defaultColor); - slot.indexList.fill(-1); - slot.count = 0; - return this; - } - - public fillDataAt(slot: number, indexList: number[], color: Color): this { - this.dataDirty = true; - let data = this.slots[slot]; - if (data) { - data.indexList.fill(-1); - for (let i = 0, c = indexList.length; i < c; i++) { - data.indexList[i] = indexList[i]; - } - data.count = indexList.length; - data.color.copyForm(color); - } - return this; - } - - public fetchData(target: { dirty: boolean; slots: OutlinePostSlot[] }): this { - target.dirty = this.dataDirty; - target.slots = this.slots; - this.dataDirty = false; - return this; - } -} /** * post effect out line @@ -138,11 +75,8 @@ export class OutlinePost extends PostBase { oldOutlineColor: StorageGPUBuffer; rtFrame: RTFrame; - outlineData: OutlinePostData; - constructor() { super(); - this.outlineData = new OutlinePostData(); } /** @@ -208,7 +142,7 @@ export class OutlinePost extends PostBase { private createCompute() { let rtFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer"); - let visibleMap = rtFrame.getPositionMap();// RTResourceMap.getTexture(RTResourceConfig.zBufferTexture_NAME); + let visibleMap = rtFrame.getPositionMap(); this.calcWeightCompute = new ComputeShader(OutlineCalcOutline_cs); this.calcWeightCompute.setStorageBuffer('outlineSetting', this.outlineSetting); @@ -263,29 +197,18 @@ export class OutlinePost extends PostBase { outDec.clearValue = [0, 0, 0, 1]; outDec.loadOp = `clear`; - this.rtFrame = new RTFrame([ - this.outlineTex - ], [ - outDec - ]); - - let rtFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer"); - - // RTResourceMap.createRTTextures( - // [RTResourceConfig.colorBufferTex_NAME, RTResourceConfig.positionBufferTex_NAME, RTResourceConfig.normalBufferTex_NAME, RTResourceConfig.materialBufferTex_NAME], - // [GPUTextureFormat.rgba16float, GPUTextureFormat.rgba16float, GPUTextureFormat.rgba8unorm, GPUTextureFormat.rgba8unorm], - // ); + this.rtFrame = new RTFrame([this.outlineTex], [outDec]); this.outlineSetting = new UniformGPUBuffer(8); this.weightBuffer = new StorageGPUBuffer(this.lowTexSize.x * this.lowTexSize.y * 4, GPUBufferUsage.COPY_SRC); this.oldOutlineColor = new StorageGPUBuffer(this.lowTexSize.x * this.lowTexSize.y * 4, GPUBufferUsage.COPY_SRC); - this.slotsArray = new Float32Array(this.outlineData.SlotCount * 4); + this.slotsArray = new Float32Array(outlinePostData.SlotCount * 4); this.slotsBuffer = new StorageGPUBuffer(this.slotsArray.length); this.slotsBuffer.setFloat32Array('slotsArray', this.slotsArray); this.slotsBuffer.apply(); - this.entitiesArray = new Float32Array(this.outlineData.SlotCount * this.outlineData.MaxEntities); + this.entitiesArray = new Float32Array(outlinePostData.SlotCount * outlinePostData.MaxEntities); this.entitiesBuffer = new StorageGPUBuffer(this.entitiesArray.length); this.entitiesBuffer.setFloat32Array('entitiesArray', this.entitiesArray); this.slotsBuffer.apply(); @@ -296,10 +219,10 @@ export class OutlinePost extends PostBase { private fetchData: { dirty: boolean; slots: OutlinePostSlot[] }; private fetchOutlineData(): void { - this.outlineData.fetchData(this.fetchData); + outlinePostData.fetchData(this.fetchData); if (this.fetchData.dirty) { - let slotCount = this.outlineData.SlotCount; - let maxEntities = this.outlineData.MaxEntities; + let slotCount = outlinePostData.SlotCount; + let maxEntities = outlinePostData.MaxEntities; for (let i = 0; i < slotCount; i++) { let offset = 4 * i; let slot = this.fetchData.slots[i]; diff --git a/src/io/OutlineManager.ts b/src/io/OutlineManager.ts new file mode 100644 index 00000000..3c79a72b --- /dev/null +++ b/src/io/OutlineManager.ts @@ -0,0 +1,68 @@ +import { Object3D, Color, MeshRenderer, outlinePostData } from "@orillusion/core"; + +/** + * manager of outline effect + * @group IO + */ +export class OutlinePostManager { + + private _tempIndexArray: number[] = []; + + /** + * config outline manager. + * Specify specific 3D objects to use the specified color for display outline + * @param objectList A set of 3D objects + * @param color Specified color for outline + */ + public setOutline(objectList: Object3D[], color?: Color) { + this.setOutlineList([objectList], color ? [color] : null); + } + + /** + * config outline manager. + * The first set of objects uses the first color to display outline, and so on + * @param groupList A group of 3D objects set + * @param colorList Specified color list for outline + */ + public setOutlineList(groupList: Object3D[][], colorList?: Color[]) { + groupList ||= []; + let defaultColor = outlinePostData.defaultColor; + let maxGroup = outlinePostData.SlotCount; + for (let i = 0; i < maxGroup; i++) { + this._tempIndexArray.length = 0; + let group = groupList[i]; + let color = (colorList ? colorList[i] : null) || defaultColor; + if (group) { + for (const item of group) { + this.getEntityIdList(item, this._tempIndexArray); + } + } + outlinePostData.fillDataAt(i, this._tempIndexArray, color); + } + } + + /** + * clear outline effect + */ + public clearOutline(): this { + outlinePostData.clear(); + return this; + } + + private _rendererList: MeshRenderer[] = []; + + private getEntityIdList(item: Object3D, target: number[]): void { + this._rendererList.length = 0; + let renderers = item.getComponents(MeshRenderer, this._rendererList); + for (const render of renderers) { + target.push(render.object3D.transform._worldMatrix.index); + } + } + + +} + +/** + * @internal + */ +export let outlinePostManager: OutlinePostManager = new OutlinePostManager(); diff --git a/src/io/OutlinePostData.ts b/src/io/OutlinePostData.ts new file mode 100644 index 00000000..4aef8446 --- /dev/null +++ b/src/io/OutlinePostData.ts @@ -0,0 +1,67 @@ +import { Engine3D } from "../Engine3D"; +import { Color } from "../math/Color"; + +export class OutlinePostSlot { + public indexList: Float32Array; + public color: Color; + public count: number; +} + +export class OutlinePostData { + //Supports up to 8 sets of colors + public readonly SlotCount: number = 8; + public readonly MaxEntities: number = 16; + public readonly defaultColor: Color = new Color(0.2, 1, 1, 1); + private readonly slots: OutlinePostSlot[] = []; + + private dataDirty: boolean = true; + + constructor() { + let groupCount = Engine3D.setting.render.postProcessing.outline.groupCount; + this.SlotCount = Math.max(1, Math.min(groupCount, this.SlotCount)); + for (let i = 0; i < this.SlotCount; i++) { + let slot: OutlinePostSlot = (this.slots[i] = new OutlinePostSlot()); + slot.indexList = new Float32Array(this.MaxEntities); + slot.color = this.defaultColor.clone(); + slot.count = 0; + } + } + + public clear(): void { + for (let i = 0; i < this.SlotCount; i++) { + this.clearAt(i); + } + } + + public clearAt(slotIndex: number): this { + this.dataDirty = true; + let slot: OutlinePostSlot = this.slots[slotIndex]; + slot.color.copyForm(this.defaultColor); + slot.indexList.fill(-1); + slot.count = 0; + return this; + } + + public fillDataAt(slot: number, indexList: number[], color: Color): this { + this.dataDirty = true; + let data = this.slots[slot]; + if (data) { + data.indexList.fill(-1); + for (let i = 0, c = indexList.length; i < c; i++) { + data.indexList[i] = indexList[i]; + } + data.count = indexList.length; + data.color.copyForm(color); + } + return this; + } + + public fetchData(target: { dirty: boolean; slots: OutlinePostSlot[] }): this { + target.dirty = this.dataDirty; + target.slots = this.slots; + this.dataDirty = false; + return this; + } +} + +export let outlinePostData: OutlinePostData = new OutlinePostData(); \ No newline at end of file From 5dff35cf5a945b9a238930b0553164fbcbaabc45 Mon Sep 17 00:00:00 2001 From: hellmor Date: Sat, 6 May 2023 15:35:05 +0800 Subject: [PATCH 093/100] feat(outline): add OutlineManager (#104) Revert "feat(outline): add outlineManager (#97)" Add outlineManager. --- src/index.ts | 2 ++ src/io/OutlineManager.ts | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 690142d5..1996f6b8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -295,6 +295,8 @@ export * from "./gfx/renderJob/post/PostBase" export * from "./gfx/renderJob/post/SSRPost" export * from "./gfx/renderJob/post/TAAPost" export * from "./io/InputSystem" +export * from "./io/OutlineManager" +export * from "./io/OutlinePostData" export * from "./io/PickFire" export * from "./io/PickResult" export * from "./io/RayCastMeshDetail" diff --git a/src/io/OutlineManager.ts b/src/io/OutlineManager.ts index 3c79a72b..5b91379a 100644 --- a/src/io/OutlineManager.ts +++ b/src/io/OutlineManager.ts @@ -1,4 +1,7 @@ -import { Object3D, Color, MeshRenderer, outlinePostData } from "@orillusion/core"; +import { MeshRenderer } from "../components/renderer/MeshRenderer"; +import { Object3D } from "../core/entities/Object3D"; +import { Color } from "../math/Color"; +import { outlinePostData } from "./OutlinePostData"; /** * manager of outline effect From 391679490468a63856765a03426539d344615585 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Sat, 6 May 2023 16:45:49 +0800 Subject: [PATCH 094/100] chore: import dat.gui types(packages) & remove underscore.js(test) (#103) * import dat.gui types * remove underscore.js * rename wrong filename tests --- packages/debug/GUIHelp.ts | 2 - packages/debug/dat.gui.d.ts | 138 +++ packages/debug/tsconfig.json | 12 + src/index.ts | 896 +++++++++--------- test/base/EngineInit.test.ts | 9 + test/base/base.test.ts | 7 - .../{component.test.ts => Component.test.ts} | 0 ...test.ts => ComponentLife-Camera3D.test.ts} | 0 ...gShadow.test.ts => LightingShadow.test.ts} | 0 .../{transform.test.ts => Transform.test.ts} | 0 test/index.ts | 2 +- test/util.ts | 28 +- 12 files changed, 633 insertions(+), 461 deletions(-) create mode 100644 packages/debug/dat.gui.d.ts create mode 100644 packages/debug/tsconfig.json create mode 100644 test/base/EngineInit.test.ts delete mode 100644 test/base/base.test.ts rename test/components/{component.test.ts => Component.test.ts} (100%) rename test/components/{componentLife-Camera3D.test.ts => ComponentLife-Camera3D.test.ts} (100%) rename test/components/{lightingShadow.test.ts => LightingShadow.test.ts} (100%) rename test/components/{transform.test.ts => Transform.test.ts} (100%) diff --git a/packages/debug/GUIHelp.ts b/packages/debug/GUIHelp.ts index c2136dac..4d0a564b 100644 --- a/packages/debug/GUIHelp.ts +++ b/packages/debug/GUIHelp.ts @@ -1,7 +1,5 @@ -// @ts-ignore import { GUI } from 'https://unpkg.com/dat.gui@0.7.9/build/dat.gui.module.js' - /** * @internal */ diff --git a/packages/debug/dat.gui.d.ts b/packages/debug/dat.gui.d.ts new file mode 100644 index 00000000..4485e2c7 --- /dev/null +++ b/packages/debug/dat.gui.d.ts @@ -0,0 +1,138 @@ +declare module "https://unpkg.com/dat.gui*" { + export interface GUIParams { + /** + * Handles GUI's element placement for you. + * @default true + */ + autoPlace?: boolean | undefined; + /** + * If true, starts closed. + * @default false + */ + closed?: boolean | undefined; + /** + * If true, close/open button shows on top of the GUI. + * @default false + */ + closeOnTop?: boolean | undefined; + /** + * If true, GUI is closed by the "h" keypress. + * @default false + */ + hideable?: boolean | undefined; + /** + * JSON object representing the saved state of this GUI. + */ + load?: any; + /** + * The name of this GUI. + */ + name?: string | undefined; + /** + * The identifier for a set of saved values. + */ + preset?: string | undefined; + /** + * The width of GUI element. + */ + width?: number | undefined; + } + export class GUI { + static CLASS_AUTO_PLACE: string; + static CLASS_AUTO_PLACE_CONTAINER: string; + static CLASS_MAIN: string; + static CLASS_CONTROLLER_ROW: string; + static CLASS_TOO_TALL: string; + static CLASS_CLOSED: string; + static CLASS_CLOSE_BUTTON: string; + static CLASS_CLOSE_TOP: string; + static CLASS_CLOSE_BOTTOM: string; + static CLASS_DRAG: string; + static DEFAULT_WIDTH: number; + static TEXT_CLOSED: string; + static TEXT_OPEN: string; + + constructor(option?: GUIParams); + + __controllers: GUIController[]; + __folders: { [folderName: string]: GUI }; + domElement: HTMLElement; + + add( + target: T, + propName: keyof T, + min?: number, + max?: number, + step?: number, + ): GUIController; + add(target: T, propName: keyof T, status: boolean): GUIController; + add(target: T, propName: keyof T, items: string[]): GUIController; + add(target: T, propName: keyof T, items: number[]): GUIController; + add(target: T, propName: keyof T, items: Object): GUIController; + + addColor(target: Object, propName: string): GUIController; + + remove(controller: GUIController): void; + destroy(): void; + + addFolder(propName: string): GUI; + removeFolder(subFolder: GUI): void; + + open(): void; + close(): void; + hide(): void; + show(): void; + + remember(target: Object, ...additionalTargets: Object[]): void; + getRoot(): GUI; + + getSaveObject(): Object; + save(): void; + saveAs(presetName: string): void; + revert(gui: GUI): void; + + listen(controller: GUIController): void; + updateDisplay(): void; + + // gui properties in dat/gui/GUI.js + readonly parent: GUI; + readonly scrollable: boolean; + readonly autoPlace: boolean; + preset: string; + width: number; + name: string; + closed: boolean; + readonly load: Object; + useLocalStorage: boolean; + } + export class GUIController { + domElement: HTMLElement; + object: Object; + property: string; + + constructor(object: T, property: keyof T); + + options(option: any): GUIController; + name(name: string): GUIController; + + listen(): GUIController; + remove(): GUIController; + + onChange(fnc: (value?: any) => void): GUIController; + onFinishChange(fnc: (value?: any) => void): GUIController; + + setValue(value: any): GUIController; + getValue(): any; + + updateDisplay(): GUIController; + isModified(): boolean; + + // NumberController + min(n: number): GUIController; + max(n: number): GUIController; + step(n: number): GUIController; + + // FunctionController + fire(): GUIController; + } +} \ No newline at end of file diff --git a/packages/debug/tsconfig.json b/packages/debug/tsconfig.json new file mode 100644 index 00000000..6472f19e --- /dev/null +++ b/packages/debug/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "Node", + "sourceMap": false, + "resolveJsonModule": true, + "esModuleInterop": true + } +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 1996f6b8..618425cd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,448 +1,448 @@ -export * from "./Engine3D" -export * from "./assets/Res" -export * from "./assets/shader/ShaderLib" -export * from "./assets/shader/anim/SkeletonAnimation_shader" -export * from "./assets/shader/cluster/ClusterBoundsSource_cs" -export * from "./assets/shader/cluster/ClusterLighting_cs" -export * from "./assets/shader/compute/BLUR_CsShader" -export * from "./assets/shader/compute/BlurEffectCreator_cs" -export * from "./assets/shader/compute/DepthOfView_cs" -export * from "./assets/shader/compute/ErpImage2CubeMapCreateCube_cs" -export * from "./assets/shader/compute/ErpImage2CubeMapRgbe2rgba_cs" -export * from "./assets/shader/compute/GTAO_cs" -export * from "./assets/shader/compute/IBLEnvMapCreator_cs" -export * from "./assets/shader/compute/MergeRGBA_cs" -export * from "./assets/shader/compute/MultiBouncePass_cs" -export * from "./assets/shader/compute/OutLineBlendColor_cs" -export * from "./assets/shader/compute/OutlineCalcOutline_cs" -export * from "./assets/shader/compute/Outline_cs" -export * from "./assets/shader/compute/Picker_cs" -export * from "./assets/shader/compute/SSAO_cs" -export * from "./assets/shader/compute/SSR_BlendColor_cs" -export * from "./assets/shader/compute/SSR_IS_cs" -export * from "./assets/shader/compute/SSR_RayTrace_cs" -export * from "./assets/shader/compute/TAACopyTex_cs" -export * from "./assets/shader/compute/TAASharpTex_cs" -export * from "./assets/shader/compute/TAA_cs" -export * from "./assets/shader/core/base/Common_frag" -export * from "./assets/shader/core/base/Common_vert" -export * from "./assets/shader/core/common/BrdfLut_frag" -export * from "./assets/shader/core/common/EnvMap_frag" -export * from "./assets/shader/core/common/GlobalUniform" -export * from "./assets/shader/core/common/InstanceUniform" -export * from "./assets/shader/core/common/WorldMatrixUniform" -export * from "./assets/shader/core/inline/Inline_vert" -export * from "./assets/shader/core/pass/CastShadow_pass" -export * from "./assets/shader/core/pass/FrustumCulling_cs" -export * from "./assets/shader/core/pass/GBuffer_pass" -export * from "./assets/shader/core/pass/SkyGBuffer_pass" -export * from "./assets/shader/core/pass/ZPassShader_cs" -export * from "./assets/shader/core/pass/ZPassShader_fs" -export * from "./assets/shader/core/pass/ZPassShader_vs" -export * from "./assets/shader/core/struct/ColorPassFragmentOutput" -export * from "./assets/shader/core/struct/EmptyFrag_CommonFragment" -export * from "./assets/shader/core/struct/EmptyFrag_FragmentOutput" -export * from "./assets/shader/core/struct/FragmentVarying" -export * from "./assets/shader/core/struct/LightStruct" -export * from "./assets/shader/core/struct/LightStructFrag" -export * from "./assets/shader/core/struct/ShadingInput" -export * from "./assets/shader/core/struct/VertexAttributes" -export * from "./assets/shader/glsl/Quad_glsl" -export * from "./assets/shader/glsl/Sky_glsl" -export * from "./assets/shader/glsl/post/LUT_glsl" -export * from "./assets/shader/graphic/Graphic3DShader_fs" -export * from "./assets/shader/graphic/Graphic3DShader_vs" -export * from "./assets/shader/lighting/BRDF_frag" -export * from "./assets/shader/lighting/BxDF_frag" -export * from "./assets/shader/lighting/IESProfiles_frag" -export * from "./assets/shader/lighting/IrradianceVolumeData_frag" -export * from "./assets/shader/lighting/Irradiance_frag" -export * from "./assets/shader/lighting/LightingFunction_frag" -export * from "./assets/shader/lighting/UnLit_frag" -export * from "./assets/shader/materials/ColorLitShader" -export * from "./assets/shader/materials/GlassShader" -export * from "./assets/shader/materials/Lambert_shader" -export * from "./assets/shader/materials/LitShader" -export * from "./assets/shader/materials/OutlinePass" -export * from "./assets/shader/materials/PBRLItShader" -export * from "./assets/shader/materials/PavementShader" -export * from "./assets/shader/materials/PointShadowDebug" -export * from "./assets/shader/materials/UnLit" -export * from "./assets/shader/materials/program/BxdfDebug_frag" -export * from "./assets/shader/materials/program/Clearcoat_frag" -export * from "./assets/shader/materials/program/ClusterDebug_frag" -export * from "./assets/shader/materials/program/NormalMap_frag" -export * from "./assets/shader/materials/program/ShadowMapping_frag" -export * from "./assets/shader/materials/uniforms/MaterialUniform" -export * from "./assets/shader/materials/uniforms/PhysicMaterialUniform_frag" -export * from "./assets/shader/materials/uniforms/UnLitMaterialUniform_frag" -export * from "./assets/shader/materials/uniforms/VideoUniform_frag" -export * from "./assets/shader/math/FastMathShader" -export * from "./assets/shader/math/MathShader" -export * from "./assets/shader/post/Bloom_shader" -export * from "./assets/shader/post/FXAAShader" -export * from "./assets/shader/post/GlobalFog_shader" -export * from "./assets/shader/quad/Quad_shader" -export * from "./assets/shader/sky/AtmosphericScatteringSky_shader" -export * from "./assets/shader/sky/CubeSky_Shader" -export * from "./assets/shader/utils/BRDFLUT" -export * from "./assets/shader/utils/ColorUtil" -export * from "./assets/shader/utils/GenerayRandomDir" -export * from "./components/AtmosphericComponent" -export * from "./components/BillboardComponent" -export * from "./components/ColliderComponent" -export * from "./components/ComponentBase" -export * from "./components/IComponent" -export * from "./components/SkeletonAnimationComponent" -export * from "./components/Transform" -export * from "./components/anim/OAnimationEvent" -export * from "./components/anim/curveAnim/AnimationMonitor" -export * from "./components/anim/curveAnim/AttributeAnimCurve" -export * from "./components/anim/curveAnim/PropertyAnimClip" -export * from "./components/anim/curveAnim/PropertyAnimation" -export * from "./components/anim/curveAnim/PropertyAnimationEvent" -export * from "./components/anim/curveAnim/PropertyHelp" -export * from "./components/anim/morphAnim/MorphTargetBlender" -export * from "./components/anim/morphAnim/MorphTargetData" -export * from "./components/anim/morphAnim/MorphTargetFrame" -export * from "./components/anim/morphAnim/MorphTargetKey" -export * from "./components/anim/morphAnim/MorphTarget_shader" -export * from "./components/anim/skeletonAnim/Joint" -export * from "./components/anim/skeletonAnim/JointPose" -export * from "./components/anim/skeletonAnim/Skeleton" -export * from "./components/anim/skeletonAnim/SkeletonAnimationClip" -export * from "./components/anim/skeletonAnim/SkeletonAnimationClipState" -export * from "./components/anim/skeletonAnim/SkeletonAnimationCompute" -export * from "./components/anim/skeletonAnim/SkeletonPose" -export * from "./components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs" -export * from "./components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs" -export * from "./components/anim/skeletonAnim/shader/compute_skeleton_blend" -export * from "./components/anim/skeletonAnim/shader/compute_skeleton_transform" -export * from "./components/audio/AudioListener" -export * from "./components/audio/PositionAudio" -export * from "./components/audio/StaticAudio" -export * from "./components/controller/CameraControllerBase" -export * from "./components/controller/FirstPersonCameraController" -export * from "./components/controller/FlyCameraController" -export * from "./components/controller/HoverCameraController" -export * from "./components/controller/OrbitController" -export * from "./components/controller/ThirdPersonCameraController" -export * from "./components/lights/DirectLight" -export * from "./components/lights/GILighting" -export * from "./components/lights/IESProfiles" -export * from "./components/lights/ILight" -export * from "./components/lights/LightBase" -export * from "./components/lights/LightData" -export * from "./components/lights/PointLight" -export * from "./components/lights/SpotLight" -export * from "./components/post/PostProcessingComponent" -export * from "./components/renderer/InstanceDrawComponent" -export * from "./components/renderer/MaterialComponent" -export * from "./components/renderer/MeshComponent" -export * from "./components/renderer/MeshRenderer" -export * from "./components/renderer/RenderNode" -export * from "./components/renderer/SkinnedMeshRenderer" -export * from "./components/renderer/SkyRenderer" -export * from "./components/shape/BoxColliderShape" -export * from "./components/shape/CapsuleColliderShape" -export * from "./components/shape/ColliderShape" -export * from "./components/shape/MeshColliderShape" -export * from "./components/shape/SphereColliderShape" -export * from "./core/Camera3D" -export * from "./core/CameraType" -export * from "./core/CubeCamera" -export * from "./core/PointShadowCubeCamera" -export * from "./core/Scene3D" -export * from "./core/View3D" -export * from "./core/ViewQuad" -export * from "./core/bound/BoundingBox" -export * from "./core/bound/BoundingSphere" -export * from "./core/bound/Frustum" -export * from "./core/bound/IBound" -export * from "./core/entities/Entity" -export * from "./core/entities/InstancedMesh" -export * from "./core/entities/Object3D" -export * from "./core/geometry/GeometryBase" -export * from "./core/geometry/GeometryIndicesBuffer" -export * from "./core/geometry/GeometryVertexBuffer" -export * from "./core/geometry/GeometryVertexType" -export * from "./core/geometry/VertexAttribute" -export * from "./core/geometry/VertexAttributeData" -export * from "./core/geometry/VertexAttributeName" -export * from "./core/geometry/VertexAttributeSize" -export * from "./core/geometry/VertexAttributeStride" -export * from "./core/geometry/VertexFormat" -export * from "./core/pool/ObjectPool" -export * from "./core/pool/memory/MatrixDO" -export * from "./core/pool/memory/MemoryDO" -export * from "./core/pool/memory/MemoryInfo" -export * from "./core/tree/kdTree/IKDTreeUserData" -export * from "./core/tree/kdTree/KDTreeEntity" -export * from "./core/tree/kdTree/KDTreeNode" -export * from "./core/tree/kdTree/KDTreeSpace" -export * from "./event/CEvent" -export * from "./event/CEventDispatcher" -export * from "./event/CEventListener" -export * from "./event/CResizeEvent" -export * from "./event/KeyCode" -export * from "./event/MouseCode" -export * from "./event/eventConst/KeyEvent" -export * from "./event/eventConst/LoaderEvent" -export * from "./event/eventConst/Object3DEvent" -export * from "./event/eventConst/PointerEvent3D" -export * from "./event/eventConst/UIEvent" -export * from "./gfx/data/IrradianceVolume" -export * from "./gfx/generate/BrdfLUTGenerate" -export * from "./gfx/generate/PassGenerate" -export * from "./gfx/generate/convert/BlurEffectCreator" -export * from "./gfx/generate/convert/ErpImage2CubeMap" -export * from "./gfx/generate/convert/IBLEnvMapCreator" -export * from "./gfx/generate/convert/MergeRGBACreator" -export * from "./gfx/generate/convert/TextureCubeStdCreator" -export * from "./gfx/generate/convert/TextureCubeUtils" -export * from "./gfx/graphics/webGpu/CanvasConfig" -export * from "./gfx/graphics/webGpu/Context3D" -export * from "./gfx/graphics/webGpu/WebGPUConst" -export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup" -export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout" -export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup" -export * from "./gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup" -export * from "./gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup" -export * from "./gfx/graphics/webGpu/core/bindGroups/groups/LightEntries" -export * from "./gfx/graphics/webGpu/core/buffer/ArrayBufferData" -export * from "./gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferBase" -export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferType" -export * from "./gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/StorageGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/UniformGPUBuffer" -export * from "./gfx/graphics/webGpu/core/buffer/VertexGPUBuffer" -export * from "./gfx/graphics/webGpu/core/texture/ITexture" -export * from "./gfx/graphics/webGpu/core/texture/Texture" -export * from "./gfx/graphics/webGpu/core/texture/TextureCube" -export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapCompute" -export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapGenerator" -export * from "./gfx/graphics/webGpu/core/uniforms/UniformNode" -export * from "./gfx/graphics/webGpu/descriptor/RTDescriptor" -export * from "./gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator" -export * from "./gfx/graphics/webGpu/shader/ComputeShader" -export * from "./gfx/graphics/webGpu/shader/RenderShader" -export * from "./gfx/graphics/webGpu/shader/ShaderBase" -export * from "./gfx/graphics/webGpu/shader/ShaderStage" -export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexer" -export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexerToken" -export * from "./gfx/graphics/webGpu/shader/converter/GLSLPreprocessor" -export * from "./gfx/graphics/webGpu/shader/converter/GLSLSyntax" -export * from "./gfx/graphics/webGpu/shader/converter/Reader" -export * from "./gfx/graphics/webGpu/shader/converter/ShaderConverter" -export * from "./gfx/graphics/webGpu/shader/converter/StatementNode" -export * from "./gfx/graphics/webGpu/shader/converter/WGSLTranslator" -export * from "./gfx/graphics/webGpu/shader/util/MorePassParser" -export * from "./gfx/graphics/webGpu/shader/util/Preprocessor" -export * from "./gfx/graphics/webGpu/shader/util/ShaderUtil" -export * from "./gfx/graphics/webGpu/shader/value/ConstValue" -export * from "./gfx/graphics/webGpu/shader/value/DefineValue" -export * from "./gfx/graphics/webGpu/shader/value/ShaderReflectionInfo" -export * from "./gfx/graphics/webGpu/shader/value/ShaderState" -export * from "./gfx/graphics/webGpu/shader/value/ShaderValue" -export * from "./gfx/graphics/webGpu/shader/value/UniformValue" -export * from "./gfx/renderJob/GPUContext" -export * from "./gfx/renderJob/collect/CollectInfo" -export * from "./gfx/renderJob/collect/ComponentCollect" -export * from "./gfx/renderJob/collect/EntityBatchCollect" -export * from "./gfx/renderJob/collect/EntityCollect" -export * from "./gfx/renderJob/collect/RenderGroup" -export * from "./gfx/renderJob/collect/ShadowLightsCollect" -export * from "./gfx/renderJob/config/RTResourceConfig" -export * from "./gfx/renderJob/config/RenderLayer" -export * from "./gfx/renderJob/frame/GBufferFrame" -export * from "./gfx/renderJob/frame/ProbeGBufferFrame" -export * from "./gfx/renderJob/frame/RTFrame" -export * from "./gfx/renderJob/frame/RTResourceMap" -export * from "./gfx/renderJob/jobs/ForwardRenderJob" -export * from "./gfx/renderJob/jobs/RenderMap" -export * from "./gfx/renderJob/jobs/RendererJob" -export * from "./gfx/renderJob/occlusion/OcclusionSystem" -export * from "./gfx/renderJob/passRenderer/RenderContext" -export * from "./gfx/renderJob/passRenderer/RendererBase" -export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer" -export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingRender" -export * from "./gfx/renderJob/passRenderer/color/ColorPassRenderer" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer" -export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DRender" -export * from "./gfx/renderJob/passRenderer/graphic/GraphicConfig" -export * from "./gfx/renderJob/passRenderer/graphic/Graphics3DShape" -export * from "./gfx/renderJob/passRenderer/post/PostRenderer" -export * from "./gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer" -export * from "./gfx/renderJob/passRenderer/preDepth/ZCullingCompute" -export * from "./gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer" -export * from "./gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer" -export * from "./gfx/renderJob/passRenderer/state/RendererMask" -export * from "./gfx/renderJob/passRenderer/state/RendererPassState" -export * from "./gfx/renderJob/passRenderer/state/RendererType" -export * from "./gfx/renderJob/post/DepthOfFieldPost" -export * from "./gfx/renderJob/post/FXAAPost" -export * from "./gfx/renderJob/post/GTAOPost" -export * from "./gfx/renderJob/post/GlobalFog" -export * from "./gfx/renderJob/post/HDRBloomPost" -export * from "./gfx/renderJob/post/OutlinePost" -export * from "./gfx/renderJob/post/PostBase" -export * from "./gfx/renderJob/post/SSRPost" -export * from "./gfx/renderJob/post/TAAPost" -export * from "./io/InputSystem" -export * from "./io/OutlineManager" -export * from "./io/OutlinePostData" -export * from "./io/PickFire" -export * from "./io/PickResult" -export * from "./io/RayCastMeshDetail" -export * from "./io/TouchData" -export * from "./io/picker/PickCompute" -export * from "./loader/FileLoader" -export * from "./loader/LoaderBase" -export * from "./loader/LoaderData" -export * from "./loader/LoaderFunctions" -export * from "./loader/LoaderManager" -export * from "./loader/parser/B3DMParser" -export * from "./loader/parser/I3DMParser" -export * from "./loader/parser/OBJParser" -export * from "./loader/parser/ParserBase" -export * from "./loader/parser/RGBEParser" -export * from "./loader/parser/b3dm/B3DMLoader" -export * from "./loader/parser/b3dm/B3DMLoaderBase" -export * from "./loader/parser/b3dm/FeatureTable" -export * from "./loader/parser/b3dm/arrayToString" -export * from "./loader/parser/b3dm/readMagicBytes" -export * from "./loader/parser/gltf/GLBParser" -export * from "./loader/parser/gltf/GLTFInfo" -export * from "./loader/parser/gltf/GLTFParser" -export * from "./loader/parser/gltf/GLTFSubParser" -export * from "./loader/parser/gltf/GLTFSubParserCamera" -export * from "./loader/parser/gltf/GLTFSubParserConverter" -export * from "./loader/parser/gltf/GLTFSubParserMaterial" -export * from "./loader/parser/gltf/GLTFSubParserMesh" -export * from "./loader/parser/gltf/GLTFSubParserSkeleton" -export * from "./loader/parser/gltf/GLTFSubParserSkin" -export * from "./loader/parser/gltf/GLTFType" -export * from "./loader/parser/gltf/TypeArray" -export * from "./loader/parser/gltf/extends/KHR_draco_mesh_compression" -export * from "./loader/parser/gltf/extends/KHR_lights_punctual" -export * from "./loader/parser/gltf/extends/KHR_materials_clearcoat" -export * from "./loader/parser/gltf/extends/KHR_materials_emissive_strength" -export * from "./loader/parser/gltf/extends/KHR_materials_ior" -export * from "./loader/parser/gltf/extends/KHR_materials_sheen" -export * from "./loader/parser/gltf/extends/KHR_materials_specular" -export * from "./loader/parser/gltf/extends/KHR_materials_transmission" -export * from "./loader/parser/gltf/extends/KHR_materials_unlit" -export * from "./loader/parser/gltf/extends/KHR_materials_variants" -export * from "./loader/parser/gltf/extends/KHR_materials_volume" -export * from "./loader/parser/gltf/extends/KHR_mesh_quantization" -export * from "./loader/parser/gltf/extends/KHR_texture_basisu" -export * from "./loader/parser/gltf/extends/KHR_texture_transform" -export * from "./loader/parser/i3dm/I3DMLoader" -export * from "./loader/parser/i3dm/I3DMLoaderBase" -export * from "./loader/parser/tileRenderer/TileSet" -export * from "./loader/parser/tileRenderer/TilesRenderer" -export * from "./materials/BlendMode" -export * from "./materials/ColorLitMaterial" -export * from "./materials/GlassMaterial" -export * from "./materials/LambertMaterial" -export * from "./materials/LitMaterial" -export * from "./materials/MaterialBase" -export * from "./materials/MaterialPass" -export * from "./materials/MaterialRegister" -export * from "./materials/PavementMaterial" -export * from "./materials/PhysicMaterial" -export * from "./materials/PointMaterial" -export * from "./materials/SkyMaterial" -export * from "./materials/UnLitMaterial" -export * from "./materials/multiPass/CastPointShadowMaterialPass" -export * from "./materials/multiPass/CastShadowMaterialPass" -export * from "./materials/multiPass/DepthMaterialPass" -export * from "./materials/multiPass/GBufferPass" -export * from "./materials/multiPass/SkyGBufferPass" -export * from "./math/AnimationCurve" -export * from "./math/Bezier2D" -export * from "./math/Bezier3D" -export * from "./math/Color" -export * from "./math/CubicBezierCurve" -export * from "./math/CubicBezierPath" -export * from "./math/HaltonSeq" -export * from "./math/Line" -export * from "./math/MathUtil" -export * from "./math/Matrix3" -export * from "./math/Matrix4" -export * from "./math/Orientation3D" -export * from "./math/ParticleMath" -export * from "./math/ParticleSystemCurves" -export * from "./math/Plane" -export * from "./math/PolynomialCurve" -export * from "./math/Polynomials" -export * from "./math/Quaternion" -export * from "./math/Rand" -export * from "./math/Random" -export * from "./math/Ray" -export * from "./math/Rect" -export * from "./math/TimeInterpolator" -export * from "./math/Triangle" -export * from "./math/UV" -export * from "./math/Vector2" -export * from "./math/Vector3" -export * from "./math/Vector4" -export * from "./setting/EngineSetting" -export * from "./setting/GlobalIlluminationSetting" -export * from "./setting/LightSetting" -export * from "./setting/MaterialSetting" -export * from "./setting/OcclusionQuerySetting" -export * from "./setting/PickSetting" -export * from "./setting/RenderSetting" -export * from "./setting/ShadowSetting" -export * from "./setting/SkySetting" -export * from "./setting/post/BloomSetting" -export * from "./setting/post/DepthOfViewSetting" -export * from "./setting/post/GTAOSetting" -export * from "./setting/post/GlobalFogSetting" -export * from "./setting/post/OutlineSetting" -export * from "./setting/post/SSRSetting" -export * from "./setting/post/TAASetting" -export * from "./shape/BoxGeometry" -export * from "./shape/CylinderGeometry" -export * from "./shape/PlaneGeometry" -export * from "./shape/SphereGeometry" -export * from "./shape/TorusGeometry" -export * from "./textures/AtmosphericScatteringSky" -export * from "./textures/BitmapTexture2D" -export * from "./textures/BitmapTexture2DArray" -export * from "./textures/BitmapTextureCube" -export * from "./textures/Depth2DTextureArray" -export * from "./textures/DepthCubeArrayTexture" -export * from "./textures/DepthCubeTexture" -export * from "./textures/Float16ArrayTexture" -export * from "./textures/Float32ArrayTexture" -export * from "./textures/HDRTexture" -export * from "./textures/HDRTextureCube" -export * from "./textures/LDRTextureCube" -export * from "./textures/SolidColorSky" -export * from "./textures/Uint16Texture" -export * from "./textures/Uint8ArrayTexture" -export * from "./textures/VirtualTexture" -export * from "./util/AxisObject" -export * from "./util/BytesStream" -export * from "./util/CameraUtil" -export * from "./util/Convert" -export * from "./util/GeometryUtil" -export * from "./util/Global" -export * from "./util/KelvinUtil" -export * from "./util/Object3DUtil" -export * from "./util/ProfilerUtil" -export * from "./util/StringUtil" -export * from "./util/Time" -export * from "./util/Vector3Ex" -export * from "./util/ZSorterUtil" -export * from "./util/struct/Struct" -export * from "./util/struct/StructValue" -export * from "./util/struct/Vector3Struct" +export * from "./Engine3D" +export * from "./assets/Res" +export * from "./assets/shader/ShaderLib" +export * from "./assets/shader/anim/SkeletonAnimation_shader" +export * from "./assets/shader/cluster/ClusterBoundsSource_cs" +export * from "./assets/shader/cluster/ClusterLighting_cs" +export * from "./assets/shader/compute/BLUR_CsShader" +export * from "./assets/shader/compute/BlurEffectCreator_cs" +export * from "./assets/shader/compute/DepthOfView_cs" +export * from "./assets/shader/compute/ErpImage2CubeMapCreateCube_cs" +export * from "./assets/shader/compute/ErpImage2CubeMapRgbe2rgba_cs" +export * from "./assets/shader/compute/GTAO_cs" +export * from "./assets/shader/compute/IBLEnvMapCreator_cs" +export * from "./assets/shader/compute/MergeRGBA_cs" +export * from "./assets/shader/compute/MultiBouncePass_cs" +export * from "./assets/shader/compute/OutLineBlendColor_cs" +export * from "./assets/shader/compute/OutlineCalcOutline_cs" +export * from "./assets/shader/compute/Outline_cs" +export * from "./assets/shader/compute/Picker_cs" +export * from "./assets/shader/compute/SSAO_cs" +export * from "./assets/shader/compute/SSR_BlendColor_cs" +export * from "./assets/shader/compute/SSR_IS_cs" +export * from "./assets/shader/compute/SSR_RayTrace_cs" +export * from "./assets/shader/compute/TAACopyTex_cs" +export * from "./assets/shader/compute/TAASharpTex_cs" +export * from "./assets/shader/compute/TAA_cs" +export * from "./assets/shader/core/base/Common_frag" +export * from "./assets/shader/core/base/Common_vert" +export * from "./assets/shader/core/common/BrdfLut_frag" +export * from "./assets/shader/core/common/EnvMap_frag" +export * from "./assets/shader/core/common/GlobalUniform" +export * from "./assets/shader/core/common/InstanceUniform" +export * from "./assets/shader/core/common/WorldMatrixUniform" +export * from "./assets/shader/core/inline/Inline_vert" +export * from "./assets/shader/core/pass/CastShadow_pass" +export * from "./assets/shader/core/pass/FrustumCulling_cs" +export * from "./assets/shader/core/pass/GBuffer_pass" +export * from "./assets/shader/core/pass/SkyGBuffer_pass" +export * from "./assets/shader/core/pass/ZPassShader_cs" +export * from "./assets/shader/core/pass/ZPassShader_fs" +export * from "./assets/shader/core/pass/ZPassShader_vs" +export * from "./assets/shader/core/struct/ColorPassFragmentOutput" +export * from "./assets/shader/core/struct/EmptyFrag_CommonFragment" +export * from "./assets/shader/core/struct/EmptyFrag_FragmentOutput" +export * from "./assets/shader/core/struct/FragmentVarying" +export * from "./assets/shader/core/struct/LightStruct" +export * from "./assets/shader/core/struct/LightStructFrag" +export * from "./assets/shader/core/struct/ShadingInput" +export * from "./assets/shader/core/struct/VertexAttributes" +export * from "./assets/shader/glsl/Quad_glsl" +export * from "./assets/shader/glsl/Sky_glsl" +export * from "./assets/shader/glsl/post/LUT_glsl" +export * from "./assets/shader/graphic/Graphic3DShader_fs" +export * from "./assets/shader/graphic/Graphic3DShader_vs" +export * from "./assets/shader/lighting/BRDF_frag" +export * from "./assets/shader/lighting/BxDF_frag" +export * from "./assets/shader/lighting/IESProfiles_frag" +export * from "./assets/shader/lighting/IrradianceVolumeData_frag" +export * from "./assets/shader/lighting/Irradiance_frag" +export * from "./assets/shader/lighting/LightingFunction_frag" +export * from "./assets/shader/lighting/UnLit_frag" +export * from "./assets/shader/materials/ColorLitShader" +export * from "./assets/shader/materials/GlassShader" +export * from "./assets/shader/materials/Lambert_shader" +export * from "./assets/shader/materials/LitShader" +export * from "./assets/shader/materials/OutlinePass" +export * from "./assets/shader/materials/PBRLItShader" +export * from "./assets/shader/materials/PavementShader" +export * from "./assets/shader/materials/PointShadowDebug" +export * from "./assets/shader/materials/UnLit" +export * from "./assets/shader/materials/program/BxdfDebug_frag" +export * from "./assets/shader/materials/program/Clearcoat_frag" +export * from "./assets/shader/materials/program/ClusterDebug_frag" +export * from "./assets/shader/materials/program/NormalMap_frag" +export * from "./assets/shader/materials/program/ShadowMapping_frag" +export * from "./assets/shader/materials/uniforms/MaterialUniform" +export * from "./assets/shader/materials/uniforms/PhysicMaterialUniform_frag" +export * from "./assets/shader/materials/uniforms/UnLitMaterialUniform_frag" +export * from "./assets/shader/materials/uniforms/VideoUniform_frag" +export * from "./assets/shader/math/FastMathShader" +export * from "./assets/shader/math/MathShader" +export * from "./assets/shader/post/Bloom_shader" +export * from "./assets/shader/post/FXAAShader" +export * from "./assets/shader/post/GlobalFog_shader" +export * from "./assets/shader/quad/Quad_shader" +export * from "./assets/shader/sky/AtmosphericScatteringSky_shader" +export * from "./assets/shader/sky/CubeSky_Shader" +export * from "./assets/shader/utils/BRDFLUT" +export * from "./assets/shader/utils/ColorUtil" +export * from "./assets/shader/utils/GenerayRandomDir" +export * from "./components/AtmosphericComponent" +export * from "./components/BillboardComponent" +export * from "./components/ColliderComponent" +export * from "./components/ComponentBase" +export * from "./components/IComponent" +export * from "./components/SkeletonAnimationComponent" +export * from "./components/Transform" +export * from "./components/anim/OAnimationEvent" +export * from "./components/anim/curveAnim/AnimationMonitor" +export * from "./components/anim/curveAnim/AttributeAnimCurve" +export * from "./components/anim/curveAnim/PropertyAnimClip" +export * from "./components/anim/curveAnim/PropertyAnimation" +export * from "./components/anim/curveAnim/PropertyAnimationEvent" +export * from "./components/anim/curveAnim/PropertyHelp" +export * from "./components/anim/morphAnim/MorphTargetBlender" +export * from "./components/anim/morphAnim/MorphTargetData" +export * from "./components/anim/morphAnim/MorphTargetFrame" +export * from "./components/anim/morphAnim/MorphTargetKey" +export * from "./components/anim/morphAnim/MorphTarget_shader" +export * from "./components/anim/skeletonAnim/Joint" +export * from "./components/anim/skeletonAnim/JointPose" +export * from "./components/anim/skeletonAnim/Skeleton" +export * from "./components/anim/skeletonAnim/SkeletonAnimationClip" +export * from "./components/anim/skeletonAnim/SkeletonAnimationClipState" +export * from "./components/anim/skeletonAnim/SkeletonAnimationCompute" +export * from "./components/anim/skeletonAnim/SkeletonPose" +export * from "./components/anim/skeletonAnim/buffer/SkeletonBlendComputeArgs" +export * from "./components/anim/skeletonAnim/buffer/SkeletonTransformComputeArgs" +export * from "./components/anim/skeletonAnim/shader/compute_skeleton_blend" +export * from "./components/anim/skeletonAnim/shader/compute_skeleton_transform" +export * from "./components/audio/AudioListener" +export * from "./components/audio/PositionAudio" +export * from "./components/audio/StaticAudio" +export * from "./components/controller/CameraControllerBase" +export * from "./components/controller/FirstPersonCameraController" +export * from "./components/controller/FlyCameraController" +export * from "./components/controller/HoverCameraController" +export * from "./components/controller/OrbitController" +export * from "./components/controller/ThirdPersonCameraController" +export * from "./components/lights/DirectLight" +export * from "./components/lights/GILighting" +export * from "./components/lights/IESProfiles" +export * from "./components/lights/ILight" +export * from "./components/lights/LightBase" +export * from "./components/lights/LightData" +export * from "./components/lights/PointLight" +export * from "./components/lights/SpotLight" +export * from "./components/post/PostProcessingComponent" +export * from "./components/renderer/InstanceDrawComponent" +export * from "./components/renderer/MaterialComponent" +export * from "./components/renderer/MeshComponent" +export * from "./components/renderer/MeshRenderer" +export * from "./components/renderer/RenderNode" +export * from "./components/renderer/SkinnedMeshRenderer" +export * from "./components/renderer/SkyRenderer" +export * from "./components/shape/BoxColliderShape" +export * from "./components/shape/CapsuleColliderShape" +export * from "./components/shape/ColliderShape" +export * from "./components/shape/MeshColliderShape" +export * from "./components/shape/SphereColliderShape" +export * from "./core/Camera3D" +export * from "./core/CameraType" +export * from "./core/CubeCamera" +export * from "./core/PointShadowCubeCamera" +export * from "./core/Scene3D" +export * from "./core/View3D" +export * from "./core/ViewQuad" +export * from "./core/bound/BoundingBox" +export * from "./core/bound/BoundingSphere" +export * from "./core/bound/Frustum" +export * from "./core/bound/IBound" +export * from "./core/entities/Entity" +export * from "./core/entities/InstancedMesh" +export * from "./core/entities/Object3D" +export * from "./core/geometry/GeometryBase" +export * from "./core/geometry/GeometryIndicesBuffer" +export * from "./core/geometry/GeometryVertexBuffer" +export * from "./core/geometry/GeometryVertexType" +export * from "./core/geometry/VertexAttribute" +export * from "./core/geometry/VertexAttributeData" +export * from "./core/geometry/VertexAttributeName" +export * from "./core/geometry/VertexAttributeSize" +export * from "./core/geometry/VertexAttributeStride" +export * from "./core/geometry/VertexFormat" +export * from "./core/pool/ObjectPool" +export * from "./core/pool/memory/MatrixDO" +export * from "./core/pool/memory/MemoryDO" +export * from "./core/pool/memory/MemoryInfo" +export * from "./core/tree/kdTree/IKDTreeUserData" +export * from "./core/tree/kdTree/KDTreeEntity" +export * from "./core/tree/kdTree/KDTreeNode" +export * from "./core/tree/kdTree/KDTreeSpace" +export * from "./event/CEvent" +export * from "./event/CEventDispatcher" +export * from "./event/CEventListener" +export * from "./event/CResizeEvent" +export * from "./event/KeyCode" +export * from "./event/MouseCode" +export * from "./event/eventConst/KeyEvent" +export * from "./event/eventConst/LoaderEvent" +export * from "./event/eventConst/Object3DEvent" +export * from "./event/eventConst/PointerEvent3D" +export * from "./event/eventConst/UIEvent" +export * from "./gfx/data/IrradianceVolume" +export * from "./gfx/generate/BrdfLUTGenerate" +export * from "./gfx/generate/PassGenerate" +export * from "./gfx/generate/convert/BlurEffectCreator" +export * from "./gfx/generate/convert/ErpImage2CubeMap" +export * from "./gfx/generate/convert/IBLEnvMapCreator" +export * from "./gfx/generate/convert/MergeRGBACreator" +export * from "./gfx/generate/convert/TextureCubeStdCreator" +export * from "./gfx/generate/convert/TextureCubeUtils" +export * from "./gfx/graphics/webGpu/CanvasConfig" +export * from "./gfx/graphics/webGpu/Context3D" +export * from "./gfx/graphics/webGpu/WebGPUConst" +export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalBindGroupLayout" +export * from "./gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/TexturesBindGroup" +export * from "./gfx/graphics/webGpu/core/bindGroups/groups/LightEntries" +export * from "./gfx/graphics/webGpu/core/buffer/ArrayBufferData" +export * from "./gfx/graphics/webGpu/core/buffer/ComputeGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferBase" +export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferType" +export * from "./gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/StorageGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/UniformGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/VertexGPUBuffer" +export * from "./gfx/graphics/webGpu/core/texture/ITexture" +export * from "./gfx/graphics/webGpu/core/texture/Texture" +export * from "./gfx/graphics/webGpu/core/texture/TextureCube" +export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapCompute" +export * from "./gfx/graphics/webGpu/core/texture/TextureMipmapGenerator" +export * from "./gfx/graphics/webGpu/core/uniforms/UniformNode" +export * from "./gfx/graphics/webGpu/descriptor/RTDescriptor" +export * from "./gfx/graphics/webGpu/descriptor/WebGPUDescriptorCreator" +export * from "./gfx/graphics/webGpu/shader/ComputeShader" +export * from "./gfx/graphics/webGpu/shader/RenderShader" +export * from "./gfx/graphics/webGpu/shader/ShaderBase" +export * from "./gfx/graphics/webGpu/shader/ShaderStage" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexer" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLLexerToken" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLPreprocessor" +export * from "./gfx/graphics/webGpu/shader/converter/GLSLSyntax" +export * from "./gfx/graphics/webGpu/shader/converter/Reader" +export * from "./gfx/graphics/webGpu/shader/converter/ShaderConverter" +export * from "./gfx/graphics/webGpu/shader/converter/StatementNode" +export * from "./gfx/graphics/webGpu/shader/converter/WGSLTranslator" +export * from "./gfx/graphics/webGpu/shader/util/MorePassParser" +export * from "./gfx/graphics/webGpu/shader/util/Preprocessor" +export * from "./gfx/graphics/webGpu/shader/util/ShaderUtil" +export * from "./gfx/graphics/webGpu/shader/value/ConstValue" +export * from "./gfx/graphics/webGpu/shader/value/DefineValue" +export * from "./gfx/graphics/webGpu/shader/value/ShaderReflectionInfo" +export * from "./gfx/graphics/webGpu/shader/value/ShaderState" +export * from "./gfx/graphics/webGpu/shader/value/ShaderValue" +export * from "./gfx/graphics/webGpu/shader/value/UniformValue" +export * from "./gfx/renderJob/GPUContext" +export * from "./gfx/renderJob/collect/CollectInfo" +export * from "./gfx/renderJob/collect/ComponentCollect" +export * from "./gfx/renderJob/collect/EntityBatchCollect" +export * from "./gfx/renderJob/collect/EntityCollect" +export * from "./gfx/renderJob/collect/RenderGroup" +export * from "./gfx/renderJob/collect/ShadowLightsCollect" +export * from "./gfx/renderJob/config/RTResourceConfig" +export * from "./gfx/renderJob/config/RenderLayer" +export * from "./gfx/renderJob/frame/GBufferFrame" +export * from "./gfx/renderJob/frame/ProbeGBufferFrame" +export * from "./gfx/renderJob/frame/RTFrame" +export * from "./gfx/renderJob/frame/RTResourceMap" +export * from "./gfx/renderJob/jobs/ForwardRenderJob" +export * from "./gfx/renderJob/jobs/RenderMap" +export * from "./gfx/renderJob/jobs/RendererJob" +export * from "./gfx/renderJob/occlusion/OcclusionSystem" +export * from "./gfx/renderJob/passRenderer/RenderContext" +export * from "./gfx/renderJob/passRenderer/RendererBase" +export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingBuffer" +export * from "./gfx/renderJob/passRenderer/cluster/ClusterLightingRender" +export * from "./gfx/renderJob/passRenderer/color/ColorPassRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer" +export * from "./gfx/renderJob/passRenderer/graphic/Graphic3DRender" +export * from "./gfx/renderJob/passRenderer/graphic/GraphicConfig" +export * from "./gfx/renderJob/passRenderer/graphic/Graphics3DShape" +export * from "./gfx/renderJob/passRenderer/post/PostRenderer" +export * from "./gfx/renderJob/passRenderer/preDepth/PreDepthPassRenderer" +export * from "./gfx/renderJob/passRenderer/preDepth/ZCullingCompute" +export * from "./gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer" +export * from "./gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer" +export * from "./gfx/renderJob/passRenderer/state/RendererMask" +export * from "./gfx/renderJob/passRenderer/state/RendererPassState" +export * from "./gfx/renderJob/passRenderer/state/RendererType" +export * from "./gfx/renderJob/post/DepthOfFieldPost" +export * from "./gfx/renderJob/post/FXAAPost" +export * from "./gfx/renderJob/post/GTAOPost" +export * from "./gfx/renderJob/post/GlobalFog" +export * from "./gfx/renderJob/post/HDRBloomPost" +export * from "./gfx/renderJob/post/OutlinePost" +export * from "./gfx/renderJob/post/PostBase" +export * from "./gfx/renderJob/post/SSRPost" +export * from "./gfx/renderJob/post/TAAPost" +export * from "./io/InputSystem" +export * from "./io/OutlineManager" +export * from "./io/OutlinePostData" +export * from "./io/PickFire" +export * from "./io/PickResult" +export * from "./io/RayCastMeshDetail" +export * from "./io/TouchData" +export * from "./io/picker/PickCompute" +export * from "./loader/FileLoader" +export * from "./loader/LoaderBase" +export * from "./loader/LoaderData" +export * from "./loader/LoaderFunctions" +export * from "./loader/LoaderManager" +export * from "./loader/parser/B3DMParser" +export * from "./loader/parser/I3DMParser" +export * from "./loader/parser/OBJParser" +export * from "./loader/parser/ParserBase" +export * from "./loader/parser/RGBEParser" +export * from "./loader/parser/b3dm/B3DMLoader" +export * from "./loader/parser/b3dm/B3DMLoaderBase" +export * from "./loader/parser/b3dm/FeatureTable" +export * from "./loader/parser/b3dm/arrayToString" +export * from "./loader/parser/b3dm/readMagicBytes" +export * from "./loader/parser/gltf/GLBParser" +export * from "./loader/parser/gltf/GLTFInfo" +export * from "./loader/parser/gltf/GLTFParser" +export * from "./loader/parser/gltf/GLTFSubParser" +export * from "./loader/parser/gltf/GLTFSubParserCamera" +export * from "./loader/parser/gltf/GLTFSubParserConverter" +export * from "./loader/parser/gltf/GLTFSubParserMaterial" +export * from "./loader/parser/gltf/GLTFSubParserMesh" +export * from "./loader/parser/gltf/GLTFSubParserSkeleton" +export * from "./loader/parser/gltf/GLTFSubParserSkin" +export * from "./loader/parser/gltf/GLTFType" +export * from "./loader/parser/gltf/TypeArray" +export * from "./loader/parser/gltf/extends/KHR_draco_mesh_compression" +export * from "./loader/parser/gltf/extends/KHR_lights_punctual" +export * from "./loader/parser/gltf/extends/KHR_materials_clearcoat" +export * from "./loader/parser/gltf/extends/KHR_materials_emissive_strength" +export * from "./loader/parser/gltf/extends/KHR_materials_ior" +export * from "./loader/parser/gltf/extends/KHR_materials_sheen" +export * from "./loader/parser/gltf/extends/KHR_materials_specular" +export * from "./loader/parser/gltf/extends/KHR_materials_transmission" +export * from "./loader/parser/gltf/extends/KHR_materials_unlit" +export * from "./loader/parser/gltf/extends/KHR_materials_variants" +export * from "./loader/parser/gltf/extends/KHR_materials_volume" +export * from "./loader/parser/gltf/extends/KHR_mesh_quantization" +export * from "./loader/parser/gltf/extends/KHR_texture_basisu" +export * from "./loader/parser/gltf/extends/KHR_texture_transform" +export * from "./loader/parser/i3dm/I3DMLoader" +export * from "./loader/parser/i3dm/I3DMLoaderBase" +export * from "./loader/parser/tileRenderer/TileSet" +export * from "./loader/parser/tileRenderer/TilesRenderer" +export * from "./materials/BlendMode" +export * from "./materials/ColorLitMaterial" +export * from "./materials/GlassMaterial" +export * from "./materials/LambertMaterial" +export * from "./materials/LitMaterial" +export * from "./materials/MaterialBase" +export * from "./materials/MaterialPass" +export * from "./materials/MaterialRegister" +export * from "./materials/PavementMaterial" +export * from "./materials/PhysicMaterial" +export * from "./materials/PointMaterial" +export * from "./materials/SkyMaterial" +export * from "./materials/UnLitMaterial" +export * from "./materials/multiPass/CastPointShadowMaterialPass" +export * from "./materials/multiPass/CastShadowMaterialPass" +export * from "./materials/multiPass/DepthMaterialPass" +export * from "./materials/multiPass/GBufferPass" +export * from "./materials/multiPass/SkyGBufferPass" +export * from "./math/AnimationCurve" +export * from "./math/Bezier2D" +export * from "./math/Bezier3D" +export * from "./math/Color" +export * from "./math/CubicBezierCurve" +export * from "./math/CubicBezierPath" +export * from "./math/HaltonSeq" +export * from "./math/Line" +export * from "./math/MathUtil" +export * from "./math/Matrix3" +export * from "./math/Matrix4" +export * from "./math/Orientation3D" +export * from "./math/ParticleMath" +export * from "./math/ParticleSystemCurves" +export * from "./math/Plane" +export * from "./math/PolynomialCurve" +export * from "./math/Polynomials" +export * from "./math/Quaternion" +export * from "./math/Rand" +export * from "./math/Random" +export * from "./math/Ray" +export * from "./math/Rect" +export * from "./math/TimeInterpolator" +export * from "./math/Triangle" +export * from "./math/UV" +export * from "./math/Vector2" +export * from "./math/Vector3" +export * from "./math/Vector4" +export * from "./setting/EngineSetting" +export * from "./setting/GlobalIlluminationSetting" +export * from "./setting/LightSetting" +export * from "./setting/MaterialSetting" +export * from "./setting/OcclusionQuerySetting" +export * from "./setting/PickSetting" +export * from "./setting/RenderSetting" +export * from "./setting/ShadowSetting" +export * from "./setting/SkySetting" +export * from "./setting/post/BloomSetting" +export * from "./setting/post/DepthOfViewSetting" +export * from "./setting/post/GTAOSetting" +export * from "./setting/post/GlobalFogSetting" +export * from "./setting/post/OutlineSetting" +export * from "./setting/post/SSRSetting" +export * from "./setting/post/TAASetting" +export * from "./shape/BoxGeometry" +export * from "./shape/CylinderGeometry" +export * from "./shape/PlaneGeometry" +export * from "./shape/SphereGeometry" +export * from "./shape/TorusGeometry" +export * from "./textures/AtmosphericScatteringSky" +export * from "./textures/BitmapTexture2D" +export * from "./textures/BitmapTexture2DArray" +export * from "./textures/BitmapTextureCube" +export * from "./textures/Depth2DTextureArray" +export * from "./textures/DepthCubeArrayTexture" +export * from "./textures/DepthCubeTexture" +export * from "./textures/Float16ArrayTexture" +export * from "./textures/Float32ArrayTexture" +export * from "./textures/HDRTexture" +export * from "./textures/HDRTextureCube" +export * from "./textures/LDRTextureCube" +export * from "./textures/SolidColorSky" +export * from "./textures/Uint16Texture" +export * from "./textures/Uint8ArrayTexture" +export * from "./textures/VirtualTexture" +export * from "./util/AxisObject" +export * from "./util/BytesStream" +export * from "./util/CameraUtil" +export * from "./util/Convert" +export * from "./util/GeometryUtil" +export * from "./util/Global" +export * from "./util/KelvinUtil" +export * from "./util/Object3DUtil" +export * from "./util/ProfilerUtil" +export * from "./util/StringUtil" +export * from "./util/Time" +export * from "./util/Vector3Ex" +export * from "./util/ZSorterUtil" +export * from "./util/struct/Struct" +export * from "./util/struct/StructValue" +export * from "./util/struct/Vector3Struct" diff --git a/test/base/EngineInit.test.ts b/test/base/EngineInit.test.ts new file mode 100644 index 00000000..d7c00506 --- /dev/null +++ b/test/base/EngineInit.test.ts @@ -0,0 +1,9 @@ +import { test, end, expect } from '../util' +import { Engine3D } from '@orillusion/core'; + +await test('Init', async () => { + await Engine3D.init(); + expect(Engine3D.aspect).toEqual(window.innerWidth/window.innerHeight) +}) + +setTimeout(end, 500) \ No newline at end of file diff --git a/test/base/base.test.ts b/test/base/base.test.ts deleted file mode 100644 index fed99653..00000000 --- a/test/base/base.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { test, end } from '../util' - -await test('Init', async () => { - // console.log(Orillusion) -}) - -setTimeout(end, 500) \ No newline at end of file diff --git a/test/components/component.test.ts b/test/components/Component.test.ts similarity index 100% rename from test/components/component.test.ts rename to test/components/Component.test.ts diff --git a/test/components/componentLife-Camera3D.test.ts b/test/components/ComponentLife-Camera3D.test.ts similarity index 100% rename from test/components/componentLife-Camera3D.test.ts rename to test/components/ComponentLife-Camera3D.test.ts diff --git a/test/components/lightingShadow.test.ts b/test/components/LightingShadow.test.ts similarity index 100% rename from test/components/lightingShadow.test.ts rename to test/components/LightingShadow.test.ts diff --git a/test/components/transform.test.ts b/test/components/Transform.test.ts similarity index 100% rename from test/components/transform.test.ts rename to test/components/Transform.test.ts diff --git a/test/index.ts b/test/index.ts index 3b4348bd..d6f609a5 100644 --- a/test/index.ts +++ b/test/index.ts @@ -5,7 +5,7 @@ let title = '', list = '' for (const path in modules) { const arr = path.split('/') let _title = arr[1] - let _demo = arr[2].replace(/Sample_|Sample|\.ts/g, '') + let _demo = arr[2].replace(/\.test\.ts/g, '') if (_title != title) { list += `

${_title}

` title = _title diff --git a/test/util.ts b/test/util.ts index 28f56daa..f250cc39 100644 --- a/test/util.ts +++ b/test/util.ts @@ -1,6 +1,3 @@ -// @ts-ignore -import { isEqual, isMatch } from 'https://unpkg.com/underscore@1.13.6/underscore-esm-min.js' - let target = sessionStorage.target.split('/').pop() let result: { [key: string]: any } = {} let totalS = 0, totalF = 0 @@ -99,4 +96,29 @@ function delay(time?: number) { setTimeout(res, time || 200) }) } + +// no funcion types +function isEqual(a: any, b: any) { + if (a === b) return a !== 0 || 1 / a === 1 / b; + if (a == null || b == null) return false; + if (a !== a) return b !== b; + if(typeof a === 'function' || typeof b === 'function') + return false; + if (typeof a !== 'object' || typeof b != 'object') + return false; + // for other objects just compare stringify results + return JSON.stringify(a) === JSON.stringify(b) +} + +function isMatch(object: any, attrs: { [key: string]: any }) { + const _keys = Object.keys(attrs), length = _keys.length; + if (object == null) return !length; + const obj = Object(object); + for (let i = 0; i < length; i++) { + const key = _keys[i]; + if (attrs[key] !== obj[key] || !(key in obj)) return false; + } + return true; +} + export { test, expect, end, delay } \ No newline at end of file From d2cd53cdaab9980897c1810e2eedf6224e8d88b6 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Sun, 7 May 2023 08:06:35 +0800 Subject: [PATCH 095/100] chore: bump packages version --- packages/ammo/ammo.d.ts | 2 +- packages/ammo/package.json | 2 +- packages/media-extention/package.json | 2 +- packages/media-extention/tsconfig.json | 2 +- packages/physics/package.json | 2 +- packages/physics/tsconfig.json | 2 +- packages/stats/package.json | 4 ++-- packages/stats/tsconfig.json | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/ammo/ammo.d.ts b/packages/ammo/ammo.d.ts index ff5363d7..ff259acf 100644 --- a/packages/ammo/ammo.d.ts +++ b/packages/ammo/ammo.d.ts @@ -4,7 +4,7 @@ export default Ammo; */ declare function Ammo(target?: T): Promise; /** - * Ammo 原生类 by Bullet2 + * Ammo.js by Bullet2 */ declare module Ammo { function destroy(obj: any): void; diff --git a/packages/ammo/package.json b/packages/ammo/package.json index 634e3838..ead43bf3 100644 --- a/packages/ammo/package.json +++ b/packages/ammo/package.json @@ -1,6 +1,6 @@ { "name": "@orillusion/ammo", - "version": "0.1.1", + "version": "0.1.2", "author": "Orillusion", "description": "Orillusion WebGPU Engine", "main": "ammo.js", diff --git a/packages/media-extention/package.json b/packages/media-extention/package.json index 4eab7e8f..b8c05be7 100644 --- a/packages/media-extention/package.json +++ b/packages/media-extention/package.json @@ -1,6 +1,6 @@ { "name": "@orillusion/media-extention", - "version": "0.1.7", + "version": "0.2.0", "author": "Orillusion", "description": "Orillusion Media Material Extention", "main": "./dist/media.umd.js", diff --git a/packages/media-extention/tsconfig.json b/packages/media-extention/tsconfig.json index 07928127..f9768622 100644 --- a/packages/media-extention/tsconfig.json +++ b/packages/media-extention/tsconfig.json @@ -4,7 +4,7 @@ "useDefineForClassFields": true, "module": "ESNext", "lib": ["ESNext", "DOM"], - "moduleResolution": "Node", + "moduleResolution": "bundler", "sourceMap": false, "resolveJsonModule": true, "esModuleInterop": true, diff --git a/packages/physics/package.json b/packages/physics/package.json index ac357459..6d802bf4 100644 --- a/packages/physics/package.json +++ b/packages/physics/package.json @@ -1,6 +1,6 @@ { "name": "@orillusion/physics", - "version": "0.1.8", + "version": "0.2.0", "author": "Orillusion", "description": "Orillusion Physics Plugin, Powerd by Ammo.js", "main": "./dist/physics.umd.js", diff --git a/packages/physics/tsconfig.json b/packages/physics/tsconfig.json index 15244be5..c7f21f28 100644 --- a/packages/physics/tsconfig.json +++ b/packages/physics/tsconfig.json @@ -4,7 +4,7 @@ "useDefineForClassFields": true, "module": "ESNext", "lib": ["ESNext", "DOM"], - "moduleResolution": "Node", + "moduleResolution": "bundler", "sourceMap": false, "resolveJsonModule": true, "esModuleInterop": true, diff --git a/packages/stats/package.json b/packages/stats/package.json index 8b108fb6..2bc62291 100644 --- a/packages/stats/package.json +++ b/packages/stats/package.json @@ -1,6 +1,6 @@ { "name": "@orillusion/stats", - "version": "0.1.5", + "version": "0.2.0", "author": "Orillusion", "description": "Orillusion Stats Plugin", "main": "./dist/stats.umd.js", @@ -21,6 +21,6 @@ "url": "git+https://github.com/Orillusion/orillusion.git" }, "dependencies": { - "@orillusion/core": ">=0.4.0" + "@orillusion/core": "^0.6.0" } } diff --git a/packages/stats/tsconfig.json b/packages/stats/tsconfig.json index 07928127..f9768622 100644 --- a/packages/stats/tsconfig.json +++ b/packages/stats/tsconfig.json @@ -4,7 +4,7 @@ "useDefineForClassFields": true, "module": "ESNext", "lib": ["ESNext", "DOM"], - "moduleResolution": "Node", + "moduleResolution": "bundler", "sourceMap": false, "resolveJsonModule": true, "esModuleInterop": true, From f455f42b27f3b8a2d1b98b6b3e7f8cd180cc549b Mon Sep 17 00:00:00 2001 From: hellmor Date: Sun, 7 May 2023 16:03:43 +0800 Subject: [PATCH 096/100] feat(sample): add samples about material (#105) Examples of using various materials and modifying material properties. Add GUIUtil file. fix reference of engine lib. --- samples/base/Sample_Transform.ts | 14 +-- samples/index.ts | 2 +- samples/loader/Sample_FlightHelmet.ts | 104 +++++++++++++++++ samples/loader/Sample_LoadGLTF.ts | 100 ++++++++++++++++ samples/material/Sample_CustomMaterial.ts | 106 +++++++++++++++++ samples/material/Sample_PBR.ts | 73 ++++++++++++ samples/material/Sample_PBRMaterial.ts | 81 +++++++++++++ samples/material/Sample_RenderPassClean.ts | 89 +++++++++++++++ samples/material/Sample_ReplaceMaterial.ts | 78 +++++++++++++ samples/material/Sample_UVMove.ts | 96 ++++++++++++++++ samples/material/Sample_UnlitMaterial.ts | 79 +++++++++++++ samples/material/script/UVMoveComponent.ts | 33 ++++++ samples/render/Sample_BlendMode2.ts | 107 +++++++++++++++++ samples/render/Sample_CullMode.ts | 62 ++++++++++ samples/render/Sample_TextureSample.ts | 127 +++++++++++++++++++++ samples/sky/Sample_AtmosphericSky.ts | 21 +--- samples/utils/GUIUtil.ts | 71 ++++++++++++ test/components/test/TestComponents.ts | 2 +- 18 files changed, 1214 insertions(+), 31 deletions(-) create mode 100644 samples/loader/Sample_FlightHelmet.ts create mode 100644 samples/loader/Sample_LoadGLTF.ts create mode 100644 samples/material/Sample_CustomMaterial.ts create mode 100644 samples/material/Sample_PBR.ts create mode 100644 samples/material/Sample_PBRMaterial.ts create mode 100644 samples/material/Sample_RenderPassClean.ts create mode 100644 samples/material/Sample_ReplaceMaterial.ts create mode 100644 samples/material/Sample_UVMove.ts create mode 100644 samples/material/Sample_UnlitMaterial.ts create mode 100644 samples/material/script/UVMoveComponent.ts create mode 100644 samples/render/Sample_BlendMode2.ts create mode 100644 samples/render/Sample_CullMode.ts create mode 100644 samples/render/Sample_TextureSample.ts create mode 100644 samples/utils/GUIUtil.ts diff --git a/samples/base/Sample_Transform.ts b/samples/base/Sample_Transform.ts index 3d080569..1841bbe4 100644 --- a/samples/base/Sample_Transform.ts +++ b/samples/base/Sample_Transform.ts @@ -1,6 +1,7 @@ import { GUIHelp } from '@orillusion/debug/GUIHelp'; import { Stats } from '@orillusion/stats' import { Engine3D, Scene3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, Object3D, MeshRenderer, BoxGeometry, LitMaterial, DirectLight, KelvinUtil, View3D } from '@orillusion/core'; +import { GUIUtil } from '@samples/utils/GUIUtil'; // simple base demo class Sample_Transform { @@ -54,18 +55,7 @@ class Sample_Transform { let transform = cubeObj.transform; // debug GUI GUIHelp.init(); - GUIHelp.addFolder('Transform'); - GUIHelp.add(transform, 'x', -10.0, 10.0, 0.01); - GUIHelp.add(transform, 'y', -10.0, 10.0, 0.01); - GUIHelp.add(transform, 'z', -10.0, 10.0, 0.01); - GUIHelp.add(transform, 'rotationX', 0.0, 360.0, 0.01); - GUIHelp.add(transform, 'rotationY', 0.0, 360.0, 0.01); - GUIHelp.add(transform, 'rotationZ', 0.0, 360.0, 0.01); - GUIHelp.add(transform, 'scaleX', 0.0, 2.0, 0.01); - GUIHelp.add(transform, 'scaleY', 0.0, 2.0, 0.01); - GUIHelp.add(transform, 'scaleZ', 0.0, 2.0, 0.01); - GUIHelp.open(); - GUIHelp.endFolder(); + GUIUtil.renderTransform(transform); } } diff --git a/samples/index.ts b/samples/index.ts index 69c8d7fe..c1e5f1e4 100644 --- a/samples/index.ts +++ b/samples/index.ts @@ -8,7 +8,7 @@ if (!path.includes('Sample_')) continue const arr = path.split('/') const _title = arr[1] - const _demo = arr[2].replace(/Sample_|Sample|\.ts/g, '') + const _demo = arr[2].replace(/Sample_|\.ts/g, '') if (_title != title) { list += `

${_title}

` title = _title diff --git a/samples/loader/Sample_FlightHelmet.ts b/samples/loader/Sample_FlightHelmet.ts new file mode 100644 index 00000000..b8ac22bd --- /dev/null +++ b/samples/loader/Sample_FlightHelmet.ts @@ -0,0 +1,104 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Object3D, Camera3D, Scene3D, HoverCameraController, Engine3D, CameraUtil, webGPUContext, View3D, SSRPost, HDRBloomPost, AtmosphericComponent, DirectLight, KelvinUtil, Time } from "@orillusion/core"; +import { GUIUtil as GUIUtil } from "@samples/utils/GUIUtil"; + +class Sample_FlightHelmet { + lightObj3D: Object3D; + scene: Scene3D; + autoRotate: boolean = false; + flightHelmetObj: Object3D; + + async run() { + await Engine3D.init({ + canvasConfig: { + alpha: true, + zIndex: 0, + backgroundImage: '/logo/bg.webp' + }, + renderLoop: () => this.loop(), + }); + + Engine3D.setting.material.materialChannelDebug = true; + Engine3D.setting.shadow.debug = true; + Engine3D.setting.shadow.autoUpdate = true; + Engine3D.setting.shadow.shadowBound = 10; + Engine3D.setting.shadow.shadowBias = 0.00001; + + Engine3D.setting.render.postProcessing.ssao.radius = 0.018; + Engine3D.setting.render.postProcessing.ssao.aoPower = 1; + Engine3D.setting.render.postProcessing.gtao.debug = false; + + Engine3D.setting.render.postProcessing.bloom = { + enable: true, + blurX: 4, + blurY: 4, + intensity: 0.5, + brightness: 1.25, + debug: false + }; + + + this.scene = new Scene3D(); + this.scene.hideSky(); + let camera = CameraUtil.createCamera3DObject(this.scene); + camera.perspective(60, webGPUContext.aspect, 1, 5000.0); + + camera.object3D.addComponent(HoverCameraController).setCamera(-45, -30, 15); + + let view = new View3D(); + view.scene = this.scene; + view.camera = camera; + + Engine3D.startRenderView(view); + + await this.initScene(); + } + + async initScene() { + /******** auto rotate *******/ + { + GUIHelp.init(); + GUIHelp.add(this, 'autoRotate'); + GUIHelp.open(); + } + + /******** sky *******/ + { + let atmospheric = this.scene.addComponent(AtmosphericComponent); + atmospheric.sunY = 0.73; + atmospheric.sunRadiance = 47; + } + /******** light *******/ + { + this.lightObj3D = new Object3D(); + this.lightObj3D.rotationX = 53.2; + this.lightObj3D.rotationY = 220; + this.lightObj3D.rotationZ = 5.58; + let directLight = this.lightObj3D.addComponent(DirectLight); + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = true; + directLight.intensity = 44; + this.scene.addChild(this.lightObj3D); + GUIUtil.renderDirLight(directLight); + } + + /******** load model *******/ + { + let model = (await Engine3D.res.loadGltf('PBR/FlightHelmet/FlightHelmet.gltf', {})) as Object3D; + model.transform.scaleX = 10; + model.transform.scaleY = 10; + model.transform.scaleZ = 10; + model.transform.y = -2; + this.scene.addChild(model); + this.flightHelmetObj = model; + } + } + + loop() { + if (this.flightHelmetObj && this.autoRotate) { + this.flightHelmetObj.rotationY += Time.delta * 0.05; + } + } +} + +new Sample_FlightHelmet().run(); diff --git a/samples/loader/Sample_LoadGLTF.ts b/samples/loader/Sample_LoadGLTF.ts new file mode 100644 index 00000000..c729f6c1 --- /dev/null +++ b/samples/loader/Sample_LoadGLTF.ts @@ -0,0 +1,100 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Object3D, Scene3D, Engine3D, CameraUtil, webGPUContext, HoverCameraController, View3D, AtmosphericComponent, DirectLight, KelvinUtil } from "@orillusion/core"; +import { GUIUtil } from "@samples/utils/GUIUtil"; + +//Samples to show models, they are using PBR material +class Sample_LoadGLTF { + lightObj3D: Object3D; + scene: Scene3D; + async run() { + //config settings + Engine3D.setting.material.materialChannelDebug = true; + Engine3D.setting.shadow.shadowBound = 5; + Engine3D.setting.shadow.shadowBias = 0.002; + Engine3D.setting.render.postProcessing.bloom = { + enable: true, + blurX: 4, + blurY: 4, + intensity: 5, + brightness: 0.86, + debug: true + }; + + //init engine + await Engine3D.init(); + + this.scene = new Scene3D(); + + let camera = CameraUtil.createCamera3DObject(this.scene); + camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); + camera.object3D.addComponent(HoverCameraController).setCamera(25, -5, 100); + + let view = new View3D(); + view.scene = this.scene; + view.camera = camera; + + Engine3D.startRenderView(view); + + await this.initScene(); + } + + async initScene() { + /******** sky *******/ + { + let atmospheric = this.scene.addComponent(AtmosphericComponent); + atmospheric.sunY = 0.62; + atmospheric.sunRadiance = 47; + this.scene.exposure = 1; + this.scene.roughness = 0.56; + } + + /******** light *******/ + { + this.lightObj3D = new Object3D(); + this.lightObj3D.rotationX = 57; + this.lightObj3D.rotationY = 148; + this.lightObj3D.rotationZ = 10; + let directLight = this.lightObj3D.addComponent(DirectLight); + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = true; + directLight.intensity = 18; + GUIHelp.init(); + GUIUtil.renderDirLight(directLight); + this.scene.addChild(this.lightObj3D); + } + + { + /******** player1 *******/ + let player1 = (await Engine3D.res.loadGltf('gltfs/anim/Minion_Lane_Super_Dawn/Minion_Lane_Super_Dawn.glb', {})) as Object3D; + player1.transform.x = -10; + player1.transform.z = 20; + player1.transform.scaleX = 10; + player1.transform.scaleY = 10; + player1.transform.scaleZ = 10; + player1.transform.y = 5; + this.scene.addChild(player1); + + /******** player2 *******/ + let player2 = (await Engine3D.res.loadGltf('gltfs/anim/Minion_Lane_Super_Dawn/Prime_Helix.glb', {})) as Object3D; + player2.transform.x = 10; + player2.transform.scaleX = 10; + player2.transform.scaleY = 10; + player2.transform.scaleZ = 10; + player2.transform.y = 5; + this.scene.addChild(player2); + + /******** player3 *******/ + let player3 = (await Engine3D.res.loadGltf('gltfs/anim/Minion_Lane_Super_Dawn/Minion_Lane_Ranged_Dusk.glb', {})) as Object3D; + player3.transform.x = 10; + player3.transform.z = 20; + player3.transform.scaleX = 10; + player3.transform.scaleY = 10; + player3.transform.scaleZ = 10; + player3.transform.y = 5; + this.scene.addChild(player3); + } + } + +} + +new Sample_LoadGLTF().run(); \ No newline at end of file diff --git a/samples/material/Sample_CustomMaterial.ts b/samples/material/Sample_CustomMaterial.ts new file mode 100644 index 00000000..1c468ea5 --- /dev/null +++ b/samples/material/Sample_CustomMaterial.ts @@ -0,0 +1,106 @@ +import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, DirectLight, KelvinUtil, UnLitMaterial, Color, MeshRenderer, Object3DUtil } from "@orillusion/core"; +import { GUIUtil } from "@samples/utils/GUIUtil"; + +//Display UnLit shaders unaffected by light +class Sample_CustomMaterial { + lightObj3D: Object3D; + scene: Scene3D; + + async run() { + Engine3D.setting.material.materialChannelDebug = true; + + Engine3D.setting.shadow.shadowBound = 200; + Engine3D.setting.shadow.shadowBias = 0.002; + Engine3D.setting.shadow.debug = true; + Engine3D.setting.shadow.autoUpdate = true; + Engine3D.setting.shadow.updateFrameRate = 1; + + await Engine3D.init(); + + this.scene = new Scene3D(); + this.scene.addComponent(AtmosphericComponent); + + let mainCamera = CameraUtil.createCamera3DObject(this.scene); + + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.object3D.addComponent(HoverCameraController).setCamera(45, -45, 20); + + await this.initScene(this.scene); + + let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + Engine3D.startRenderView(view); + } + + async initScene(scene: Scene3D) { + //create light + { + this.lightObj3D = new Object3D(); + this.lightObj3D.x = 0; + this.lightObj3D.y = 30; + this.lightObj3D.z = -40; + this.lightObj3D.rotationX = 77; + this.lightObj3D.rotationY = 77; + this.lightObj3D.rotationZ = 41; + let lc = this.lightObj3D.addComponent(DirectLight); + lc.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + lc.castShadow = true; + lc.intensity = 10; + GUIUtil.renderDirLight(lc); + scene.addChild(this.lightObj3D); + } + { + //create floor + let floor = Object3DUtil.GetCube(); + floor.scaleX = 1000; + floor.scaleY = 1; + floor.scaleZ = 1000; + this.scene.addChild(floor); + + //center + let centerCube = Object3DUtil.GetCube(); + centerCube.scaleX = 1; + centerCube.scaleY = 1; + centerCube.scaleZ = 1; + centerCube.x = 2.5; + centerCube.y = 2.5; + this.scene.addChild(centerCube); + + //left + let leftCube = Object3DUtil.GetCube(); + leftCube.scaleX = 4; + leftCube.scaleY = 4; + leftCube.scaleZ = 1; + leftCube.x = 4; + leftCube.y = 2; + this.scene.addChild(leftCube); + + //right + let rightCube = Object3DUtil.GetCube(); + rightCube.scaleX = 4; + rightCube.scaleY = 4; + rightCube.scaleZ = 1; + rightCube.x = -4; + rightCube.y = 2; + this.scene.addChild(rightCube); + + //ulit material + let unlitObj = new Object3D(); + let unlitMat = new UnLitMaterial(); + unlitMat.baseColor = Color.random(); + let mr = unlitObj.addComponent(MeshRenderer); + mr.geometry = Object3DUtil.CubeMesh; + mr.material = unlitMat; + unlitObj.scaleX = 2; + unlitObj.scaleY = 2; + unlitObj.scaleZ = 2; + unlitObj.y = 2; + this.scene.addChild(unlitObj); + } + return true; + } +} + +new Sample_CustomMaterial().run(); \ No newline at end of file diff --git a/samples/material/Sample_PBR.ts b/samples/material/Sample_PBR.ts new file mode 100644 index 00000000..e155e7e1 --- /dev/null +++ b/samples/material/Sample_PBR.ts @@ -0,0 +1,73 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, DirectLight, KelvinUtil, LitMaterial, MeshRenderer, BoxGeometry, SphereGeometry } from "@orillusion/core"; +import { GUIUtil } from "@samples/utils/GUIUtil"; + +class Sample_PBR { + lightObj3D: Object3D; + scene: Scene3D; + + constructor() { } + + async run() { + await Engine3D.init({}); + + Engine3D.setting.shadow.shadowBound = 5; + Engine3D.setting.shadow.shadowBias = 0.002; + + GUIHelp.init(); + + this.scene = new Scene3D(); + this.scene.addComponent(AtmosphericComponent); + let camera = CameraUtil.createCamera3DObject(this.scene); + camera.perspective(60, webGPUContext.aspect, 1, 5000.0); + + camera.object3D.addComponent(HoverCameraController).setCamera(30, 0, 120); + + let view = new View3D(); + view.scene = this.scene; + view.camera = camera; + + Engine3D.startRenderView(view); + + await this.initScene(); + } + + async initScene() { + /******** light *******/ + { + this.lightObj3D = new Object3D(); + this.lightObj3D.rotationX = 21; + this.lightObj3D.rotationY = 108; + this.lightObj3D.rotationZ = 10; + let directLight = this.lightObj3D.addComponent(DirectLight); + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = false; + directLight.intensity = 10; + GUIUtil.renderDirLight(directLight); + this.scene.addChild(this.lightObj3D); + } + + let geometry = new SphereGeometry(3, 25, 25); + for (let i = 0; i < 10; i++) { + for (let j = 0; j < 10; j++) { + //Create materials with different roughness and metallic + let mat = new LitMaterial(); + mat.baseMap = Engine3D.res.whiteTexture; + mat.roughness = i / 10; + mat.metallic = j / 10; + //Create balls + let ball = new Object3D(); + ball.transform.x = i * 8 - 8 * 10 * 0.5; + ball.transform.y = 8 * 10 * 0.5 - j * 8; + let renderder = ball.addComponent(MeshRenderer); + renderder.geometry = geometry; + renderder.material = mat; + + //add ball into scene + this.scene.addChild(ball); + } + } + } +} + +new Sample_PBR().run(); \ No newline at end of file diff --git a/samples/material/Sample_PBRMaterial.ts b/samples/material/Sample_PBRMaterial.ts new file mode 100644 index 00000000..1c9c7b41 --- /dev/null +++ b/samples/material/Sample_PBRMaterial.ts @@ -0,0 +1,81 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Object3D, Scene3D, Engine3D, CameraUtil, webGPUContext, HoverCameraController, View3D, AtmosphericComponent, DirectLight, KelvinUtil, MeshRenderer, LitMaterial } from "@orillusion/core"; +import { GUIUtil } from "@samples/utils/GUIUtil"; + +class Sample_PBRMaterial { + lightObj3D: Object3D; + scene: Scene3D; + + async run() { + await Engine3D.init({ canvasConfig: { alpha: true, zIndex: 11, backgroundImage: '/logo/bg.webp' } }); + + //config settings + Engine3D.setting.material.materialDebug = true; + Engine3D.setting.material.materialChannelDebug = true; + Engine3D.setting.shadow.shadowBound = 50; + Engine3D.setting.shadow.shadowBias = 0.002; + Engine3D.setting.render.postProcessing.bloom = { + enable: true, + blurX: 4, + blurY: 4, + intensity: 1.6, + brightness: 0.8, + debug: true + }; + + GUIHelp.init(999); + + this.scene = new Scene3D(); + this.scene.hideSky(); + let camera = CameraUtil.createCamera3DObject(this.scene); + camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); + + camera.object3D.addComponent(HoverCameraController).setCamera(-25, -5, 30); + + let view = new View3D(); + view.scene = this.scene; + view.camera = camera; + + Engine3D.startRenderView(view); + await this.initScene(); + } + + async initScene() { + /******** sky *******/ + { + this.scene.addComponent(AtmosphericComponent); + } + /******** light *******/ + { + this.lightObj3D = new Object3D(); + this.lightObj3D.rotationX = 124; + this.lightObj3D.rotationY = 327; + this.lightObj3D.rotationZ = 10; + let directLight = this.lightObj3D.addComponent(DirectLight); + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = true; + directLight.intensity = 43; + GUIUtil.renderDirLight(directLight); + this.scene.addChild(this.lightObj3D); + } + + { + let model = (await Engine3D.res.loadGltf('gltfs/wukong/wukong.gltf', {})) as Object3D; + let renderList = model.getComponentsInChild(MeshRenderer); + for (const item of renderList) { + let material = item.material; + if (material instanceof LitMaterial) { + material.metallic = 1; + } + } + model.transform.scaleX = 10; + model.transform.scaleY = 10; + model.transform.scaleZ = 10; + model.transform.y = -5; + + this.scene.addChild(model); + } + } +} + +new Sample_PBRMaterial().run(); \ No newline at end of file diff --git a/samples/material/Sample_RenderPassClean.ts b/samples/material/Sample_RenderPassClean.ts new file mode 100644 index 00000000..0a1ca2fe --- /dev/null +++ b/samples/material/Sample_RenderPassClean.ts @@ -0,0 +1,89 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, DirectLight, KelvinUtil, MeshRenderer, LitMaterial, BlendMode, BoxGeometry, Color, PlaneGeometry } from "@orillusion/core"; +import { GUIUtil } from "@samples/utils/GUIUtil"; + +class Sample_RenderPassClean { + lightObj3D: Object3D; + scene: Scene3D; + + async run() { + await Engine3D.init(); + + Engine3D.setting.material.materialChannelDebug = true; + Engine3D.setting.shadow.shadowBound = 50; + Engine3D.setting.shadow.shadowBias = 0.00197; + Engine3D.setting.shadow.debug = true; + + this.scene = new Scene3D(); + this.scene.addComponent(AtmosphericComponent); + + let camera = CameraUtil.createCamera3DObject(this.scene); + camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); + + camera.object3D.addComponent(HoverCameraController).setCamera(25, -5, 20); + + let view = new View3D(); + view.scene = this.scene; + view.camera = camera; + + Engine3D.startRenderView(view); + + await this.initScene(); + } + + async initScene() { + /******** sky *******/ + { + this.scene.exposure = 1; + this.scene.roughness = 0.56; + } + + /******** light *******/ + { + this.lightObj3D = new Object3D(); + this.lightObj3D.rotationX = 57; + this.lightObj3D.rotationY = 347; + this.lightObj3D.rotationZ = 10; + let directLight = this.lightObj3D.addComponent(DirectLight); + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = true; + directLight.intensity = 20; + this.scene.addChild(this.lightObj3D); + + GUIHelp.init(); + GUIUtil.renderDirLight(directLight); + } + + { + let texture = await Engine3D.res.loadTexture("particle/T_Fx_Object_229.png"); + + //add leaf + let leafMaterial = new LitMaterial(); + leafMaterial.doubleSide = true; + leafMaterial.baseMap = texture; + leafMaterial.blendMode = BlendMode.ALPHA; + let geometry = new BoxGeometry(2, 2, 2); + for (let i = 0; i < 25; i++) { + let leaf = new Object3D(); + let renderer = leaf.addComponent(MeshRenderer); + renderer.material = leafMaterial; + renderer.geometry = geometry; + this.scene.addChild(leaf); + leaf.x = Math.random() * 20 - 10; + leaf.y = 3 + Math.random(); + leaf.z = Math.random() * 20 - 10; + } + + //add floor + let floorMaterial = new LitMaterial(); + floorMaterial.baseColor = new Color(1.0, 1.0, 1.0, 1); + let floor = new Object3D(); + let renderer = floor.addComponent(MeshRenderer); + renderer.material = floorMaterial; + renderer.geometry = new PlaneGeometry(100, 100, 1, 1); + this.scene.addChild(floor); + } + } +} + +new Sample_RenderPassClean().run(); \ No newline at end of file diff --git a/samples/material/Sample_ReplaceMaterial.ts b/samples/material/Sample_ReplaceMaterial.ts new file mode 100644 index 00000000..99b032b6 --- /dev/null +++ b/samples/material/Sample_ReplaceMaterial.ts @@ -0,0 +1,78 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Engine3D, Scene3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Object3D, MeshRenderer, UnLitMaterial, DirectLight, KelvinUtil, Color, GPUCullMode, LitMaterial } from "@orillusion/core"; + +//Sample of change meshRenderer's material +class Sample_ReplaceMaterial { + lightObj3D: Object3D; + + async run() { + await Engine3D.init({ canvasConfig: { alpha: false, zIndex: 0 } }); + + let scene = new Scene3D(); + scene.addComponent(AtmosphericComponent); + + let camera = CameraUtil.createCamera3DObject(scene); + camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); + + camera.object3D.addComponent(HoverCameraController).setCamera(0, 0, 20); + + let view = new View3D(); + view.scene = scene; + view.camera = camera; + Engine3D.startRenderView(view); + + this.createLight(scene); + + await this.loadModel(scene); + } + + //create light + createLight(scene: Scene3D) { + this.lightObj3D = new Object3D(); + this.lightObj3D.x = 0; + this.lightObj3D.y = 30; + this.lightObj3D.z = -40; + this.lightObj3D.rotationX = 77; + this.lightObj3D.rotationY = 77; + this.lightObj3D.rotationZ = 41; + + let directLight = this.lightObj3D.addComponent(DirectLight); + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = true; + directLight.intensity = 10; + scene.addChild(this.lightObj3D); + } + + async loadModel(scene: Scene3D) { + let monitor = await Engine3D.res.loadGltf('gltfs/monitor/scene.gltf'); + scene.addChild(monitor); + monitor.scaleX = monitor.scaleY = monitor.scaleZ = 2; + + // get child by name 'Screen' + let screen = monitor.getChildByName('Screen') as Object3D; + let meshRenderer = screen.getComponentsInChild(MeshRenderer)[0]; + + let material1 = new UnLitMaterial(); + material1.baseMap = await Engine3D.res.loadTexture('textures/normal.jpg'); + + let material2 = new UnLitMaterial(); + material2.baseMap = await Engine3D.res.loadTexture('textures/diffuse.jpg'); + + meshRenderer.material = material2; + + // init gui + GUIHelp.init(); + GUIHelp.addButton('Switch Material', () => { + if (meshRenderer.material == material2) { + meshRenderer.material = material1; + } else { + meshRenderer.material = material2; + } + }); + GUIHelp.open(); + GUIHelp.endFolder(); + } +} + + +new Sample_ReplaceMaterial().run(); \ No newline at end of file diff --git a/samples/material/Sample_UVMove.ts b/samples/material/Sample_UVMove.ts new file mode 100644 index 00000000..942c4745 --- /dev/null +++ b/samples/material/Sample_UVMove.ts @@ -0,0 +1,96 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Object3D, DirectLight, KelvinUtil, MeshRenderer, UnLitMaterial, PlaneGeometry, LitMaterial, Color } from "@orillusion/core"; +import { UVMoveComponent } from "@samples/material/script/UVMoveComponent"; +import { GUIUtil } from "@samples/utils/GUIUtil"; + + +class Sample_UVMove { + scene: Scene3D; + + async run() { + await Engine3D.init(); + + Engine3D.setting.material.materialChannelDebug = true; + Engine3D.setting.shadow.shadowBound = 5; + Engine3D.setting.shadow.shadowBias = 0.002; + Engine3D.setting.render.postProcessing.bloom = { + enable: true, + blurX: 4, + blurY: 4, + intensity: 5, + brightness: 0.629, + debug: true + }; + + this.scene = new Scene3D(); + this.scene.addComponent(AtmosphericComponent); + + let camera = CameraUtil.createCamera3DObject(this.scene); + camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); + + camera.object3D.addComponent(HoverCameraController).setCamera(25, -25, 200); + + let view = new View3D(); + view.scene = this.scene; + view.camera = camera; + + Engine3D.startRenderView(view); + + await this.initScene(); + } + + async initScene() { + /******** sky *******/ + { + this.scene.exposure = 1; + this.scene.roughness = 0.0; + } + /******** light *******/ + { + let lightObj = new Object3D(); + lightObj.rotationX = 57; + lightObj.rotationY = 347; + lightObj.rotationZ = 10; + + let directLight = lightObj.addComponent(DirectLight); + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = true; + directLight.intensity = 6; + this.scene.addChild(lightObj); + } + + { + // add plane into scene + let plane = new Object3D(); + let renderer = plane.addComponent(MeshRenderer); + let material = new UnLitMaterial(); + material.baseMap = await Engine3D.res.loadTexture("particle/T_Fx_Object_229.png");; + renderer.material = material; + renderer.geometry = new PlaneGeometry(100, 100, 1, 1); + this.scene.addChild(plane); + + // add UVMoveComponents + GUIHelp.init(); + let component = plane.addComponent(UVMoveComponent); + GUIUtil.renderUVMove(component); + } + + { + // add floor + let floor = new Object3D(); + let material = new LitMaterial(); + material.doubleSide = true; + material.baseMap = await Engine3D.res.loadTexture("textures/diffuse.jpg"); + + let renderer = floor.addComponent(MeshRenderer); + renderer.material = material; + renderer.geometry = new PlaneGeometry(200, 200, 1, 1); + + floor.y = -10; + this.scene.addChild(floor); + } + } + +} + +new Sample_UVMove().run(); \ No newline at end of file diff --git a/samples/material/Sample_UnlitMaterial.ts b/samples/material/Sample_UnlitMaterial.ts new file mode 100644 index 00000000..fd1f88f1 --- /dev/null +++ b/samples/material/Sample_UnlitMaterial.ts @@ -0,0 +1,79 @@ +import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, DirectLight, KelvinUtil, BitmapTexture2D, PointLight, Texture, LambertMaterial, Color, PlaneGeometry, MeshRenderer, Object3DUtil, UnLitMaterial } from "@orillusion/core"; + +class Sample_UnlitMaterial { + lightObj3D: Object3D; + scene: Scene3D; + + async run() { + await Engine3D.init(); + + this.scene = new Scene3D(); + this.scene.addComponent(AtmosphericComponent); + + let mainCamera = CameraUtil.createCamera3DObject(this.scene); + + mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.object3D.addComponent(HoverCameraController).setCamera(45, -45, 50); + + await this.initScene(this.scene); + + let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + Engine3D.startRenderView(view); + + } + + async initScene(scene: Scene3D) { + { + this.lightObj3D = new Object3D(); + this.lightObj3D.x = 0; + this.lightObj3D.y = 30; + this.lightObj3D.z = -40; + this.lightObj3D.rotationX = 46; + this.lightObj3D.rotationY = 62; + this.lightObj3D.rotationZ = 160; + let directLight = this.lightObj3D.addComponent(DirectLight); + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = true; + directLight.intensity = 0.0; + scene.addChild(this.lightObj3D); + } + + // load texture + let texture = new BitmapTexture2D(); + await texture.load('gltfs/Demonstration/T_Rollets_BC.jpg'); + + this.createObject(scene, texture); + { + let sphere = Object3DUtil.Sphere; + sphere.scaleX = 5; + sphere.scaleY = 5; + sphere.scaleZ = 5; + sphere.y = 10; + this.scene.addChild(sphere); + } + return true; + } + + private createObject(scene: Scene3D, texture: Texture): Object3D { + let mat = new UnLitMaterial(); + mat.shaderState.acceptGI = false; + mat.baseMap = texture; + mat.baseColor = new Color(1, 1, 1, 1); + + let obj: Object3D = new Object3D(); + + let render = obj.addComponent(MeshRenderer); + render.material = mat; + render.geometry = new PlaneGeometry(200, 200); + obj.y = 1; + scene.addChild(obj); + + return obj; + } + +} + +new Sample_UnlitMaterial().run(); diff --git a/samples/material/script/UVMoveComponent.ts b/samples/material/script/UVMoveComponent.ts new file mode 100644 index 00000000..bf1b23cd --- /dev/null +++ b/samples/material/script/UVMoveComponent.ts @@ -0,0 +1,33 @@ +import { ComponentBase, MaterialBase, Vector4, MeshRenderer, Time } from "@orillusion/core"; + +export class UVMoveComponent extends ComponentBase { + + private _material: MaterialBase; + private readonly _speed: Vector4 = new Vector4(0.1, 0.1, 1, 1); + + public get speed(): Vector4 { + return this._speed; + } + + public set speed(value: Vector4) { + this._speed.copyFrom(value); + } + + start(): void { + let mr = this.object3D.getComponent(MeshRenderer); + if (mr) { + this._material = mr.material; + } + } + + onUpdate(): void { + if (this._material) { + let value = this._material.uvTransform_1; + value.x += Time.delta * this._speed.x * 0.001; + value.y += Time.delta * this._speed.y * 0.001; + value.z = this._speed.z; + value.w = this._speed.w; + this._material.uvTransform_1 = value;; + } + } +} \ No newline at end of file diff --git a/samples/render/Sample_BlendMode2.ts b/samples/render/Sample_BlendMode2.ts new file mode 100644 index 00000000..320d573b --- /dev/null +++ b/samples/render/Sample_BlendMode2.ts @@ -0,0 +1,107 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Object3D, DirectLight, KelvinUtil, MeshRenderer, UnLitMaterial, PlaneGeometry, BlendMode, GPUCullMode, LitMaterial, Color } from "@orillusion/core"; + +class Sample_BlendMode2 { + scene: Scene3D; + + async run() { + await Engine3D.init(); + + Engine3D.setting.material.materialChannelDebug = true; + Engine3D.setting.shadow.shadowBound = 5; + Engine3D.setting.shadow.shadowBias = 0.002; + Engine3D.setting.render.postProcessing.bloom = { + enable: true, + blurX: 4, + blurY: 4, + intensity: 5, + brightness: 0.629, + debug: true + }; + + this.scene = new Scene3D(); + this.scene.addComponent(AtmosphericComponent); + + let camera = CameraUtil.createCamera3DObject(this.scene); + camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); + + camera.object3D.addComponent(HoverCameraController).setCamera(25, -60, 200); + + let view = new View3D(); + view.scene = this.scene; + view.camera = camera; + + Engine3D.startRenderView(view); + + await this.initScene(); + } + + async initScene() { + /******** sky *******/ + { + this.scene.exposure = 1; + this.scene.roughness = 0.0; + } + /******** light *******/ + { + let lightObj = new Object3D(); + lightObj.rotationX = 57; + lightObj.rotationY = 347; + lightObj.rotationZ = 10; + + let directLight = lightObj.addComponent(DirectLight); + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = true; + directLight.intensity = 6; + directLight.debug(); + this.scene.addChild(lightObj); + } + + { + // add plane into scene + let plane = new Object3D(); + let renderer = plane.addComponent(MeshRenderer); + let material = new UnLitMaterial(); + material.baseMap = await Engine3D.res.loadTexture("particle/T_Fx_Object_229.png");; + renderer.material = material; + renderer.geometry = new PlaneGeometry(100, 100, 1, 1); + material.blendMode = BlendMode.ALPHA; + this.scene.addChild(plane); + + GUIHelp.init(); + + // blend mode + let blendMode = { + NONE: BlendMode.NONE, + NORMAL: BlendMode.NORMAL, + ADD: BlendMode.ADD, + ALPHA: BlendMode.ALPHA, + } + // change blend mode by click dropdown box + GUIHelp.add({ blendMode: material.blendMode }, 'blendMode', blendMode).onChange((v) => { + material.blendMode = BlendMode[BlendMode[parseInt(v)]]; + }); + GUIHelp.open(); + GUIHelp.endFolder(); + + } + + { + // add floor + let floor = new Object3D(); + let material = new LitMaterial(); + material.doubleSide = true; + material.baseMap = await Engine3D.res.loadTexture("textures/diffuse.jpg"); + + let renderer = floor.addComponent(MeshRenderer); + renderer.material = material; + renderer.geometry = new PlaneGeometry(200, 200, 1, 1); + + floor.y = -10; + this.scene.addChild(floor); + } + } + +} + +new Sample_BlendMode2().run(); \ No newline at end of file diff --git a/samples/render/Sample_CullMode.ts b/samples/render/Sample_CullMode.ts new file mode 100644 index 00000000..1dd93832 --- /dev/null +++ b/samples/render/Sample_CullMode.ts @@ -0,0 +1,62 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Engine3D, Scene3D, AtmosphericComponent, Object3D, Camera3D, OrbitController, DirectLight, Color, View3D, BitmapTexture2D, UnLitMaterial, MeshRenderer, PlaneGeometry, Vector3, GPUCullMode, CameraUtil, webGPUContext } from "@orillusion/core"; + +class Sample_CullMode { + async run() { + await Engine3D.init(); + GUIHelp.init(); + + let scene = new Scene3D(); + scene.addComponent(AtmosphericComponent); + + let camera = CameraUtil.createCamera3DObject(scene); + camera.perspective(60, webGPUContext.aspect, 0.01, 10000.0); + camera.object3D.z = 3; + + let oribit = camera.object3D.addComponent(OrbitController); + oribit.autoRotate = true; + oribit.autoRotateSpeed = 1; + + let view = new View3D(); + view.scene = scene; + view.camera = camera; + + Engine3D.startRenderView(view); + + // add direct light + let lightObj = new Object3D(); + lightObj.rotationX = -45; + let light = lightObj.addComponent(DirectLight); + light.lightColor = new Color(1.0, 1.0, 1.0, 1.0); + light.intensity = 10; + scene.addChild(lightObj); + + let planeObj: Object3D; + let texture = new BitmapTexture2D(); + await texture.load('https://cdn.orillusion.com/gltfs/cube/material_02.png'); + let material = new UnLitMaterial(); + material.baseMap = texture; + material.cullMode = GPUCullMode.none; + + planeObj = new Object3D(); + let mr = planeObj.addComponent(MeshRenderer); + mr.geometry = new PlaneGeometry(2, 2, 10, 10, Vector3.Z_AXIS); + mr.material = material; + scene.addChild(planeObj); + + //cull mode + let cullMode = {}; + cullMode[GPUCullMode.none] = GPUCullMode.none; + cullMode[GPUCullMode.front] = GPUCullMode.front; + cullMode[GPUCullMode.back] = GPUCullMode.back; + + // change cull mode by click dropdown box + GUIHelp.add({ cullMode: GPUCullMode.none }, 'cullMode', cullMode).onChange((v) => { + material.cullMode = v; + }); + GUIHelp.open(); + GUIHelp.endFolder(); + } +} + +new Sample_CullMode().run(); \ No newline at end of file diff --git a/samples/render/Sample_TextureSample.ts b/samples/render/Sample_TextureSample.ts new file mode 100644 index 00000000..624a2eac --- /dev/null +++ b/samples/render/Sample_TextureSample.ts @@ -0,0 +1,127 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, DirectLight, KelvinUtil, UnLitMaterial, MeshRenderer, PlaneGeometry, GPUAddressMode, GPUFilterMode, GPUCompareFunction, LitMaterial, Object3DUtil } from "@orillusion/core"; +import { GUIUtil } from "@samples/utils/GUIUtil"; +import { UVMoveComponent } from "@samples/material/script/UVMoveComponent"; + +class Sample_TextureSample { + lightObj3D: Object3D; + scene: Scene3D; + + async run() { + Engine3D.setting.material.materialChannelDebug = true; + Engine3D.setting.shadow.shadowBound = 5; + Engine3D.setting.shadow.shadowBias = 0.002; + + await Engine3D.init(); + + this.scene = new Scene3D(); + this.scene.addComponent(AtmosphericComponent); + let camera = CameraUtil.createCamera3DObject(this.scene); + camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); + + camera.object3D.addComponent(HoverCameraController).setCamera(25, -30, 100); + + let view = new View3D(); + view.scene = this.scene; + view.camera = camera; + + Engine3D.startRenderView(view); + + await this.initScene(); + } + + async initScene() { + /******** sky *******/ + { + this.scene.exposure = 1; + this.scene.roughness = 0.0; + } + /******** light *******/ + { + this.lightObj3D = new Object3D(); + this.lightObj3D.rotationX = 57; + this.lightObj3D.rotationY = 347; + this.lightObj3D.rotationZ = 10; + let directLight = this.lightObj3D.addComponent(DirectLight); + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = true; + directLight.intensity = 6; + GUIHelp.init(); + GUIUtil.renderDirLight(directLight, false); + this.scene.addChild(this.lightObj3D); + } + + { + // load texture + let texture = await Engine3D.res.loadTexture("textures/diffuse.jpg"); + let material = new LitMaterial(); + material.baseMap = texture; + + let plane = new Object3D(); + let renderer = plane.addComponent(MeshRenderer); + renderer.material = material; + renderer.geometry = new PlaneGeometry(100, 100, 1, 1); + this.scene.addChild(plane); + + let component = plane.addComponent(UVMoveComponent); + GUIUtil.renderUVMove(component); + + + this.scene.addChild(Object3DUtil.GetSingleCube(10, 10, 10, 1, 0.5, 0.5)); + + // enum GPUAddressMode + let address = {} + address[GPUAddressMode.repeat] = GPUAddressMode.repeat; + address[GPUAddressMode.clamp_to_edge] = GPUAddressMode.clamp_to_edge; + address[GPUAddressMode.mirror_repeat] = GPUAddressMode.mirror_repeat; + + // enum GPUFilterMode + let filter = {} + filter[GPUFilterMode.nearest] = GPUFilterMode.nearest; + filter[GPUFilterMode.linear] = GPUFilterMode.linear; + + // enum GPUCompareFunction + let depthCompare = {} + depthCompare[GPUCompareFunction.not_equal] = GPUCompareFunction.not_equal; + depthCompare[GPUCompareFunction.always] = GPUCompareFunction.always; + depthCompare[GPUCompareFunction.never] = GPUCompareFunction.never; + depthCompare[GPUCompareFunction.not_equal] = GPUCompareFunction.not_equal; + depthCompare[GPUCompareFunction.greater_equal] = GPUCompareFunction.greater_equal; + depthCompare[GPUCompareFunction.greater] = GPUCompareFunction.greater; + depthCompare[GPUCompareFunction.less_equal] = GPUCompareFunction.less_equal; + depthCompare[GPUCompareFunction.less] = GPUCompareFunction.less; + + // GUI + GUIHelp.addFolder("Texture Sampler"); + GUIHelp.add({ addressModeU: texture.addressModeU }, 'addressModeU', address).onChange((v) => { + texture.addressModeU = v; + }); + GUIHelp.add({ addressModeV: texture.addressModeV }, 'addressModeV', address).onChange((v) => { + texture.addressModeV = v; + }); + + GUIHelp.add({ minFilter: texture.minFilter }, 'minFilter', filter).onChange((v) => { + texture.minFilter = v; + }); + GUIHelp.add({ magFilter: texture.magFilter }, 'magFilter', filter).onChange((v) => { + texture.magFilter = v; + }); + + GUIHelp.add({ mipmapFilter: texture.mipmapFilter }, 'mipmapFilter', filter).onChange((v) => { + texture.mipmapFilter = v; + }); + + GUIHelp.add({ depthCompare: material.depthCompare }, 'depthCompare', depthCompare).onChange((v) => { + material.depthCompare = v; + }); + + GUIHelp.add(texture, 'useMipmap'); + + GUIHelp.open(); + GUIHelp.endFolder(); + } + } + +} + +new Sample_TextureSample().run(); \ No newline at end of file diff --git a/samples/sky/Sample_AtmosphericSky.ts b/samples/sky/Sample_AtmosphericSky.ts index cd5fb22a..327f6b02 100644 --- a/samples/sky/Sample_AtmosphericSky.ts +++ b/samples/sky/Sample_AtmosphericSky.ts @@ -1,5 +1,6 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Texture, AtmosphericScatteringSky } from "@orillusion/core"; +import { GUIUtil } from "@samples/utils/GUIUtil"; // sample of AtmosphericSky class Sample_AtmosphericSky { @@ -19,8 +20,7 @@ class Sample_AtmosphericSky { mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); // camera controller - let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); - hoverCameraController.setCamera(45, -10, 10); + mainCamera.object3D.addComponent(HoverCameraController).setCamera(45, -10, 10); // init view3D let view = new View3D(); @@ -31,23 +31,10 @@ class Sample_AtmosphericSky { Engine3D.startRenderView(view); // gui - this.debug(component); - } - - private debug(component: AtmosphericComponent) { GUIHelp.init(); - GUIHelp.addFolder('AtmosphericSky'); - GUIHelp.add(component, 'sunX', 0, 1, 0.01); - GUIHelp.add(component, 'sunY', 0, 1, 0.01); - GUIHelp.add(component, 'eyePos', 0, 5000, 1); - GUIHelp.add(component, 'sunRadius', 0, 1000, 0.01); - GUIHelp.add(component, 'sunRadiance', 0, 100, 0.01); - GUIHelp.add(component, 'sunBrightness', 0, 10, 0.01); - GUIHelp.add(component, 'exposure', 0, 2, 0.01); - GUIHelp.add(component, 'displaySun', 0, 1, 0.01); - GUIHelp.open(); - GUIHelp.endFolder(); + GUIUtil.renderAtomosphericSky(component); } + } new Sample_AtmosphericSky().run(); \ No newline at end of file diff --git a/samples/utils/GUIUtil.ts b/samples/utils/GUIUtil.ts new file mode 100644 index 00000000..4840e6ab --- /dev/null +++ b/samples/utils/GUIUtil.ts @@ -0,0 +1,71 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { AtmosphericComponent, DirectLight, Transform } from "@orillusion/core"; +import { UVMoveComponent } from "@samples/material/script/UVMoveComponent"; + +export class GUIUtil { + + //render AtmosphericComponent + public static renderAtomosphericSky(component: AtmosphericComponent, open: boolean = true, name?: string) { + name ||= 'AtmosphericSky'; + GUIHelp.addFolder(name); + GUIHelp.add(component, 'sunX', 0, 1, 0.01); + GUIHelp.add(component, 'sunY', 0, 1, 0.01); + GUIHelp.add(component, 'eyePos', 0, 5000, 1); + GUIHelp.add(component, 'sunRadius', 0, 1000, 0.01); + GUIHelp.add(component, 'sunRadiance', 0, 100, 0.01); + GUIHelp.add(component, 'sunBrightness', 0, 10, 0.01); + GUIHelp.add(component, 'exposure', 0, 2, 0.01); + GUIHelp.add(component, 'displaySun', 0, 1, 0.01); + open && GUIHelp.open(); + GUIHelp.endFolder(); + } + + //render transform + public static renderTransform(transform: Transform, open: boolean = true, name?: string) { + name ||= 'Transform'; + GUIHelp.addFolder(name); + GUIHelp.add(transform, 'x', -10.0, 10.0, 0.01); + GUIHelp.add(transform, 'y', -10.0, 10.0, 0.01); + GUIHelp.add(transform, 'z', -10.0, 10.0, 0.01); + GUIHelp.add(transform, 'rotationX', 0.0, 360.0, 0.01); + GUIHelp.add(transform, 'rotationY', 0.0, 360.0, 0.01); + GUIHelp.add(transform, 'rotationZ', 0.0, 360.0, 0.01); + GUIHelp.add(transform, 'scaleX', 0.0, 2.0, 0.01); + GUIHelp.add(transform, 'scaleY', 0.0, 2.0, 0.01); + GUIHelp.add(transform, 'scaleZ', 0.0, 2.0, 0.01); + + open && GUIHelp.open(); + GUIHelp.endFolder(); + } + + //render direct light gui panel + public static renderDirLight(light: DirectLight, open: boolean = true, name?: string) { + name ||= 'DirectLight'; + GUIHelp.addFolder(name); + GUIHelp.add(light.transform, 'rotationX', 0.0, 360.0, 0.01); + GUIHelp.add(light.transform, 'rotationY', 0.0, 360.0, 0.01); + GUIHelp.add(light.transform, 'rotationZ', 0.0, 360.0, 0.01); + GUIHelp.addColor(light, 'lightColor'); + GUIHelp.add(light, 'intensity', 0.0, 160.0, 0.01); + GUIHelp.add(light, 'indirect', 0.0, 10.0, 0.01); + + open && GUIHelp.open(); + GUIHelp.endFolder(); + } + + //render uv move component + public static renderUVMove(component: UVMoveComponent, open: boolean = true, name?: string) { + name ||= 'UV Move'; + GUIHelp.addFolder(name); + GUIHelp.add(component.speed, 'x', -1, 1, 0.01); + GUIHelp.add(component.speed, 'y', -1, 1, 0.01); + GUIHelp.add(component.speed, 'z', 0.1, 10, 0.01); + GUIHelp.add(component.speed, 'w', 0.1, 10, 0.01); + GUIHelp.add(component, 'enable'); + + open && GUIHelp.open(); + GUIHelp.endFolder(); + } + + +} \ No newline at end of file diff --git a/test/components/test/TestComponents.ts b/test/components/test/TestComponents.ts index 78f470d6..d49f8030 100644 --- a/test/components/test/TestComponents.ts +++ b/test/components/test/TestComponents.ts @@ -1,4 +1,4 @@ -import { ComponentBase } from "../../../src/components/ComponentBase"; +import { ComponentBase } from "@orillusion/core"; export class TestComponents extends ComponentBase { public initState: boolean = false; From 5e6fcdbc1e980a4e7b99e9865753572cf3150cd9 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Sun, 7 May 2023 16:38:41 +0800 Subject: [PATCH 097/100] fix(MatrixDO): MatrixDO Buffer (#108) * fix(MatrixDO): MatrixDO Buffer fix matrixDO Buffer Descript bytesLength count wrong --- samples/base/Sample_Transform.ts | 2 +- samples/material/Sample_PBRMaterial.ts | 4 +- src/Engine3D.ts | 4 +- src/components/Transform.ts | 12 +-- src/components/renderer/RenderNode.ts | 75 +++++++++---------- src/core/Scene3D.ts | 10 --- .../core/bindGroups/GlobalUniformGroup.ts | 15 +--- .../webGpu/core/bindGroups/MatrixBindGroup.ts | 1 + src/math/Matrix4.ts | 23 +++--- 9 files changed, 56 insertions(+), 90 deletions(-) diff --git a/samples/base/Sample_Transform.ts b/samples/base/Sample_Transform.ts index 1841bbe4..79f38006 100644 --- a/samples/base/Sample_Transform.ts +++ b/samples/base/Sample_Transform.ts @@ -24,7 +24,7 @@ class Sample_Transform { // add a basic camera controller let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); - hoverCameraController.setCamera(15, -15, 10); + hoverCameraController.setCamera(15, -15, 300); // create a basic cube let cubeObj = new Object3D(); diff --git a/samples/material/Sample_PBRMaterial.ts b/samples/material/Sample_PBRMaterial.ts index 1c9c7b41..47382321 100644 --- a/samples/material/Sample_PBRMaterial.ts +++ b/samples/material/Sample_PBRMaterial.ts @@ -26,7 +26,6 @@ class Sample_PBRMaterial { GUIHelp.init(999); this.scene = new Scene3D(); - this.scene.hideSky(); let camera = CameraUtil.createCamera3DObject(this.scene); camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); @@ -43,7 +42,8 @@ class Sample_PBRMaterial { async initScene() { /******** sky *******/ { - this.scene.addComponent(AtmosphericComponent); + let sky = this.scene.addComponent(AtmosphericComponent); + sky.enable = false; } /******** light *******/ { diff --git a/src/Engine3D.ts b/src/Engine3D.ts index da6717df..de6a82c0 100644 --- a/src/Engine3D.ts +++ b/src/Engine3D.ts @@ -294,7 +294,7 @@ export class Engine3D { this.renderJobs.set(view, renderJob); renderJob.addPost(new FXAAPost()); renderJob.start(); - this.render(0); + this.resume(); return renderJob; } @@ -314,7 +314,7 @@ export class Engine3D { renderJob.addPost(new FXAAPost()); renderJob.start(); } - this.render(0); + this.resume(); } /** diff --git a/src/components/Transform.ts b/src/components/Transform.ts index 1c17ae97..8675dba0 100644 --- a/src/components/Transform.ts +++ b/src/components/Transform.ts @@ -94,7 +94,7 @@ export class Transform extends ComponentBase { private _left: Vector3 = new Vector3(); private _up: Vector3 = new Vector3(); private _down: Vector3 = new Vector3(); - public _worldMatrix: Matrix4; + public readonly _worldMatrix: Matrix4; private _localChange: boolean = true; private _targetPos: Vector3; @@ -160,7 +160,7 @@ export class Transform extends ComponentBase { constructor() { super(); - this.worldMatrix = new Matrix4(false); + this._worldMatrix = new Matrix4(true); this._localPos = new Vector3(); this._localRot = new Vector3(); this._localRotQuat = new Quaternion(); @@ -352,13 +352,6 @@ export class Transform extends ComponentBase { return this._worldMatrix; } - /** - * @internal - */ - public set worldMatrix(value: Matrix4) { - this._worldMatrix = value; - } - /** * * Update the matrix4 in world space @@ -429,7 +422,6 @@ export class Transform extends ComponentBase { this.localRotQuat = null; this.localRotation = null; this.localScale = null; - this._worldMatrix = null; } super.destroy(); } diff --git a/src/components/renderer/RenderNode.ts b/src/components/renderer/RenderNode.ts index 07982f0e..5ecffb53 100644 --- a/src/components/renderer/RenderNode.ts +++ b/src/components/renderer/RenderNode.ts @@ -240,8 +240,6 @@ export class RenderNode extends ComponentBase { this._castReflection = value; } - - public renderPass(view: View3D, passType: RendererType, renderContext: RenderContext) { let renderNode = this; for (let i = 0; i < renderNode.materials.length; i++) { @@ -251,7 +249,7 @@ export class RenderNode extends ComponentBase { if (!passes || passes.length == 0) continue; GPUContext.bindGeometryBuffer(renderContext.encoder, renderNode._geometry); - let worldMatrix = renderNode.object3D.transform._worldMatrix; + let worldMatrix = renderNode.transform._worldMatrix; for (let j = 0; j < passes.length; j++) { if (!passes || passes.length == 0) continue; let matPass = passes[j]; @@ -260,7 +258,6 @@ export class RenderNode extends ComponentBase { // for (let j = passes.length > 1 ? 1 : 0 ; j < passes.length; j++) { const renderShader = matPass.renderShader; if (renderShader.shaderState.splitTexture) { - renderContext.endRenderPass(); RTResourceMap.WriteSplitColorTexture(renderNode.instanceID); renderContext.beginRenderPass(); @@ -270,17 +267,17 @@ export class RenderNode extends ComponentBase { } GPUContext.bindPipeline(renderContext.encoder, renderShader); let subGeometries = renderNode._geometry.subGeometries; - for (let k = 0; k < subGeometries.length; k++) { - const subGeometry = subGeometries[k]; - let lodInfos = subGeometry.lodLevels; - let lodInfo = lodInfos[renderNode.lodLevel]; + // for (let k = 0; k < subGeometries.length; k++) { + const subGeometry = subGeometries[i]; + let lodInfos = subGeometry.lodLevels; + let lodInfo = lodInfos[renderNode.lodLevel]; - if (renderNode.instanceCount > 0) { - GPUContext.drawIndexed(renderContext.encoder, lodInfo.indexCount, renderNode.instanceCount, lodInfo.indexStart, 0, 0); - } else { - GPUContext.drawIndexed(renderContext.encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); - } + if (renderNode.instanceCount > 0) { + GPUContext.drawIndexed(renderContext.encoder, lodInfo.indexCount, renderNode.instanceCount, lodInfo.indexStart, 0, 0); + } else { + GPUContext.drawIndexed(renderContext.encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); } + // } } } } @@ -305,24 +302,21 @@ export class RenderNode extends ComponentBase { let worldMatrix = node.object3D.transform._worldMatrix; if (this.drawType == 2) { - for (let i = 0; i < passes.length; i++) { - let renderShader = passes[i].renderShader; + for (let j = 0; j < passes.length; j++) { + let renderShader = passes[j].renderShader; GPUContext.bindPipeline(encoder, renderShader); GPUContext.draw(encoder, 6, 1, 0, worldMatrix.index); } } else { GPUContext.bindGeometryBuffer(encoder, node._geometry); - for (let i = 0; i < passes.length; i++) { - let renderShader = passes[i].renderShader; - + for (let j = 0; j < passes.length; j++) { + let renderShader = passes[j].renderShader; GPUContext.bindPipeline(encoder, renderShader); let subGeometries = node._geometry.subGeometries; - for (let k = 0; k < subGeometries.length; k++) { - const subGeometry = subGeometries[k]; - let lodInfos = subGeometry.lodLevels; - let lodInfo = lodInfos[node.lodLevel]; - GPUContext.drawIndexed(encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); - } + const subGeometry = subGeometries[i]; + let lodInfos = subGeometry.lodLevels; + let lodInfo = lodInfos[node.lodLevel]; + GPUContext.drawIndexed(encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); } } @@ -343,17 +337,14 @@ export class RenderNode extends ComponentBase { if (!passes || passes.length == 0) return; let worldMatrix = node.object3D.transform._worldMatrix; - for (let i = 0; i < passes.length; i++) { - const renderShader = passes[i].renderShader; - + for (let j = 0; j < passes.length; j++) { + const renderShader = passes[j].renderShader; GPUContext.bindPipeline(encoder, renderShader); let subGeometries = node._geometry.subGeometries; - for (let k = 0; k < subGeometries.length; k++) { - const subGeometry = subGeometries[k]; - let lodInfos = subGeometry.lodLevels; - let lodInfo = lodInfos[node.lodLevel]; - GPUContext.drawIndexed(encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); - } + const subGeometry = subGeometries[i]; + let lodInfos = subGeometry.lodLevels; + let lodInfo = lodInfos[node.lodLevel]; + GPUContext.drawIndexed(encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); } } @@ -373,16 +364,15 @@ export class RenderNode extends ComponentBase { let passes = material.renderPasses.get(passType); if (passes) { for (let i = 0; i < passes.length; i++) { - const pass = passes[i];// RenderShader.getShader(passes[i].shaderID); - const renderShader = pass.renderShader;// RenderShader.getShader(passes[i].shaderID); - + const pass = passes[i]; + // RenderShader.getShader(passes[i].shaderID); + const renderShader = pass.renderShader; + // RenderShader.getShader(passes[i].shaderID); if (renderShader.shaderState.splitTexture) { let splitTexture = RTResourceMap.CreateSplitTexture(this.instanceID); renderShader.setTexture("splitTexture_Map", splitTexture); } - // renderShader.setUniformVector3("center", this.transform.worldPosition); - // if(scene3D.envMapChange){ if (!this._ignoreEnvMap) { renderShader.setTexture(`envMap`, view.scene.envMap); @@ -400,13 +390,16 @@ export class RenderNode extends ComponentBase { let bdrflutTex = Engine3D.res.getTexture(`BRDFLUT`); renderShader.setTexture(`brdflutMap`, bdrflutTex); - if (Engine3D.getRenderJob(view).shadowMapPassRenderer.depth2DTextureArray) { + let shadowRenderer = Engine3D.getRenderJob(view).shadowMapPassRenderer; + if (shadowRenderer && shadowRenderer.depth2DTextureArray) { renderShader.setTexture(`shadowMap`, Engine3D.getRenderJob(view).shadowMapPassRenderer.depth2DTextureArray); } - // let shadowLight = ShadowLights.list; // if (shadowLight.length) { - renderShader.setTexture(`pointShadowMap`, Engine3D.getRenderJob(view).pointLightShadowRenderer.cubeTextureArray); + let pointShadowRenderer = Engine3D.getRenderJob(view).pointLightShadowRenderer; + if (pointShadowRenderer && pointShadowRenderer.cubeTextureArray) { + renderShader.setTexture(`pointShadowMap`, pointShadowRenderer.cubeTextureArray); + } // } let iesTexture = IESProfiles.iesTexture; diff --git a/src/core/Scene3D.ts b/src/core/Scene3D.ts index a5e36b0a..0a74dcea 100644 --- a/src/core/Scene3D.ts +++ b/src/core/Scene3D.ts @@ -47,16 +47,6 @@ export class Scene3D extends Object3D { EntityCollect.instance.sky.map = value; } - public showSky() { - // if (EntityCollect.instance.sky) - // EntityCollect.instance.sky.enable = true; - } - - public hideSky() { - // if (EntityCollect.instance.sky) - // EntityCollect.instance.sky.enable = false; - } - /** * Exposure of Sky Box. A larger value produces a sky box with stronger exposure and a brighter appearance. * A smaller value produces a sky box with weaker exposure and a darker appearance. diff --git a/src/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts b/src/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts index 3df006b0..bab2d9b3 100644 --- a/src/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts +++ b/src/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts @@ -40,7 +40,7 @@ export class GlobalUniformGroup { createBindGroup() { this.uniformByteLength = this.uniformGPUBuffer.memory.shareDataBuffer.byteLength; - this.matrixesByteLength = Matrix4.blockBytes * Matrix4.totalCount; + this.matrixesByteLength = Matrix4.blockBytes * Matrix4.maxCount; this.globalBindGroup = webGPUContext.device.createBindGroup({ label: `global_bindGroupLayout`, @@ -130,18 +130,5 @@ export class GlobalUniformGroup { public addUniformNode() { } - writeBuffer() { - const matBytes = Matrix4.matrixBytes; - let totalBytes = matBytes.byteLength; - let offsetBytes = 0; - // webGPUContext.device.queue.writeBuffer(this.matrixBufferDst, offsetBytes, matBytes.buffer, matBytes.byteOffset, matBytes.byteLength); - - const space = 5000 * 64; // 5000 * 16 * 4 - while (offsetBytes < totalBytes) { - let len = Math.min(space, totalBytes - offsetBytes); - webGPUContext.device.queue.writeBuffer(this.matrixBindGroup.matrixBufferDst.buffer, offsetBytes, matBytes.buffer, matBytes.byteOffset + offsetBytes, len); - offsetBytes += len; - } - } } diff --git a/src/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts b/src/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts index 32eecb67..21453b60 100644 --- a/src/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts +++ b/src/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts @@ -22,6 +22,7 @@ export class MatrixBindGroup { this.cacheWorldMatrix(); } + private cacheWorldMatrix() { this.groupBufferSize = Matrix4.maxCount * Matrix4.blockBytes; this.matrixBufferDst = new StorageGPUBuffer(this.groupBufferSize / 4); diff --git a/src/math/Matrix4.ts b/src/math/Matrix4.ts index fe4ad483..0d51d853 100644 --- a/src/math/Matrix4.ts +++ b/src/math/Matrix4.ts @@ -24,12 +24,12 @@ export class Matrix4 { /** * matrix do total count */ - public static totalCount: number = 0; + public static allocCount: number = 0; /** * matrix has max limit count */ - public static maxCount: number = 300000; + public static maxCount: number = 200000; /** * current matrix use count @@ -119,10 +119,10 @@ export class Matrix4 { * @param count every alloc matrix count * @version Orillusion3D 0.5.1 */ - public static allocMatrix(totalCount: number) { - this.totalCount = totalCount; + public static allocMatrix(allocCount: number) { + this.allocCount = allocCount; - Matrix4.matrixBytes = new Float32Array(totalCount * 16); + Matrix4.matrixBytes = new Float32Array(allocCount * 16); Matrix4.buffer = Matrix4.matrixBytes.buffer; Matrix4.wasmMatrixPtr = 0; @@ -317,10 +317,10 @@ export class Matrix4 { * * @param local -- */ - constructor(local: boolean = true) { - // if (!local) { - if (Matrix4.useCount >= Matrix4.totalCount) { - Matrix4.allocMatrix(Matrix4.totalCount + 1000); + constructor(doMatrix: boolean = false) { + // if (doMatrix) { + if (Matrix4.useCount >= Matrix4.allocCount) { + Matrix4.allocMatrix(Matrix4.allocCount + 1000); } this.index = Matrix4.useCount; @@ -328,8 +328,11 @@ export class Matrix4 { Matrix4.globalMatrixRef[this.index] = this; Matrix4.useCount++; - + // console.log(this.index); this.rawData = new Float32Array(Matrix4.matrixBytes.buffer, this.offset, 16); + // } else { + // this.rawData = new Float32Array(16); + // } this._position = new Vector3(); From efc5f4defa031963107fe679bf31b21903a82898 Mon Sep 17 00:00:00 2001 From: "Mr.xu" <397939361@qq.com> Date: Sun, 7 May 2023 18:53:15 +0800 Subject: [PATCH 098/100] fix(ies): light ies has bug (#109) fix ies index not write --- src/components/lights/LightBase.ts | 12 ++++++------ src/components/lights/LightData.ts | 2 +- .../webGpu/core/bindGroups/groups/LightEntries.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/lights/LightBase.ts b/src/components/lights/LightBase.ts index e58b46f5..1160e703 100644 --- a/src/components/lights/LightBase.ts +++ b/src/components/lights/LightBase.ts @@ -48,7 +48,7 @@ export class LightBase extends ComponentBase implements ILight { protected _castGI: boolean = false; protected _castShadow: boolean = false; - private _iesPofiles: IESProfiles; + private _iesProfiles: IESProfiles; constructor() { super(); @@ -106,15 +106,15 @@ export class LightBase extends ComponentBase implements ILight { EntityCollect.instance.removeLight(this.transform.scene3D, this); } - public set iesPofile(iesPofiles: IESProfiles) { - this._iesPofiles = iesPofiles; - this.lightData.iesPofiles = iesPofiles.index; + public set iesProfiles(iesProfiles: IESProfiles) { + this._iesProfiles = iesProfiles; + this.lightData.iesIndex = iesProfiles.index; IESProfiles.use = true; this.onChange(); } - public get iesPofile(): IESProfiles { - return this._iesPofiles; + public get iesProfile(): IESProfiles { + return this._iesProfiles; } /** diff --git a/src/components/lights/LightData.ts b/src/components/lights/LightData.ts index 15a36410..88278cf0 100644 --- a/src/components/lights/LightData.ts +++ b/src/components/lights/LightData.ts @@ -103,5 +103,5 @@ export class LightData extends Struct { /** * Whether to use lighting ies */ - public iesPofiles: number = -1; + public iesIndex: number = -1; } diff --git a/src/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts b/src/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts index c75de7d4..1420d90c 100644 --- a/src/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts +++ b/src/gfx/graphics/webGpu/core/bindGroups/groups/LightEntries.ts @@ -65,6 +65,6 @@ export class LightEntries { memory.writeInt32(light.castShadowIndex); memory.writeVector3(light.lightTangent); - memory.writeFloat(-1); + memory.writeFloat(light.iesIndex); } } From 34ba5d9631f21cfc353dda61ff47fbe649d9d5cf Mon Sep 17 00:00:00 2001 From: Codeboy-cn Date: Sun, 7 May 2023 18:53:41 +0800 Subject: [PATCH 099/100] fix(HDRBloomPost): add luminosityThreshold arg (#106) add luminosityThreshold arg --- src/Engine3D.ts | 5 +++-- src/gfx/renderJob/post/HDRBloomPost.ts | 20 +++++++++++--------- src/setting/post/BloomSetting.ts | 10 +++++++--- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/Engine3D.ts b/src/Engine3D.ts index de6a82c0..26143bff 100644 --- a/src/Engine3D.ts +++ b/src/Engine3D.ts @@ -193,8 +193,9 @@ export class Engine3D { enable: false, blurX: 4, blurY: 4, - intensity: 0.25, - brightness: 1.3, + strength: 0.25, + radius: 1.3, + luminosityThreshold: 0.98, debug: false, }, fxaa: { diff --git a/src/gfx/renderJob/post/HDRBloomPost.ts b/src/gfx/renderJob/post/HDRBloomPost.ts index c75e78ca..6016ffb9 100644 --- a/src/gfx/renderJob/post/HDRBloomPost.ts +++ b/src/gfx/renderJob/post/HDRBloomPost.ts @@ -28,10 +28,12 @@ export class HDRBloomPost extends PostBase { public blurY: number = 1; constructor() { super(); - Engine3D.setting.render.postProcessing.bloom.enable = true; + const bloomSetting = Engine3D.setting.render.postProcessing.bloom; + + bloomSetting.enable = true; - this.blurX = Engine3D.setting.render.postProcessing.bloom.blurX; - this.blurY = Engine3D.setting.render.postProcessing.bloom.blurY; + this.blurX = bloomSetting.blurX; + this.blurY = bloomSetting.blurY; let presentationSize = webGPUContext.presentationSize; let outTextures = this.createRTTexture('HDRBloomPost-outTextures', presentationSize[0], presentationSize[1], GPUTextureFormat.rgba16float, false); @@ -41,7 +43,7 @@ export class HDRBloomPost extends PostBase { let brightnessTextures = this.createRTTexture('brightnessTextures', presentationSize[0], presentationSize[1], GPUTextureFormat.rgba16float, false); this.brightnessView = this.createViewQuad(`brightnessView`, `Bloom_Brightness_frag_wgsl`, brightnessTextures, { - luminosityThreshold: new UniformNode(Engine3D.setting.render.postProcessing.bloom.brightness), + luminosityThreshold: new UniformNode(bloomSetting.luminosityThreshold), }); } @@ -78,7 +80,7 @@ export class HDRBloomPost extends PostBase { { this.compositeView = this.createViewQuad(`compositeView`, `Bloom_composite_frag_wgsl`, outTextures, { - bloomStrength: new UniformNode(Engine3D.setting.render.postProcessing.bloom.intensity), + bloomStrength: new UniformNode(bloomSetting.strength), bloomRadius: new UniformNode(1), }); } @@ -94,19 +96,19 @@ export class HDRBloomPost extends PostBase { public debug() { } - public get bloomStrength() { + public get strength() { return this.compositeView.uniforms['bloomStrength'].value; } - public set bloomStrength(value: number) { + public set strength(value: number) { this.compositeView.uniforms['bloomStrength'].value = value; } - public get bloomRadius() { + public get radius() { return this.compositeView.uniforms['bloomRadius'].value; } - public set bloomRadius(value: number) { + public set radius(value: number) { this.compositeView.uniforms['bloomRadius'].value = value; } diff --git a/src/setting/post/BloomSetting.ts b/src/setting/post/BloomSetting.ts index c04b25f4..fcfa94c5 100644 --- a/src/setting/post/BloomSetting.ts +++ b/src/setting/post/BloomSetting.ts @@ -19,11 +19,15 @@ export type BloomSetting = { /** * Strength setting */ - intensity: number; + strength: number; /** - * Brightness setting + * Radius setting */ - brightness: number; + radius: number; + /** + * Luminosity threshold + */ + luminosityThreshold: number; /** * use debug or not */ From e47e027cfd27f61a6a0271732dc2bdc305806228 Mon Sep 17 00:00:00 2001 From: ShuangLiu Date: Sun, 7 May 2023 18:54:10 +0800 Subject: [PATCH 100/100] fix(sample): remove errors (#110) remove errors --- samples/base/Sample_InitEngine.ts | 4 +- samples/base/Sample_Transform.ts | 6 +- samples/base/Sample_UseComponent.ts | 4 +- samples/lights/Sample_DirectLight.ts | 4 +- samples/lights/Sample_PointLight.ts | 4 +- samples/lights/Sample_PointLightShadow.ts | 4 +- samples/lights/Sample_SpotLight.ts | 10 +- samples/loader/Sample_FlightHelmet.ts | 13 +-- samples/loader/Sample_LoadGLTF.ts | 19 ++-- samples/material/Sample_CustomMaterial.ts | 106 --------------------- samples/material/Sample_PBR.ts | 4 +- samples/material/Sample_PBRMaterial.ts | 10 +- samples/material/Sample_RenderPassClean.ts | 10 +- samples/material/Sample_ReplaceMaterial.ts | 78 --------------- samples/material/Sample_UVMove.ts | 4 +- samples/material/Sample_UnlitMaterial.ts | 15 ++- samples/render/Sample_BlendMode.ts | 4 +- samples/render/Sample_BlendMode2.ts | 4 +- samples/render/Sample_ChangeTexture.ts | 4 +- samples/render/Sample_CullMode.ts | 2 +- samples/render/Sample_TextureSample.ts | 6 +- samples/sky/Sample_AtmosphericSky.ts | 4 +- samples/sky/Sample_BitmapCubeSky.ts | 22 +---- samples/sky/Sample_BitmapCubeStdSky.ts | 23 ++--- samples/sky/Sample_HDRSky.ts | 22 ++--- samples/sky/Sample_LDRSky.ts | 23 ++--- samples/sky/Sample_SolidColorSky.ts | 24 +---- 27 files changed, 90 insertions(+), 343 deletions(-) delete mode 100644 samples/material/Sample_CustomMaterial.ts delete mode 100644 samples/material/Sample_ReplaceMaterial.ts diff --git a/samples/base/Sample_InitEngine.ts b/samples/base/Sample_InitEngine.ts index 5f952e9d..d8b94367 100644 --- a/samples/base/Sample_InitEngine.ts +++ b/samples/base/Sample_InitEngine.ts @@ -1,4 +1,4 @@ -import { Engine3D, Scene3D, CameraUtil, webGPUContext, View3D, AtmosphericComponent } from "@orillusion/core"; +import { Engine3D, Scene3D, CameraUtil, View3D, AtmosphericComponent } from "@orillusion/core"; // init engine class Sample_InitEngine { @@ -12,7 +12,7 @@ class Sample_InitEngine { // init camera3D let mainCamera = CameraUtil.createCamera3D(null, scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); // create a view with target scene and camera let view = new View3D(); diff --git a/samples/base/Sample_Transform.ts b/samples/base/Sample_Transform.ts index 79f38006..3de4144e 100644 --- a/samples/base/Sample_Transform.ts +++ b/samples/base/Sample_Transform.ts @@ -1,6 +1,6 @@ import { GUIHelp } from '@orillusion/debug/GUIHelp'; import { Stats } from '@orillusion/stats' -import { Engine3D, Scene3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, Object3D, MeshRenderer, BoxGeometry, LitMaterial, DirectLight, KelvinUtil, View3D } from '@orillusion/core'; +import { Engine3D, Scene3D, AtmosphericComponent, CameraUtil, HoverCameraController, Object3D, MeshRenderer, BoxGeometry, LitMaterial, DirectLight, KelvinUtil, View3D } from '@orillusion/core'; import { GUIUtil } from '@samples/utils/GUIUtil'; // simple base demo @@ -20,11 +20,11 @@ class Sample_Transform { // init camera3D let mainCamera = CameraUtil.createCamera3D(null, scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); // add a basic camera controller let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); - hoverCameraController.setCamera(15, -15, 300); + hoverCameraController.setCamera(15, -15, 10); // create a basic cube let cubeObj = new Object3D(); diff --git a/samples/base/Sample_UseComponent.ts b/samples/base/Sample_UseComponent.ts index fbe69eb1..e0c6fcb0 100644 --- a/samples/base/Sample_UseComponent.ts +++ b/samples/base/Sample_UseComponent.ts @@ -1,4 +1,4 @@ -import { Engine3D, Scene3D, CameraUtil, webGPUContext, View3D, AtmosphericComponent, ComponentBase, Time, AxisObject, Object3DUtil, KelvinUtil, DirectLight, Object3D, HoverCameraController } from "@orillusion/core"; +import { Engine3D, Scene3D, CameraUtil, View3D, AtmosphericComponent, ComponentBase, Time, AxisObject, Object3DUtil, KelvinUtil, DirectLight, Object3D, HoverCameraController } from "@orillusion/core"; import { GUIHelp } from "@orillusion/debug/GUIHelp"; // sample use component @@ -13,7 +13,7 @@ class Sample_UseComponent { // init camera3D let mainCamera = CameraUtil.createCamera3D(null, scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); hoverCameraController.setCamera(15, -30, 10); diff --git a/samples/lights/Sample_DirectLight.ts b/samples/lights/Sample_DirectLight.ts index ac9e909e..46018c58 100644 --- a/samples/lights/Sample_DirectLight.ts +++ b/samples/lights/Sample_DirectLight.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Scene3D, HoverCameraController, Engine3D, AtmosphericComponent, Object3D, Camera3D, webGPUContext, Vector3, View3D, DirectLight, KelvinUtil, LitMaterial, MeshRenderer, BoxGeometry, CameraUtil } from "@orillusion/core"; +import { Scene3D, HoverCameraController, Engine3D, AtmosphericComponent, Object3D, Camera3D, Vector3, View3D, DirectLight, KelvinUtil, LitMaterial, MeshRenderer, BoxGeometry, CameraUtil } from "@orillusion/core"; //sample of direction light class Sample_DirectLight { @@ -16,7 +16,7 @@ class Sample_DirectLight { // init camera3D let mainCamera = CameraUtil.createCamera3D(null, this.scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); //set camera data mainCamera.object3D.addComponent(HoverCameraController).setCamera(0, -25, 1000); diff --git a/samples/lights/Sample_PointLight.ts b/samples/lights/Sample_PointLight.ts index 5c6f01b7..24ed0a25 100644 --- a/samples/lights/Sample_PointLight.ts +++ b/samples/lights/Sample_PointLight.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { AtmosphericComponent, BoxGeometry, CameraUtil, Engine3D, HoverCameraController, LitMaterial, MeshRenderer, Object3D, Object3DUtil, PointLight, Scene3D, SphereGeometry, View3D, webGPUContext, } from "@orillusion/core"; +import { AtmosphericComponent, BoxGeometry, CameraUtil, Engine3D, HoverCameraController, LitMaterial, MeshRenderer, Object3D, Object3DUtil, PointLight, Scene3D, SphereGeometry, View3D, } from "@orillusion/core"; import { PointLightsScript } from "./PointLightsScript"; class Sample_PointLight { @@ -18,7 +18,7 @@ class Sample_PointLight { this.scene.addComponent(AtmosphericComponent); // init camera3D let mainCamera = CameraUtil.createCamera3D(null, this.scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); //set camera data mainCamera.object3D.addComponent(HoverCameraController).setCamera(0, -25, 500); diff --git a/samples/lights/Sample_PointLightShadow.ts b/samples/lights/Sample_PointLightShadow.ts index 56d38d3a..a9a18ecd 100644 --- a/samples/lights/Sample_PointLightShadow.ts +++ b/samples/lights/Sample_PointLightShadow.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, Vector3, View3D, SphereGeometry, Object3D, MeshRenderer, LitMaterial, PointLight, BoxGeometry, Object3DUtil } from "@orillusion/core"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, Vector3, View3D, SphereGeometry, Object3D, MeshRenderer, LitMaterial, PointLight, BoxGeometry, Object3DUtil } from "@orillusion/core"; // sample of point light shadow class Sample_PointLightShadow { @@ -19,7 +19,7 @@ class Sample_PointLightShadow { // init camera3D let mainCamera = CameraUtil.createCamera3D(null, this.scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); //set camera data mainCamera.object3D.addComponent(HoverCameraController).setCamera(0, -45, 500); diff --git a/samples/lights/Sample_SpotLight.ts b/samples/lights/Sample_SpotLight.ts index 0ee635f1..2dae4bc8 100644 --- a/samples/lights/Sample_SpotLight.ts +++ b/samples/lights/Sample_SpotLight.ts @@ -1,4 +1,4 @@ -import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, SphereGeometry, Object3D, MeshRenderer, LitMaterial, SpotLight, BoxGeometry, Vector3 } from "@orillusion/core"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, SphereGeometry, Object3D, MeshRenderer, LitMaterial, SpotLight, BoxGeometry, Vector3 } from "@orillusion/core"; import { GUIHelp } from "@orillusion/debug/GUIHelp"; // sample of SpotLight @@ -8,7 +8,7 @@ class Sample_SpotLight { async run() { Engine3D.setting.occlusionQuery.enable = false; Engine3D.setting.shadow.enable = true; - Engine3D.setting.shadow.pointShadowBias = 0.075; + Engine3D.setting.shadow.pointShadowBias = 0.0001; await Engine3D.init({}); GUIHelp.init(); @@ -18,7 +18,7 @@ class Sample_SpotLight { // init camera3D let mainCamera = CameraUtil.createCamera3D(null, this.scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); //set camera data mainCamera.object3D.addComponent(HoverCameraController).setCamera(0, -25, 1000); @@ -46,8 +46,8 @@ class Sample_SpotLight { let spotLight = lightObj3D.addComponent(SpotLight); lightObj3D.x = -86; - lightObj3D.y = 130; - lightObj3D.z = -395; + lightObj3D.y = 200; + lightObj3D.z = -300; lightObj3D.transform.rotationX = 342; lightObj3D.transform.rotationY = 360; lightObj3D.transform.rotationZ = 199; diff --git a/samples/loader/Sample_FlightHelmet.ts b/samples/loader/Sample_FlightHelmet.ts index b8ac22bd..14333356 100644 --- a/samples/loader/Sample_FlightHelmet.ts +++ b/samples/loader/Sample_FlightHelmet.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Object3D, Camera3D, Scene3D, HoverCameraController, Engine3D, CameraUtil, webGPUContext, View3D, SSRPost, HDRBloomPost, AtmosphericComponent, DirectLight, KelvinUtil, Time } from "@orillusion/core"; +import { Object3D, Camera3D, Scene3D, HoverCameraController, Engine3D, CameraUtil, View3D, SSRPost, HDRBloomPost, AtmosphericComponent, DirectLight, KelvinUtil, Time } from "@orillusion/core"; import { GUIUtil as GUIUtil } from "@samples/utils/GUIUtil"; class Sample_FlightHelmet { @@ -18,16 +18,11 @@ class Sample_FlightHelmet { renderLoop: () => this.loop(), }); - Engine3D.setting.material.materialChannelDebug = true; - Engine3D.setting.shadow.debug = true; Engine3D.setting.shadow.autoUpdate = true; Engine3D.setting.shadow.shadowBound = 10; - Engine3D.setting.shadow.shadowBias = 0.00001; - + Engine3D.setting.shadow.shadowBias = 0.0001; Engine3D.setting.render.postProcessing.ssao.radius = 0.018; Engine3D.setting.render.postProcessing.ssao.aoPower = 1; - Engine3D.setting.render.postProcessing.gtao.debug = false; - Engine3D.setting.render.postProcessing.bloom = { enable: true, blurX: 4, @@ -39,9 +34,8 @@ class Sample_FlightHelmet { this.scene = new Scene3D(); - this.scene.hideSky(); let camera = CameraUtil.createCamera3DObject(this.scene); - camera.perspective(60, webGPUContext.aspect, 1, 5000.0); + camera.perspective(60, Engine3D.aspect, 1, 5000.0); camera.object3D.addComponent(HoverCameraController).setCamera(-45, -30, 15); @@ -67,6 +61,7 @@ class Sample_FlightHelmet { let atmospheric = this.scene.addComponent(AtmosphericComponent); atmospheric.sunY = 0.73; atmospheric.sunRadiance = 47; + atmospheric.enable = false } /******** light *******/ { diff --git a/samples/loader/Sample_LoadGLTF.ts b/samples/loader/Sample_LoadGLTF.ts index c729f6c1..18601976 100644 --- a/samples/loader/Sample_LoadGLTF.ts +++ b/samples/loader/Sample_LoadGLTF.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Object3D, Scene3D, Engine3D, CameraUtil, webGPUContext, HoverCameraController, View3D, AtmosphericComponent, DirectLight, KelvinUtil } from "@orillusion/core"; +import { Object3D, Scene3D, Engine3D, CameraUtil, HoverCameraController, View3D, AtmosphericComponent, DirectLight, KelvinUtil } from "@orillusion/core"; import { GUIUtil } from "@samples/utils/GUIUtil"; //Samples to show models, they are using PBR material @@ -10,14 +10,14 @@ class Sample_LoadGLTF { //config settings Engine3D.setting.material.materialChannelDebug = true; Engine3D.setting.shadow.shadowBound = 5; - Engine3D.setting.shadow.shadowBias = 0.002; + Engine3D.setting.shadow.shadowBias = 0.0001; Engine3D.setting.render.postProcessing.bloom = { enable: true, blurX: 4, blurY: 4, intensity: 5, brightness: 0.86, - debug: true + debug: false }; //init engine @@ -26,7 +26,7 @@ class Sample_LoadGLTF { this.scene = new Scene3D(); let camera = CameraUtil.createCamera3DObject(this.scene); - camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); + camera.perspective(60, Engine3D.aspect, 0.01, 5000.0); camera.object3D.addComponent(HoverCameraController).setCamera(25, -5, 100); let view = new View3D(); @@ -44,8 +44,8 @@ class Sample_LoadGLTF { let atmospheric = this.scene.addComponent(AtmosphericComponent); atmospheric.sunY = 0.62; atmospheric.sunRadiance = 47; - this.scene.exposure = 1; - this.scene.roughness = 0.56; + atmospheric.exposure = 1; + atmospheric.roughness = 0.56; } /******** light *******/ @@ -67,34 +67,33 @@ class Sample_LoadGLTF { /******** player1 *******/ let player1 = (await Engine3D.res.loadGltf('gltfs/anim/Minion_Lane_Super_Dawn/Minion_Lane_Super_Dawn.glb', {})) as Object3D; player1.transform.x = -10; + player1.transform.y = -10; player1.transform.z = 20; player1.transform.scaleX = 10; player1.transform.scaleY = 10; player1.transform.scaleZ = 10; - player1.transform.y = 5; this.scene.addChild(player1); /******** player2 *******/ let player2 = (await Engine3D.res.loadGltf('gltfs/anim/Minion_Lane_Super_Dawn/Prime_Helix.glb', {})) as Object3D; player2.transform.x = 10; + player2.transform.y = -10; player2.transform.scaleX = 10; player2.transform.scaleY = 10; player2.transform.scaleZ = 10; - player2.transform.y = 5; this.scene.addChild(player2); /******** player3 *******/ let player3 = (await Engine3D.res.loadGltf('gltfs/anim/Minion_Lane_Super_Dawn/Minion_Lane_Ranged_Dusk.glb', {})) as Object3D; player3.transform.x = 10; + player3.transform.y = -10; player3.transform.z = 20; player3.transform.scaleX = 10; player3.transform.scaleY = 10; player3.transform.scaleZ = 10; - player3.transform.y = 5; this.scene.addChild(player3); } } - } new Sample_LoadGLTF().run(); \ No newline at end of file diff --git a/samples/material/Sample_CustomMaterial.ts b/samples/material/Sample_CustomMaterial.ts deleted file mode 100644 index 1c468ea5..00000000 --- a/samples/material/Sample_CustomMaterial.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, DirectLight, KelvinUtil, UnLitMaterial, Color, MeshRenderer, Object3DUtil } from "@orillusion/core"; -import { GUIUtil } from "@samples/utils/GUIUtil"; - -//Display UnLit shaders unaffected by light -class Sample_CustomMaterial { - lightObj3D: Object3D; - scene: Scene3D; - - async run() { - Engine3D.setting.material.materialChannelDebug = true; - - Engine3D.setting.shadow.shadowBound = 200; - Engine3D.setting.shadow.shadowBias = 0.002; - Engine3D.setting.shadow.debug = true; - Engine3D.setting.shadow.autoUpdate = true; - Engine3D.setting.shadow.updateFrameRate = 1; - - await Engine3D.init(); - - this.scene = new Scene3D(); - this.scene.addComponent(AtmosphericComponent); - - let mainCamera = CameraUtil.createCamera3DObject(this.scene); - - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); - mainCamera.object3D.addComponent(HoverCameraController).setCamera(45, -45, 20); - - await this.initScene(this.scene); - - let view = new View3D(); - view.scene = this.scene; - view.camera = mainCamera; - - Engine3D.startRenderView(view); - } - - async initScene(scene: Scene3D) { - //create light - { - this.lightObj3D = new Object3D(); - this.lightObj3D.x = 0; - this.lightObj3D.y = 30; - this.lightObj3D.z = -40; - this.lightObj3D.rotationX = 77; - this.lightObj3D.rotationY = 77; - this.lightObj3D.rotationZ = 41; - let lc = this.lightObj3D.addComponent(DirectLight); - lc.lightColor = KelvinUtil.color_temperature_to_rgb(5355); - lc.castShadow = true; - lc.intensity = 10; - GUIUtil.renderDirLight(lc); - scene.addChild(this.lightObj3D); - } - { - //create floor - let floor = Object3DUtil.GetCube(); - floor.scaleX = 1000; - floor.scaleY = 1; - floor.scaleZ = 1000; - this.scene.addChild(floor); - - //center - let centerCube = Object3DUtil.GetCube(); - centerCube.scaleX = 1; - centerCube.scaleY = 1; - centerCube.scaleZ = 1; - centerCube.x = 2.5; - centerCube.y = 2.5; - this.scene.addChild(centerCube); - - //left - let leftCube = Object3DUtil.GetCube(); - leftCube.scaleX = 4; - leftCube.scaleY = 4; - leftCube.scaleZ = 1; - leftCube.x = 4; - leftCube.y = 2; - this.scene.addChild(leftCube); - - //right - let rightCube = Object3DUtil.GetCube(); - rightCube.scaleX = 4; - rightCube.scaleY = 4; - rightCube.scaleZ = 1; - rightCube.x = -4; - rightCube.y = 2; - this.scene.addChild(rightCube); - - //ulit material - let unlitObj = new Object3D(); - let unlitMat = new UnLitMaterial(); - unlitMat.baseColor = Color.random(); - let mr = unlitObj.addComponent(MeshRenderer); - mr.geometry = Object3DUtil.CubeMesh; - mr.material = unlitMat; - unlitObj.scaleX = 2; - unlitObj.scaleY = 2; - unlitObj.scaleZ = 2; - unlitObj.y = 2; - this.scene.addChild(unlitObj); - } - return true; - } -} - -new Sample_CustomMaterial().run(); \ No newline at end of file diff --git a/samples/material/Sample_PBR.ts b/samples/material/Sample_PBR.ts index e155e7e1..e81b3c04 100644 --- a/samples/material/Sample_PBR.ts +++ b/samples/material/Sample_PBR.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, DirectLight, KelvinUtil, LitMaterial, MeshRenderer, BoxGeometry, SphereGeometry } from "@orillusion/core"; +import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, DirectLight, KelvinUtil, LitMaterial, MeshRenderer, BoxGeometry, SphereGeometry } from "@orillusion/core"; import { GUIUtil } from "@samples/utils/GUIUtil"; class Sample_PBR { @@ -19,7 +19,7 @@ class Sample_PBR { this.scene = new Scene3D(); this.scene.addComponent(AtmosphericComponent); let camera = CameraUtil.createCamera3DObject(this.scene); - camera.perspective(60, webGPUContext.aspect, 1, 5000.0); + camera.perspective(60, Engine3D.aspect, 1, 5000.0); camera.object3D.addComponent(HoverCameraController).setCamera(30, 0, 120); diff --git a/samples/material/Sample_PBRMaterial.ts b/samples/material/Sample_PBRMaterial.ts index 47382321..72407f70 100644 --- a/samples/material/Sample_PBRMaterial.ts +++ b/samples/material/Sample_PBRMaterial.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Object3D, Scene3D, Engine3D, CameraUtil, webGPUContext, HoverCameraController, View3D, AtmosphericComponent, DirectLight, KelvinUtil, MeshRenderer, LitMaterial } from "@orillusion/core"; +import { Object3D, Scene3D, Engine3D, CameraUtil, HoverCameraController, View3D, AtmosphericComponent, DirectLight, KelvinUtil, MeshRenderer, LitMaterial } from "@orillusion/core"; import { GUIUtil } from "@samples/utils/GUIUtil"; class Sample_PBRMaterial { @@ -10,24 +10,22 @@ class Sample_PBRMaterial { await Engine3D.init({ canvasConfig: { alpha: true, zIndex: 11, backgroundImage: '/logo/bg.webp' } }); //config settings - Engine3D.setting.material.materialDebug = true; - Engine3D.setting.material.materialChannelDebug = true; Engine3D.setting.shadow.shadowBound = 50; - Engine3D.setting.shadow.shadowBias = 0.002; + Engine3D.setting.shadow.shadowBias = 0.0001; Engine3D.setting.render.postProcessing.bloom = { enable: true, blurX: 4, blurY: 4, intensity: 1.6, brightness: 0.8, - debug: true + debug: false }; GUIHelp.init(999); this.scene = new Scene3D(); let camera = CameraUtil.createCamera3DObject(this.scene); - camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); + camera.perspective(60, Engine3D.aspect, 0.01, 5000.0); camera.object3D.addComponent(HoverCameraController).setCamera(-25, -5, 30); diff --git a/samples/material/Sample_RenderPassClean.ts b/samples/material/Sample_RenderPassClean.ts index 0a1ca2fe..def7ee21 100644 --- a/samples/material/Sample_RenderPassClean.ts +++ b/samples/material/Sample_RenderPassClean.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, DirectLight, KelvinUtil, MeshRenderer, LitMaterial, BlendMode, BoxGeometry, Color, PlaneGeometry } from "@orillusion/core"; +import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, DirectLight, KelvinUtil, MeshRenderer, LitMaterial, BlendMode, BoxGeometry, Color, PlaneGeometry } from "@orillusion/core"; import { GUIUtil } from "@samples/utils/GUIUtil"; class Sample_RenderPassClean { @@ -9,16 +9,14 @@ class Sample_RenderPassClean { async run() { await Engine3D.init(); - Engine3D.setting.material.materialChannelDebug = true; - Engine3D.setting.shadow.shadowBound = 50; - Engine3D.setting.shadow.shadowBias = 0.00197; - Engine3D.setting.shadow.debug = true; + Engine3D.setting.shadow.shadowBound = 200; + Engine3D.setting.shadow.shadowBias = 0.0001; this.scene = new Scene3D(); this.scene.addComponent(AtmosphericComponent); let camera = CameraUtil.createCamera3DObject(this.scene); - camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); + camera.perspective(60, Engine3D.aspect, 0.01, 5000.0); camera.object3D.addComponent(HoverCameraController).setCamera(25, -5, 20); diff --git a/samples/material/Sample_ReplaceMaterial.ts b/samples/material/Sample_ReplaceMaterial.ts deleted file mode 100644 index 99b032b6..00000000 --- a/samples/material/Sample_ReplaceMaterial.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Engine3D, Scene3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Object3D, MeshRenderer, UnLitMaterial, DirectLight, KelvinUtil, Color, GPUCullMode, LitMaterial } from "@orillusion/core"; - -//Sample of change meshRenderer's material -class Sample_ReplaceMaterial { - lightObj3D: Object3D; - - async run() { - await Engine3D.init({ canvasConfig: { alpha: false, zIndex: 0 } }); - - let scene = new Scene3D(); - scene.addComponent(AtmosphericComponent); - - let camera = CameraUtil.createCamera3DObject(scene); - camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); - - camera.object3D.addComponent(HoverCameraController).setCamera(0, 0, 20); - - let view = new View3D(); - view.scene = scene; - view.camera = camera; - Engine3D.startRenderView(view); - - this.createLight(scene); - - await this.loadModel(scene); - } - - //create light - createLight(scene: Scene3D) { - this.lightObj3D = new Object3D(); - this.lightObj3D.x = 0; - this.lightObj3D.y = 30; - this.lightObj3D.z = -40; - this.lightObj3D.rotationX = 77; - this.lightObj3D.rotationY = 77; - this.lightObj3D.rotationZ = 41; - - let directLight = this.lightObj3D.addComponent(DirectLight); - directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); - directLight.castShadow = true; - directLight.intensity = 10; - scene.addChild(this.lightObj3D); - } - - async loadModel(scene: Scene3D) { - let monitor = await Engine3D.res.loadGltf('gltfs/monitor/scene.gltf'); - scene.addChild(monitor); - monitor.scaleX = monitor.scaleY = monitor.scaleZ = 2; - - // get child by name 'Screen' - let screen = monitor.getChildByName('Screen') as Object3D; - let meshRenderer = screen.getComponentsInChild(MeshRenderer)[0]; - - let material1 = new UnLitMaterial(); - material1.baseMap = await Engine3D.res.loadTexture('textures/normal.jpg'); - - let material2 = new UnLitMaterial(); - material2.baseMap = await Engine3D.res.loadTexture('textures/diffuse.jpg'); - - meshRenderer.material = material2; - - // init gui - GUIHelp.init(); - GUIHelp.addButton('Switch Material', () => { - if (meshRenderer.material == material2) { - meshRenderer.material = material1; - } else { - meshRenderer.material = material2; - } - }); - GUIHelp.open(); - GUIHelp.endFolder(); - } -} - - -new Sample_ReplaceMaterial().run(); \ No newline at end of file diff --git a/samples/material/Sample_UVMove.ts b/samples/material/Sample_UVMove.ts index 942c4745..c1603d58 100644 --- a/samples/material/Sample_UVMove.ts +++ b/samples/material/Sample_UVMove.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Object3D, DirectLight, KelvinUtil, MeshRenderer, UnLitMaterial, PlaneGeometry, LitMaterial, Color } from "@orillusion/core"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, Object3D, DirectLight, KelvinUtil, MeshRenderer, UnLitMaterial, PlaneGeometry, LitMaterial, Color } from "@orillusion/core"; import { UVMoveComponent } from "@samples/material/script/UVMoveComponent"; import { GUIUtil } from "@samples/utils/GUIUtil"; @@ -26,7 +26,7 @@ class Sample_UVMove { this.scene.addComponent(AtmosphericComponent); let camera = CameraUtil.createCamera3DObject(this.scene); - camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); + camera.perspective(60, Engine3D.aspect, 0.01, 5000.0); camera.object3D.addComponent(HoverCameraController).setCamera(25, -25, 200); diff --git a/samples/material/Sample_UnlitMaterial.ts b/samples/material/Sample_UnlitMaterial.ts index fd1f88f1..53bfd19b 100644 --- a/samples/material/Sample_UnlitMaterial.ts +++ b/samples/material/Sample_UnlitMaterial.ts @@ -1,4 +1,4 @@ -import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, DirectLight, KelvinUtil, BitmapTexture2D, PointLight, Texture, LambertMaterial, Color, PlaneGeometry, MeshRenderer, Object3DUtil, UnLitMaterial } from "@orillusion/core"; +import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, DirectLight, KelvinUtil, BitmapTexture2D, PointLight, Texture, LambertMaterial, Color, PlaneGeometry, MeshRenderer, Object3DUtil, UnLitMaterial } from "@orillusion/core"; class Sample_UnlitMaterial { lightObj3D: Object3D; @@ -12,7 +12,7 @@ class Sample_UnlitMaterial { let mainCamera = CameraUtil.createCamera3DObject(this.scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); mainCamera.object3D.addComponent(HoverCameraController).setCamera(45, -45, 50); await this.initScene(this.scene); @@ -22,7 +22,6 @@ class Sample_UnlitMaterial { view.camera = mainCamera; Engine3D.startRenderView(view); - } async initScene(scene: Scene3D) { @@ -33,19 +32,20 @@ class Sample_UnlitMaterial { this.lightObj3D.z = -40; this.lightObj3D.rotationX = 46; this.lightObj3D.rotationY = 62; - this.lightObj3D.rotationZ = 160; + this.lightObj3D.rotationZ = 0; let directLight = this.lightObj3D.addComponent(DirectLight); directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); directLight.castShadow = true; - directLight.intensity = 0.0; + directLight.intensity = 20; scene.addChild(this.lightObj3D); } - // load texture + // create a unlit plane let texture = new BitmapTexture2D(); await texture.load('gltfs/Demonstration/T_Rollets_BC.jpg'); - this.createObject(scene, texture); + + // add a lit sphere { let sphere = Object3DUtil.Sphere; sphere.scaleX = 5; @@ -59,7 +59,6 @@ class Sample_UnlitMaterial { private createObject(scene: Scene3D, texture: Texture): Object3D { let mat = new UnLitMaterial(); - mat.shaderState.acceptGI = false; mat.baseMap = texture; mat.baseColor = new Color(1, 1, 1, 1); diff --git a/samples/render/Sample_BlendMode.ts b/samples/render/Sample_BlendMode.ts index e0389e48..a88a4842 100644 --- a/samples/render/Sample_BlendMode.ts +++ b/samples/render/Sample_BlendMode.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Object3D, Scene3D, HoverCameraController, Engine3D, AtmosphericComponent, webGPUContext, View3D, DirectLight, KelvinUtil, MeshRenderer, BoxGeometry, LitMaterial, Color, BlendMode, GPUCullMode, CameraUtil } from "@orillusion/core"; +import { Object3D, Scene3D, HoverCameraController, Engine3D, AtmosphericComponent, View3D, DirectLight, KelvinUtil, MeshRenderer, BoxGeometry, LitMaterial, Color, BlendMode, GPUCullMode, CameraUtil } from "@orillusion/core"; //sample of change BlendMode and CullMode class Sample_BlendMode { @@ -15,7 +15,7 @@ class Sample_BlendMode { this.scene.addComponent(AtmosphericComponent); let mainCamera = CameraUtil.createCamera3DObject(this.scene, 'camera'); - mainCamera.perspective(60, webGPUContext.aspect, 1, 5000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 5000.0); mainCamera.object3D.addComponent(HoverCameraController).setCamera(-125, 0, 120); diff --git a/samples/render/Sample_BlendMode2.ts b/samples/render/Sample_BlendMode2.ts index 320d573b..913124f3 100644 --- a/samples/render/Sample_BlendMode2.ts +++ b/samples/render/Sample_BlendMode2.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Object3D, DirectLight, KelvinUtil, MeshRenderer, UnLitMaterial, PlaneGeometry, BlendMode, GPUCullMode, LitMaterial, Color } from "@orillusion/core"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, Object3D, DirectLight, KelvinUtil, MeshRenderer, UnLitMaterial, PlaneGeometry, BlendMode, GPUCullMode, LitMaterial, Color } from "@orillusion/core"; class Sample_BlendMode2 { scene: Scene3D; @@ -23,7 +23,7 @@ class Sample_BlendMode2 { this.scene.addComponent(AtmosphericComponent); let camera = CameraUtil.createCamera3DObject(this.scene); - camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); + camera.perspective(60, Engine3D.aspect, 0.01, 5000.0); camera.object3D.addComponent(HoverCameraController).setCamera(25, -60, 200); diff --git a/samples/render/Sample_ChangeTexture.ts b/samples/render/Sample_ChangeTexture.ts index d0546a86..b6cf0380 100644 --- a/samples/render/Sample_ChangeTexture.ts +++ b/samples/render/Sample_ChangeTexture.ts @@ -1,4 +1,4 @@ -import { Object3D, Scene3D, Engine3D, AtmosphericComponent, webGPUContext, HoverCameraController, View3D, DirectLight, KelvinUtil, MeshRenderer, BoxGeometry, LitMaterial, Vector3, Color, BlendMode, CameraUtil } from "@orillusion/core"; +import { Object3D, Scene3D, Engine3D, AtmosphericComponent, HoverCameraController, View3D, DirectLight, KelvinUtil, MeshRenderer, BoxGeometry, LitMaterial, Vector3, Color, BlendMode, CameraUtil } from "@orillusion/core"; class Sample_ChangeTexture { lightObj: Object3D; @@ -19,7 +19,7 @@ class Sample_ChangeTexture { //camera let mainCamera = CameraUtil.createCamera3DObject(this.scene, 'camera'); - mainCamera.perspective(60, webGPUContext.aspect, 1, 5000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 5000.0); mainCamera.object3D.addComponent(HoverCameraController).setCamera(-125, -10, 10); await this.initScene(); diff --git a/samples/render/Sample_CullMode.ts b/samples/render/Sample_CullMode.ts index 1dd93832..f95c11ae 100644 --- a/samples/render/Sample_CullMode.ts +++ b/samples/render/Sample_CullMode.ts @@ -10,7 +10,7 @@ class Sample_CullMode { scene.addComponent(AtmosphericComponent); let camera = CameraUtil.createCamera3DObject(scene); - camera.perspective(60, webGPUContext.aspect, 0.01, 10000.0); + camera.perspective(60, Engine3D.aspect, 0.01, 10000.0); camera.object3D.z = 3; let oribit = camera.object3D.addComponent(OrbitController); diff --git a/samples/render/Sample_TextureSample.ts b/samples/render/Sample_TextureSample.ts index 624a2eac..68cef9fd 100644 --- a/samples/render/Sample_TextureSample.ts +++ b/samples/render/Sample_TextureSample.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, DirectLight, KelvinUtil, UnLitMaterial, MeshRenderer, PlaneGeometry, GPUAddressMode, GPUFilterMode, GPUCompareFunction, LitMaterial, Object3DUtil } from "@orillusion/core"; +import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, DirectLight, KelvinUtil, UnLitMaterial, MeshRenderer, PlaneGeometry, GPUAddressMode, GPUFilterMode, GPUCompareFunction, LitMaterial, Object3DUtil } from "@orillusion/core"; import { GUIUtil } from "@samples/utils/GUIUtil"; import { UVMoveComponent } from "@samples/material/script/UVMoveComponent"; @@ -10,14 +10,14 @@ class Sample_TextureSample { async run() { Engine3D.setting.material.materialChannelDebug = true; Engine3D.setting.shadow.shadowBound = 5; - Engine3D.setting.shadow.shadowBias = 0.002; + Engine3D.setting.shadow.shadowBias = 0.001; await Engine3D.init(); this.scene = new Scene3D(); this.scene.addComponent(AtmosphericComponent); let camera = CameraUtil.createCamera3DObject(this.scene); - camera.perspective(60, webGPUContext.aspect, 0.01, 5000.0); + camera.perspective(60, Engine3D.aspect, 0.01, 5000.0); camera.object3D.addComponent(HoverCameraController).setCamera(25, -30, 100); diff --git a/samples/sky/Sample_AtmosphericSky.ts b/samples/sky/Sample_AtmosphericSky.ts index 327f6b02..7286d383 100644 --- a/samples/sky/Sample_AtmosphericSky.ts +++ b/samples/sky/Sample_AtmosphericSky.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Texture, AtmosphericScatteringSky } from "@orillusion/core"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, Texture, AtmosphericScatteringSky } from "@orillusion/core"; import { GUIUtil } from "@samples/utils/GUIUtil"; // sample of AtmosphericSky @@ -17,7 +17,7 @@ class Sample_AtmosphericSky { // init camera3D let mainCamera = CameraUtil.createCamera3D(null, this._scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); // camera controller mainCamera.object3D.addComponent(HoverCameraController).setCamera(45, -10, 10); diff --git a/samples/sky/Sample_BitmapCubeSky.ts b/samples/sky/Sample_BitmapCubeSky.ts index ec0f0d92..82e27862 100644 --- a/samples/sky/Sample_BitmapCubeSky.ts +++ b/samples/sky/Sample_BitmapCubeSky.ts @@ -1,24 +1,19 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Texture } from "@orillusion/core"; +import { Scene3D, Engine3D, CameraUtil, HoverCameraController, View3D, Texture, SkyRenderer } from "@orillusion/core"; // sample to replace sky map. (witch contains 6 faces) class Sample_BitmapCubeSky { private _scene: Scene3D; - private _originTexture: Texture; - private _externalTexture: Texture; - private _useExternal: boolean = false; async run() { // init engine await Engine3D.init({}); // init scene this._scene = new Scene3D(); - // add sky - this._scene.addComponent(AtmosphericComponent); // init camera3D let mainCamera = CameraUtil.createCamera3D(null, this._scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); // camera controller let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); @@ -41,16 +36,9 @@ class Sample_BitmapCubeSky { urls.push('textures/cubemap/skybox_nz.png'); urls.push('textures/cubemap/skybox_pz.png'); - this._externalTexture = await Engine3D.res.loadTextureCubeMaps(urls); - - // gui - GUIHelp.init(); - GUIHelp.addButton('Switch Maps', () => { - this._originTexture ||= this._scene.envMap; - this._useExternal = !this._useExternal; - this._scene.envMap = this._useExternal ? this._externalTexture : this._originTexture; - }) - GUIHelp.open(); + let sky = this._scene.addComponent(SkyRenderer) + sky.map = await Engine3D.res.loadTextureCubeMaps(urls); + this._scene.envMap = sky.map } } diff --git a/samples/sky/Sample_BitmapCubeStdSky.ts b/samples/sky/Sample_BitmapCubeStdSky.ts index 110d3132..e89cc361 100644 --- a/samples/sky/Sample_BitmapCubeStdSky.ts +++ b/samples/sky/Sample_BitmapCubeStdSky.ts @@ -1,24 +1,19 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Texture } from "@orillusion/core"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, Texture, SkyRenderer } from "@orillusion/core"; // sample to replace standard sky map class Sample_BitmapCubeStdSky { private _scene: Scene3D; - private _originTexture: Texture; - private _externalTexture: Texture; - private _useExternal: boolean = false; async run() { // init engine await Engine3D.init({}); // init scene this._scene = new Scene3D(); - // add sky - this._scene.addComponent(AtmosphericComponent); // init camera3D let mainCamera = CameraUtil.createCamera3D(null, this._scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); // camera controller let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); @@ -34,16 +29,10 @@ class Sample_BitmapCubeStdSky { // load standard sky texture let url = 'sky/StandardCubeMap-2.jpg'; - this._externalTexture = await Engine3D.res.loadTextureCubeStd(url); - - // gui - GUIHelp.init(); - GUIHelp.addButton('Switch Maps', () => { - this._originTexture ||= this._scene.envMap; - this._useExternal = !this._useExternal; - this._scene.envMap = this._useExternal ? this._externalTexture : this._originTexture; - }) - GUIHelp.open(); + + let sky = this._scene.addComponent(SkyRenderer) + sky.map = await Engine3D.res.loadTextureCubeStd(url); + this._scene.envMap = sky.map } } diff --git a/samples/sky/Sample_HDRSky.ts b/samples/sky/Sample_HDRSky.ts index a641d6d9..5e9c2db2 100644 --- a/samples/sky/Sample_HDRSky.ts +++ b/samples/sky/Sample_HDRSky.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Texture } from "@orillusion/core"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, Texture, SkyRenderer } from "@orillusion/core"; // sample to replace hdr sky map class Sample_HDRSky { @@ -13,12 +13,14 @@ class Sample_HDRSky { // init scene this._scene = new Scene3D(); - // add sky - this._scene.addComponent(AtmosphericComponent); + // load sky texture + let sky = this._scene.addComponent(SkyRenderer) + sky.map = await Engine3D.res.loadHDRTextureCube('/hdri/sunset.hdr'); + this._scene.envMap = sky.map // init camera3D let mainCamera = CameraUtil.createCamera3D(null, this._scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); // camera controller let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); @@ -31,18 +33,6 @@ class Sample_HDRSky { // start renderer Engine3D.startRenderView(view); - - // load sky texture - this._externalTexture = await Engine3D.res.loadHDRTextureCube('hdri/sunset.hdr'); - - // gui - GUIHelp.init(); - GUIHelp.addButton('Switch Maps', () => { - this._originTexture ||= this._scene.envMap; - this._useExternal = !this._useExternal; - this._scene.envMap = this._useExternal ? this._externalTexture : this._originTexture; - }) - GUIHelp.open(); } } diff --git a/samples/sky/Sample_LDRSky.ts b/samples/sky/Sample_LDRSky.ts index 34f1e8de..6fce6c79 100644 --- a/samples/sky/Sample_LDRSky.ts +++ b/samples/sky/Sample_LDRSky.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Texture } from "@orillusion/core"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, Texture, SkyRenderer } from "@orillusion/core"; // sample to replace ldr sky map class Sample_LDRSky { @@ -13,12 +13,13 @@ class Sample_LDRSky { // init scene this._scene = new Scene3D(); - // add sky - this._scene.addComponent(AtmosphericComponent); - + let sky = this._scene.addComponent(SkyRenderer) + sky.map = await Engine3D.res.loadLDRTextureCube('sky/LDR_sky.jpg') + this._scene.envMap = sky.map + // init camera3D let mainCamera = CameraUtil.createCamera3D(null, this._scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); // camera controller let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); @@ -31,18 +32,6 @@ class Sample_LDRSky { // start renderer Engine3D.startRenderView(view); - - // load LDR sky texture - this._externalTexture = await Engine3D.res.loadLDRTextureCube('sky/LDR_sky.jpg'); - - // gui - GUIHelp.init(); - GUIHelp.addButton('Switch Maps', () => { - this._originTexture ||= this._scene.envMap; - this._useExternal = !this._useExternal; - this._scene.envMap = this._useExternal ? this._externalTexture : this._originTexture; - }) - GUIHelp.open(); } } diff --git a/samples/sky/Sample_SolidColorSky.ts b/samples/sky/Sample_SolidColorSky.ts index 5c4909e1..5b15e445 100644 --- a/samples/sky/Sample_SolidColorSky.ts +++ b/samples/sky/Sample_SolidColorSky.ts @@ -1,5 +1,5 @@ import { GUIHelp } from "@orillusion/debug/GUIHelp"; -import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, webGPUContext, HoverCameraController, View3D, Texture, Color, SolidColorSky, Object3DUtil } from "@orillusion/core"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, Texture, Color, SolidColorSky, Object3DUtil, SkyRenderer } from "@orillusion/core"; // sample to display solid color sky class HDRSkyMap { @@ -14,12 +14,13 @@ class HDRSkyMap { // init scene this._scene = new Scene3D(); - // add default sky - this._scene.addComponent(AtmosphericComponent); + let sky = this._scene.addComponent(SkyRenderer) + sky.map = new SolidColorSky(new Color(0.5, 0.8, 0, 1)) + this._scene.envMap = sky.map // init camera3D let mainCamera = CameraUtil.createCamera3D(null, this._scene); - mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); // camera controller let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); @@ -32,21 +33,6 @@ class HDRSkyMap { // start renderer Engine3D.startRenderView(view); - - // gui - GUIHelp.init(); - GUIHelp.addButton('Switch Maps', () => { - if (!this._externalTexture) { - // init solid color sky - this._externalTexture = new SolidColorSky(new Color(0.5, 0.8, 0, 1)); - this._originTexture = this._scene.envMap; - GUIHelp.addColor(this._externalTexture, 'color'); - } - - this._useExternal = !this._useExternal; - this._scene.envMap = this._useExternal ? this._externalTexture : this._originTexture; - }) - GUIHelp.open(); } }

>>0?d+1|0:d;d=j>>31;g=d;h=e^d;d=(d^j)-(d+(d>>>0>h>>>0)|0)|0;t=h-g|0;h=i>>31;g=h;A=g^l;C=A-g|0;g=(i^g)-((g>>>0>A>>>0)+g|0)|0;h=(d|0)==(g|0)&t>>>0>C>>>0|d>>>0>g>>>0;A=h?t:C;d=h?d:g;h=m>>31;g=h;C=g^v;t=C-g|0;g=(g^m)-((g>>>0>C>>>0)+g|0)|0;h=(d|0)==(g|0)&t>>>0>>0|d>>>0>g>>>0;h=hi(-1,2147483647,h?A:t,h?d:g)>>>0>>0;d=aa;t=0;if(h&(d|0)<=(p|0)|(d|0)<(p|0)){break e}g=1;d=0;h=s;s=r;r=gi(fi(l,i,z,p),aa,u,o);i=s+r|0;l=aa+K|0;l=i>>>0>>0?l+1|0:l;l=N-((i>>>0>h>>>0)+l|0)|0;i=h-i|0;i=fi(i,l,i,l);l=aa;h=O;r=i;j=gi(fi(e,j,z,p),aa,u,o);e=j+G|0;i=aa+L|0;i=e>>>0>>0?i+1|0:i;i=P-((e>>>0>h>>>0)+i|0)|0;e=h-e|0;j=fi(e,i,e,i);i=r+j|0;e=aa+l|0;e=i>>>0>>0?e+1|0:e;j=i;i=e;e=Q;h=j;m=gi(fi(v,m,z,p),aa,u,o);j=m+H|0;l=aa+M|0;l=j>>>0>>0?l+1|0:l;m=R-((e>>>0>>0)+l|0)|0;e=e-j|0;j=fi(e,m,e,m);e=h+j|0;i=aa+i|0;j=fi(e,e>>>0>>0?i+1|0:i,u,o);e=aa;m=e;if(!e&j>>>0<=1){break h}h=j;e=m;while(1){i=d<<1|g>>>31;g=g<<1;d=i;l=!e&h>>>0>7|(e|0)!=0;h=(e&3)<<30|h>>>2;e=e>>>2|0;if(l){continue}break}break g}if((g|0)<(q|0)){d=g<<1}else{if((q|0)<=0){D[n+8>>2]=0;D[n+12>>2]=0;break j}d=(q<<1)-2|0}d=(d<<2)+c|0;D[n+8>>2]=D[d>>2];D[n+12>>2]=D[d+4>>2]}t=1;break e}va();T()}d=m;g=j;if(g-1|0){break f}}while(1){e=hi(j,m,g,d)+g|0;h=d+aa|0;h=e>>>0>>0?h+1|0:h;g=(h&1)<<31|e>>>1;d=h>>>1|0;e=fi(g,d,g,d);i=aa;if((m|0)==(i|0)&e>>>0>j>>>0|i>>>0>m>>>0){continue}break}}i=D[n+20>>2];if(i){e=i-1|0;m=D[D[n+16>>2]+(e>>>3&536870908)>>2];D[n+20>>2]=e;j=x;v=w-j|0;h=j>>31;w=(w>>31)-(h+(j>>>0>w>>>0)|0)|0;j=fi(z,p,v,w);l=aa;h=fi(x,h,u,o);j=h+j|0;l=aa+l|0;l=h>>>0>j>>>0?l+1|0:l;s=j;j=F;x=y-j|0;r=j>>31;y=(y>>31)-(r+(j>>>0>y>>>0)|0)|0;j=fi(g,d,x,y);h=j;e=m>>>e&1;m=e?0-j|0:j;j=s+m|0;s=l;l=aa;h=s+(e?0-(l+((h|0)!=0)|0)|0:l)|0;V=n,W=gi(j,j>>>0>>0?h+1|0:h,u,o),D[V+12>>2]=W;j=fi(x,y,z,p);m=aa;h=fi(u,o,F,r);j=h+j|0;l=aa+m|0;l=h>>>0>j>>>0?l+1|0:l;h=j;d=fi(g,d,v,w);j=e?d:0-d|0;g=h+j|0;m=aa;e=(e?m:0-(((d|0)!=0)+m|0)|0)+l|0;V=n,W=gi(g,j>>>0>g>>>0?e+1|0:e,u,o),D[V+8>>2]=W}t=(i|0)!=0}$=k+80|0;if(!t){break c}l:{if(D[a+8>>2]<=0){break l}i=D[I>>2];d=0;while(1){e=d<<2;f=D[e+U>>2];g=D[a+16>>2];m:{if((f|0)>(g|0)){D[e+i>>2]=g;break m}e=e+i|0;g=D[a+12>>2];if((g|0)>(f|0)){D[e>>2]=g;break m}D[e>>2]=f}d=d+1|0;f=D[a+8>>2];if((d|0)<(f|0)){continue}break}e=0;if((f|0)<=0){break l}d=q<<3;g=d+c|0;j=b+d|0;while(1){f=e<<2;d=f+g|0;f=D[f+j>>2]+D[f+i>>2]|0;D[d>>2]=f;n:{if((f|0)>D[a+16>>2]){f=f-D[a+20>>2]|0}else{if((f|0)>=D[a+12>>2]){break n}f=f+D[a+20>>2]|0}D[d>>2]=f}e=e+1|0;if((e|0)>2]){continue}break}}q=q+1|0;f=(J|0)>(q|0);if((q|0)!=(S|0)){continue}break}}a=f^1}else{a=0}return a&1}va();T()}function Kc(a){var b=0,c=0,d=0,e=0,f=0,g=0;e=$-16|0;$=e;D[e+12>>2]=a;a:{if(a>>>0<=211){d=D[Jc(10352,10544,e+12|0)>>2];break a}if(a>>>0>=4294967292){W();T()}f=(a>>>0)/210|0;d=J(f,210);D[e+8>>2]=a-d;g=Jc(10544,10736,e+8|0)-10544>>2;while(1){d=D[(g<<2)+10544>>2]+d|0;a=5;b:{while(1){c:{if((a|0)==47){a=211;while(1){b=(d>>>0)/(a>>>0)|0;if(b>>>0>>0){break b}if((J(a,b)|0)==(d|0)){break c}b=a+10|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+12|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+16|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+18|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+22|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+28|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+30|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+36|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+40|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+42|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+46|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+52|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+58|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+60|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+66|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+70|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+72|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+78|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+82|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+88|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+96|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+100|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+102|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+106|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+108|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+112|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+120|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+126|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+130|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+136|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+138|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+142|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+148|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+150|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+156|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+162|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+166|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+168|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+172|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+178|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+180|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+186|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+190|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+192|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+196|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+198|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}if((J(b,c)|0)==(d|0)){break c}b=a+208|0;c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}a=a+210|0;if((J(b,c)|0)!=(d|0)){continue}break}break c}b=D[(a<<2)+10352>>2];c=(d>>>0)/(b>>>0)|0;if(b>>>0>c>>>0){break b}a=a+1|0;if((J(b,c)|0)!=(d|0)){continue}}break}d=g+1|0;a=(d|0)==48;g=a?0:d;f=a+f|0;d=J(f,210);continue}break}D[e+12>>2]=d}$=e+16|0;return d}function Ia(a,b,c,d){var e=0,f=0,g=0,h=0,i=K(0),j=0,k=0,l=K(0),m=0;a:{if(!d){break a}b:{c:{switch(D[a+28>>2]-1|0){case 0:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];g=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=g+b|0;h=D[e+4>>2];while(1){if(b>>>0>=h>>>0){break a}e=(f<<3)+d|0;g=B[b|0];D[e>>2]=g;D[e+4>>2]=g>>31;b=b+1|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break a}c=c-e|0;a=(e<<3)+d|0;break b;case 1:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];g=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=g+b|0;h=D[e+4>>2];while(1){if(b>>>0>=h>>>0){break a}e=(f<<3)+d|0;D[e>>2]=E[b|0];D[e+4>>2]=0;b=b+1|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break a}c=c-e|0;a=(e<<3)+d|0;break b;case 2:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];g=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=g+b|0;h=D[e+4>>2];while(1){if(b>>>0>=h>>>0){break a}e=(f<<3)+d|0;g=C[b>>1];D[e>>2]=g;D[e+4>>2]=g>>31;b=b+2|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break a}c=c-e|0;a=(e<<3)+d|0;break b;case 3:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];g=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=g+b|0;h=D[e+4>>2];while(1){if(b>>>0>=h>>>0){break a}e=(f<<3)+d|0;D[e>>2]=F[b>>1];D[e+4>>2]=0;b=b+2|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break a}c=c-e|0;a=(e<<3)+d|0;break b;case 4:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];g=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=g+b|0;h=D[e+4>>2];while(1){if(b>>>0>=h>>>0){break a}e=(f<<3)+d|0;g=D[b>>2];D[e>>2]=g;D[e+4>>2]=g>>31;b=b+4|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break a}c=c-e|0;a=(e<<3)+d|0;break b;case 5:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];g=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=g+b|0;h=D[e+4>>2];while(1){if(b>>>0>=h>>>0){break a}e=(f<<3)+d|0;D[e>>2]=D[b>>2];D[e+4>>2]=0;b=b+4|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break a}c=c-e|0;a=(e<<3)+d|0;break b;case 6:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];g=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=g+b|0;h=D[e+4>>2];while(1){if(b>>>0>=h>>>0){break a}g=D[b+4>>2];e=(f<<3)+d|0;D[e>>2]=D[b>>2];D[e+4>>2]=g;b=b+8|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break a}c=c-e|0;a=(e<<3)+d|0;break b;case 7:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];g=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=g+b|0;h=D[e+4>>2];while(1){if(b>>>0>=h>>>0){break a}e=D[b>>2];g=D[b+4>>2];if((g|0)<0){break a}k=(f<<3)+d|0;D[k>>2]=e;D[k+4>>2]=g;b=b+8|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break a}c=c-e|0;a=(e<<3)+d|0;break b;case 8:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];g=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=g+b|0;k=D[e+4>>2];while(1){if(b>>>0>=k>>>0){break a}i=H[b>>2];if(i>K(0x8000000000000000)|i=K(1)?~~(i>K(0)?K(N(K(P(K(i*K(2.3283064365386963e-10)))),K(4294967296))):K(Q(K(K(i-K(~~i>>>0>>>0))*K(2.3283064365386963e-10)))))>>>0:0;h=~~i>>>0;break d}g=-2147483648;h=0}D[e>>2]=h;D[e+4>>2]=g;b=b+4|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break a}c=c-e|0;a=(e<<3)+d|0;break b;case 9:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];g=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=g+b|0;k=D[e+4>>2];while(1){if(b>>>0>=k>>>0){break a}j=I[b>>3];if(j>0x8000000000000000|j<-0x8000000000000000|j!=j){break a}m=L(j);if(m==V){break a}e=(f<<3)+d|0;e:{if(m<0x8000000000000000){g=L(j)>=1?~~(j>0?N(P(j*2.3283064365386963e-10),4294967295):Q((j-+(~~j>>>0>>>0))*2.3283064365386963e-10))>>>0:0;h=~~j>>>0;break e}g=-2147483648;h=0}D[e>>2]=h;D[e+4>>2]=g;b=b+8|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break a}c=c-e|0;a=(e<<3)+d|0;break b;case 10:break c;default:break a}}e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];g=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=g+b|0;h=D[e+4>>2];while(1){if(b>>>0>=h>>>0){break a}e=(f<<3)+d|0;D[e>>2]=E[b|0];D[e+4>>2]=0;b=b+1|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break a}c=c-e|0;a=(e<<3)+d|0}qa(a,0,c<<3)}}function od(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;a:{b:{c:{d:{e:{if(D[a+92>>2]==D[a+88>>2]){break e}c=D[a+52>>2];f:{if((c|0)!=D[a+56>>2]){D[c>>2]=b;D[a+52>>2]=c+4;break f}d=D[a+48>>2];h=c-d|0;f=h>>2;e=f+1|0;if(e>>>0>=1073741824){break a}c=h>>1;e=h>>>0<2147483644?c>>>0>e>>>0?c:e:1073741823;if(e){if(e>>>0>=1073741824){break d}c=na(e<<2)}else{c=0}f=c+(f<<2)|0;D[f>>2]=b;if((h|0)>0){oa(c,d,h)}D[a+56>>2]=c+(e<<2);D[a+52>>2]=f+4;D[a+48>>2]=c;if(!d){break f}ma(d)}D[a+84>>2]=0;f=-1;c=-1;g:{if((b|0)==-1){break g}e=D[a+4>>2];c=b+1|0;c=(c>>>0)%3|0?c:b-2|0;if((c|0)!=-1){f=D[D[e>>2]+(c<<2)>>2]}h:{if((b>>>0)%3|0){d=b-1|0;break h}d=b+2|0;c=-1;if((d|0)==-1){break g}}c=D[D[e>>2]+(d<<2)>>2]}i=c>>>3&536870908;e=D[a+36>>2];g=e+(f>>>3&536870908)|0;h=D[g>>2];d=1<>2]=d|h;g=a+8|0;if((b|0)!=-1){e=b+1|0;d=(e>>>0)%3|0?e:b-2|0}else{d=-1}Ma(g,f,d);e=D[a+36>>2]}d=e+i|0;e=D[d>>2];f=1<>2]=e|f;d=a+8|0;f=-1;i:{if((b|0)==-1){break i}f=b-1|0;if((b>>>0)%3|0){break i}f=b+2|0}Ma(d,c,f)}f=-1;f=(b|0)!=-1?D[D[D[a+4>>2]>>2]+(b<<2)>>2]:f;d=D[a+36>>2]+(f>>>3&536870908)|0;e=D[d>>2];c=1<>2]=c|e;Ma(a+8|0,f,b)}d=D[a+84>>2];if((d|0)>2){break e}while(1){f=J(d,12)+a|0;b=D[f+52>>2];if((b|0)==D[f+48>>2]){d=d+1|0;if((d|0)!=3){continue}break e}c=b-4|0;b=D[c>>2];D[f+52>>2]=c;D[a+84>>2]=d;if((b|0)==-1){break e}f=D[a+24>>2];c=(b>>>0)/3|0;j:{if(D[f+(c>>>3&268435452)>>2]>>>c&1){break j}k:{while(1){i=(b>>>0)/3|0;c=(i>>>3&268435452)+f|0;D[c>>2]=D[c>>2]|1<>2]>>2]+(b<<2)>>2]:f;d=D[a+36>>2]+(f>>>3&536870908)|0;e=D[d>>2];c=1<>2]=c|e;h=D[(D[D[a+16>>2]+96>>2]+J(i,12)|0)+((b>>>0)%3<<2)>>2];k=D[D[a+20>>2]+4>>2];c=D[k+4>>2];t:{if((c|0)!=D[k+8>>2]){D[c>>2]=h;D[k+4>>2]=c+4;break t}g=D[k>>2];j=c-g|0;e=j>>2;d=e+1|0;if(d>>>0>=1073741824){break s}c=j>>1;d=j>>>0<2147483644?c>>>0>d>>>0?c:d:1073741823;if(d){if(d>>>0>=1073741824){break d}c=na(d<<2)}else{c=0}e=c+(e<<2)|0;D[e>>2]=h;if((j|0)>0){oa(c,g,j)}D[k+8>>2]=c+(d<<2);D[k+4>>2]=e+4;D[k>>2]=c;if(!g){break t}ma(g)}j=D[a+12>>2];c=D[j+4>>2];u:{if((c|0)!=D[j+8>>2]){D[c>>2]=b;D[j+4>>2]=c+4;break u}h=D[j>>2];g=c-h|0;e=g>>2;d=e+1|0;if(d>>>0>=1073741824){break r}c=g>>1;d=g>>>0<2147483644?c>>>0>d>>>0?c:d:1073741823;if(d){if(d>>>0>=1073741824){break d}c=na(d<<2)}else{c=0}e=c+(e<<2)|0;D[e>>2]=b;if((g|0)>0){oa(c,h,g)}D[j+8>>2]=c+(d<<2);D[j+4>>2]=e+4;D[j>>2]=c;if(!h){break u}ma(h)}c=D[a+12>>2];D[D[c+12>>2]+(f<<2)>>2]=D[c+24>>2];D[c+24>>2]=D[c+24>>2]+1}if((b|0)==-1){break k}g=D[a+4>>2];f=-1;c=b+1|0;c=(c>>>0)%3|0?c:b-2|0;if((c|0)!=-1){f=D[D[g+12>>2]+(c<<2)>>2]}v:{w:{if((J(i,3)|0)!=(b|0)){e=b-1|0;break w}e=b+2|0;b=-1;if((e|0)==-1){break v}}b=D[D[g+12>>2]+(e<<2)>>2]}h=(b|0)==-1;e=(b>>>0)/3|0;if((f|0)!=-1){c=(f>>>0)/3|0;c=D[D[a+24>>2]+(c>>>3&268435452)>>2]&1<>2]+(c>>>3&536870908)>>2]>>>c&1){break x}e=0;c=D[D[g>>2]+(b<<2)>>2];if(!(D[D[a+36>>2]+(c>>>3&536870908)>>2]>>>c&1)){c=D[a+88>>2]+(c<<2)|0;e=D[c>>2];D[c>>2]=e+1;e=(e|0)<=0?2:1}if(D[a+84>>2]>=(e|0)?d:0){break m}k=J(e,12)+a|0;c=D[k+52>>2];y:{if((c|0)!=D[k+56>>2]){D[c>>2]=b;D[k+52>>2]=c+4;break y}i=D[k+48>>2];j=c-i|0;h=j>>2;g=h+1|0;if(g>>>0>=1073741824){break c}c=j>>1;g=j>>>0<2147483644?c>>>0>g>>>0?c:g:1073741823;if(g){if(g>>>0>=1073741824){break d}c=na(g<<2)}else{c=0}h=c+(h<<2)|0;D[h>>2]=b;if((j|0)>0){oa(c,i,j)}D[k+48>>2]=c;D[k+52>>2]=h+4;D[k+56>>2]=c+(g<<2);if(!i){break y}ma(i)}if(D[a+84>>2]<=(e|0)){break x}D[a+84>>2]=e}if(d){break k}b=-1;if((f|0)==-1){break n}}b=D[D[D[a+4>>2]>>2]+(f<<2)>>2]}e=0;if(!(D[D[a+36>>2]+(b>>>3&536870908)>>2]>>>b&1)){b=D[a+88>>2]+(b<<2)|0;c=D[b>>2];D[b>>2]=c+1;e=(c|0)<=0?2:1}if(D[a+84>>2]<(e|0)){break l}b=f}f=D[a+24>>2];continue}break}i=J(e,12)+a|0;b=D[i+52>>2];z:{if((b|0)!=D[i+56>>2]){D[b>>2]=f;D[i+52>>2]=b+4;break z}h=D[i+48>>2];g=b-h|0;c=g>>2;d=c+1|0;if(d>>>0>=1073741824){break b}b=g>>1;d=g>>>0<2147483644?b>>>0>d>>>0?b:d:1073741823;if(d){if(d>>>0>=1073741824){break d}b=na(d<<2)}else{b=0}c=b+(c<<2)|0;D[c>>2]=f;if((g|0)>0){oa(b,h,g)}D[i+48>>2]=b;D[i+52>>2]=c+4;D[i+56>>2]=b+(d<<2);if(!h){break z}ma(h)}d=D[a+84>>2];if((d|0)<=(e|0)){break j}D[a+84>>2]=e;d=e;break j}d=D[a+84>>2]}if((d|0)<3){continue}break}}return 1}sa();T()}pa();T()}pa();T()}pa();T()}function Bb(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=K(0),k=0,l=K(0),m=0;a:{b:{if(!d){break b}c:{d:{switch(D[a+28>>2]-1|0){case 0:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}C[(g<<1)+d>>1]=B[b|0];b=b+1|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 1:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}C[(g<<1)+d>>1]=E[b|0];b=b+1|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 2:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}C[(g<<1)+d>>1]=F[b>>1];b=b+2|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 3:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=C[b>>1];if((e|0)<0){break b}C[(g<<1)+d>>1]=e;b=b+2|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}h=1;if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 4:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=D[b>>2];if(e-32768>>>0<4294901760){break a}C[(g<<1)+d>>1]=e;b=b+4|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 5:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=D[b>>2];if(e>>>0>32767){break a}C[(g<<1)+d>>1]=e;b=b+4|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 6:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}i=D[b>>2];e=D[b+4>>2]-(i>>>0<32768)|0;if((e|0)==-1&i-32768>>>0<4294901760|(e|0)!=-1){break a}C[(g<<1)+d>>1]=i;b=b+8|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 7:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=D[b+4>>2];i=D[b>>2];if(!e&i>>>0>32767|e){break a}C[(g<<1)+d>>1]=i;b=b+8|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 8:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}j=H[b>>2];if(j>K(32767)|j>1]=e;b=b+4|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 9:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}k=I[b>>3];if(k>32767|k<-32768|k!=k){break a}m=L(k);if(m==V){break a}i=(g<<1)+d|0;if(m<2147483648){e=~~k}else{e=-2147483648}C[i>>1]=e;b=b+8|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 10:break d;default:break b}}h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}C[(g<<1)+d>>1]=E[b|0];b=b+1|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0}qa(a,0,c<<1)}return h}return 0}function Ab(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=K(0),k=0;a:{b:{if(!d){break b}c:{d:{switch(D[a+28>>2]-1|0){case 0:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=B[b|0];if((e|0)<0){break b}C[(g<<1)+d>>1]=e&255;b=b+1|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}h=1;if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 1:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}C[(g<<1)+d>>1]=E[b|0];b=b+1|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 2:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=C[b>>1];if((e|0)<0){break b}C[(g<<1)+d>>1]=e;b=b+2|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}h=1;if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 3:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}C[(g<<1)+d>>1]=F[b>>1];b=b+2|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 4:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=D[b>>2];if(e>>>0>65535){break a}C[(g<<1)+d>>1]=e;b=b+4|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 5:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=D[b>>2];if(e>>>0>65535){break a}C[(g<<1)+d>>1]=e;b=b+4|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 6:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=D[b+4>>2];i=D[b>>2];if(!e&i>>>0>65535|e){break a}C[(g<<1)+d>>1]=i;b=b+8|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 7:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=D[b+4>>2];i=D[b>>2];if(!e&i>>>0>65535|e){break a}C[(g<<1)+d>>1]=i;b=b+8|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 8:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}j=H[b>>2];if(j>K(65535)|j=K(0)){e=~~j>>>0}else{e=0}C[i>>1]=e;b=b+4|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 9:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}k=I[b>>3];if(k>65535|k<0|(L(k)==V|k!=k)){break a}i=(g<<1)+d|0;if(k<4294967296&k>=0){e=~~k>>>0}else{e=0}C[i>>1]=e;b=b+8|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0;break c;case 10:break d;default:break b}}h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}C[(g<<1)+d>>1]=E[b|0];b=b+1|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<1)+d|0}qa(a,0,c<<1)}return h}return 0}function zb(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=K(0),k=0,l=K(0),m=0;a:{b:{if(!d){break b}c:{d:{switch(D[a+28>>2]-1|0){case 0:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}D[(g<<2)+d>>2]=B[b|0];b=b+1|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 1:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}D[(g<<2)+d>>2]=E[b|0];b=b+1|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 2:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}D[(g<<2)+d>>2]=C[b>>1];b=b+2|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 3:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}D[(g<<2)+d>>2]=F[b>>1];b=b+2|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 4:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}D[(g<<2)+d>>2]=D[b>>2];b=b+4|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 5:e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=D[b>>2];if((e|0)<0){break b}D[(g<<2)+d>>2]=e;b=b+4|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}h=1;if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 6:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=D[b>>2];if((D[b+4>>2]-(e>>>0<2147483648)|0)!=-1){break a}D[(g<<2)+d>>2]=e;b=b+8|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 7:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=D[b+4>>2];i=D[b>>2];if(!e&i>>>0>2147483647|e){break a}D[(g<<2)+d>>2]=i;b=b+8|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 8:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}j=H[b>>2];if(j>K(2147483648)|j>2]=e;b=b+4|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 9:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}k=I[b>>3];if(k>2147483647|k<-2147483648|k!=k){break a}m=L(k);if(m==V){break a}i=(g<<2)+d|0;if(m<2147483648){e=~~k}else{e=-2147483648}D[i>>2]=e;b=b+8|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 10:break d;default:break b}}h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}D[(g<<2)+d>>2]=E[b|0];b=b+1|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0}qa(a,0,c<<2)}return h}return 0}function yb(a,b,c,d){var e=0,f=0,g=0,h=0,i=K(0),j=0,k=0;a:{b:{if(!d){break b}c:{d:{switch(D[a+28>>2]-1|0){case 0:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}D[(g<<2)+d>>2]=B[b|0];b=b+1|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 1:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}D[(g<<2)+d>>2]=E[b|0];b=b+1|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 2:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}D[(g<<2)+d>>2]=C[b>>1];b=b+2|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 3:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}D[(g<<2)+d>>2]=F[b>>1];b=b+2|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 4:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}D[(g<<2)+d>>2]=D[b>>2];b=b+4|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 5:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}D[(g<<2)+d>>2]=D[b>>2];b=b+4|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 6:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=D[b>>2];if(D[b+4>>2]){break a}D[(g<<2)+d>>2]=e;b=b+8|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 7:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}e=D[b>>2];if(D[b+4>>2]){break a}D[(g<<2)+d>>2]=e;b=b+8|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 8:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}i=H[b>>2];if(i>K(4294967296)|i=K(0)){e=~~i>>>0}else{e=0}D[k>>2]=e;b=b+4|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 9:h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}j=I[b>>3];if(j>4294967295|j<0|(L(j)==V|j!=j)){break a}k=(g<<2)+d|0;if(j<4294967296&j>=0){e=~~j>>>0}else{e=0}D[k>>2]=e;b=b+8|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0;break c;case 10:break d;default:break b}}h=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[a>>2];f=D[e>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=f+b|0;f=D[e+4>>2];while(1){if(b>>>0>=f>>>0){break a}D[(g<<2)+d>>2]=E[b|0];b=b+1|0;g=g+1|0;e=B[a+24|0];if((g|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break b}c=c-e|0;a=(e<<2)+d|0}qa(a,0,c<<2)}return h}return 0}function Mb(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;f=$-96|0;$=f;e=D[a+16>>2];B[f+92|0]=1;D[f+88>>2]=b;D[f+84>>2]=b;D[f+80>>2]=e;k=D[a+20>>2];d=D[k>>2];a:{b:{e=D[D[e+28>>2]+(b<<2)>>2];if(e>>>0>2]-d>>2>>>0){d=D[D[a+8>>2]+(D[d+(e<<2)>>2]<<2)>>2];e=D[a+4>>2];if(!E[e+84|0]){d=D[D[e+68>>2]+(d<<2)>>2]}D[f+72>>2]=0;D[f+76>>2]=0;k=f- -64|0;D[k>>2]=0;D[k+4>>2]=0;D[f+56>>2]=0;D[f+60>>2]=0;Ia(e,d,B[e+24|0],f+56|0);if((b|0)!=-1){e=b+1|0;k=(e>>>0)%3|0?e:b-2|0;i=((b>>>0)%3|0?-1:2)+b|0;while(1){d=k;e=i;c:{if(!D[a+28>>2]){break c}e=b+1|0;d=(e>>>0)%3|0?e:b-2|0;e=b-1|0;if((b>>>0)%3|0){break c}e=b+2|0}h=D[a+20>>2];b=D[h>>2];d=D[D[D[a+16>>2]+28>>2]+(d<<2)>>2];if(d>>>0>=D[h+4>>2]-b>>2>>>0){break b}d=D[D[a+8>>2]+(D[b+(d<<2)>>2]<<2)>>2];b=D[a+4>>2];if(!E[b+84|0]){d=D[D[b+68>>2]+(d<<2)>>2]}D[f+48>>2]=0;D[f+52>>2]=0;D[f+40>>2]=0;D[f+44>>2]=0;D[f+32>>2]=0;D[f+36>>2]=0;Ia(b,d,B[b+24|0],f+32|0);d=D[a+20>>2];b=D[d>>2];e=D[D[D[a+16>>2]+28>>2]+(e<<2)>>2];if(e>>>0>=D[d+4>>2]-b>>2>>>0){break a}d=D[D[a+8>>2]+(D[b+(e<<2)>>2]<<2)>>2];b=D[a+4>>2];if(!E[b+84|0]){d=D[D[b+68>>2]+(d<<2)>>2]}D[f+24>>2]=0;D[f+28>>2]=0;D[f+16>>2]=0;D[f+20>>2]=0;D[f+8>>2]=0;D[f+12>>2]=0;Ia(b,d,B[b+24|0],f+8|0);e=D[f+8>>2];b=D[f+56>>2];d=e-b|0;h=D[f+60>>2];j=D[f+12>>2]-(h+(b>>>0>e>>>0)|0)|0;p=D[f+40>>2];e=D[f+64>>2];s=p-e|0;t=D[f+68>>2];p=D[f+44>>2]-(t+(e>>>0>p>>>0)|0)|0;u=fi(d,j,s,p);v=n-u|0;n=g-(aa+(n>>>0>>0)|0)|0;o=v;g=D[f+16>>2];u=g-e|0;t=D[f+20>>2]-((e>>>0>g>>>0)+t|0)|0;g=D[f+32>>2];v=g-b|0;h=D[f+36>>2]-((b>>>0>g>>>0)+h|0)|0;e=fi(u,t,v,h);b=o+e|0;g=aa+n|0;g=b>>>0>>0?g+1|0:g;n=b;e=l;o=d;x=j;b=D[f+48>>2];l=D[f+72>>2];d=b-l|0;j=D[f+76>>2];w=D[f+52>>2]-(j+(b>>>0>>0)|0)|0;o=fi(o,x,d,w);e=e+o|0;b=aa+m|0;b=e>>>0>>0?b+1|0:b;m=D[f+24>>2];o=m-l|0;j=D[f+28>>2]-((l>>>0>m>>>0)+j|0)|0;m=fi(o,j,v,h);l=e-m|0;m=b-(aa+(e>>>0>>0)|0)|0;b=fi(u,t,d,w);e=q-b|0;b=r-(aa+(b>>>0>q>>>0)|0)|0;r=fi(o,j,s,p);q=r+e|0;b=aa+b|0;b=q>>>0>>0?b+1|0:b;r=b;b=D[f+88>>2];e=D[f+80>>2];d:{if(E[f+92|0]){e:{f:{g:{h:{if((b|0)==-1){break h}d=b+1|0;b=(d>>>0)%3|0?d:b-2|0;if((b|0)==-1|D[D[e>>2]+(b>>>3&536870908)>>2]>>>b&1){break h}b=D[D[D[e+64>>2]+12>>2]+(b<<2)>>2];if((b|0)!=-1){break g}}D[f+88>>2]=-1;break f}d=b+1|0;b=(d>>>0)%3|0?d:b-2|0;D[f+88>>2]=b;if((b|0)!=-1){break e}}b=D[f+84>>2];d=-1;i:{if((b|0)==-1){break i}j:{if((b>>>0)%3|0){b=b-1|0;break j}b=b+2|0;d=-1;if((b|0)==-1){break i}}d=-1;if(D[D[e>>2]+(b>>>3&536870908)>>2]>>>b&1){break i}b=D[D[D[e+64>>2]+12>>2]+(b<<2)>>2];d=-1;if((b|0)==-1){break i}d=b-1|0;if((b>>>0)%3|0){break i}d=b+2|0}B[f+92|0]=0;D[f+88>>2]=d;break d}if((b|0)!=D[f+84>>2]){break d}D[f+88>>2]=-1;break d}d=-1;k:{if((b|0)==-1){break k}l:{if((b>>>0)%3|0){b=b-1|0;break l}b=b+2|0;d=-1;if((b|0)==-1){break k}}d=-1;if(D[D[e>>2]+(b>>>3&536870908)>>2]>>>b&1){break k}b=D[D[D[e+64>>2]+12>>2]+(b<<2)>>2];d=-1;if((b|0)==-1){break k}d=b-1|0;if((b>>>0)%3|0){break k}d=b+2|0}D[f+88>>2]=d}b=D[f+88>>2];if((b|0)!=-1){continue}break}}b=r>>31;e=b^q;j=e-b|0;h=(b^r)-((b>>>0>e>>>0)+b|0)|0;p=-1;e=2147483647;b=m>>31;k=b^l;d=(b^m)-((b>>>0>k>>>0)+b|0)|0;b=k-b|0;s=b^-1;i=d^2147483647;k=g;m:{n:{if(!D[a+28>>2]){if((i|0)==(h|0)&j>>>0>s>>>0|i>>>0>>0){break m}i=g;a=b;e=b+j|0;b=d+h|0;b=a>>>0>e>>>0?b+1|0:b;a=g>>31;d=a;h=d^n;j=h-d|0;g=e+j|0;d=(d^i)-((d>>>0>h>>>0)+d|0)|0;a=g;g=d^2147483647;g=(g|0)==(b|0)&(j^-1)>>>0>>0|b>>>0>g>>>0;a=g?-1:a;if(!(g&0)&(a|0)<=536870912|(a|0)<536870912){break m}b=0;a=a>>>29|0;break n}o:{if((i|0)==(h|0)&j>>>0>s>>>0|i>>>0>>0){break o}a=b;i=b+j|0;b=d+h|0;b=a>>>0>i>>>0?b+1|0:b;a=i;h=g;d=g>>31;g=d;i=d^n;d=(d^h)-(d+(d>>>0>i>>>0)|0)|0;g=i-g|0;i=d^2147483647;if((i|0)==(b|0)&(g^-1)>>>0>>0|b>>>0>i>>>0){break o}b=b+d|0;a=a+g|0;b=a>>>0>>0?b+1|0:b;p=a;e=b;if(!b&a>>>0<536870913){break m}}b=e>>>29|0;a=(e&536870911)<<3|p>>>29}n=gi(n,k,a,b);l=gi(l,m,a,b);q=gi(q,r,a,b)}D[c+8>>2]=n;D[c+4>>2]=l;D[c>>2]=q;$=f+96|0;return}va();T()}va();T()}va();T()}function Db(a,b,c,d){var e=0,f=0,g=0,h=0,i=K(0),j=0,k=K(0),l=0;a:{b:{c:{if(!d){break c}d:{switch(D[a+28>>2]-1|0){case 0:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}B[d+f|0]=E[b|0];b=b+1|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 1:g=B[a+24|0];if((((c|0)>(g|0)?g:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}g=0;e=B[b|0];if((e|0)<0){break c}B[d+f|0]=e;b=b+1|0;f=f+1|0;g=B[a+24|0];if((f|0)<(((c|0)>(g|0)?g:c)|0)){continue}break}}if((c|0)<=(g|0)){return 1}qa(d+g|0,0,c-g|0);return 1;case 2:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}e=F[b>>1];if((e-128&65535)>>>0<65280){break b}B[d+f|0]=e;b=b+2|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 3:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}e=F[b>>1];if(e>>>0>127){break b}B[d+f|0]=e;b=b+2|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 4:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}e=D[b>>2];if(e-128>>>0<4294967040){break b}B[d+f|0]=e;b=b+4|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 5:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}e=D[b>>2];if(e>>>0>127){break b}B[d+f|0]=e;b=b+4|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 6:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}h=D[b>>2];e=D[b+4>>2]-(h>>>0<128)|0;if((e|0)==-1&h-128>>>0<4294967040|(e|0)!=-1){break b}B[d+f|0]=h;b=b+8|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 7:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}e=D[b+4>>2];h=D[b>>2];if(!e&h>>>0>127|e){break b}B[d+f|0]=h;b=b+8|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 8:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}i=H[b>>2];if(i>K(127)|i(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 9:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}j=I[b>>3];if(j>127|j<-128|j!=j){break b}l=L(j);if(l==V){break b}h=d+f|0;if(l<2147483648){e=~~j}else{e=-2147483648}B[h|0]=e;b=b+8|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 10:break d;default:break c}}g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}B[d+f|0]=E[b|0];b=b+1|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}qa(d+e|0,0,c-e|0)}return g}return 0}qa(d+e|0,0,c-e|0);return 1}function Cb(a,b,c,d){var e=0,f=0,g=0,h=0,i=K(0),j=0;a:{b:{c:{if(!d){break c}d:{switch(D[a+28>>2]-1|0){case 0:g=B[a+24|0];if((((c|0)>(g|0)?g:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}g=0;e=B[b|0];if((e|0)<0){break c}B[d+f|0]=e;b=b+1|0;f=f+1|0;g=B[a+24|0];if((f|0)<(((c|0)>(g|0)?g:c)|0)){continue}break}}if((c|0)<=(g|0)){return 1}qa(d+g|0,0,c-g|0);return 1;case 1:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}B[d+f|0]=E[b|0];b=b+1|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 2:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}e=F[b>>1];if(e>>>0>255){break b}B[d+f|0]=e;b=b+2|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 3:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}e=F[b>>1];if(e>>>0>255){break b}B[d+f|0]=e;b=b+2|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 4:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}e=D[b>>2];if(e>>>0>255){break b}B[d+f|0]=e;b=b+4|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 5:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}e=D[b>>2];if(e>>>0>255){break b}B[d+f|0]=e;b=b+4|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 6:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}e=D[b+4>>2];h=D[b>>2];if(!e&h>>>0>255|e){break b}B[d+f|0]=h;b=b+8|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 7:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}e=D[b+4>>2];h=D[b>>2];if(!e&h>>>0>255|e){break b}B[d+f|0]=h;b=b+8|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 8:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}i=H[b>>2];if(i>K(255)|i=K(0)){e=~~i>>>0}else{e=0}B[h|0]=e;b=b+4|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 9:g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}j=I[b>>3];if(j>255|j<0|(L(j)==V|j!=j)){break b}h=d+f|0;if(j<4294967296&j>=0){e=~~j>>>0}else{e=0}B[h|0]=e;b=b+8|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}break a;case 10:break d;default:break c}}g=1;e=B[a+24|0];if((((c|0)>(e|0)?e:c)|0)>0){e=D[D[a>>2]>>2];b=D[a+48>>2]+fi(D[a+40>>2],D[a+44>>2],b,0)|0;b=e+b|0;while(1){if(G[D[a>>2]+4>>2]<=b>>>0){break b}B[d+f|0]=E[b|0];b=b+1|0;f=f+1|0;e=B[a+24|0];if((f|0)<(((c|0)>(e|0)?e:c)|0)){continue}break}}if((c|0)<=(e|0)){break c}qa(d+e|0,0,c-e|0)}return g}return 0}qa(d+e|0,0,c-e|0);return 1}function gc(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0;e=$-48|0;$=e;d=F[5053]|F[5054]<<16;f=F[5051]|F[5052]<<16;C[e+38>>1]=f;C[e+40>>1]=f>>>16;C[e+42>>1]=d;C[e+44>>1]=d>>>16;d=D[2525];D[e+32>>2]=D[2524];D[e+36>>2]=d;d=D[2523];D[e+24>>2]=D[2522];D[e+28>>2]=d;d=D[2521];D[e+16>>2]=D[2520];D[e+20>>2]=d;f=D[b+12>>2];d=D[b+20>>2];g=D[b+16>>2];h=g+5|0;d=h>>>0<5?d+1|0:d;a:{b:{if(h>>>0>G[b+8>>2]&(d|0)>=(f|0)|(d|0)>(f|0)){b=Ba(e+16|0);if(b>>>0>=4294967280){break a}c:{d:{if(b>>>0>=11){d=b+16&-16;c=na(d);D[e+8>>2]=d|-2147483648;D[e>>2]=c;D[e+4>>2]=b;break d}B[e+11|0]=b;c=e;if(!b){break c}}oa(c,e+16|0,b)}B[b+c|0]=0;D[a>>2]=-2;a=a+4|0;if(B[e+11|0]>=0){b=D[e+4>>2];D[a>>2]=D[e>>2];D[a+4>>2]=b;D[a+8>>2]=D[e+8>>2];break b}b=a;a=D[e>>2];ta(b,a,D[e+4>>2]);ma(a);break b}d=g+D[b>>2]|0;f=E[d|0]|E[d+1|0]<<8|(E[d+2|0]<<16|E[d+3|0]<<24);B[c|0]=f;B[c+1|0]=f>>>8;B[c+2|0]=f>>>16;B[c+3|0]=f>>>24;B[c+4|0]=E[d+4|0];d=D[b+20>>2];f=D[b+16>>2]+5|0;d=f>>>0<5?d+1|0:d;D[b+16>>2]=f;D[b+20>>2]=d;if(ua(c,1250,5)){b=na(32);B[b+16|0]=E[1494];c=E[1490]|E[1491]<<8|(E[1492]<<16|E[1493]<<24);d=E[1486]|E[1487]<<8|(E[1488]<<16|E[1489]<<24);B[b+8|0]=d;B[b+9|0]=d>>>8;B[b+10|0]=d>>>16;B[b+11|0]=d>>>24;B[b+12|0]=c;B[b+13|0]=c>>>8;B[b+14|0]=c>>>16;B[b+15|0]=c>>>24;c=E[1482]|E[1483]<<8|(E[1484]<<16|E[1485]<<24);d=E[1478]|E[1479]<<8|(E[1480]<<16|E[1481]<<24);B[b|0]=d;B[b+1|0]=d>>>8;B[b+2|0]=d>>>16;B[b+3|0]=d>>>24;B[b+4|0]=c;B[b+5|0]=c>>>8;B[b+6|0]=c>>>16;B[b+7|0]=c>>>24;B[b+17|0]=0;D[a>>2]=-1;ta(a+4|0,b,17);ma(b);break b}g=D[b+12>>2];if((g|0)<=(d|0)&G[b+8>>2]<=f>>>0|(d|0)>(g|0)){b=Ba(e+16|0);if(b>>>0>=4294967280){break a}e:{f:{if(b>>>0>=11){d=b+16&-16;c=na(d);D[e+8>>2]=d|-2147483648;D[e>>2]=c;D[e+4>>2]=b;break f}B[e+11|0]=b;c=e;if(!b){break e}}oa(c,e+16|0,b)}B[b+c|0]=0;D[a>>2]=-2;a=a+4|0;if(B[e+11|0]>=0){b=D[e+4>>2];D[a>>2]=D[e>>2];D[a+4>>2]=b;D[a+8>>2]=D[e+8>>2];break b}b=a;a=D[e>>2];ta(b,a,D[e+4>>2]);ma(a);break b}B[c+5|0]=E[f+D[b>>2]|0];d=D[b+20>>2];f=D[b+16>>2]+1|0;d=f?d:d+1|0;D[b+16>>2]=f;D[b+20>>2]=d;g=D[b+12>>2];if((g|0)<=(d|0)&G[b+8>>2]<=f>>>0|(d|0)>(g|0)){b=Ba(e+16|0);if(b>>>0>=4294967280){break a}g:{h:{if(b>>>0>=11){d=b+16&-16;c=na(d);D[e+8>>2]=d|-2147483648;D[e>>2]=c;D[e+4>>2]=b;break h}B[e+11|0]=b;c=e;if(!b){break g}}oa(c,e+16|0,b)}B[b+c|0]=0;D[a>>2]=-2;a=a+4|0;if(B[e+11|0]>=0){b=D[e+4>>2];D[a>>2]=D[e>>2];D[a+4>>2]=b;D[a+8>>2]=D[e+8>>2];break b}b=a;a=D[e>>2];ta(b,a,D[e+4>>2]);ma(a);break b}B[c+6|0]=E[f+D[b>>2]|0];d=D[b+20>>2];f=D[b+16>>2]+1|0;d=f?d:d+1|0;D[b+16>>2]=f;D[b+20>>2]=d;g=D[b+12>>2];if((g|0)<=(d|0)&G[b+8>>2]<=f>>>0|(d|0)>(g|0)){b=Ba(e+16|0);if(b>>>0>=4294967280){break a}i:{j:{if(b>>>0>=11){d=b+16&-16;c=na(d);D[e+8>>2]=d|-2147483648;D[e>>2]=c;D[e+4>>2]=b;break j}B[e+11|0]=b;c=e;if(!b){break i}}oa(c,e+16|0,b)}B[b+c|0]=0;D[a>>2]=-2;a=a+4|0;if(B[e+11|0]>=0){b=D[e+4>>2];D[a>>2]=D[e>>2];D[a+4>>2]=b;D[a+8>>2]=D[e+8>>2];break b}b=a;a=D[e>>2];ta(b,a,D[e+4>>2]);ma(a);break b}B[c+7|0]=E[f+D[b>>2]|0];d=D[b+20>>2];f=D[b+16>>2]+1|0;d=f?d:d+1|0;D[b+16>>2]=f;D[b+20>>2]=d;g=D[b+12>>2];if((g|0)<=(d|0)&G[b+8>>2]<=f>>>0|(d|0)>(g|0)){b=Fb(e,e+16|0);D[a>>2]=-2;a=a+4|0;if(B[b+11|0]>=0){c=D[b+4>>2];D[a>>2]=D[b>>2];D[a+4>>2]=c;D[a+8>>2]=D[b+8>>2];break b}ta(a,D[b>>2],D[b+4>>2]);if(B[b+11|0]>=0){break b}ma(D[b>>2]);break b}B[c+8|0]=E[f+D[b>>2]|0];d=D[b+20>>2];f=d;i=D[b+16>>2];g=i+1|0;d=g?d:d+1|0;D[b+16>>2]=g;D[b+20>>2]=d;h=D[b+12>>2];d=f;f=i+3|0;d=f>>>0<3?d+1|0:d;if(f>>>0>G[b+8>>2]&(d|0)>=(h|0)|(d|0)>(h|0)){b=Fb(e,e+16|0);D[a>>2]=-2;a=a+4|0;if(B[b+11|0]>=0){c=D[b+4>>2];D[a>>2]=D[b>>2];D[a+4>>2]=c;D[a+8>>2]=D[b+8>>2];break b}ta(a,D[b>>2],D[b+4>>2]);if(B[b+11|0]>=0){break b}ma(D[b>>2]);break b}f=c;c=g+D[b>>2]|0;C[f+10>>1]=E[c|0]|E[c+1|0]<<8;d=D[b+20>>2];c=D[b+16>>2]+2|0;d=c>>>0<2?d+1|0:d;D[b+16>>2]=c;D[b+20>>2]=d;D[a+8>>2]=0;D[a+12>>2]=0;D[a>>2]=0;D[a+4>>2]=0}$=e+48|0;return}Ca();T()}function Fg(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;g=$-32|0;$=g;a:{if(!jb(1,g+28|0,D[a+32>>2])){break a}if(!jb(1,g+24|0,D[a+32>>2])){break a}m=D[g+28>>2];if(m>>>0>1431655765){break a}b=D[a+32>>2];j=D[b+8>>2];f=j;c=D[b+16>>2];h=f-c|0;e=D[b+12>>2];o=c>>>0>f>>>0;f=D[b+20>>2];n=gi(h,e-(o+f|0)|0,3,0);if(!aa&m>>>0>n>>>0){break a}n=D[g+24>>2];h=fi(m,0,3,0);if(!aa&h>>>0>>0|((e|0)<=(f|0)&c>>>0>=j>>>0|(e|0)<(f|0))){break a}e=E[c+D[b>>2]|0];c=c+1|0;f=c?f:f+1|0;D[b+16>>2]=c;D[b+20>>2]=f;b:{c:{if(!e){f=0;c=$-32|0;$=c;D[c+24>>2]=0;D[c+16>>2]=0;D[c+20>>2]=0;d:{e:{b=J(m,3);if(b){if(b>>>0>=1073741824){break e}e=J(m,12);f=na(e);D[c+16>>2]=f;qa(f,0,e)}b=jc(b,1,D[a+32>>2],f);f:{g:{if(!(!b|!m)){j=0;e=0;while(1){o=d;h=(e<<2)+f|0;d=D[h>>2];i=d>>>1|0;d=o+(d&1?0-i|0:i)|0;D[c>>2]=d;i=D[h+4>>2];k=i>>>1|0;d=d+(i&1?0-k|0:k)|0;D[c+4>>2]=d;h=D[h+8>>2];i=h>>>1|0;d=d+(h&1?0-i|0:i)|0;D[c+8>>2]=d;ob(D[a+44>>2]+96|0,c);e=e+3|0;j=j+1|0;if((j|0)!=(m|0)){continue}break}break g}if(!f){break f}}ma(f)}$=c+32|0;break d}pa();T()}if(b){break c}break a}if(n>>>0<=255){if(!m){break c}while(1){h:{D[g+16>>2]=0;D[g+8>>2]=0;D[g+12>>2]=0;c=D[a+32>>2];b=c;h=D[b+8>>2];e=D[b+12>>2];f=D[b+20>>2];j=D[b+16>>2];if((e|0)<=(f|0)&h>>>0<=j>>>0|(e|0)<(f|0)){break h}d=D[c>>2];k=E[d+j|0];b=f;i=j+1|0;b=i?b:b+1|0;D[c+16>>2]=i;D[c+20>>2]=b;D[g+8>>2]=k;if((b|0)>=(e|0)&i>>>0>=h>>>0|(b|0)>(e|0)){break h}k=E[d+i|0];b=f;i=j+2|0;b=i>>>0<2?b+1|0:b;D[c+16>>2]=i;D[c+20>>2]=b;D[g+12>>2]=k;if((b|0)>=(e|0)&i>>>0>=h>>>0|(b|0)>(e|0)){break h}b=E[d+i|0];e=j+3|0;f=e>>>0<3?f+1|0:f;D[c+16>>2]=e;D[c+20>>2]=f;D[g+16>>2]=b;ob(D[a+44>>2]+96|0,g+8|0);l=l+1|0;if((m|0)!=(l|0)){continue}break c}break}l=0;break a}if(n>>>0<=65535){if(!m){break c}while(1){i:{D[g+16>>2]=0;D[g+8>>2]=0;D[g+12>>2]=0;e=D[a+32>>2];c=D[e+12>>2];j=D[e+8>>2];b=D[e+20>>2];f=b;h=D[e+16>>2];d=h+2|0;b=d>>>0<2?b+1|0:b;if(d>>>0>j>>>0&(b|0)>=(c|0)|(b|0)>(c|0)){break i}i=D[e>>2];k=i+h|0;k=E[k|0]|E[k+1|0]<<8;D[e+16>>2]=d;D[e+20>>2]=b;D[g+8>>2]=k;b=f;k=h+4|0;b=k>>>0<4?b+1|0:b;if(k>>>0>j>>>0&(b|0)>=(c|0)|(b|0)>(c|0)){break i}d=d+i|0;d=E[d|0]|E[d+1|0]<<8;D[e+16>>2]=k;D[e+20>>2]=b;D[g+12>>2]=d;b=f;f=h+6|0;b=f>>>0<6?b+1|0:b;if(f>>>0>j>>>0&(b|0)>=(c|0)|(b|0)>(c|0)){break i}c=i+k|0;c=E[c|0]|E[c+1|0]<<8;D[e+16>>2]=f;D[e+20>>2]=b;D[g+16>>2]=c;ob(D[a+44>>2]+96|0,g+8|0);l=l+1|0;if((m|0)!=(l|0)){continue}break c}break}l=0;break a}j:{if(n>>>0>2097151){break j}b=F[a+36>>1];if(((b<<8|b>>>8)&65535)>>>0<514){break j}if(!m){break c}while(1){k:{D[g+16>>2]=0;D[g+8>>2]=0;D[g+12>>2]=0;if(!jb(1,g+4|0,D[a+32>>2])){break k}D[g+8>>2]=D[g+4>>2];if(!jb(1,g+4|0,D[a+32>>2])){break k}D[g+12>>2]=D[g+4>>2];if(!jb(1,g+4|0,D[a+32>>2])){break k}D[g+16>>2]=D[g+4>>2];ob(D[a+44>>2]+96|0,g+8|0);l=l+1|0;if((m|0)!=(l|0)){continue}break c}break}l=0;break a}if(!m){break c}while(1){D[g+16>>2]=0;D[g+8>>2]=0;D[g+12>>2]=0;e=D[a+32>>2];c=D[e+12>>2];j=D[e+8>>2];b=D[e+20>>2];f=b;h=D[e+16>>2];d=h+4|0;b=d>>>0<4?b+1|0:b;i=d;if(d>>>0>j>>>0&(b|0)>=(c|0)|(b|0)>(c|0)){break b}k=D[e>>2];d=k+h|0;d=E[d|0]|E[d+1|0]<<8|(E[d+2|0]<<16|E[d+3|0]<<24);D[e+16>>2]=i;D[e+20>>2]=b;D[g+8>>2]=d;b=f;d=h+8|0;b=d>>>0<8?b+1|0:b;o=d;if(d>>>0>j>>>0&(b|0)>=(c|0)|(b|0)>(c|0)){break b}d=i+k|0;d=E[d|0]|E[d+1|0]<<8|(E[d+2|0]<<16|E[d+3|0]<<24);D[e+16>>2]=o;D[e+20>>2]=b;D[g+12>>2]=d;b=f;f=h+12|0;b=f>>>0<12?b+1|0:b;if(f>>>0>j>>>0&(b|0)>=(c|0)|(b|0)>(c|0)){break b}c=k+o|0;c=E[c|0]|E[c+1|0]<<8|(E[c+2|0]<<16|E[c+3|0]<<24);D[e+16>>2]=f;D[e+20>>2]=b;D[g+16>>2]=c;ob(D[a+44>>2]+96|0,g+8|0);l=l+1|0;if((m|0)!=(l|0)){continue}break}}D[D[a+4>>2]+80>>2]=n;l=1;break a}l=0}$=g+32|0;return l|0}function Id(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0;g=$+-64|0;$=g;D[g+56>>2]=0;D[g+48>>2]=0;D[g+52>>2]=0;D[g+40>>2]=0;D[g+44>>2]=0;D[g+32>>2]=0;D[g+36>>2]=0;D[g+24>>2]=0;D[g+28>>2]=0;D[g+16>>2]=0;D[g+20>>2]=0;D[g+8>>2]=0;D[g+12>>2]=0;f=g+8|0;a:{b:{if(!F[b+38>>1]){break b}if(!Wa(1,f+12|0,b)){break b}d=D[b+8>>2];e=D[b+16>>2];i=d-e|0;j=D[f+12>>2];d=D[b+12>>2]-(D[b+20>>2]+(d>>>0>>0)|0)|0;if(i>>>0>>6>>>0&(d|0)<=0|(d|0)<0){break b}e=D[f>>2];d=D[f+4>>2]-e>>2;c:{if(d>>>0>>0){ra(f,j-d|0);j=D[f+12>>2];break c}if(d>>>0<=j>>>0){break c}D[f+4>>2]=e+(j<<2)}h=1;if(!j){break a}k=D[b+16>>2];d=D[b+20>>2];r=D[f>>2];s=D[b+8>>2];p=D[b+12>>2];i=0;while(1){h=0;if((d|0)>=(p|0)&k>>>0>=s>>>0|(d|0)>(p|0)){break a}h=D[b>>2];n=E[h+k|0];e=k+1|0;d=e?d:d+1|0;k=e;D[b+16>>2]=e;D[b+20>>2]=d;e=n>>>2|0;l=0;d:{e:{f:{g:{t=n&3;switch(t|0){case 3:break g;case 0:break e;default:break f}}e=e+i|0;h=0;if(e>>>0>=j>>>0){break a}qa(r+(i<<2)|0,0,(n&252)+4|0);i=e;break d}while(1){if((d|0)>=(p|0)&k>>>0>=s>>>0|(d|0)>(p|0)){break b}j=E[k+h|0];k=k+1|0;d=k?d:d+1|0;D[b+16>>2]=k;D[b+20>>2]=d;e=j<<(l<<3|6)|e;l=l+1|0;if((t|0)!=(l|0)){continue}break}}D[r+(i<<2)>>2]=e}i=i+1|0;j=D[f+12>>2];if(i>>>0>>0){continue}break}d=f+16|0;p=D[f>>2];i=D[f+16>>2];e=D[f+20>>2]-i|0;h:{if(e>>>0<=4194303){ra(d,1048576-(e>>>2|0)|0);break h}if((e|0)==4194304){break h}D[f+20>>2]=i+4194304}e=f+28|0;i=D[e>>2];h=D[f+32>>2]-i>>3;i:{if(h>>>0>>0){db(e,j-h|0);i=D[e>>2];break i}if(j>>>0>>0){D[f+32>>2]=(j<<3)+i}if(!j){break b}}k=D[d>>2];d=0;h=0;while(1){f=p+(d<<2)|0;l=D[f>>2];n=(d<<3)+i|0;e=h;D[n+4>>2]=e;D[n>>2]=l;f=D[f>>2];h=f+e|0;if(h>>>0>1048576){break b}j:{if(e>>>0>=h>>>0){break j}l=0;n=f&7;if(n){while(1){D[k+(e<<2)>>2]=d;e=e+1|0;l=l+1|0;if((n|0)!=(l|0)){continue}break}}if(f-1>>>0<=6){break j}while(1){f=k+(e<<2)|0;D[f>>2]=d;D[f+28>>2]=d;D[f+24>>2]=d;D[f+20>>2]=d;D[f+16>>2]=d;D[f+12>>2]=d;D[f+8>>2]=d;D[f+4>>2]=d;e=e+8|0;if((h|0)!=(e|0)){continue}break}}d=d+1|0;if((j|0)!=(d|0)){continue}break}m=(h|0)==1048576}h=m}k:{if(!h|(D[g+20>>2]?0:a)){break k}h=0;m=$-16|0;$=m;l:{if(!Va(1,m+8|0,b)){break l}d=D[b+8>>2];e=D[b+16>>2];f=d-e|0;j=D[m+12>>2];k=D[b+20>>2];d=D[b+12>>2]-(k+(d>>>0>>0)|0)|0;i=D[m+8>>2];if((j|0)==(d|0)&f>>>0>>0|d>>>0>>0){break l}d=j+k|0;f=e+i|0;d=f>>>0>>0?d+1|0:d;D[b+16>>2]=f;D[b+20>>2]=d;d=i;if((d|0)<=0){break l}b=e+D[b>>2]|0;D[g+48>>2]=b;e=d-1|0;i=e+b|0;f=E[i|0];m:{if(f>>>0<=63){D[g+52>>2]=e;b=E[i|0]&63;break m}n:{switch((f>>>6|0)-1|0){case 0:if(d>>>0<2){break l}D[g+52>>2]=d-2;b=(b+d|0)-2|0;b=E[b+1|0]<<8&16128|E[b|0];break m;case 1:if(d>>>0<3){break l}D[g+52>>2]=d-3;b=(b+d|0)-3|0;b=E[b+1|0]<<8|E[b+2|0]<<16&4128768|E[b|0];break m;default:break n}}D[g+52>>2]=d-4;b=(b+d|0)-4|0;b=E[b+2|0]<<16|E[b+3|0]<<24&1056964608|E[b+1|0]<<8|E[b|0]}D[g+56>>2]=b+4194304;h=b>>>0<1069547520}$=m+16|0;if(!h){break k}if(!a){o=1;break k}b=D[g+56>>2];d=D[g+36>>2];e=D[g+48>>2];i=D[g+24>>2];while(1){o:{if(b>>>0>4194303){break o}o=D[g+52>>2];while(1){if((o|0)<=0){break o}o=o-1|0;D[g+52>>2]=o;b=E[e+o|0]|b<<8;D[g+56>>2]=b;if(b>>>0<4194304){continue}break}}h=b&1048575;m=D[i+(h<<2)>>2];f=d+(m<<3)|0;b=(J(D[f>>2],b>>>20|0)+h|0)-D[f+4>>2]|0;D[g+56>>2]=b;D[(q<<2)+c>>2]=m;o=1;q=q+1|0;if((q|0)!=(a|0)){continue}break}}a=D[g+36>>2];if(a){D[g+40>>2]=a;ma(a)}a=D[g+24>>2];if(a){D[g+28>>2]=a;ma(a)}a=D[g+8>>2];if(a){D[g+12>>2]=a;ma(a)}$=g- -64|0;return o}function pe(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;f=$-16|0;$=f;n=ba[D[D[a>>2]+24>>2]](a)|0;a:{if((n|0)<=0){break a}r=a+48|0;g=1;while(1){b:{c:{if(!D[(ba[D[D[a>>2]+28>>2]](a)|0)+40>>2]){break c}p=h<<2;b=D[p+D[a+36>>2]>>2];d=D[b+8>>2];e=eb(b);if(!e){break c}i=D[(ba[D[D[a>>2]+28>>2]](a)|0)+40>>2];D[f+12>>2]=D[d+56>>2];b=na(32);D[f>>2]=b;D[f+4>>2]=24;D[f+8>>2]=-2147483616;B[b+24|0]=0;d=E[1196]|E[1197]<<8|(E[1198]<<16|E[1199]<<24);c=E[1192]|E[1193]<<8|(E[1194]<<16|E[1195]<<24);B[b+16|0]=c;B[b+17|0]=c>>>8;B[b+18|0]=c>>>16;B[b+19|0]=c>>>24;B[b+20|0]=d;B[b+21|0]=d>>>8;B[b+22|0]=d>>>16;B[b+23|0]=d>>>24;d=E[1188]|E[1189]<<8|(E[1190]<<16|E[1191]<<24);c=E[1184]|E[1185]<<8|(E[1186]<<16|E[1187]<<24);B[b+8|0]=c;B[b+9|0]=c>>>8;B[b+10|0]=c>>>16;B[b+11|0]=c>>>24;B[b+12|0]=d;B[b+13|0]=d>>>8;B[b+14|0]=d>>>16;B[b+15|0]=d>>>24;d=E[1180]|E[1181]<<8|(E[1182]<<16|E[1183]<<24);c=E[1176]|E[1177]<<8|(E[1178]<<16|E[1179]<<24);B[b|0]=c;B[b+1|0]=c>>>8;B[b+2|0]=c>>>16;B[b+3|0]=c>>>24;B[b+4|0]=d;B[b+5|0]=d>>>8;B[b+6|0]=d>>>16;B[b+7|0]=d>>>24;d=i+16|0;c=D[d>>2];d:{e:{if(!c){break e}j=D[f+12>>2];b=d;while(1){k=(j|0)>D[c+16>>2];b=k?b:c;c=D[(k?c+4|0:c)>>2];if(c){continue}break}if((b|0)==(d|0)|(j|0)>2]){break e}c=D[b+24>>2];if(!c){break e}j=b+20|0;b=E[f+11|0];d=b<<24>>24<0;k=d?D[f>>2]:f;b=d?D[f+4>>2]:b;while(1){d=E[c+27|0];l=d<<24>>24<0;d=l?D[c+20>>2]:d;q=d>>>0>>0;f:{g:{h:{i:{j:{k:{o=q?d:b;if(o){m=c+16|0;l=l?D[m>>2]:m;m=ua(k,l,o);if(m){break k}if(b>>>0>=d>>>0){break j}break f}if(b>>>0>=d>>>0){break i}break f}if((m|0)<0){break f}}d=ua(l,k,o);if(d){break h}}if(q){break g}b=dc(j,f);break d}if((d|0)<0){break g}b=dc(j,f);break d}c=c+4|0}c=D[c>>2];if(c){continue}break}}b=dc(i,f)}if(B[f+11|0]<0){ma(D[f>>2])}if(!b){break c}c=D[D[p+D[a+36>>2]>>2]+8>>2];if(!D[c+64>>2]){b=na(32);D[b+16>>2]=0;D[b+20>>2]=0;D[b+8>>2]=0;D[b>>2]=0;D[b+4>>2]=0;D[b+24>>2]=0;D[b+28>>2]=0;d=D[c+64>>2];D[c+64>>2]=b;if(d){b=D[d>>2];if(b){D[d+4>>2]=b;ma(b)}ma(d);b=D[c+64>>2]}D[c>>2]=b;d=D[b+20>>2];D[c+8>>2]=D[b+16>>2];D[c+12>>2]=d;d=D[b+24>>2];b=D[b+28>>2];D[c+48>>2]=0;D[c+52>>2]=0;D[c+40>>2]=0;D[c+44>>2]=0;D[c+16>>2]=d;D[c+20>>2]=b}l:{B[c+24|0]=E[e+24|0];D[c+28>>2]=D[e+28>>2];B[c+32|0]=E[e+32|0];b=D[e+44>>2];D[c+40>>2]=D[e+40>>2];D[c+44>>2]=b;b=D[e+52>>2];D[c+48>>2]=D[e+48>>2];D[c+52>>2]=b;D[c+56>>2]=D[e+56>>2];b=D[e+12>>2];D[c+8>>2]=D[e+8>>2];D[c+12>>2]=b;b=D[e+20>>2];D[c+16>>2]=D[e+16>>2];D[c+20>>2]=b;D[c+60>>2]=D[e+60>>2];d=D[e>>2];m:{if(!d){D[c>>2]=0;b=1;break m}g=D[c>>2];b=0;if(!g){break m}b=D[d>>2];kd(g,b,D[d+4>>2]-b|0,0);b=1}if(!b){break l}B[c+84|0]=E[e+84|0];D[c+80>>2]=D[e+80>>2];if((c|0)!=(e|0)){ib(c+68|0,D[e+68>>2],D[e+72>>2])}n:{e=D[e+88>>2];o:{if(e){d=na(40);b=D[e>>2];D[d+16>>2]=0;D[d+8>>2]=0;D[d+12>>2]=0;D[d>>2]=b;b=D[e+12>>2];g=D[e+8>>2];if((b|0)!=(g|0)){g=b-g|0;if((g|0)<0){break n}b=na(g);D[d+8>>2]=b;D[d+12>>2]=b;D[d+16>>2]=b+g;i=D[e+8>>2];g=D[e+12>>2]-i|0;if((g|0)>0){b=oa(b,i,g)+g|0}D[d+12>>2]=b}b=D[e+36>>2];D[d+32>>2]=D[e+32>>2];D[d+36>>2]=b;b=D[e+28>>2];D[d+24>>2]=D[e+24>>2];D[d+28>>2]=b;b=D[c+88>>2];D[c+88>>2]=d;if(b){break o}break l}b=D[c+88>>2];D[c+88>>2]=0;if(!b){break l}}d=D[b+8>>2];if(d){D[b+12>>2]=d;ma(d)}ma(b);break l}pa();T()}break b}b=D[D[a+36>>2]+(h<<2)>>2];if(!(ba[D[D[b>>2]+24>>2]](b,r)|0)){break a}}h=h+1|0;g=(n|0)>(h|0);if((h|0)!=(n|0)){continue}break}}$=f+16|0;return(g^-1)&1}function gh(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=K(0),f=0,g=0,h=0,i=0,j=0,k=0,l=K(0),m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;if(D[c>>2]==D[c+4>>2]){h=D[d+80>>2];u=$-16|0;$=u;q=D[a+4>>2];j=D[d+48>>2];d=D[D[d>>2]>>2];i=B[b+24|0];c=u+8|0;D[c>>2]=1065353216;H[c>>2]=K(-1<>2];s=na((i|0)!=(i&1073741823)?-1:i<<2);a:{if(!h|(i|0)<=0){break a}t=d+j|0;l=H[c>>2];k=D[a+8>>2];w=D[b>>2];c=D[b+48>>2];m=D[b+44>>2];v=D[b+40>>2];if(!E[b+84|0]){r=D[b+68>>2];q=i&-2;j=i&1;a=0;while(1){d=D[w>>2];b=fi(v,m,D[r+(o<<2)>>2],0)+c|0;p=oa(s,d+b|0,v);b=0;n=0;if((i|0)!=1){while(1){d=t+(a<<2)|0;g=b<<2;e=K(P(K(K(l*K(H[g+p>>2]-H[k+g>>2]))+K(.5))));b:{if(K(L(e))>2]=f;f=g|4;e=K(P(K(K(l*K(H[f+p>>2]-H[f+k>>2]))+K(.5))));c:{if(K(L(e))>2]=f;b=b+2|0;a=a+2|0;n=n+2|0;if((q|0)!=(n|0)){continue}break}}if(j){d=t+(a<<2)|0;b=b<<2;e=K(P(K(K(l*K(H[b+p>>2]-H[b+k>>2]))+K(.5))));d:{if(K(L(e))>2]=b;a=a+1|0}o=o+1|0;if((h|0)!=(o|0)){continue}break}break a}r=i&-2;q=i&1;a=0;while(1){d=D[w>>2];b=fi(v,m,p,f)+c|0;o=oa(s,d+b|0,v);b=0;n=0;if((i|0)!=1){while(1){d=t+(a<<2)|0;g=b<<2;e=K(P(K(K(l*K(H[g+o>>2]-H[k+g>>2]))+K(.5))));e:{if(K(L(e))>2]=j;j=g|4;e=K(P(K(K(l*K(H[j+o>>2]-H[k+j>>2]))+K(.5))));f:{if(K(L(e))>2]=g;b=b+2|0;a=a+2|0;n=n+2|0;if((r|0)!=(n|0)){continue}break}}if(q){d=t+(a<<2)|0;b=b<<2;e=K(P(K(K(l*K(H[b+o>>2]-H[b+k>>2]))+K(.5))));g:{if(K(L(e))>2]=b;a=a+1|0}b=p+1|0;f=b?f:f+1|0;p=b;if((h|0)!=(b|0)|f){continue}break}}ma(s);$=u+16|0;return 1}u=$-16|0;$=u;f=D[a+4>>2];j=D[d+48>>2];h=D[D[d>>2]>>2];m=B[b+24|0];d=u+8|0;D[d>>2]=1065353216;H[d>>2]=K(-1<>2];t=na((m|0)!=(m&1073741823)?-1:m<<2);f=D[c+4>>2];s=D[c>>2];h:{if((f|0)==(s|0)|(m|0)<=0){break h}n=j+h|0;c=f-s>>2;w=c>>>0>1?c:1;l=H[d>>2];i=D[a+8>>2];x=D[b>>2];d=D[b+48>>2];v=D[b+44>>2];p=D[b+40>>2];if(E[b+84|0]){q=m&-2;j=m&1;a=0;c=0;while(1){f=D[x>>2];b=fi(p,v,D[s+(c<<2)>>2],0)+d|0;g=oa(t,f+b|0,p);b=0;k=0;if((m|0)!=1){while(1){f=n+(a<<2)|0;r=b<<2;e=K(P(K(K(l*K(H[r+g>>2]-H[i+r>>2]))+K(.5))));i:{if(K(L(e))>2]=h;h=r|4;e=K(P(K(K(l*K(H[h+g>>2]-H[i+h>>2]))+K(.5))));j:{if(K(L(e))>2]=h;b=b+2|0;a=a+2|0;k=k+2|0;if((q|0)!=(k|0)){continue}break}}if(j){f=n+(a<<2)|0;b=b<<2;e=K(P(K(K(l*K(H[b+g>>2]-H[b+i>>2]))+K(.5))));k:{if(K(L(e))>2]=b;a=a+1|0}c=c+1|0;if((w|0)!=(c|0)){continue}break}break h}r=D[b+68>>2];q=m&-2;j=m&1;a=0;c=0;while(1){f=D[x>>2];b=fi(p,v,D[r+(D[s+(c<<2)>>2]<<2)>>2],0)+d|0;o=oa(t,f+b|0,p);b=0;k=0;if((m|0)!=1){while(1){f=n+(a<<2)|0;g=b<<2;e=K(P(K(K(l*K(H[g+o>>2]-H[i+g>>2]))+K(.5))));l:{if(K(L(e))>2]=h;h=g|4;e=K(P(K(K(l*K(H[h+o>>2]-H[i+h>>2]))+K(.5))));m:{if(K(L(e))>2]=g;b=b+2|0;a=a+2|0;k=k+2|0;if((q|0)!=(k|0)){continue}break}}if(j){f=n+(a<<2)|0;b=b<<2;e=K(P(K(K(l*K(H[b+o>>2]-H[b+i>>2]))+K(.5))));n:{if(K(L(e))>2]=b;a=a+1|0}c=c+1|0;if((w|0)!=(c|0)){continue}break}}ma(t);$=u+16|0;return 1} +function zd(a,b){var c=0,d=0,e=0,f=0,g=0,h=0;d=D[a+4>>2];c=D[a>>2];e=(d-c|0)/144|0;if(e>>>0>>0){c=a;e=b-e|0;f=D[a+8>>2];d=D[a+4>>2];a:{if(e>>>0<=(f-d|0)/144>>>0){b:{if(!e){break b}a=d;f=e&7;if(f){b=0;while(1){ya(a);a=a+144|0;b=b+1|0;if((f|0)!=(b|0)){continue}break}}d=J(e,144)+d|0;if((e-1&268435455)>>>0<7){break b}while(1){ya(a);ya(a+144|0);ya(a+288|0);ya(a+432|0);ya(a+576|0);ya(a+720|0);ya(a+864|0);ya(a+1008|0);a=a+1152|0;if((d|0)!=(a|0)){continue}break}}D[c+4>>2]=d;break a}c:{d:{e:{b=D[c>>2];g=(d-b|0)/144|0;a=g+e|0;if(a>>>0<29826162){d=0;b=(f-b|0)/144|0;f=b<<1;f=b>>>0<14913080?a>>>0>>0?f:a:29826161;if(f){if(f>>>0>=29826162){break e}h=na(J(f,144))}b=J(g,144)+h|0;a=b;g=e&7;if(g){a=b;while(1){ya(a);a=a+144|0;d=d+1|0;if((g|0)!=(d|0)){continue}break}}g=J(e,144)+b|0;if((e-1&268435455)>>>0>=7){while(1){ya(a);ya(a+144|0);ya(a+288|0);ya(a+432|0);ya(a+576|0);ya(a+720|0);ya(a+864|0);ya(a+1008|0);a=a+1152|0;if((g|0)!=(a|0)){continue}break}}e=J(f,144)+h|0;a=D[c+4>>2];d=D[c>>2];if((a|0)==(d|0)){break d}while(1){b=b-144|0;a=a-144|0;D[b>>2]=D[a>>2];D[b+4>>2]=D[a+4>>2];D[b+8>>2]=D[a+8>>2];D[b+12>>2]=D[a+12>>2];D[a+12>>2]=0;D[a+4>>2]=0;D[a+8>>2]=0;D[b+16>>2]=D[a+16>>2];D[b+20>>2]=D[a+20>>2];D[b+24>>2]=D[a+24>>2];D[a+24>>2]=0;D[a+16>>2]=0;D[a+20>>2]=0;f=E[a+28|0];D[b+40>>2]=0;D[b+32>>2]=0;D[b+36>>2]=0;B[b+28|0]=f;D[b+32>>2]=D[a+32>>2];D[b+36>>2]=D[a+36>>2];D[b+40>>2]=D[a+40>>2];D[a+40>>2]=0;D[a+32>>2]=0;D[a+36>>2]=0;D[b+52>>2]=0;D[b+44>>2]=0;D[b+48>>2]=0;D[b+44>>2]=D[a+44>>2];D[b+48>>2]=D[a+48>>2];D[b+52>>2]=D[a+52>>2];D[a+52>>2]=0;D[a+44>>2]=0;D[a+48>>2]=0;f=b- -64|0;D[f>>2]=0;D[b+56>>2]=0;D[b+60>>2]=0;D[b+56>>2]=D[a+56>>2];D[b+60>>2]=D[a+60>>2];h=f;f=a- -64|0;D[h>>2]=D[f>>2];D[f>>2]=0;D[a+56>>2]=0;D[a+60>>2]=0;D[b+68>>2]=D[a+68>>2];f=D[a+72>>2];D[b+84>>2]=0;D[b+76>>2]=0;D[b+80>>2]=0;D[b+72>>2]=f;D[b+76>>2]=D[a+76>>2];D[b+80>>2]=D[a+80>>2];D[b+84>>2]=D[a+84>>2];D[a+84>>2]=0;D[a+76>>2]=0;D[a+80>>2]=0;D[b+96>>2]=0;D[b+88>>2]=0;D[b+92>>2]=0;D[b+88>>2]=D[a+88>>2];D[b+92>>2]=D[a+92>>2];D[b+96>>2]=D[a+96>>2];D[a+96>>2]=0;D[a+88>>2]=0;D[a+92>>2]=0;f=E[a+100|0];D[b+112>>2]=0;D[b+104>>2]=0;D[b+108>>2]=0;B[b+100|0]=f;D[b+104>>2]=D[a+104>>2];D[b+108>>2]=D[a+108>>2];D[b+112>>2]=D[a+112>>2];D[a+112>>2]=0;D[a+104>>2]=0;D[a+108>>2]=0;D[b+124>>2]=0;D[b+116>>2]=0;D[b+120>>2]=0;D[b+116>>2]=D[a+116>>2];D[b+120>>2]=D[a+120>>2];D[b+124>>2]=D[a+124>>2];D[a+124>>2]=0;D[a+116>>2]=0;D[a+120>>2]=0;f=D[a+128>>2];D[b+140>>2]=0;D[b+132>>2]=0;D[b+136>>2]=0;D[b+128>>2]=f;D[b+132>>2]=D[a+132>>2];D[b+136>>2]=D[a+136>>2];D[b+140>>2]=D[a+140>>2];D[a+140>>2]=0;D[a+132>>2]=0;D[a+136>>2]=0;if((a|0)!=(d|0)){continue}break}D[c+8>>2]=e;a=D[c+4>>2];D[c+4>>2]=g;d=D[c>>2];D[c>>2]=b;if((a|0)==(d|0)){break c}while(1){b=a-144|0;c=D[b+132>>2];if(c){D[a-8>>2]=c;ma(c)}c=D[a-28>>2];if(c){D[a-24>>2]=c;ma(c)}c=D[a-40>>2];if(c){D[a-36>>2]=c;ma(c)}Gb(a-140|0);a=b;if((d|0)!=(a|0)){continue}break}break c}pa();T()}sa();T()}D[c+8>>2]=e;D[c+4>>2]=g;D[c>>2]=b}if(d){ma(d)}}return}if(b>>>0>>0){c=c+J(b,144)|0;if((c|0)!=(d|0)){while(1){b=d-144|0;e=D[b+132>>2];if(e){D[d-8>>2]=e;ma(e)}e=D[d-28>>2];if(e){D[d-24>>2]=e;ma(e)}e=D[d-40>>2];if(e){D[d-36>>2]=e;ma(e)}Gb(d-140|0);d=b;if((b|0)!=(c|0)){continue}break}}D[a+4>>2]=c}}function Kb(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;f=$-96|0;$=f;d=D[a+16>>2];B[f+92|0]=1;D[f+88>>2]=b;D[f+84>>2]=b;D[f+80>>2]=d;a:{if((b|0)==-1){break a}l=D[a+20>>2];e=D[l>>2];d=D[D[d>>2]+(b<<2)>>2];if(d>>>0>=D[l+4>>2]-e>>2>>>0){break a}d=D[D[a+8>>2]+(D[e+(d<<2)>>2]<<2)>>2];e=D[a+4>>2];if(!E[e+84|0]){d=D[D[e+68>>2]+(d<<2)>>2]}D[f+72>>2]=0;D[f+76>>2]=0;l=f- -64|0;D[l>>2]=0;D[l+4>>2]=0;D[f+56>>2]=0;D[f+60>>2]=0;Ia(e,d,B[e+24|0],f+56|0);d=b+1|0;l=(d>>>0)%3|0?d:b-2|0;i=((b>>>0)%3|0?-1:2)+b|0;b:{c:{while(1){e=l;d=i;d:{if(!D[a+28>>2]){break d}d=b+1|0;e=(d>>>0)%3|0?d:b-2|0;d=b-1|0;if((b>>>0)%3|0){break d}d=b+2|0}if((e|0)==-1){break b}h=D[a+20>>2];b=D[h>>2];e=D[D[D[a+16>>2]>>2]+(e<<2)>>2];if(e>>>0>=D[h+4>>2]-b>>2>>>0){break b}e=D[D[a+8>>2]+(D[(e<<2)+b>>2]<<2)>>2];b=D[a+4>>2];if(!E[b+84|0]){e=D[D[b+68>>2]+(e<<2)>>2]}D[f+48>>2]=0;D[f+52>>2]=0;D[f+40>>2]=0;D[f+44>>2]=0;D[f+32>>2]=0;D[f+36>>2]=0;Ia(b,e,B[b+24|0],f+32|0);if((d|0)==-1){break c}e=D[a+20>>2];b=D[e>>2];d=D[D[D[a+16>>2]>>2]+(d<<2)>>2];if(d>>>0>=D[e+4>>2]-b>>2>>>0){break c}e=D[D[a+8>>2]+(D[b+(d<<2)>>2]<<2)>>2];b=D[a+4>>2];if(!E[b+84|0]){e=D[D[b+68>>2]+(e<<2)>>2]}D[f+24>>2]=0;D[f+28>>2]=0;D[f+16>>2]=0;D[f+20>>2]=0;D[f+8>>2]=0;D[f+12>>2]=0;Ia(b,e,B[b+24|0],f+8|0);d=D[f+8>>2];b=D[f+56>>2];e=d-b|0;h=D[f+60>>2];j=D[f+12>>2]-(h+(b>>>0>d>>>0)|0)|0;p=D[f+40>>2];d=D[f+64>>2];s=p-d|0;t=D[f+68>>2];p=D[f+44>>2]-(t+(d>>>0>p>>>0)|0)|0;u=fi(e,j,s,p);v=o-u|0;o=g-(aa+(o>>>0>>0)|0)|0;k=v;g=D[f+16>>2];u=g-d|0;t=D[f+20>>2]-((d>>>0>g>>>0)+t|0)|0;g=D[f+32>>2];v=g-b|0;h=D[f+36>>2]-((b>>>0>g>>>0)+h|0)|0;d=fi(u,t,v,h);b=k+d|0;g=aa+o|0;g=b>>>0>>0?g+1|0:g;o=b;x=m;k=e;d=j;b=D[f+48>>2];m=D[f+72>>2];e=b-m|0;j=D[f+76>>2];w=D[f+52>>2]-(j+(b>>>0>>0)|0)|0;k=fi(k,d,e,w);d=x+k|0;b=aa+n|0;b=d>>>0>>0?b+1|0:b;n=D[f+24>>2];k=n-m|0;j=D[f+28>>2]-((m>>>0>n>>>0)+j|0)|0;n=fi(k,j,v,h);m=d-n|0;n=b-(aa+(d>>>0>>0)|0)|0;b=fi(u,t,e,w);d=q-b|0;b=r-(aa+(b>>>0>q>>>0)|0)|0;r=fi(k,j,s,p);q=r+d|0;b=aa+b|0;b=q>>>0>>0?b+1|0:b;r=b;kc(f+80|0);b=D[f+88>>2];if((b|0)!=-1){continue}break}b=r>>31;d=b^q;j=d-b|0;h=(b^r)-((b>>>0>d>>>0)+b|0)|0;p=-1;d=2147483647;b=n>>31;l=b^m;e=(b^n)-((b>>>0>l>>>0)+b|0)|0;b=l-b|0;s=b^-1;i=e^2147483647;k=g;e:{f:{if(!D[a+28>>2]){if((i|0)==(h|0)&j>>>0>s>>>0|i>>>0>>0){break e}i=g;a=b;d=b+j|0;b=e+h|0;b=a>>>0>d>>>0?b+1|0:b;a=g>>31;h=a^o;j=h-a|0;g=d+j|0;e=(a^i)-((a>>>0>h>>>0)+a|0)|0;a=g;g=e^2147483647;g=(g|0)==(b|0)&(j^-1)>>>0>>0|b>>>0>g>>>0;a=g?-1:a;if(!(g&0)&(a|0)<=536870912|(a|0)<536870912){break e}b=0;a=a>>>29|0;break f}g:{if((i|0)==(h|0)&j>>>0>s>>>0|i>>>0>>0){break g}a=b;i=b+j|0;b=e+h|0;b=a>>>0>i>>>0?b+1|0:b;a=i;h=g;e=g>>31;g=e;i=e^o;e=(e^h)-(e+(e>>>0>i>>>0)|0)|0;g=i-g|0;i=e^2147483647;if((i|0)==(b|0)&(g^-1)>>>0>>0|b>>>0>i>>>0){break g}b=b+e|0;a=a+g|0;b=a>>>0>>0?b+1|0:b;p=a;d=b;if(!b&a>>>0<536870913){break e}}b=d>>>29|0;a=(d&536870911)<<3|p>>>29}o=gi(o,k,a,b);m=gi(m,n,a,b);q=gi(q,r,a,b)}D[c+8>>2]=o;D[c+4>>2]=m;D[c>>2]=q;$=f+96|0;return}va();T()}va();T()}va();T()}function Lc(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;a:{if((b|0)<0){break a}c=D[a+12>>2];d=D[a+8>>2];if(c-d>>2>>>0<=b>>>0){break a}e=d+(b<<2)|0;d=D[e>>2];i=D[d+60>>2];g=D[d+56>>2];d=e+4|0;b:{if((d|0)!=(c|0)){while(1){h=D[d>>2];D[d>>2]=0;f=D[e>>2];D[e>>2]=h;if(f){Aa(f)}e=e+4|0;d=d+4|0;if((d|0)!=(c|0)){continue}break}c=D[a+12>>2];if((e|0)==(c|0)){break b}}while(1){c=c-4|0;d=D[c>>2];D[c>>2]=0;if(d){Aa(d)}if((c|0)!=(e|0)){continue}break}}D[a+12>>2]=e;f=D[a+4>>2];c:{if(!f|(i|0)<0){break c}c=D[f+24>>2];d=D[f+28>>2];if((c|0)==(d|0)){break c}while(1){if((i|0)==D[D[c>>2]+24>>2]){e=c+4|0;i=D[f+28>>2];d:{if((e|0)!=(i|0)){while(1){h=D[e>>2];D[e>>2]=0;d=D[c>>2];D[c>>2]=h;if(d){Fa(d+12|0,D[d+16>>2]);Ea(d,D[d+4>>2]);ma(d)}c=c+4|0;e=e+4|0;if((i|0)!=(e|0)){continue}break}e=D[f+28>>2];if((e|0)==(c|0)){break d}}while(1){e=e-4|0;d=D[e>>2];D[e>>2]=0;if(d){Fa(d+12|0,D[d+16>>2]);Ea(d,D[d+4>>2]);ma(d)}if((c|0)!=(e|0)){continue}break}}D[f+28>>2]=c;break c}c=c+4|0;if((d|0)!=(c|0)){continue}break}}e:{if((g|0)>4){break e}f:{e=J(g,12)+a|0;c=D[e+20>>2];d=D[e+24>>2];if((c|0)==(d|0)){break f}while(1){if(D[c>>2]==(b|0)){break f}c=c+4|0;if((d|0)!=(c|0)){continue}break}break e}if((c|0)==(d|0)){break e}f=c+4|0;i=d-f|0;if((d|0)!=(f|0)){Ra(c,f,i)}D[e+24>>2]=c+i}c=D[a+24>>2];e=D[a+20>>2];g:{if((c|0)==(e|0)){break g}d=c-e|0;c=d>>2;f=c>>>0>1?c:1;i=f&1;c=0;if(d>>>0>=8){f=f&-2;d=0;while(1){g=c<<2;h=g+e|0;j=D[h>>2];if((j|0)>(b|0)){D[h>>2]=j-1}g=e+(g|4)|0;h=D[g>>2];if((h|0)>(b|0)){D[g>>2]=h-1}c=c+2|0;d=d+2|0;if((f|0)!=(d|0)){continue}break}}if(!i){break g}c=e+(c<<2)|0;d=D[c>>2];if((d|0)<=(b|0)){break g}D[c>>2]=d-1}c=D[a+36>>2];e=D[a+32>>2];h:{if((c|0)==(e|0)){break h}d=c-e|0;c=d>>2;f=c>>>0>1?c:1;i=f&1;c=0;if(d>>>0>=8){f=f&-2;d=0;while(1){g=c<<2;h=g+e|0;j=D[h>>2];if((j|0)>(b|0)){D[h>>2]=j-1}g=e+(g|4)|0;h=D[g>>2];if((h|0)>(b|0)){D[g>>2]=h-1}c=c+2|0;d=d+2|0;if((f|0)!=(d|0)){continue}break}}if(!i){break h}c=e+(c<<2)|0;d=D[c>>2];if((d|0)<=(b|0)){break h}D[c>>2]=d-1}c=D[a+48>>2];e=D[a+44>>2];i:{if((c|0)==(e|0)){break i}d=c-e|0;c=d>>2;f=c>>>0>1?c:1;i=f&1;c=0;if(d>>>0>=8){f=f&-2;d=0;while(1){g=c<<2;h=g+e|0;j=D[h>>2];if((j|0)>(b|0)){D[h>>2]=j-1}g=e+(g|4)|0;h=D[g>>2];if((h|0)>(b|0)){D[g>>2]=h-1}c=c+2|0;d=d+2|0;if((f|0)!=(d|0)){continue}break}}if(!i){break i}c=e+(c<<2)|0;d=D[c>>2];if((d|0)<=(b|0)){break i}D[c>>2]=d-1}c=D[a+60>>2];e=D[a+56>>2];j:{if((c|0)==(e|0)){break j}d=c-e|0;c=d>>2;f=c>>>0>1?c:1;i=f&1;c=0;if(d>>>0>=8){f=f&-2;d=0;while(1){g=c<<2;h=g+e|0;j=D[h>>2];if((j|0)>(b|0)){D[h>>2]=j-1}g=e+(g|4)|0;h=D[g>>2];if((h|0)>(b|0)){D[g>>2]=h-1}c=c+2|0;d=d+2|0;if((f|0)!=(d|0)){continue}break}}if(!i){break j}c=e+(c<<2)|0;d=D[c>>2];if((d|0)<=(b|0)){break j}D[c>>2]=d-1}c=D[a+72>>2];a=D[a+68>>2];if((c|0)==(a|0)){break a}d=c-a|0;c=d>>2;e=c>>>0>1?c:1;f=e&1;c=0;if(d>>>0>=8){e=e&-2;d=0;while(1){i=c<<2;g=i+a|0;h=D[g>>2];if((h|0)>(b|0)){D[g>>2]=h-1}i=a+(i|4)|0;g=D[i>>2];if((g|0)>(b|0)){D[i>>2]=g-1}c=c+2|0;d=d+2|0;if((e|0)!=(d|0)){continue}break}}if(!f){break a}d=b;a=a+(c<<2)|0;b=D[a>>2];if((d|0)>=(b|0)){break a}D[a>>2]=b-1}}function ma(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;a:{if(!a){break a}d=a-8|0;b=D[a-4>>2];a=b&-8;f=d+a|0;b:{if(b&1){break b}if(!(b&3)){break a}b=D[d>>2];d=d-b|0;if(d>>>0>>0<=255){e=D[d+8>>2];b=b>>>3|0;c=D[d+12>>2];if((c|0)==(e|0)){i=11744,j=D[2936]&ji(b),D[i>>2]=j;break b}D[e+12>>2]=c;D[c+8>>2]=e;break b}h=D[d+24>>2];b=D[d+12>>2];c:{if((d|0)!=(b|0)){c=D[d+8>>2];D[c+12>>2]=b;D[b+8>>2]=c;break c}d:{e=d+20|0;c=D[e>>2];if(c){break d}e=d+16|0;c=D[e>>2];if(c){break d}b=0;break c}while(1){g=e;b=c;e=b+20|0;c=D[e>>2];if(c){continue}e=b+16|0;c=D[b+16>>2];if(c){continue}break}D[g>>2]=0}if(!h){break b}e=D[d+28>>2];c=(e<<2)+12048|0;e:{if(D[c>>2]==(d|0)){D[c>>2]=b;if(b){break e}i=11748,j=D[2937]&ji(e),D[i>>2]=j;break b}D[h+(D[h+16>>2]==(d|0)?16:20)>>2]=b;if(!b){break b}}D[b+24>>2]=h;c=D[d+16>>2];if(c){D[b+16>>2]=c;D[c+24>>2]=b}c=D[d+20>>2];if(!c){break b}D[b+20>>2]=c;D[c+24>>2]=b;break b}b=D[f+4>>2];if((b&3)!=3){break b}D[2938]=a;D[f+4>>2]=b&-2;D[d+4>>2]=a|1;D[a+d>>2]=a;return}if(d>>>0>=f>>>0){break a}b=D[f+4>>2];if(!(b&1)){break a}f:{if(!(b&2)){if(D[2942]==(f|0)){D[2942]=d;a=D[2939]+a|0;D[2939]=a;D[d+4>>2]=a|1;if(D[2941]!=(d|0)){break a}D[2938]=0;D[2941]=0;return}if(D[2941]==(f|0)){D[2941]=d;a=D[2938]+a|0;D[2938]=a;D[d+4>>2]=a|1;D[a+d>>2]=a;return}a=(b&-8)+a|0;g:{if(b>>>0<=255){e=D[f+8>>2];b=b>>>3|0;c=D[f+12>>2];if((c|0)==(e|0)){i=11744,j=D[2936]&ji(b),D[i>>2]=j;break g}D[e+12>>2]=c;D[c+8>>2]=e;break g}h=D[f+24>>2];b=D[f+12>>2];h:{if((f|0)!=(b|0)){c=D[f+8>>2];D[c+12>>2]=b;D[b+8>>2]=c;break h}i:{e=f+20|0;c=D[e>>2];if(c){break i}e=f+16|0;c=D[e>>2];if(c){break i}b=0;break h}while(1){g=e;b=c;e=b+20|0;c=D[e>>2];if(c){continue}e=b+16|0;c=D[b+16>>2];if(c){continue}break}D[g>>2]=0}if(!h){break g}e=D[f+28>>2];c=(e<<2)+12048|0;j:{if(D[c>>2]==(f|0)){D[c>>2]=b;if(b){break j}i=11748,j=D[2937]&ji(e),D[i>>2]=j;break g}D[h+(D[h+16>>2]==(f|0)?16:20)>>2]=b;if(!b){break g}}D[b+24>>2]=h;c=D[f+16>>2];if(c){D[b+16>>2]=c;D[c+24>>2]=b}c=D[f+20>>2];if(!c){break g}D[b+20>>2]=c;D[c+24>>2]=b}D[d+4>>2]=a|1;D[a+d>>2]=a;if(D[2941]!=(d|0)){break f}D[2938]=a;return}D[f+4>>2]=b&-2;D[d+4>>2]=a|1;D[a+d>>2]=a}if(a>>>0<=255){b=(a&-8)+11784|0;c=D[2936];a=1<<(a>>>3);k:{if(!(c&a)){D[2936]=a|c;a=b;break k}a=D[b+8>>2]}D[b+8>>2]=d;D[a+12>>2]=d;D[d+12>>2]=b;D[d+8>>2]=a;return}e=31;if(a>>>0<=16777215){b=a>>>8|0;g=b+1048320>>>16&8;b=b<>>16&4;b=b<>>16&2;b=(b<>>15|0)-(c|(e|g))|0;e=(b<<1|a>>>b+21&1)+28|0}D[d+28>>2]=e;D[d+16>>2]=0;D[d+20>>2]=0;g=(e<<2)+12048|0;l:{m:{c=D[2937];b=1<>2]=d;D[d+24>>2]=g;break n}e=a<<((e|0)==31?0:25-(e>>>1|0)|0);b=D[g>>2];while(1){c=b;if((D[b+4>>2]&-8)==(a|0)){break m}b=e>>>29|0;e=e<<1;g=c+(b&4)|0;b=D[g+16>>2];if(b){continue}break}D[g+16>>2]=d;D[d+24>>2]=c}D[d+12>>2]=d;D[d+8>>2]=d;break l}a=D[c+8>>2];D[a+12>>2]=d;D[c+8>>2]=d;D[d+24>>2]=0;D[d+12>>2]=c;D[d+8>>2]=a}a=D[2944]-1|0;D[2944]=a?a:-1}}function $h(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;D[a+8>>2]=e;n=a+32|0;h=D[n>>2];f=D[a+36>>2]-h>>2;a:{if(f>>>0>>0){ra(n,e-f|0);d=D[a+8>>2];break a}d=e;if(d>>>0>=f>>>0){break a}D[a+36>>2]=h+(e<<2);d=e}s=D[a+52>>2];p=D[a+48>>2];f=0;h=(e&1073741823)!=(e|0)?-1:e<<2;m=qa(na(h),0,h);b:{if((d|0)<=0){break b}g=D[a+32>>2];while(1){d=f<<2;h=D[d+m>>2];j=D[a+16>>2];c:{if((h|0)>(j|0)){D[d+g>>2]=j;break c}d=d+g|0;j=D[a+12>>2];if((j|0)>(h|0)){D[d>>2]=j;break c}D[d>>2]=h}d=D[a+8>>2];f=f+1|0;if((d|0)>(f|0)){continue}break}if((d|0)<=0){break b}f=0;while(1){h=f<<2;d=h+c|0;h=D[b+h>>2]+D[g+h>>2]|0;D[d>>2]=h;d:{if((h|0)>D[a+16>>2]){i=h-D[a+20>>2]|0}else{if((h|0)>=D[a+12>>2]){break d}i=h+D[a+20>>2]|0}D[d>>2]=i}d=D[a+8>>2];f=f+1|0;if((d|0)>(f|0)){continue}break}}f=D[a+56>>2];q=D[f>>2];f=D[f+4>>2]-q|0;if((f|0)>=5){o=f>>>2|0;t=o>>>0>2?o:2;u=e&-2;v=e&1;h=1;while(1){e:{f:{if((h|0)!=(o|0)){r=J(e,h);f=D[(h<<2)+q>>2];if((f|0)==-1){break f}f=D[D[p+12>>2]+(f<<2)>>2];if((f|0)==-1){break f}j=D[s>>2];g=D[p>>2];k=D[j+(D[g+(f<<2)>>2]<<2)>>2];i=f+1|0;i=(i>>>0)%3|0?i:f-2|0;if((i|0)!=-1){i=D[g+(i<<2)>>2]}else{i=-1}g:{h:{if((f>>>0)%3|0){f=f-1|0;break h}f=f+2|0;l=-1;if((f|0)==-1){break g}}l=D[g+(f<<2)>>2]}if((h|0)<=(k|0)){break f}f=D[(i<<2)+j>>2];if((f|0)>=(h|0)){break f}g=D[j+(l<<2)>>2];if((g|0)>=(h|0)){break f}i:{if((e|0)<=0){break i}g=J(e,g);j=J(e,f);k=J(e,k);f=0;l=0;if((e|0)!=1){while(1){D[(f<<2)+m>>2]=(D[(f+g<<2)+c>>2]+D[(f+j<<2)+c>>2]|0)-D[(f+k<<2)+c>>2];i=f|1;D[(i<<2)+m>>2]=(D[(g+i<<2)+c>>2]+D[(j+i<<2)+c>>2]|0)-D[(i+k<<2)+c>>2];f=f+2|0;l=l+2|0;if((u|0)!=(l|0)){continue}break}}if(!v){break i}D[(f<<2)+m>>2]=(D[(f+g<<2)+c>>2]+D[(f+j<<2)+c>>2]|0)-D[(f+k<<2)+c>>2]}if((d|0)<=0){break e}j=D[n>>2];f=0;while(1){d=f<<2;g=D[d+m>>2];k=D[a+16>>2];j:{if((g|0)>(k|0)){D[d+j>>2]=k;break j}d=d+j|0;k=D[a+12>>2];if((k|0)>(g|0)){D[d>>2]=k;break j}D[d>>2]=g}d=D[a+8>>2];f=f+1|0;if((d|0)>(f|0)){continue}break}f=0;if((d|0)<=0){break e}d=r<<2;k=d+c|0;i=b+d|0;while(1){g=f<<2;d=g+k|0;g=D[g+i>>2]+D[g+j>>2]|0;D[d>>2]=g;k:{if((g|0)>D[a+16>>2]){l=g-D[a+20>>2]|0}else{if((g|0)>=D[a+12>>2]){break k}l=g+D[a+20>>2]|0}D[d>>2]=l}d=D[a+8>>2];f=f+1|0;if((d|0)>(f|0)){continue}break}break e}va();T()}if((d|0)<=0){break e}k=(J(h-1|0,e)<<2)+c|0;j=D[n>>2];f=0;while(1){d=f<<2;g=D[d+k>>2];i=D[a+16>>2];l:{if((g|0)>(i|0)){D[d+j>>2]=i;break l}d=d+j|0;i=D[a+12>>2];if((i|0)>(g|0)){D[d>>2]=i;break l}D[d>>2]=g}d=D[a+8>>2];f=f+1|0;if((d|0)>(f|0)){continue}break}f=0;if((d|0)<=0){break e}d=r<<2;k=d+c|0;i=b+d|0;while(1){g=f<<2;d=g+k|0;g=D[g+i>>2]+D[g+j>>2]|0;D[d>>2]=g;m:{if((g|0)>D[a+16>>2]){l=g-D[a+20>>2]|0}else{if((g|0)>=D[a+12>>2]){break m}l=g+D[a+20>>2]|0}D[d>>2]=l}d=D[a+8>>2];f=f+1|0;if((d|0)>(f|0)){continue}break}}h=h+1|0;if((t|0)!=(h|0)){continue}break}}ma(m);return 1}function ud(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0,k=K(0),l=0,m=0,n=K(0);j=D[c>>2];a:{b:{f=D[b+4>>2];if(!f){break b}c=f-1|0;if(c&f){e=j;if(e>>>0>=f>>>0){e=(j>>>0)%(f>>>0)|0}c=D[D[b>>2]+(e<<2)>>2];if(!c){break b}while(1){c=D[c>>2];if(!c){break b}g=D[c+4>>2];if((g|0)!=(j|0)){if(f>>>0<=g>>>0){g=(g>>>0)%(f>>>0)|0}if((e|0)!=(g|0)){break b}}if(D[c+8>>2]!=(j|0)){continue}break}b=0;break a}e=c&j;c=D[D[b>>2]+(e<<2)>>2];if(!c){break b}g=f-1|0;while(1){c=D[c>>2];if(!c){break b}h=D[c+4>>2];if((h|0)!=(j|0)&(g&h)!=(e|0)){break b}if(D[c+8>>2]!=(j|0)){continue}break}b=0;break a}c=na(16);d=D[D[d>>2]>>2];D[c+12>>2]=0;D[c+8>>2]=d;D[c+4>>2]=j;D[c>>2]=0;n=K(D[b+12>>2]+1>>>0);k=H[b+16>>2];c:{if(n>K(k*K(f>>>0))?0:f){break c}d=2;g=(f-1&f)!=0|f>>>0<3|f<<1;k=K(Q(K(n/k)));d:{if(k=K(0)){e=~~k>>>0;break d}e=0}e=e>>>0>>0?g:e;e:{if((e|0)==1){break e}if(!(e&e-1)){d=e;break e}d=Kc(e);f=D[b+4>>2]}f:{if(d>>>0<=f>>>0){if(d>>>0>=f>>>0){break f}g=f>>>0<3;k=K(Q(K(K(G[b+12>>2])/H[b+16>>2])));g:{if(k=K(0)){e=~~k>>>0;break g}e=0}h:{i:{if(g){break i}if(ii(f)>>>0>1){break i}e=e>>>0<2?e:1<<32-M(e-1|0);break h}e=Kc(e)}d=d>>>0>e>>>0?d:e;if(f>>>0<=d>>>0){break f}}e=0;h=d;j:{k:{l:{if(d){if(h>>>0>=1073741824){break l}f=na(h<<2);d=D[b>>2];D[b>>2]=f;if(d){ma(d)}D[b+4>>2]=h;if(h-1>>>0>=3){g=h&-4;d=0;while(1){f=e<<2;D[f+D[b>>2]>>2]=0;D[D[b>>2]+(f|4)>>2]=0;D[D[b>>2]+(f|8)>>2]=0;D[D[b>>2]+(f|12)>>2]=0;e=e+4|0;d=d+4|0;if((g|0)!=(d|0)){continue}break}}d=h&3;if(d){while(1){D[D[b>>2]+(e<<2)>>2]=0;e=e+1|0;i=i+1|0;if((d|0)!=(i|0)){continue}break}}d=D[b+8>>2];if(!d){break j}e=b+8|0;g=D[d+4>>2];f=h-1|0;if(!(f&h)){break k}g=g>>>0>=h>>>0?(g>>>0)%(h>>>0)|0:g;D[D[b>>2]+(g<<2)>>2]=e;while(1){f=D[d>>2];if(!f){break j}i=D[f+4>>2];if(h>>>0<=i>>>0){i=(i>>>0)%(h>>>0)|0}if((g|0)==(i|0)){d=f;continue}e=f;l=i<<2;m=l+D[b>>2]|0;if(D[m>>2]){while(1){i=e;e=D[e>>2];if(D[f+8>>2]==D[e+8>>2]?e:0){continue}break}D[d>>2]=e;D[i>>2]=D[D[l+D[b>>2]>>2]>>2];D[D[l+D[b>>2]>>2]>>2]=f}else{D[m>>2]=d;d=f;g=i}continue}}d=D[b>>2];D[b>>2]=0;if(d){ma(d)}D[b+4>>2]=0;break j}sa();T()}g=f&g;D[D[b>>2]+(g<<2)>>2]=e;f=D[d>>2];if(!f){break j}l=h-1|0;while(1){h=l&D[f+4>>2];m:{if((h|0)==(g|0)){d=f;break m}e=f;i=h<<2;m=i+D[b>>2]|0;if(D[m>>2]){while(1){h=e;e=D[e>>2];if(D[f+8>>2]==D[e+8>>2]?e:0){continue}break}D[d>>2]=e;D[h>>2]=D[D[i+D[b>>2]>>2]>>2];D[D[i+D[b>>2]>>2]>>2]=f;break m}D[m>>2]=d;d=f;g=h}f=D[d>>2];if(f){continue}break}}}f=D[b+4>>2];d=f-1|0;if(!(d&f)){e=d&j;break c}if(f>>>0>j>>>0){e=j;break c}e=(j>>>0)%(f>>>0)|0}e=D[b>>2]+(e<<2)|0;d=D[e>>2];n:{o:{if(!d){d=b+8|0;D[c>>2]=D[d>>2];D[b+8>>2]=c;D[e>>2]=d;d=D[c>>2];if(!d){break n}d=D[d+4>>2];e=f-1|0;p:{if(!(e&f)){d=d&e;break p}if(d>>>0>>0){break p}d=(d>>>0)%(f>>>0)|0}d=D[b>>2]+(d<<2)|0;break o}D[c>>2]=D[d>>2]}D[d>>2]=c}D[b+12>>2]=D[b+12>>2]+1;b=1}B[a+4|0]=b;D[a>>2]=c}function Wc(a){var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;D[a+56>>2]=D[a+52>>2];D[a+44>>2]=D[a+40>>2];a:{b:{c:{e=D[a+64>>2];c=D[e+24>>2];if((c|0)!=D[e+28>>2]){while(1){d=b;i=D[(j<<2)+c>>2];d:{if((i|0)==-1){break d}b=D[a+56>>2];e:{if((b|0)!=D[a+60>>2]){D[b>>2]=d;D[a+56>>2]=b+4;break e}e=D[a+52>>2];c=b-e|0;g=c>>2;b=g+1|0;if(b>>>0>=1073741824){break c}f=c>>1;f=c>>>0<2147483644?b>>>0>>0?f:b:1073741823;if(f){if(f>>>0>=1073741824){break b}b=na(f<<2)}else{b=0}g=b+(g<<2)|0;D[g>>2]=d;if((c|0)>0){oa(b,e,c)}D[a+60>>2]=b+(f<<2);D[a+56>>2]=g+4;D[a+52>>2]=b;if(!e){break e}ma(e)}f:{if(!(D[D[a+12>>2]+(j>>>3&536870908)>>2]>>>j&1)){break f}b=i+1|0;b=(b>>>0)%3|0?b:i-2|0;if((b|0)==-1|D[D[a>>2]+(b>>>3&536870908)>>2]>>>b&1){break f}b=D[D[D[a+64>>2]+12>>2]+(b<<2)>>2];if((b|0)==-1){break f}c=b+1|0;c=(c>>>0)%3|0?c:b-2|0;if((c|0)==-1){break f}e=D[a+64>>2];f=D[a>>2];while(1){i=c;b=c+1|0;b=(b>>>0)%3|0?b:c-2|0;if((b|0)==-1|D[f+(b>>>3&536870908)>>2]>>>b&1){break f}b=D[D[e+12>>2]+(b<<2)>>2];if((b|0)==-1){break f}c=b+1|0;c=(c>>>0)%3|0?c:b-2|0;if((c|0)!=-1){continue}break}}D[D[a+28>>2]+(i<<2)>>2]=d;b=D[a+44>>2];g:{if((b|0)!=D[a+48>>2]){D[b>>2]=i;D[a+44>>2]=b+4;break g}e=D[a+40>>2];c=b-e|0;g=c>>2;b=g+1|0;if(b>>>0>=1073741824){break a}f=c>>1;f=c>>>0<2147483644?b>>>0>>0?f:b:1073741823;if(f){if(f>>>0>=1073741824){break b}b=na(f<<2)}else{b=0}g=b+(g<<2)|0;D[g>>2]=i;if((c|0)>0){oa(b,e,c)}D[a+48>>2]=b+(f<<2);D[a+44>>2]=g+4;D[a+40>>2]=b;if(!e){break g}ma(e)}b=d+1|0;e=D[a+64>>2];h:{if((i>>>0)%3|0){c=i-1|0;break h}c=i+2|0;if((c|0)==-1){break d}}c=D[D[e+12>>2]+(c<<2)>>2];if((c|0)==-1){break d}c=c+((c>>>0)%3|0?-1:2)|0;if((c|0)==-1|(c|0)==(i|0)){break d}while(1){e=c+1|0;e=(e>>>0)%3|0?e:c-2|0;if(D[D[a>>2]+(e>>>3&536870908)>>2]>>>e&1){d=D[a+56>>2];i:{if((d|0)!=D[a+60>>2]){D[d>>2]=b;D[a+56>>2]=d+4;break i}f=D[a+52>>2];e=d-f|0;h=e>>2;d=h+1|0;if(d>>>0>=1073741824){break c}g=e>>1;g=e>>>0<2147483644?d>>>0>>0?g:d:1073741823;if(g){if(g>>>0>=1073741824){break b}d=na(g<<2)}else{d=0}h=d+(h<<2)|0;D[h>>2]=b;if((e|0)>0){oa(d,f,e)}D[a+60>>2]=d+(g<<2);D[a+56>>2]=h+4;D[a+52>>2]=d;if(!f){break i}ma(f)}e=b+1|0;d=D[a+44>>2];j:{if((d|0)!=D[a+48>>2]){D[d>>2]=c;D[a+44>>2]=d+4;break j}g=D[a+40>>2];f=d-g|0;k=f>>2;d=k+1|0;if(d>>>0>=1073741824){break a}h=f>>1;h=f>>>0<2147483644?d>>>0>>0?h:d:1073741823;if(h){if(h>>>0>=1073741824){break b}d=na(h<<2)}else{d=0}k=d+(k<<2)|0;D[k>>2]=c;if((f|0)>0){oa(d,g,f)}D[a+48>>2]=d+(h<<2);D[a+44>>2]=k+4;D[a+40>>2]=d;if(!g){break j}ma(g)}d=b;b=e}D[D[a+28>>2]+(c<<2)>>2]=d;e=D[a+64>>2];k:{if((c>>>0)%3|0){c=c-1|0;break k}c=c+2|0;if((c|0)==-1){break d}}c=D[D[e+12>>2]+(c<<2)>>2];if((c|0)==-1){break d}c=c+((c>>>0)%3|0?-1:2)|0;if((c|0)==-1){break d}if((c|0)!=(i|0)){continue}break}}j=j+1|0;c=D[e+24>>2];if(j>>>0>2]-c>>2>>>0){continue}break}}return}pa();T()}sa();T()}pa();T()}function de(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;D[a+8>>2]=e;m=a+32|0;h=D[m>>2];f=D[a+36>>2]-h>>2;a:{if(f>>>0>>0){ra(m,e-f|0);d=D[a+8>>2];break a}d=e;if(d>>>0>=f>>>0){break a}D[a+36>>2]=h+(e<<2);d=e}s=D[a+52>>2];n=D[a+48>>2];f=0;h=(e&1073741823)!=(e|0)?-1:e<<2;l=qa(na(h),0,h);b:{if((d|0)<=0){break b}g=D[a+32>>2];while(1){d=f<<2;h=D[d+l>>2];i=D[a+16>>2];c:{if((h|0)>(i|0)){D[d+g>>2]=i;break c}d=d+g|0;i=D[a+12>>2];if((i|0)>(h|0)){D[d>>2]=i;break c}D[d>>2]=h}d=D[a+8>>2];f=f+1|0;if((d|0)>(f|0)){continue}break}if((d|0)<=0){break b}f=0;while(1){h=f<<2;d=h+c|0;h=D[b+h>>2]+D[g+h>>2]|0;D[d>>2]=h;d:{if((h|0)>D[a+16>>2]){h=h-D[a+20>>2]|0}else{if((h|0)>=D[a+12>>2]){break d}h=h+D[a+20>>2]|0}D[d>>2]=h}d=D[a+8>>2];f=f+1|0;if((d|0)>(f|0)){continue}break}}f=D[a+56>>2];q=D[f>>2];f=D[f+4>>2]-q|0;if((f|0)>=5){o=f>>>2|0;t=o>>>0>2?o:2;u=e&-2;v=e&1;h=1;while(1){e:{f:{if((h|0)!=(o|0)){r=J(e,h);f=D[(h<<2)+q>>2];if((f|0)==-1|D[D[n>>2]+(f>>>3&536870908)>>2]>>>f&1){break f}f=D[D[D[n+64>>2]+12>>2]+(f<<2)>>2];if((f|0)==-1){break f}i=D[s>>2];g=D[n+28>>2];k=D[i+(D[g+(f<<2)>>2]<<2)>>2];if((k|0)>=(h|0)){break f}j=f+1|0;j=D[i+(D[g+(((j>>>0)%3|0?j:f-2|0)<<2)>>2]<<2)>>2];if((j|0)>=(h|0)){break f}f=D[i+(D[g+(f+((f>>>0)%3|0?-1:2)<<2)>>2]<<2)>>2];if((f|0)>=(h|0)){break f}g:{if((e|0)<=0){break g}g=J(e,f);i=J(e,j);k=J(e,k);f=0;p=0;if((e|0)!=1){while(1){D[(f<<2)+l>>2]=(D[(f+g<<2)+c>>2]+D[(f+i<<2)+c>>2]|0)-D[(f+k<<2)+c>>2];j=f|1;D[(j<<2)+l>>2]=(D[(g+j<<2)+c>>2]+D[(i+j<<2)+c>>2]|0)-D[(k+j<<2)+c>>2];f=f+2|0;p=p+2|0;if((u|0)!=(p|0)){continue}break}}if(!v){break g}D[(f<<2)+l>>2]=(D[(f+g<<2)+c>>2]+D[(f+i<<2)+c>>2]|0)-D[(f+k<<2)+c>>2]}if((d|0)<=0){break e}i=D[m>>2];f=0;while(1){d=f<<2;g=D[d+l>>2];k=D[a+16>>2];h:{if((g|0)>(k|0)){D[d+i>>2]=k;break h}d=d+i|0;k=D[a+12>>2];if((k|0)>(g|0)){D[d>>2]=k;break h}D[d>>2]=g}d=D[a+8>>2];f=f+1|0;if((d|0)>(f|0)){continue}break}f=0;if((d|0)<=0){break e}d=r<<2;k=d+c|0;j=b+d|0;while(1){g=f<<2;d=g+k|0;g=D[g+j>>2]+D[g+i>>2]|0;D[d>>2]=g;i:{if((g|0)>D[a+16>>2]){g=g-D[a+20>>2]|0}else{if((g|0)>=D[a+12>>2]){break i}g=g+D[a+20>>2]|0}D[d>>2]=g}d=D[a+8>>2];f=f+1|0;if((d|0)>(f|0)){continue}break}break e}va();T()}if((d|0)<=0){break e}k=(J(h-1|0,e)<<2)+c|0;i=D[m>>2];f=0;while(1){d=f<<2;g=D[d+k>>2];j=D[a+16>>2];j:{if((g|0)>(j|0)){D[d+i>>2]=j;break j}d=d+i|0;j=D[a+12>>2];if((j|0)>(g|0)){D[d>>2]=j;break j}D[d>>2]=g}d=D[a+8>>2];f=f+1|0;if((d|0)>(f|0)){continue}break}f=0;if((d|0)<=0){break e}d=r<<2;k=d+c|0;j=b+d|0;while(1){g=f<<2;d=g+k|0;g=D[g+j>>2]+D[g+i>>2]|0;D[d>>2]=g;k:{if((g|0)>D[a+16>>2]){g=g-D[a+20>>2]|0}else{if((g|0)>=D[a+12>>2]){break k}g=g+D[a+20>>2]|0}D[d>>2]=g}d=D[a+8>>2];f=f+1|0;if((d|0)>(f|0)){continue}break}}h=h+1|0;if((t|0)!=(h|0)){continue}break}}ma(l);return 1}function ld(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;if((b|0)==-1){return 1}c=(b>>>0)/3|0;if(!(D[D[a+24>>2]+(c>>>3&268435452)>>2]>>>c&1)){d=D[a+48>>2];D[a+52>>2]=d;a:{if((d|0)!=D[a+56>>2]){D[d>>2]=b;D[a+52>>2]=d+4;break a}e=na(4);D[e>>2]=b;f=e+4|0;D[a+56>>2]=f;D[a+52>>2]=f;D[a+48>>2]=e;if(!d){break a}ma(d)}f=D[D[a+4>>2]+28>>2];d=b+1|0;e=(d>>>0)%3|0?d:b-2|0;d=D[f+(e<<2)>>2];if((d|0)==-1){return 0}g=(b-J(c,3)|0?-1:2)+b|0;c=D[f+(g<<2)>>2];if((c|0)==-1){return 0}b=D[a+36>>2];f=b+(d>>>3&536870908)|0;h=D[f>>2];i=1<>2]=h|i;Ma(a+8|0,d,e);b=D[a+36>>2]}b=(c>>>3&536870908)+b|0;d=D[b>>2];e=1<>2]=d|e;Ma(a+8|0,c,g)}c=D[a+52>>2];if((c|0)==D[a+48>>2]){return 1}k=a+8|0;while(1){b:{c:{c=c-4|0;b=D[c>>2];if((b|0)==-1){break c}d=(b>>>0)/3|0;e=D[a+24>>2]+(d>>>3&268435452)|0;f=D[e>>2];d=1<>2]=d|f;e=D[a+4>>2];d=D[D[e+28>>2]+(b<<2)>>2];if((d|0)==-1){return 0}while(1){c=b;d:{e:{f=D[a+36>>2]+(d>>>3&536870908)|0;g=D[f>>2];h=1<>2]+(d<<2)>>2];g:{if((b|0)==-1){break g}i=b+1|0;b=(i>>>0)%3|0?i:b-2|0;if((b|0)==-1|D[D[e>>2]+(b>>>3&536870908)>>2]>>>b&1){break g}b=D[D[D[e+64>>2]+12>>2]+(b<<2)>>2];if((b|0)!=-1){break f}}D[f>>2]=g|h;Ma(k,d,c);break e}D[f>>2]=g|h;Ma(k,d,c);d=b+1|0;if((((d>>>0)%3|0?d:b-2|0)|0)==-1){break e}b=-1;e=D[a+4>>2];h:{if((c|0)==-1){break h}d=c+1|0;d=(d>>>0)%3|0?d:c-2|0;if((d|0)==-1|D[D[e>>2]+(d>>>3&536870908)>>2]>>>d&1){break h}b=D[D[D[e+64>>2]+12>>2]+(d<<2)>>2]}d=(b>>>0)/3|0;h=1<>2];i=d>>>5|0;f=D[c+(i<<2)>>2];break d}i:{j:{if((c|0)==-1){break j}d=-1;b=c+1|0;b=(b>>>0)%3|0?b:c-2|0;e=D[a+4>>2];if(!((b|0)==-1|D[D[e>>2]+(b>>>3&536870908)>>2]>>>b&1)){d=D[D[D[e+64>>2]+12>>2]+(b<<2)>>2]}k:{l:{if((c>>>0)%3|0){c=c-1|0;break l}c=c+2|0;b=-1;if((c|0)==-1){break k}}b=-1;if(D[D[e>>2]+(c>>>3&536870908)>>2]>>>c&1){break k}b=D[D[D[e+64>>2]+12>>2]+(c<<2)>>2]}j=(b|0)==-1;g=j?-1:(b>>>0)/3|0;if((d|0)!=-1){c=D[a+24>>2];h=(d>>>0)/3|0;i=h>>>5|0;f=D[c+(i<<2)>>2];h=1<>2];i=g>>>5|0;f=D[c+(i<<2)>>2];if(!(h&f)){break d}}c=D[a+52>>2]-4|0;D[a+52>>2]=c;break b}if(j){b=d;break d}if(D[(g>>>3&536870908)+c>>2]>>>g&1){b=d;break d}c=D[a+52>>2];D[c-4>>2]=b;if((c|0)!=D[a+56>>2]){D[c>>2]=d;c=c+4|0;break c}m:{f=D[a+48>>2];e=c-f|0;c=e>>2;b=c+1|0;if(b>>>0<1073741824){g=e>>1;g=e>>>0<2147483644?b>>>0>>0?g:b:1073741823;if(g){if(g>>>0>=1073741824){break m}b=na(g<<2)}else{b=0}c=b+(c<<2)|0;D[c>>2]=d;c=c+4|0;if((e|0)>0){oa(b,f,e)}D[a+56>>2]=b+(g<<2);D[a+52>>2]=c;D[a+48>>2]=b;if(!f){break b}ma(f);c=D[a+52>>2];break b}pa();T()}sa();T()}D[(i<<2)+c>>2]=f|h;d=D[D[e+28>>2]+(b<<2)>>2];if((d|0)!=-1){continue}break}return 0}D[a+52>>2]=c}if(D[a+48>>2]!=(c|0)){continue}break}}return 1}function Tb(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;i=J(b,12)+a|0;D[i+12>>2]=D[i+8>>2];j=(c|0)==-1?-1:(c>>>0)/3|0;l=1;k=c;a:{b:{c:{while(1){d:{n=e&1;if(n){if((k|0)==-1){break d}if((Uc(a,((k>>>0)%3|0?-1:2)+k|0)|0)==-1){break a}c=k+1|0;c=(c>>>0)%3|0?c:k-2|0;if((c|0)==-1){break a}e=c+1|0;c=(e>>>0)%3|0?e:c-2|0;if((c|0)==-1){break a}c=D[D[D[a+4>>2]+12>>2]+(c<<2)>>2];if((c|0)==-1){break a}e=c+1|0;c=(e>>>0)%3|0?e:c-2|0;if((c|0)==-1){break a}j=(c>>>0)/3|0}d=D[a+56>>2]+(j>>>3&536870908)|0;g=D[d>>2];f=1<>2]=g|f;d=D[i+12>>2];f:{if((d|0)!=D[i+16>>2]){D[d>>2]=j;D[i+12>>2]=d+4;break f}g=D[i+8>>2];h=d-g|0;m=h>>2;d=m+1|0;if(d>>>0>=1073741824){break c}f=h>>1;f=h>>>0<2147483644?d>>>0>>0?f:d:1073741823;if(f){if(f>>>0>=1073741824){break b}d=na(f<<2)}else{d=0}m=d+(m<<2)|0;D[m>>2]=j;if((h|0)>0){oa(d,g,h)}D[i+8>>2]=d;D[i+12>>2]=m+4;D[i+16>>2]=d+(f<<2);if(!g){break f}ma(g)}h=e+1|0;g:{h:{i:{if(!e){break i}if(h&1){if((c|0)==-1){c=-1;break g}e=c+1|0;c=(e>>>0)%3|0?e:c-2|0;break i}k=n?c:k;if((c|0)==-1){c=-1;break g}if((c>>>0)%3|0){e=c-1|0;break h}c=c+2|0}d=c;c=-1;e=d;if((d|0)==-1){break g}}c=D[D[D[a+4>>2]+12>>2]+(e<<2)>>2];d=-1;g=-1;f=e+1|0;f=(f>>>0)%3|0?f:e-2|0;if((f|0)>=0){g=(f>>>0)/3|0;g=D[(D[D[a>>2]+96>>2]+J(g,12)|0)+(f-J(g,3)<<2)>>2]}j:{if((c|0)==-1){break j}f=((c>>>0)%3|0?-1:2)+c|0;if((f|0)<0){break j}d=(f>>>0)/3|0;d=D[(D[D[a>>2]+96>>2]+J(d,12)|0)+(f-J(d,3)<<2)>>2]}if((d|0)!=(g|0)){c=-1;break g}k:{l:{e=((e>>>0)%3|0?-1:2)+e|0;if((e|0)>=0){d=(e>>>0)/3|0;if((c|0)!=-1){break l}c=-1;break g}e=-1;if((c|0)!=-1){break k}c=-1;break g}e=D[(D[D[a>>2]+96>>2]+J(d,12)|0)+(e-J(d,3)<<2)>>2]}d=c+1|0;d=(d>>>0)%3|0?d:c-2|0;if((d|0)>=0){g=(d>>>0)/3|0;d=D[(D[D[a>>2]+96>>2]+J(g,12)|0)+(d-J(g,3)<<2)>>2]}else{d=-1}if((d|0)!=(e|0)){c=-1;break g}e=h;j=(c>>>0)/3|0;d=D[a+56>>2]+(j>>>3&268435452)|0;g=D[d>>2];f=1<>2]-4|0;d=D[e>>2];h=D[a+56>>2]+(d>>>3&536870908)|0;g=D[h>>2];o=h,p=ji(d)&g,D[o>>2]=p;D[i+12>>2]=e}e=1;d=l;l=0;if(d){continue}break a}break}k=-1;Uc(a,-1);break a}pa();T()}sa();T()}D[((b<<2)+a|0)+44>>2]=k;c=D[i+12>>2];b=D[i+8>>2];m:{if((c|0)==(b|0)){break m}e=c-b|0;c=e>>2;d=c>>>0>1?c:1;k=d&1;a=D[a+56>>2];c=0;if(e>>>0>=8){e=d&-2;j=0;while(1){d=c<<2;h=D[d+b>>2];l=a+(h>>>3&536870908)|0;i=D[l>>2];o=l,p=ji(h)&i,D[o>>2]=p;d=D[b+(d|4)>>2];h=a+(d>>>3&536870908)|0;l=D[h>>2];o=h,p=ji(d)&l,D[o>>2]=p;c=c+2|0;j=j+2|0;if((e|0)!=(j|0)){continue}break}}if(!k){break m}b=D[b+(c<<2)>>2];a=a+(b>>>3&536870908)|0;c=D[a>>2];o=a,p=ji(b)&c,D[o>>2]=p}}function md(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;if((b|0)==-1){return 1}d=(b>>>0)/3|0;if(!(D[D[a+24>>2]+(d>>>3&268435452)>>2]>>>d&1)){c=D[a+48>>2];D[a+52>>2]=c;a:{if((c|0)!=D[a+56>>2]){D[c>>2]=b;D[a+52>>2]=c+4;break a}e=na(4);D[e>>2]=b;f=e+4|0;D[a+56>>2]=f;D[a+52>>2]=f;D[a+48>>2]=e;if(!c){break a}ma(c)}e=-1;f=D[a+4>>2];c=b+1|0;g=(c>>>0)%3|0?c:b-2|0;if((g|0)!=-1){e=D[D[f>>2]+(g<<2)>>2]}b:{h=b-J(d,3)|0;if(h){c=b-1|0;break b}c=b+2|0;if((c|0)!=-1){break b}return 0}if((e|0)==-1){return 0}d=D[D[f>>2]+(c<<2)>>2];if((d|0)==-1){return 0}c=D[a+36>>2];f=c+(e>>>3&536870908)|0;i=D[f>>2];j=1<>2]=i|j;Ma(a+8|0,e,g);c=D[a+36>>2]}c=(d>>>3&536870908)+c|0;e=D[c>>2];f=1<>2]=e|f;Ma(a+8|0,d,(h?-1:2)+b|0)}c=D[a+52>>2];if((c|0)==D[a+48>>2]){return 1}j=a+8|0;while(1){c:{d:{c=c-4|0;b=D[c>>2];if((b|0)==-1){break d}d=(b>>>0)/3|0;e=D[a+24>>2]+(d>>>3&268435452)|0;f=D[e>>2];d=1<>2]=d|f;while(1){d=D[a+4>>2];c=D[D[d>>2]+(b<<2)>>2];if((c|0)==-1){return 0}e:{f:{e=D[a+36>>2]+(c>>>3&536870908)|0;f=D[e>>2];g=1<>2]+(c<<2)>>2];h:{if((h|0)==-1){break h}i=h+1|0;h=(i>>>0)%3|0?i:h-2|0;if((h|0)==-1){break h}d=D[D[d+12>>2]+(h<<2)>>2];if((d|0)!=-1){break g}}D[e>>2]=f|g;Ma(j,c,b);break f}D[e>>2]=f|g;Ma(j,c,b);c=d+1|0;if((((c>>>0)%3|0?c:d-2|0)|0)==-1){break f}d=b-2|0;c=b+1|0;b=-1;c=(c>>>0)%3|0?c:d;if((c|0)!=-1){b=D[D[D[a+4>>2]+12>>2]+(c<<2)>>2]}c=(b>>>0)/3|0;g=1<>2];h=c>>>5|0;d=D[e+(h<<2)>>2];break e}c=-1;f=D[a+4>>2];d=b+1|0;d=(d>>>0)%3|0?d:b-2|0;if((d|0)!=-1){c=D[D[f+12>>2]+(d<<2)>>2]}i:{j:{if((b>>>0)%3|0){e=b-1|0;break j}e=b+2|0;b=-1;if((e|0)==-1){break i}}b=D[D[f+12>>2]+(e<<2)>>2]}i=(b|0)==-1;f=i?-1:(b>>>0)/3|0;k:{if((c|0)!=-1){e=D[a+24>>2];g=(c>>>0)/3|0;h=g>>>5|0;d=D[e+(h<<2)>>2];g=1<>2];h=f>>>5|0;d=D[e+(h<<2)>>2];if(!(g&d)){break e}}c=D[a+52>>2]-4|0;D[a+52>>2]=c;break c}if(i){b=c;break e}if(D[(f>>>3&536870908)+e>>2]>>>f&1){b=c;break e}d=D[a+52>>2];D[d-4>>2]=b;if((d|0)!=D[a+56>>2]){D[d>>2]=c;c=d+4|0;break d}l:{e=D[a+48>>2];d=d-e|0;g=d>>2;b=g+1|0;if(b>>>0<1073741824){f=d>>1;f=d>>>0<2147483644?b>>>0>>0?f:b:1073741823;if(f){if(f>>>0>=1073741824){break l}b=na(f<<2)}else{b=0}g=b+(g<<2)|0;D[g>>2]=c;c=g+4|0;if((d|0)>0){oa(b,e,d)}D[a+56>>2]=b+(f<<2);D[a+52>>2]=c;D[a+48>>2]=b;if(!e){break c}ma(e);c=D[a+52>>2];break c}pa();T()}sa();T()}D[(h<<2)+e>>2]=d|g;if((b|0)!=-1){continue}break}return 0}D[a+52>>2]=c}if(D[a+48>>2]!=(c|0)){continue}break}}return 1}function ae(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;h=$-32|0;$=h;a:{b:{if(!Pa(1,h+28|0,b)){break b}d=D[h+28>>2];c=D[D[a+48>>2]+64>>2];if(d>>>0>D[c+4>>2]-D[c>>2]>>2>>>0){break b}c:{if(d){Oa(a+60|0,d);c=h+8|0;D[c>>2]=0;D[c+4>>2]=0;B[c+5|0]=0;B[c+6|0]=0;B[c+7|0]=0;B[c+8|0]=0;B[c+9|0]=0;B[c+10|0]=0;B[c+11|0]=0;B[c+12|0]=0;if(!Da(c,b)){break c}while(1){f=1<>2]+(e>>>3&536870908)|0;if(i){f=f|D[g>>2]}else{f=D[g>>2]&(f^-1)}D[g>>2]=f;e=e+1|0;if((d|0)!=(e|0)){continue}break}}if(!Pa(1,h+28|0,b)){break b}d=D[h+28>>2];c=D[D[a+48>>2]+64>>2];if(d>>>0>D[c+4>>2]-D[c>>2]>>2>>>0){break b}if(d){e=0;Oa(a+72|0,d);c=h+8|0;D[c>>2]=0;D[c+4>>2]=0;B[c+5|0]=0;B[c+6|0]=0;B[c+7|0]=0;B[c+8|0]=0;B[c+9|0]=0;B[c+10|0]=0;B[c+11|0]=0;B[c+12|0]=0;if(!Da(c,b)){break c}while(1){f=1<>2]+(e>>>3&536870908)|0;if(i){f=f|D[g>>2]}else{f=D[g>>2]&(f^-1)}D[g>>2]=f;e=e+1|0;if((d|0)!=(e|0)){continue}break}}if(!Pa(1,h+28|0,b)){break b}d=D[h+28>>2];c=D[D[a+48>>2]+64>>2];if(d>>>0>D[c+4>>2]-D[c>>2]>>2>>>0){break b}if(d){e=0;Oa(a+84|0,d);c=h+8|0;D[c>>2]=0;D[c+4>>2]=0;B[c+5|0]=0;B[c+6|0]=0;B[c+7|0]=0;B[c+8|0]=0;B[c+9|0]=0;B[c+10|0]=0;B[c+11|0]=0;B[c+12|0]=0;if(!Da(c,b)){break c}while(1){f=1<>2]+(e>>>3&536870908)|0;if(i){f=f|D[g>>2]}else{f=D[g>>2]&(f^-1)}D[g>>2]=f;e=e+1|0;if((d|0)!=(e|0)){continue}break}}if(!Pa(1,h+28|0,b)){break b}d=D[h+28>>2];c=D[D[a+48>>2]+64>>2];if(d>>>0>D[c+4>>2]-D[c>>2]>>2>>>0){break b}if(d){e=0;Oa(a+96|0,d);c=h+8|0;D[c>>2]=0;D[c+4>>2]=0;B[c+5|0]=0;B[c+6|0]=0;B[c+7|0]=0;B[c+8|0]=0;B[c+9|0]=0;B[c+10|0]=0;B[c+11|0]=0;B[c+12|0]=0;if(!Da(c,b)){break c}while(1){f=1<>2]+(e>>>3&536870908)|0;if(i){f=f|D[g>>2]}else{f=D[g>>2]&(f^-1)}D[g>>2]=f;e=e+1|0;if((d|0)!=(e|0)){continue}break}}e=0;d=D[b+12>>2];f=d;c=D[b+20>>2];g=c;i=D[b+16>>2];j=i+4|0;c=j>>>0<4?c+1|0:c;k=D[b+8>>2];if(k>>>0>>0&(c|0)>=(d|0)|(c|0)>(d|0)){break a}l=D[b>>2];d=l+i|0;d=E[d|0]|E[d+1|0]<<8|(E[d+2|0]<<16|E[d+3|0]<<24);D[b+16>>2]=j;D[b+20>>2]=c;c=g;g=i+8|0;c=g>>>0<8?c+1|0:c;i=g;g=c;if(i>>>0>k>>>0&(c|0)>=(f|0)|(c|0)>(f|0)){break a}c=j+l|0;c=E[c|0]|E[c+1|0]<<8|(E[c+2|0]<<16|E[c+3|0]<<24);D[b+16>>2]=i;D[b+20>>2]=g;if((c|0)<(d|0)){break a}D[a+16>>2]=c;D[a+12>>2]=d;b=(c>>31)-((d>>31)+(c>>>0>>0)|0)|0;c=c-d|0;if(!b&c>>>0>2147483646|b){break a}e=1;b=c+1|0;D[a+20>>2]=b;c=b>>>1|0;D[a+24>>2]=c;D[a+28>>2]=0-c;if(b&1){break a}D[a+24>>2]=c-1;break a}}e=0}$=h+32|0;return e|0}function Yh(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;h=$-32|0;$=h;a:{b:{if(!Pa(1,h+28|0,b)){break b}d=D[h+28>>2];c=D[a+48>>2];if(d>>>0>D[c+4>>2]-D[c>>2]>>2>>>0){break b}c:{if(d){Oa(a+60|0,d);c=h+8|0;D[c>>2]=0;D[c+4>>2]=0;B[c+5|0]=0;B[c+6|0]=0;B[c+7|0]=0;B[c+8|0]=0;B[c+9|0]=0;B[c+10|0]=0;B[c+11|0]=0;B[c+12|0]=0;if(!Da(c,b)){break c}while(1){f=1<>2]+(e>>>3&536870908)|0;if(i){f=f|D[g>>2]}else{f=D[g>>2]&(f^-1)}D[g>>2]=f;e=e+1|0;if((d|0)!=(e|0)){continue}break}}if(!Pa(1,h+28|0,b)){break b}d=D[h+28>>2];c=D[a+48>>2];if(d>>>0>D[c+4>>2]-D[c>>2]>>2>>>0){break b}if(d){e=0;Oa(a+72|0,d);c=h+8|0;D[c>>2]=0;D[c+4>>2]=0;B[c+5|0]=0;B[c+6|0]=0;B[c+7|0]=0;B[c+8|0]=0;B[c+9|0]=0;B[c+10|0]=0;B[c+11|0]=0;B[c+12|0]=0;if(!Da(c,b)){break c}while(1){f=1<>2]+(e>>>3&536870908)|0;if(i){f=f|D[g>>2]}else{f=D[g>>2]&(f^-1)}D[g>>2]=f;e=e+1|0;if((d|0)!=(e|0)){continue}break}}if(!Pa(1,h+28|0,b)){break b}d=D[h+28>>2];c=D[a+48>>2];if(d>>>0>D[c+4>>2]-D[c>>2]>>2>>>0){break b}if(d){e=0;Oa(a+84|0,d);c=h+8|0;D[c>>2]=0;D[c+4>>2]=0;B[c+5|0]=0;B[c+6|0]=0;B[c+7|0]=0;B[c+8|0]=0;B[c+9|0]=0;B[c+10|0]=0;B[c+11|0]=0;B[c+12|0]=0;if(!Da(c,b)){break c}while(1){f=1<>2]+(e>>>3&536870908)|0;if(i){f=f|D[g>>2]}else{f=D[g>>2]&(f^-1)}D[g>>2]=f;e=e+1|0;if((d|0)!=(e|0)){continue}break}}if(!Pa(1,h+28|0,b)){break b}d=D[h+28>>2];c=D[a+48>>2];if(d>>>0>D[c+4>>2]-D[c>>2]>>2>>>0){break b}if(d){e=0;Oa(a+96|0,d);c=h+8|0;D[c>>2]=0;D[c+4>>2]=0;B[c+5|0]=0;B[c+6|0]=0;B[c+7|0]=0;B[c+8|0]=0;B[c+9|0]=0;B[c+10|0]=0;B[c+11|0]=0;B[c+12|0]=0;if(!Da(c,b)){break c}while(1){f=1<>2]+(e>>>3&536870908)|0;if(i){f=f|D[g>>2]}else{f=D[g>>2]&(f^-1)}D[g>>2]=f;e=e+1|0;if((d|0)!=(e|0)){continue}break}}e=0;d=D[b+12>>2];f=d;c=D[b+20>>2];g=c;i=D[b+16>>2];j=i+4|0;c=j>>>0<4?c+1|0:c;k=D[b+8>>2];if(k>>>0>>0&(c|0)>=(d|0)|(c|0)>(d|0)){break a}l=D[b>>2];d=l+i|0;d=E[d|0]|E[d+1|0]<<8|(E[d+2|0]<<16|E[d+3|0]<<24);D[b+16>>2]=j;D[b+20>>2]=c;c=g;g=i+8|0;c=g>>>0<8?c+1|0:c;i=g;g=c;if(i>>>0>k>>>0&(c|0)>=(f|0)|(c|0)>(f|0)){break a}c=j+l|0;c=E[c|0]|E[c+1|0]<<8|(E[c+2|0]<<16|E[c+3|0]<<24);D[b+16>>2]=i;D[b+20>>2]=g;if((c|0)<(d|0)){break a}D[a+16>>2]=c;D[a+12>>2]=d;b=(c>>31)-((d>>31)+(c>>>0>>0)|0)|0;c=c-d|0;if(!b&c>>>0>2147483646|b){break a}e=1;b=c+1|0;D[a+20>>2]=b;c=b>>>1|0;D[a+24>>2]=c;D[a+28>>2]=0-c;if(b&1){break a}D[a+24>>2]=c-1;break a}}e=0}$=h+32|0;return e|0}function qh(a){a=a|0;var b=0,c=0,d=0,e=0,f=0;b=D[a+32>>2];e=D[b+16>>2];d=D[b+12>>2];c=D[b+20>>2];if(G[b+8>>2]>e>>>0&(d|0)>=(c|0)|(c|0)<(d|0)){f=E[e+D[b>>2]|0];d=e+1|0;c=d?c:c+1|0;D[b+16>>2]=d;D[b+20>>2]=c;b=D[a+48>>2];D[a+48>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}a:{b:{c:{d:{switch(f|0){case 0:b=na(384);D[b>>2]=8284;qa(b+4|0,0,80);D[b+96>>2]=0;D[b+100>>2]=0;D[b+92>>2]=-1;D[b+84>>2]=-1;D[b+88>>2]=-1;D[b+104>>2]=0;D[b+108>>2]=0;D[b+112>>2]=0;D[b+116>>2]=0;D[b+120>>2]=0;D[b+124>>2]=0;D[b+128>>2]=0;D[b+132>>2]=0;D[b+136>>2]=0;D[b+140>>2]=0;D[b+144>>2]=0;D[b+148>>2]=0;D[b+156>>2]=0;D[b+160>>2]=0;D[b+152>>2]=1065353216;D[b+164>>2]=0;D[b+168>>2]=0;D[b+172>>2]=0;D[b+176>>2]=0;D[b+180>>2]=0;D[b+184>>2]=0;D[b+188>>2]=0;D[b+192>>2]=0;D[b+196>>2]=0;D[b+200>>2]=0;D[b+204>>2]=0;D[b+208>>2]=0;D[b+212>>2]=-1;D[b+216>>2]=0;D[b+220>>2]=0;D[b+224>>2]=0;La(b+232|0);La(b+272|0);c=b+312|0;D[c>>2]=0;D[c+4>>2]=0;B[c+5|0]=0;B[c+6|0]=0;B[c+7|0]=0;B[c+8|0]=0;B[c+9|0]=0;B[c+10|0]=0;B[c+11|0]=0;B[c+12|0]=0;La(b+328|0);D[b+376>>2]=0;D[b+368>>2]=0;D[b+372>>2]=0;break c;case 2:break d;default:break b}}b=na(440);D[b>>2]=8336;qa(b+4|0,0,80);D[b+96>>2]=0;D[b+100>>2]=0;D[b+92>>2]=-1;D[b+84>>2]=-1;D[b+88>>2]=-1;D[b+104>>2]=0;D[b+108>>2]=0;D[b+112>>2]=0;D[b+116>>2]=0;D[b+120>>2]=0;D[b+124>>2]=0;D[b+128>>2]=0;D[b+132>>2]=0;D[b+136>>2]=0;D[b+140>>2]=0;D[b+144>>2]=0;D[b+148>>2]=0;D[b+156>>2]=0;D[b+160>>2]=0;D[b+152>>2]=1065353216;D[b+164>>2]=0;D[b+168>>2]=0;D[b+172>>2]=0;D[b+176>>2]=0;D[b+180>>2]=0;D[b+184>>2]=0;D[b+188>>2]=0;D[b+192>>2]=0;D[b+196>>2]=0;D[b+200>>2]=0;D[b+204>>2]=0;D[b+208>>2]=0;D[b+212>>2]=-1;D[b+216>>2]=0;D[b+220>>2]=0;D[b+224>>2]=0;La(b+232|0);La(b+272|0);c=b+312|0;D[c>>2]=0;D[c+4>>2]=0;B[c+5|0]=0;B[c+6|0]=0;B[c+7|0]=0;B[c+8|0]=0;B[c+9|0]=0;B[c+10|0]=0;B[c+11|0]=0;B[c+12|0]=0;La(b+328|0);D[b+392>>2]=0;D[b+396>>2]=0;D[b+384>>2]=0;D[b+388>>2]=0;D[b+376>>2]=0;D[b+380>>2]=0;D[b+368>>2]=0;D[b+372>>2]=0;D[b+416>>2]=0;D[b+420>>2]=0;D[b+408>>2]=2;D[b+412>>2]=7;D[b+400>>2]=-1;D[b+404>>2]=-1;D[b+424>>2]=0;D[b+428>>2]=0;D[b+432>>2]=0;D[b+436>>2]=0}c=D[a+48>>2];D[a+48>>2]=b;if(!c){break a}ba[D[D[c>>2]+4>>2]](c)}b=D[a+48>>2];if(b){break a}return 0}a=ba[D[D[b>>2]+8>>2]](b,a)|0}else{a=0}return a|0}function ai(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;g=$-32|0;$=g;D[a+68>>2]=f;d=D[a+56>>2];e=D[d>>2];d=D[d+4>>2];D[g+24>>2]=0;D[g+16>>2]=0;D[g+20>>2]=0;a:{d=d-e|0;if((d|0)>0){m=a+60|0;d=d>>>2|0;n=d>>>0>1?d:1;o=a+112|0;while(1){e=D[a+56>>2];d=D[e>>2];if(D[e+4>>2]-d>>2>>>0<=k>>>0){break a}Mb(m,D[d+(k<<2)>>2],g+16|0);e=D[g+20>>2];d=e>>31;f=D[g+16>>2];h=f>>31;j=D[g+24>>2];i=j>>31;i=(i^j)-i|0;h=i+((d^e)-d+((f^h)-h)|0)|0;d=0;d=h>>>0>>0?1:d;b:{if(!(d|h)){D[g+16>>2]=D[a+108>>2];break b}i=D[a+108>>2];l=i>>31;f=gi(fi(i,l,f,f>>31),aa,h,d);D[g+16>>2]=f;d=gi(fi(i,l,e,e>>31),aa,h,d);D[g+20>>2]=d;e=d;d=d>>31;e=(e^d)-d|0;d=f>>31;d=e+((d^f)-d|0)|0;if((j|0)>=0){D[g+24>>2]=i-d;break b}D[g+24>>2]=d-i}d=za(o);f=D[g+16>>2];c:{if(d){D[g+24>>2]=0-D[g+24>>2];e=0-D[g+20>>2]|0;D[g+20>>2]=e;f=0-f|0;D[g+16>>2]=f;break c}e=D[g+20>>2]}d:{if((f|0)>=0){f=D[a+108>>2];d=f+D[g+24>>2]|0;f=e+f|0;break d}e:{if((e|0)<0){d=D[g+24>>2];f=d>>31;f=(d^f)-f|0;break e}d=D[g+24>>2];f=d>>31;f=D[a+100>>2]+(f-(d^f)|0)|0}if((d|0)<0){d=e>>31;d=(d^e)-d|0;break d}d=e>>31;d=D[a+100>>2]+(d-(d^e)|0)|0}e=D[a+100>>2];f:{if(!(d|f)){d=e;f=d;break f}if(!((d|0)!=(e|0)|f)){f=d;break f}if(!((e|0)!=(f|0)|d)){d=f;break f}g:{if(f){break g}h=D[a+108>>2];if((h|0)>=(d|0)){break g}d=(h<<1)-d|0;f=0;break f}h:{if((e|0)!=(f|0)){break h}h=D[a+108>>2];if((h|0)<=(d|0)){break h}d=(h<<1)-d|0;break f}i:{if((d|0)!=(e|0)){break i}e=D[a+108>>2];if((e|0)<=(f|0)){break i}f=(e<<1)-f|0;break f}if(d){break f}d=0;e=D[a+108>>2];if((e|0)>=(f|0)){break f}f=(e<<1)-f|0}D[g+12>>2]=d;D[g+8>>2]=f;j:{if(D[a+8>>2]<=0){break j}h=D[a+32>>2];f=0;while(1){d=f<<2;e=D[d+(g+8|0)>>2];j=D[a+16>>2];k:{if((e|0)>(j|0)){D[d+h>>2]=j;break k}d=d+h|0;j=D[a+12>>2];if((j|0)>(e|0)){D[d>>2]=j;break k}D[d>>2]=e}f=f+1|0;e=D[a+8>>2];if((f|0)<(e|0)){continue}break}d=0;if((e|0)<=0){break j}e=k<<3;j=e+c|0;i=b+e|0;while(1){f=d<<2;e=f+j|0;f=D[f+i>>2]+D[f+h>>2]|0;D[e>>2]=f;l:{if((f|0)>D[a+16>>2]){f=f-D[a+20>>2]|0}else{if((f|0)>=D[a+12>>2]){break l}f=f+D[a+20>>2]|0}D[e>>2]=f}d=d+1|0;if((d|0)>2]){continue}break}}k=k+1|0;if((n|0)!=(k|0)){continue}break}}$=g+32|0;return 1}va();T()}function Rh(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;g=$-32|0;$=g;D[a+68>>2]=f;d=D[a+56>>2];e=D[d>>2];d=D[d+4>>2];D[g+24>>2]=0;D[g+16>>2]=0;D[g+20>>2]=0;a:{d=d-e|0;if((d|0)>0){m=a+60|0;d=d>>>2|0;n=d>>>0>1?d:1;o=a+112|0;while(1){e=D[a+56>>2];d=D[e>>2];if(D[e+4>>2]-d>>2>>>0<=k>>>0){break a}Kb(m,D[d+(k<<2)>>2],g+16|0);e=D[g+20>>2];d=e>>31;f=D[g+16>>2];h=f>>31;j=D[g+24>>2];i=j>>31;i=(i^j)-i|0;h=i+((d^e)-d+((f^h)-h)|0)|0;d=0;d=h>>>0>>0?1:d;b:{if(!(d|h)){D[g+16>>2]=D[a+108>>2];break b}i=D[a+108>>2];l=i>>31;f=gi(fi(i,l,f,f>>31),aa,h,d);D[g+16>>2]=f;d=gi(fi(i,l,e,e>>31),aa,h,d);D[g+20>>2]=d;e=d;d=d>>31;e=(e^d)-d|0;d=f>>31;d=e+((d^f)-d|0)|0;if((j|0)>=0){D[g+24>>2]=i-d;break b}D[g+24>>2]=d-i}d=za(o);f=D[g+16>>2];c:{if(d){D[g+24>>2]=0-D[g+24>>2];e=0-D[g+20>>2]|0;D[g+20>>2]=e;f=0-f|0;D[g+16>>2]=f;break c}e=D[g+20>>2]}d:{if((f|0)>=0){f=D[a+108>>2];d=f+D[g+24>>2]|0;f=e+f|0;break d}e:{if((e|0)<0){d=D[g+24>>2];f=d>>31;f=(d^f)-f|0;break e}d=D[g+24>>2];f=d>>31;f=D[a+100>>2]+(f-(d^f)|0)|0}if((d|0)<0){d=e>>31;d=(d^e)-d|0;break d}d=e>>31;d=D[a+100>>2]+(d-(d^e)|0)|0}e=D[a+100>>2];f:{if(!(d|f)){d=e;f=d;break f}if(!((d|0)!=(e|0)|f)){f=d;break f}if(!((e|0)!=(f|0)|d)){d=f;break f}g:{if(f){break g}h=D[a+108>>2];if((h|0)>=(d|0)){break g}d=(h<<1)-d|0;f=0;break f}h:{if((e|0)!=(f|0)){break h}h=D[a+108>>2];if((h|0)<=(d|0)){break h}d=(h<<1)-d|0;break f}i:{if((d|0)!=(e|0)){break i}e=D[a+108>>2];if((e|0)<=(f|0)){break i}f=(e<<1)-f|0;break f}if(d){break f}d=0;e=D[a+108>>2];if((e|0)>=(f|0)){break f}f=(e<<1)-f|0}D[g+12>>2]=d;D[g+8>>2]=f;j:{if(D[a+8>>2]<=0){break j}h=D[a+32>>2];f=0;while(1){d=f<<2;e=D[d+(g+8|0)>>2];j=D[a+16>>2];k:{if((e|0)>(j|0)){D[d+h>>2]=j;break k}d=d+h|0;j=D[a+12>>2];if((j|0)>(e|0)){D[d>>2]=j;break k}D[d>>2]=e}f=f+1|0;e=D[a+8>>2];if((f|0)<(e|0)){continue}break}d=0;if((e|0)<=0){break j}e=k<<3;j=e+c|0;i=b+e|0;while(1){f=d<<2;e=f+j|0;f=D[f+i>>2]+D[f+h>>2]|0;D[e>>2]=f;l:{if((f|0)>D[a+16>>2]){f=f-D[a+20>>2]|0}else{if((f|0)>=D[a+12>>2]){break l}f=f+D[a+20>>2]|0}D[e>>2]=f}d=d+1|0;if((d|0)>2]){continue}break}}k=k+1|0;if((n|0)!=(k|0)){continue}break}}$=g+32|0;return 1}va();T()}function vc(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;l=ba[D[D[a>>2]+44>>2]](a)|0;a:{if((l|0)<=0){break a}h=D[b+4>>2]-D[b>>2]>>2;e=$+-64|0;$=e;d=mb(e);f=J(D[2541],l);$b(d,D[D[a+8>>2]+56>>2],l<<24>>24,5,0,f,f>>31);d=_b(na(96),d);B[d+84|0]=1;D[d+72>>2]=D[d+68>>2];Zb(d,h);D[d+60>>2]=D[D[a+8>>2]+60>>2];f=D[a+16>>2];D[a+16>>2]=d;if(f){Aa(f)}$=e- -64|0;d=D[a+16>>2];if(!D[d+80>>2]){break a}j=D[D[d>>2]>>2];if(!j){break a}i=D[c+12>>2];g=i;e=D[c+20>>2];k=D[c+8>>2];f=D[c+16>>2];if((g|0)<=(e|0)&k>>>0<=f>>>0|(e|0)>(g|0)){break a}h=J(h,l);j=j+D[d+48>>2]|0;m=D[c>>2];n=E[m+f|0];d=e;g=f+1|0;d=g?d:d+1|0;D[c+16>>2]=g;D[c+20>>2]=d;b:{c:{if(n){if(jc(h,l,c,j)){break c}break a}if((d|0)>=(i|0)&g>>>0>=k>>>0|(d|0)>(i|0)){break a}d=E[g+m|0];f=f+2|0;e=f>>>0<2?e+1|0:e;D[c+16>>2]=f;D[c+20>>2]=e;e=D[D[a+16>>2]+64>>2];e=D[e+4>>2]-D[e>>2]|0;if((d|0)==D[2541]){d=h<<2;if(d>>>0>e>>>0){break a}f=D[c+12>>2];e=D[c+20>>2];i=D[c+16>>2];g=d+i|0;e=g>>>0>>0?e+1|0:e;if(g>>>0>G[c+8>>2]&(e|0)>=(f|0)|(e|0)>(f|0)){break a}oa(j,i+D[c>>2]|0,d);e=d;f=d+D[c+16>>2]|0;d=D[c+20>>2];D[c+16>>2]=f;D[c+20>>2]=e>>>0>f>>>0?d+1|0:d;break c}if(e>>>0>>0){break a}e=D[c+8>>2];i=D[c+16>>2];f=i;g=e-f|0;f=e>>>0>>0;e=D[c+20>>2];f=D[c+12>>2]-(f+e|0)|0;k=fi(d,0,h,0)>>>0>g>>>0;g=aa;if(k&(g|0)>=(f|0)|(f|0)<(g|0)){break a}f=1;if(!h){break b}g=0;while(1){m=d+i|0;k=D[c+12>>2];e=d>>>0>m>>>0?e+1|0:e;if(m>>>0>G[c+8>>2]&(k|0)<=(e|0)|(e|0)>(k|0)){return 0}oa(j+(g<<2)|0,i+D[c>>2]|0,d);e=D[c+20>>2];i=d+D[c+16>>2]|0;e=i>>>0>>0?e+1|0:e;D[c+16>>2]=i;D[c+20>>2]=e;g=g+1|0;if((h|0)!=(g|0)){continue}break}}f=1;if(!h){break b}d=D[a+20>>2];if(d){f=0;if(ba[D[D[d>>2]+32>>2]](d)|0){break b}}d=0;g=0;d:{if((h|0)<=0){break d}if((h|0)!=1){i=h&-2;while(1){e=d<<2;f=D[e+j>>2];D[e+j>>2]=0-(f&1)^f>>>1;f=e|4;e=D[f+j>>2];D[f+j>>2]=0-(e&1)^e>>>1;d=d+2|0;g=g+2|0;if((i|0)!=(g|0)){continue}break}}if(!(h&1)){break d}e=d<<2;d=D[e+j>>2];D[e+j>>2]=0-(d&1)^d>>>1}f=0}d=D[a+20>>2];e:{if(!d){break e}if(!(ba[D[D[d>>2]+40>>2]](d,c)|0)){break a}if(f){break e}a=D[a+20>>2];if(!(ba[D[D[a>>2]+44>>2]](a,j,j,h,l,D[b>>2])|0)){break a}}o=1}return o|0}function Xa(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;g=$-32|0;$=g;a:{b:{if(D[a+8>>2]<<5>>>0>=b>>>0){break b}if((b|0)<0){break a}b=(b-1>>>5|0)+1|0;c=na(b<<2);D[g+24>>2]=b;D[g+20>>2]=0;D[g+16>>2]=c;b=D[a>>2];D[g+12>>2]=0;D[g+8>>2]=b;c=D[a+4>>2];D[g+4>>2]=c&31;D[g>>2]=b+(c>>>3&536870908);f=$-32|0;$=f;i=D[g+4>>2];e=D[g+12>>2];j=D[g>>2];h=D[g+8>>2];b=(i-e|0)+(j-h<<3)|0;d=D[g+20>>2];c=b+d|0;D[g+20>>2]=c;if(!((c-1^d-1)>>>0<32?d:0)){D[D[g+16>>2]+((c>>>0<33?0:c-1>>>5|0)<<2)>>2]=0}c=D[g+16>>2]+(d>>>3&536870908)|0;d=d&31;c:{if((d|0)==(e|0)){if((b|0)<=0){break c}if(e){i=32-e|0;d=(b|0)<(i|0)?b:i;i=-1<>>i-d;D[c>>2]=D[c>>2]&(i^-1)|i&D[h>>2];b=b-d|0;h=h+4|0;c=c+(d+e>>>3&536870908)|0}j=c;e=(b|0)/32|0;c=e<<2;d=Ra(j,h,c);b=b-(e<<5)|0;if((b|0)<=0){break c}e=c+d|0;b=-1>>>32-b|0;D[e>>2]=D[e>>2]&(b^-1)|b&D[c+h>>2];break c}D[f+28>>2]=e;D[f+24>>2]=h;D[f+20>>2]=i;D[f+16>>2]=j;D[f+12>>2]=d;D[f+8>>2]=c;b=D[f+28>>2];c=D[f+24>>2];h=(D[f+20>>2]-b|0)+(D[f+16>>2]-c<<3)|0;d:{if((h|0)<=0){b=D[f+12>>2];break d}e:{if(!b){b=D[f+12>>2];break e}e=D[f+12>>2];j=32-e|0;k=32-b|0;d=(h|0)<(k|0)?h:k;i=d>>>0>j>>>0?j:d;l=D[f+8>>2];m=D[l>>2]&(-1<>>j-i^-1);j=D[c>>2]&(-1<>>k-d);D[l>>2]=m|(b>>>0>>0?j<>>b-e|0);c=e+i|0;b=c&31;D[f+12>>2]=b;e=l+(c>>>3&536870908)|0;D[f+8>>2]=e;c=d-i|0;if((c|0)>0){D[e>>2]=D[e>>2]&(-1>>>32-c^-1)|j>>>i+D[f+28>>2];D[f+12>>2]=c;b=c}h=h-d|0;c=D[f+24>>2]+4|0;D[f+24>>2]=c}i=-1<=32){j=i^-1;while(1){d=D[f+8>>2];c=D[c>>2];D[d>>2]=j&D[d>>2]|c<>2]=d+4;D[d+4>>2]=i&D[d+4>>2]|c>>>e;c=D[f+24>>2]+4|0;D[f+24>>2]=c;d=h>>>0>63;h=h-32|0;if(d){continue}break}}if((h|0)<=0){break d}d=D[f+8>>2];j=e;e=(e|0)<(h|0)?e:h;j=D[d>>2]&(i&-1>>>j-e^-1);i=D[c>>2]&-1>>>32-h;D[d>>2]=j|i<>2]=b;d=d+(c>>>3&536870908)|0;D[f+8>>2]=d;c=h-e|0;if((c|0)<=0){break d}D[d>>2]=D[d>>2]&(-1>>>32-c^-1)|i>>>e;D[f+12>>2]=c;b=c}c=D[f+8>>2];D[f+4>>2]=b;D[f>>2]=c}$=f+32|0;b=D[a>>2];D[a>>2]=D[g+16>>2];D[g+16>>2]=b;c=D[a+4>>2];D[a+4>>2]=D[g+20>>2];D[g+20>>2]=c;c=D[a+8>>2];D[a+8>>2]=D[g+24>>2];D[g+24>>2]=c;if(!b){break b}ma(b)}$=g+32|0;return}pa();T()}function Hh(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=$-48|0;$=g;d=D[a+8>>2];if(d-31>>>0>=4294967267){D[a+76>>2]=d;e=-1<>2]=d;D[a+80>>2]=e^-1;D[a+92>>2]=(d|0)/2;H[a+88>>2]=K(2)/K(d|0)}D[a+52>>2]=f;d=D[a+40>>2];e=D[d>>2];d=D[d+4>>2];D[g+16>>2]=0;D[g+8>>2]=0;D[g+12>>2]=0;a:{d=d-e|0;if((d|0)>0){m=a+8|0;n=a+44|0;d=d>>>2|0;o=d>>>0>1?d:1;p=a+96|0;while(1){e=D[a+40>>2];d=D[e>>2];if(D[e+4>>2]-d>>2>>>0<=j>>>0){break a}Mb(n,D[d+(j<<2)>>2],g+8|0);e=D[g+12>>2];d=e>>31;f=D[g+8>>2];h=f>>31;k=D[g+16>>2];i=k>>31;i=(i^k)-i|0;h=i+((d^e)-d+((f^h)-h)|0)|0;d=0;d=h>>>0>>0?1:d;b:{if(!(d|h)){D[g+8>>2]=D[a+92>>2];break b}i=D[a+92>>2];l=i>>31;f=gi(fi(i,l,f,f>>31),aa,h,d);D[g+8>>2]=f;d=gi(fi(i,l,e,e>>31),aa,h,d);D[g+12>>2]=d;e=d>>31;e=(d^e)-e|0;d=f>>31;d=e+((d^f)-d|0)|0;if((k|0)>=0){D[g+16>>2]=i-d;break b}D[g+16>>2]=d-i}d=za(p);f=D[g+8>>2];c:{if(d){D[g+16>>2]=0-D[g+16>>2];e=0-D[g+12>>2]|0;D[g+12>>2]=e;f=0-f|0;D[g+8>>2]=f;break c}e=D[g+12>>2]}d:{if((f|0)>=0){f=D[a+92>>2];d=f+D[g+16>>2]|0;f=e+f|0;break d}e:{if((e|0)<0){d=D[g+16>>2];f=d>>31;f=(d^f)-f|0;break e}d=D[g+16>>2];f=d>>31;f=D[a+84>>2]+(f-(d^f)|0)|0}if((d|0)<0){d=e>>31;d=(d^e)-d|0;break d}d=e>>31;d=D[a+84>>2]+(d-(d^e)|0)|0}e=D[a+84>>2];f:{if(!(d|f)){d=e;f=d;break f}if(!((d|0)!=(e|0)|f)){f=d;break f}if(!((e|0)!=(f|0)|d)){d=f;break f}g:{if(f){break g}h=D[a+92>>2];if((h|0)>=(d|0)){break g}d=(h<<1)-d|0;f=0;break f}h:{if((e|0)!=(f|0)){break h}h=D[a+92>>2];if((h|0)<=(d|0)){break h}d=(h<<1)-d|0;break f}i:{if((d|0)!=(e|0)){break i}e=D[a+92>>2];if((e|0)<=(f|0)){break i}f=(e<<1)-f|0;break f}if(d){break f}d=0;e=D[a+92>>2];if((e|0)>=(f|0)){break f}f=(e<<1)-f|0}e=j<<3;h=e+b|0;k=D[h+4>>2];h=D[h>>2];D[g+36>>2]=d;D[g+32>>2]=f;D[g+24>>2]=h;D[g+28>>2]=k;Jb(g+40|0,m,g+32|0,g+24|0);d=c+e|0;D[d>>2]=D[g+40>>2];D[d+4>>2]=D[g+44>>2];j=j+1|0;if((o|0)!=(j|0)){continue}break}}$=g+48|0;return 1}va();T()}function Dh(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=$-48|0;$=g;d=D[a+8>>2];if(d-31>>>0>=4294967267){D[a+76>>2]=d;e=-1<>2]=d;D[a+80>>2]=e^-1;D[a+92>>2]=(d|0)/2;H[a+88>>2]=K(2)/K(d|0)}D[a+52>>2]=f;d=D[a+40>>2];e=D[d>>2];d=D[d+4>>2];D[g+16>>2]=0;D[g+8>>2]=0;D[g+12>>2]=0;a:{d=d-e|0;if((d|0)>0){m=a+8|0;n=a+44|0;d=d>>>2|0;o=d>>>0>1?d:1;p=a+96|0;while(1){e=D[a+40>>2];d=D[e>>2];if(D[e+4>>2]-d>>2>>>0<=j>>>0){break a}Kb(n,D[d+(j<<2)>>2],g+8|0);e=D[g+12>>2];d=e>>31;f=D[g+8>>2];h=f>>31;k=D[g+16>>2];i=k>>31;i=(i^k)-i|0;h=i+((d^e)-d+((f^h)-h)|0)|0;d=0;d=h>>>0>>0?1:d;b:{if(!(d|h)){D[g+8>>2]=D[a+92>>2];break b}i=D[a+92>>2];l=i>>31;f=gi(fi(i,l,f,f>>31),aa,h,d);D[g+8>>2]=f;d=gi(fi(i,l,e,e>>31),aa,h,d);D[g+12>>2]=d;e=d>>31;e=(d^e)-e|0;d=f>>31;d=e+((d^f)-d|0)|0;if((k|0)>=0){D[g+16>>2]=i-d;break b}D[g+16>>2]=d-i}d=za(p);f=D[g+8>>2];c:{if(d){D[g+16>>2]=0-D[g+16>>2];e=0-D[g+12>>2]|0;D[g+12>>2]=e;f=0-f|0;D[g+8>>2]=f;break c}e=D[g+12>>2]}d:{if((f|0)>=0){f=D[a+92>>2];d=f+D[g+16>>2]|0;f=e+f|0;break d}e:{if((e|0)<0){d=D[g+16>>2];f=d>>31;f=(d^f)-f|0;break e}d=D[g+16>>2];f=d>>31;f=D[a+84>>2]+(f-(d^f)|0)|0}if((d|0)<0){d=e>>31;d=(d^e)-d|0;break d}d=e>>31;d=D[a+84>>2]+(d-(d^e)|0)|0}e=D[a+84>>2];f:{if(!(d|f)){d=e;f=d;break f}if(!((d|0)!=(e|0)|f)){f=d;break f}if(!((e|0)!=(f|0)|d)){d=f;break f}g:{if(f){break g}h=D[a+92>>2];if((h|0)>=(d|0)){break g}d=(h<<1)-d|0;f=0;break f}h:{if((e|0)!=(f|0)){break h}h=D[a+92>>2];if((h|0)<=(d|0)){break h}d=(h<<1)-d|0;break f}i:{if((d|0)!=(e|0)){break i}e=D[a+92>>2];if((e|0)<=(f|0)){break i}f=(e<<1)-f|0;break f}if(d){break f}d=0;e=D[a+92>>2];if((e|0)>=(f|0)){break f}f=(e<<1)-f|0}e=j<<3;h=e+b|0;k=D[h+4>>2];h=D[h>>2];D[g+36>>2]=d;D[g+32>>2]=f;D[g+24>>2]=h;D[g+28>>2]=k;Jb(g+40|0,m,g+32|0,g+24|0);d=c+e|0;D[d>>2]=D[g+40>>2];D[d+4>>2]=D[g+44>>2];j=j+1|0;if((o|0)!=(j|0)){continue}break}}$=g+48|0;return 1}va();T()}function Kd(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;a:{if(!F[b+38>>1]){break a}if(!Wa(1,a+12|0,b)){break a}c=D[b+8>>2];d=D[b+16>>2];f=c-d|0;e=D[a+12>>2];c=D[b+12>>2]-(D[b+20>>2]+(c>>>0>>0)|0)|0;if(f>>>0>>6>>>0&(c|0)<=0|(c|0)<0){break a}d=D[a>>2];c=D[a+4>>2]-d>>2;b:{if(c>>>0>>0){ra(a,e-c|0);e=D[a+12>>2];break b}if(c>>>0<=e>>>0){break b}D[a+4>>2]=d+(e<<2)}if(!e){return 1}g=D[b+16>>2];c=D[b+20>>2];k=D[a>>2];l=D[b+8>>2];j=D[b+12>>2];f=0;while(1){if((c|0)>=(j|0)&g>>>0>=l>>>0|(c|0)>(j|0)){return 0}m=D[b>>2];i=E[m+g|0];d=g+1|0;c=d?c:c+1|0;g=d;D[b+16>>2]=d;D[b+20>>2]=c;d=i>>>2|0;h=0;c:{d:{e:{f:{n=i&3;switch(n|0){case 3:break f;case 0:break d;default:break e}}d=d+f|0;if(d>>>0>=e>>>0){return 0}qa(k+(f<<2)|0,0,(i&252)+4|0);f=d;break c}while(1){if((c|0)>=(j|0)&g>>>0>=l>>>0|(c|0)>(j|0)){break a}e=E[g+m|0];g=g+1|0;c=g?c:c+1|0;D[b+16>>2]=g;D[b+20>>2]=c;d=e<<(h<<3|6)|d;h=h+1|0;if((n|0)!=(h|0)){continue}break}}D[k+(f<<2)>>2]=d}e=D[a+12>>2];f=f+1|0;if(e>>>0>f>>>0){continue}break}b=a+16|0;j=D[a>>2];d=D[a+16>>2];c=D[a+20>>2]-d|0;g:{if(c>>>0<=16383){ra(b,4096-(c>>>2|0)|0);break g}if((c|0)==16384){break g}D[a+20>>2]=d+16384}c=a+28|0;f=D[c>>2];d=D[a+32>>2]-f>>3;h:{if(d>>>0>>0){db(c,e-d|0);f=D[c>>2];break h}if(d>>>0>e>>>0){D[a+32>>2]=(e<<3)+f}if(!e){break a}}g=D[b>>2];b=0;a=0;while(1){c=j+(b<<2)|0;h=D[c>>2];d=a;i=(b<<3)+f|0;D[i+4>>2]=a;D[i>>2]=h;c=D[c>>2];a=c+a|0;if(a>>>0>4096){break a}i:{if(a>>>0<=d>>>0){break i}h=0;i=c&7;if(i){while(1){D[g+(d<<2)>>2]=b;d=d+1|0;h=h+1|0;if((i|0)!=(h|0)){continue}break}}if(c-1>>>0<=6){break i}while(1){c=g+(d<<2)|0;D[c>>2]=b;D[c+28>>2]=b;D[c+24>>2]=b;D[c+20>>2]=b;D[c+16>>2]=b;D[c+12>>2]=b;D[c+8>>2]=b;D[c+4>>2]=b;d=d+8|0;if((d|0)!=(a|0)){continue}break}}b=b+1|0;if((e|0)!=(b|0)){continue}break}o=(a|0)==4096}return o}function mf(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0;f=$-32|0;$=f;e=f+8|0;c=$-80|0;$=c;a=D[b+36>>2];D[c+72>>2]=D[b+32>>2];D[c+76>>2]=a;d=D[b+28>>2];a=c- -64|0;D[a>>2]=D[b+24>>2];D[a+4>>2]=d;a=D[b+20>>2];D[c+56>>2]=D[b+16>>2];D[c+60>>2]=a;a=D[b+12>>2];D[c+48>>2]=D[b+8>>2];D[c+52>>2]=a;a=D[b+4>>2];D[c+40>>2]=D[b>>2];D[c+44>>2]=a;gc(c+8|0,c+40|0,c+24|0);a=D[c+8>>2];a:{if(a){D[e>>2]=a;a=e+4|0;if(B[c+23|0]>=0){b=c+8|4;e=D[b+4>>2];D[a>>2]=D[b>>2];D[a+4>>2]=e;D[a+8>>2]=D[b+8>>2];break a}ta(a,D[c+12>>2],D[c+16>>2]);if(B[c+23|0]>=0){break a}ma(D[c+12>>2]);break a}if(B[c+23|0]<0){ma(D[c+12>>2])}a=E[c+31|0];if(a>>>0>=2){b=na(32);a=E[1475]|E[1476]<<8;B[b+24|0]=a;B[b+25|0]=a>>>8;a=E[1471]|E[1472]<<8|(E[1473]<<16|E[1474]<<24);d=E[1467]|E[1468]<<8|(E[1469]<<16|E[1470]<<24);B[b+16|0]=d;B[b+17|0]=d>>>8;B[b+18|0]=d>>>16;B[b+19|0]=d>>>24;B[b+20|0]=a;B[b+21|0]=a>>>8;B[b+22|0]=a>>>16;B[b+23|0]=a>>>24;a=E[1463]|E[1464]<<8|(E[1465]<<16|E[1466]<<24);d=E[1459]|E[1460]<<8|(E[1461]<<16|E[1462]<<24);B[b+8|0]=d;B[b+9|0]=d>>>8;B[b+10|0]=d>>>16;B[b+11|0]=d>>>24;B[b+12|0]=a;B[b+13|0]=a>>>8;B[b+14|0]=a>>>16;B[b+15|0]=a>>>24;a=E[1455]|E[1456]<<8|(E[1457]<<16|E[1458]<<24);d=E[1451]|E[1452]<<8|(E[1453]<<16|E[1454]<<24);B[b|0]=d;B[b+1|0]=d>>>8;B[b+2|0]=d>>>16;B[b+3|0]=d>>>24;B[b+4|0]=a;B[b+5|0]=a>>>8;B[b+6|0]=a>>>16;B[b+7|0]=a>>>24;B[b+26|0]=0;D[c+8>>2]=-1;a=c+8|4;ta(a,b,26);d=B[c+23|0];D[e>>2]=D[c+8>>2];e=e+4|0;if((d|0)>=0){d=D[a+4>>2];D[e>>2]=D[a>>2];D[e+4>>2]=d;D[e+8>>2]=D[a+8>>2];ma(b);break a}ta(e,D[c+12>>2],D[c+16>>2]);if(B[c+23|0]<0){ma(D[c+12>>2])}ma(b);break a}D[e>>2]=0;D[e+4>>2]=0;D[e+16>>2]=a;D[e+8>>2]=0;D[e+12>>2]=0}$=c+80|0;a=D[f+24>>2];if(B[f+23|0]<0){ma(D[f+12>>2])}$=f+32|0;return a|0}function Mh(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0;e=$-32|0;$=e;a:{if((c|0)!=3){break a}c=D[a+4>>2];f=D[a+12>>2];D[e+24>>2]=-1;D[e+16>>2]=-1;D[e+20>>2]=1065353216;D[e+8>>2]=-1;D[e+12>>2]=-1;if((b|0)==-2){break a}i=D[D[D[c+4>>2]+8>>2]+(f<<2)>>2];if((ba[D[D[c>>2]+8>>2]](c)|0)==1){h=D[D[D[c+4>>2]+8>>2]+(f<<2)>>2];b:{if((ba[D[D[c>>2]+8>>2]](c)|0)!=1|b-1>>>0>5){break b}g=ba[D[D[c>>2]+36>>2]](c)|0;a=ba[D[D[c>>2]+44>>2]](c,f)|0;if(!g|!a){break b}f=ba[D[D[c>>2]+40>>2]](c,f)|0;c:{if(f){if((b|0)!=6){break b}b=D[c+44>>2];d=na(112);D[d+4>>2]=h;c=D[e+12>>2];D[d+8>>2]=D[e+8>>2];D[d+12>>2]=c;c=D[e+20>>2];D[d+16>>2]=D[e+16>>2];D[d+20>>2]=c;D[d+24>>2]=D[e+24>>2];D[d+40>>2]=a;c=a+12|0;D[d+36>>2]=c;D[d+32>>2]=f;D[d+28>>2]=b;D[d+68>>2]=a;D[d- -64>>2]=c;D[d+60>>2]=f;D[d+56>>2]=b;D[d+48>>2]=0;D[d+52>>2]=0;D[d>>2]=5928;D[d+88>>2]=1065353216;D[d+92>>2]=-1;D[d+80>>2]=-1;D[d+84>>2]=-1;D[d+72>>2]=1;D[d+76>>2]=-1;D[d+44>>2]=6492;a=d+96|0;break c}if((b|0)!=6){break b}b=D[c+44>>2];d=na(112);D[d+4>>2]=h;c=D[e+12>>2];D[d+8>>2]=D[e+8>>2];D[d+12>>2]=c;c=D[e+20>>2];D[d+16>>2]=D[e+16>>2];D[d+20>>2]=c;D[d+24>>2]=D[e+24>>2];D[d+40>>2]=a;c=a+12|0;D[d+36>>2]=c;D[d+32>>2]=g;D[d+28>>2]=b;D[d+68>>2]=a;D[d- -64>>2]=c;D[d+60>>2]=g;D[d+56>>2]=b;D[d+48>>2]=0;D[d+52>>2]=0;D[d>>2]=6932;D[d+88>>2]=1065353216;D[d+92>>2]=-1;D[d+80>>2]=-1;D[d+84>>2]=-1;D[d+72>>2]=1;D[d+76>>2]=-1;D[d+44>>2]=7352;a=d+96|0}D[a>>2]=0;D[a+4>>2]=0;B[a+5|0]=0;B[a+6|0]=0;B[a+7|0]=0;B[a+8|0]=0;B[a+9|0]=0;B[a+10|0]=0;B[a+11|0]=0;B[a+12|0]=0}if(d){break a}}d=na(28);D[d+4>>2]=i;a=D[e+12>>2];D[d+8>>2]=D[e+8>>2];D[d+12>>2]=a;a=D[e+20>>2];D[d+16>>2]=D[e+16>>2];D[d+20>>2]=a;D[d+24>>2]=D[e+24>>2];D[d>>2]=7764}$=e+32|0;return d|0}function Zc(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;g=$-80|0;$=g;a:{if(!Ub(1,g+76|0,b)){break a}h=D[g+76>>2];if(!h){break a}d=D[b+8>>2];c=D[b+16>>2];d=fi(d-c|0,D[b+12>>2]-(D[b+20>>2]+(c>>>0>d>>>0)|0)|0,5,0);c=aa;if(d>>>0>>0&(c|0)<=0|(c|0)<0){break a}c=D[a+4>>2];d=D[a+8>>2]-c>>2;b:{if(d>>>0>>0){ra(a+4|0,h-d|0);break b}if(d>>>0<=h>>>0){break b}D[a+8>>2]=c+(h<<2)}r=a+16|0;j=D[a+32>>2];k=1;while(1){c:{e=D[b+12>>2];c=e;d=D[b+20>>2];p=D[b+8>>2];m=D[b+16>>2];if((c|0)<=(d|0)&p>>>0<=m>>>0|(c|0)<(d|0)){break c}q=D[b>>2];o=E[q+m|0];c=d;f=m+1|0;c=f?c:c+1|0;D[b+16>>2]=f;D[b+20>>2]=c;if((c|0)>=(e|0)&f>>>0>=p>>>0|(c|0)>(e|0)){break c}f=E[f+q|0];c=d;i=m+2|0;c=i>>>0<2?c+1|0:c;D[b+16>>2]=i;D[b+20>>2]=c;if((c|0)>=(e|0)&i>>>0>=p>>>0|(c|0)>(e|0)){break c}i=E[i+q|0];c=d;n=m+3|0;c=n>>>0<3?c+1|0:c;D[b+16>>2]=n;D[b+20>>2]=c;if((c|0)>=(e|0)&n>>>0>=p>>>0|(c|0)>(e|0)){break c}e=E[n+q|0];c=d;d=m+4|0;c=d>>>0<4?c+1|0:c;D[b+16>>2]=d;D[b+20>>2]=c;if(!i|((f-12&255)>>>0<245|o>>>0>4)){break c}c=mb(g+8|0);n=i<<24>>24;e=(e|0)!=0;d=f-1|0;if(d>>>0<=10){d=D[(d<<2)+10148>>2]}else{d=-1}d=J(d,i);$b(c,o,n,f,e,d,d>>31);if(!Ub(1,g+4|0,b)){break c}f=D[g+4>>2];D[g+68>>2]=f;d=_b(na(96),c);ba[D[D[j>>2]+8>>2]](j,D[j+12>>2]-D[j+8>>2]>>2,d);d=(D[j+12>>2]-D[j+8>>2]>>2)-1|0;o=d<<2;D[D[o+D[j+8>>2]>>2]+60>>2]=f;D[D[a+4>>2]+(l<<2)>>2]=d;k=D[a+16>>2];c=D[a+20>>2]-k>>2;d:{if((c|0)>(d|0)){break d}D[g>>2]=-1;d=d+1|0;if(d>>>0>c>>>0){xa(r,d-c|0,g);k=D[r>>2];break d}if(c>>>0<=d>>>0){break d}D[a+20>>2]=(d<<2)+k}D[k+o>>2]=l;l=l+1|0;k=l>>>0>>0;if((h|0)!=(l|0)){continue}}break}l=!k}$=g+80|0;return l&1}function Mc(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;k=$-16|0;$=k;D[k+8>>2]=c;e=D[a+12>>2];d=D[a+8>>2];f=e-d>>2;a:{if((f|0)>(b|0)){break a}h=b+1|0;if(h>>>0>f>>>0){f=h-f|0;g=D[a+16>>2];d=D[a+12>>2];if(f>>>0<=g-d>>2>>>0){if(f){e=d;d=f<<2;d=qa(e,0,d)+d|0}D[a+12>>2]=d;break a}b:{c:{d:{h=D[a+8>>2];i=d-h>>2;e=i+f|0;if(e>>>0<1073741824){g=g-h|0;l=g>>1;g=g>>>0<2147483644?e>>>0>>0?l:e:1073741823;if(g){if(g>>>0>=1073741824){break d}j=na(g<<2)}e=(i<<2)+j|0;i=f<<2;f=qa(e,0,i);i=f+i|0;g=(g<<2)+j|0;if((d|0)==(h|0)){break c}while(1){d=d-4|0;f=D[d>>2];D[d>>2]=0;e=e-4|0;D[e>>2]=f;if((d|0)!=(h|0)){continue}break}D[a+16>>2]=g;f=D[a+12>>2];D[a+12>>2]=i;d=D[a+8>>2];D[a+8>>2]=e;if((d|0)==(f|0)){break b}while(1){f=f-4|0;e=D[f>>2];D[f>>2]=0;if(e){Aa(e)}if((d|0)!=(f|0)){continue}break}break b}pa();T()}sa();T()}D[a+16>>2]=g;D[a+12>>2]=i;D[a+8>>2]=f}if(d){ma(d)}break a}if(f>>>0<=h>>>0){break a}d=d+(h<<2)|0;if((d|0)!=(e|0)){while(1){e=e-4|0;c=D[e>>2];D[e>>2]=0;if(c){Aa(c)}if((d|0)!=(e|0)){continue}break}c=D[k+8>>2]}D[a+12>>2]=d}e:{f:{d=D[c+56>>2];g:{if((d|0)>4){break g}e=J(d,12)+a|0;d=D[e+24>>2];if((d|0)!=D[e+28>>2]){D[d>>2]=b;D[e+24>>2]=d+4;break g}h=D[e+20>>2];f=d-h|0;j=f>>2;d=j+1|0;if(d>>>0>=1073741824){break f}g=f>>1;g=f>>>0<2147483644?d>>>0>>0?g:d:1073741823;if(g){if(g>>>0>=1073741824){break e}d=na(g<<2)}else{d=0}j=d+(j<<2)|0;D[j>>2]=b;if((f|0)>0){oa(d,h,f)}D[e+20>>2]=d;D[e+24>>2]=j+4;D[e+28>>2]=d+(g<<2);if(!h){break g}ma(h)}D[c+60>>2]=b;a=D[a+8>>2];D[k+8>>2]=0;b=a+(b<<2)|0;a=D[b>>2];D[b>>2]=c;if(a){Aa(a)}a=D[k+8>>2];D[k+8>>2]=0;if(a){Aa(a)}$=k+16|0;return}pa();T()}sa();T()}function xd(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;i=$-16|0;$=i;D[i>>2]=b;g=-1;a:{if((b|0)==-1){D[i+4>>2]=-1;break a}c=b+1|0;D[i+4>>2]=(c>>>0)%3|0?c:b-2|0;if((b>>>0)%3|0){g=b-1|0;break a}g=b+2|0}D[i+8>>2]=g;n=(b>>>0)/3|0;b:{c:{d:{while(1){e:{f:{k=D[(l<<2)+i>>2];if((k|0)!=-1){c=D[D[D[a+8>>2]+12>>2]+(k<<2)>>2];if((c|0)!=-1){break f}}g=0;c=D[a+216>>2];if((c|0)==D[a+220>>2]){break e}while(1){f=J(g,144)+c|0;c=D[f+136>>2];d=D[f+140>>2];g:{if(c>>>0>>0){D[c>>2]=k;D[f+136>>2]=c+4;break g}h=D[f+132>>2];j=c-h|0;e=j>>2;c=e+1|0;if(c>>>0>=1073741824){break d}m=e<<2;d=d-h|0;e=d>>1;d=d>>>0<2147483644?c>>>0>>0?e:c:1073741823;if(d){if(d>>>0>=1073741824){break c}c=na(d<<2)}else{c=0}e=m+c|0;D[e>>2]=k;if((j|0)>0){oa(c,h,j)}D[f+132>>2]=c;D[f+136>>2]=e+4;D[f+140>>2]=c+(d<<2);if(!h){break g}ma(h)}g=g+1|0;c=D[a+216>>2];if(g>>>0<(D[a+220>>2]-c|0)/144>>>0){continue}break}break e}if((b|0)==-1|(c>>>0)/3>>>0>>0){break e}g=0;if(D[a+220>>2]==D[a+216>>2]){break e}while(1){h:{if(!za(D[a+368>>2]+(g<<4)|0)){break h}f=D[a+216>>2]+J(g,144)|0;c=D[f+136>>2];d=D[f+140>>2];if(c>>>0>>0){D[c>>2]=k;D[f+136>>2]=c+4;break h}h=D[f+132>>2];j=c-h|0;e=j>>2;c=e+1|0;if(c>>>0>=1073741824){break b}m=e<<2;d=d-h|0;e=d>>1;d=d>>>0<2147483644?c>>>0>>0?e:c:1073741823;if(d){if(d>>>0>=1073741824){break c}c=na(d<<2)}else{c=0}e=m+c|0;D[e>>2]=k;if((j|0)>0){oa(c,h,j)}D[f+132>>2]=c;D[f+136>>2]=e+4;D[f+140>>2]=c+(d<<2);if(!h){break h}ma(h)}g=g+1|0;if(g>>>0<(D[a+220>>2]-D[a+216>>2]|0)/144>>>0){continue}break}}l=l+1|0;if((l|0)!=3){continue}break}$=i+16|0;return 1}pa();T()}sa();T()}pa();T()}function Lf(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;e=a;a:{if(D[a+12>>2]==(b|0)){break a}d=D[e+4>>2];a=D[e>>2];if((d|0)!=(a|0)){while(1){d=d-12|0;if(B[d+11|0]<0){ma(D[d>>2])}if((a|0)!=(d|0)){continue}break}}D[e+12>>2]=b;D[e+4>>2]=a;d=D[b>>2];j=b+4|0;if((d|0)==(j|0)){break a}while(1){a=D[e+4>>2];b:{if((a|0)!=D[e+8>>2]){c:{if(B[d+27|0]>=0){b=D[d+20>>2];D[a>>2]=D[d+16>>2];D[a+4>>2]=b;D[a+8>>2]=D[d+24>>2];break c}ta(a,D[d+16>>2],D[d+20>>2])}D[e+4>>2]=a+12;break b}h=0;d:{e:{f:{b=D[e+4>>2];a=D[e>>2];g=(b-a|0)/12|0;f=g+1|0;if(f>>>0<357913942){i=(D[e+8>>2]-a|0)/12|0;k=i<<1;f=i>>>0<178956970?f>>>0>>0?k:f:357913941;if(f){if(f>>>0>=357913942){break f}h=na(J(f,12))}i=J(f,12);f=J(g,12)+h|0;g:{if(B[d+27|0]>=0){g=D[d+20>>2];D[f>>2]=D[d+16>>2];D[f+4>>2]=g;D[f+8>>2]=D[d+24>>2];break g}ta(f,D[d+16>>2],D[d+20>>2]);b=D[e+4>>2];a=D[e>>2]}h=h+i|0;g=f+12|0;if((a|0)==(b|0)){break e}while(1){b=b-12|0;i=D[b+4>>2];f=f-12|0;D[f>>2]=D[b>>2];D[f+4>>2]=i;D[f+8>>2]=D[b+8>>2];D[b>>2]=0;D[b+4>>2]=0;D[b+8>>2]=0;if((a|0)!=(b|0)){continue}break}D[e+8>>2]=h;a=D[e+4>>2];D[e+4>>2]=g;b=D[e>>2];D[e>>2]=f;if((a|0)==(b|0)){break d}while(1){a=a-12|0;if(B[a+11|0]<0){ma(D[a>>2])}if((a|0)!=(b|0)){continue}break}break d}pa();T()}sa();T()}D[e+8>>2]=h;D[e+4>>2]=g;D[e>>2]=f}if(b){ma(b)}}a=D[d+4>>2];h:{if(a){while(1){d=a;a=D[a>>2];if(a){continue}break h}}while(1){a=d;d=D[d+8>>2];if((a|0)!=D[d>>2]){continue}break}}if((d|0)!=(j|0)){continue}break}}d=0;i:{if((c|0)<0){break i}a=D[e>>2];if((D[e+4>>2]-a|0)/12>>>0<=c>>>0){break i}a=a+J(c,12)|0;d=B[a+11|0]<0?D[a>>2]:a}return d|0}function yd(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;h=$-16|0;$=h;m=-1;a:{b:{c:{if(!Ga(1,h+12|0,b)){break c}k=D[h+12>>2];if(k){c=D[a+8>>2];if((D[c+4>>2]-D[c>>2]>>2>>>0)/3>>>0>>0){break c}while(1){if(!Ga(1,h+8|0,b)){break c}c=D[h+8>>2];if(!Ga(1,h+8|0,b)){break c}e=c+e|0;c=D[h+8>>2];if(e>>>0>>0){break c}f=e-c|0;c=D[a+40>>2];d:{if((c|0)!=D[a+44>>2]){D[c+4>>2]=e;D[c>>2]=f;D[a+40>>2]=c+12;k=D[h+12>>2];break d}d=D[a+36>>2];i=c-d|0;g=(i|0)/12|0;c=g+1|0;if(c>>>0>=357913942){break b}j=g<<1;j=g>>>0<178956970?c>>>0>>0?j:c:357913941;if(j){if(j>>>0>=357913942){break a}c=na(J(j,12))}else{c=0}g=c+J(g,12)|0;D[g+4>>2]=e;D[g>>2]=f;f=g+J((i|0)/-12|0,12)|0;if((i|0)>0){oa(f,d,i)}D[a+44>>2]=c+J(j,12);D[a+40>>2]=g+12;D[a+36>>2]=f;if(!d){break d}ma(d)}l=l+1|0;if(l>>>0>>0){continue}break}e=0;ec(b,0,0);if(k){while(1){c=E[b+36|0];d=F[D[a+4>>2]+36>>1];e:{f:{if(((d<<8|d>>>8)&65535)>>>0<=513){if(!c){break e}f=0;d=D[b+32>>2];l=d>>>3|0;i=D[b+24>>2];c=l+i|0;g=D[b+28>>2];g:{if(c>>>0>=g>>>0){c=d;break g}f=E[c|0];c=d+1|0;D[b+32>>2]=c;l=c>>>3|0;f=f>>>(d&7)&1}if(g>>>0>i+l>>>0){break f}break e}if(!c){break e}f=0;c=D[b+32>>2];d=D[b+24>>2]+(c>>>3|0)|0;if(d>>>0>=G[b+28>>2]){break e}f=E[d|0]>>>(c&7)&1}D[b+32>>2]=c+1}c=D[a+36>>2]+J(e,12)|0;B[c+8|0]=E[c+8|0]&254|f&1;e=e+1|0;if((k|0)!=(e|0)){continue}break}}B[b+36|0]=0;d=D[b+20>>2];a=0;c=D[b+32>>2]+7|0;a=c>>>0<7?1:a;e=a<<29|c>>>3;c=e+D[b+16>>2]|0;a=(a>>>3|0)+d|0;D[b+16>>2]=c;D[b+20>>2]=c>>>0>>0?a+1|0:a}m=D[b+16>>2]}$=h+16|0;return m}pa();T()}sa();T()}function tf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;a=0;g=$-16|0;$=g;i=B[c+24|0];k=D[b+80>>2];b=J(i,k);a:{b:{c:{e=D[c+28>>2];d:{if(!(!E[c+84|0]|(e|0)!=1&(e|0)!=2)){a=D[c+48>>2];c=D[D[c>>2]>>2];D[g+8>>2]=0;D[g>>2]=0;D[g+4>>2]=0;e=0;if(b){if((b|0)<0){break b}e=na(b);f=oa(e,a+c|0,b)+b|0}a=D[d>>2];if(a){D[d+4>>2]=a;ma(a)}D[d+8>>2]=f;D[d+4>>2]=f;D[d>>2]=e;a=1;break d}D[g+8>>2]=0;D[g>>2]=0;D[g+4>>2]=0;if(i){if((i|0)<0){break b}a=na(i);D[g>>2]=a;f=a+i|0;D[g+8>>2]=f;qa(a,0,i);D[g+4>>2]=f}h=D[d+4>>2];f=D[d>>2];e=h-f|0;e:{if(e>>>0>>0){l=b-e|0;j=D[d+8>>2];if(l>>>0<=j-h>>>0){m=d,n=qa(h,0,l)+l|0,D[m+4>>2]=n;break e}if((b|0)<0){break c}h=j-f|0;j=h<<1;j=h>>>0<1073741823?b>>>0>>0?j:b:2147483647;h=na(j);qa(h+e|0,0,l);if((e|0)>0){oa(h,f,e)}D[d+8>>2]=h+j;D[d+4>>2]=b+h;D[d>>2]=h;if(!f){break e}ma(f);break e}if(b>>>0>=e>>>0){break e}D[d+4>>2]=b+f}f:{if(!k){e=0;break f}if(!i){b=0;e=1;while(1){if(!Db(c,E[c+84|0]?b:D[D[c+68>>2]+(b<<2)>>2],B[c+24|0],a)){break f}b=b+1|0;e=k>>>0>b>>>0;if((b|0)!=(k|0)){continue}break}break f}h=i&-2;l=i&1;b=0;e=1;a=0;while(1){if(Db(c,E[c+84|0]?a:D[D[c+68>>2]+(a<<2)>>2],B[c+24|0],D[g>>2])){f=0;e=0;if((i|0)!=1){while(1){B[D[d>>2]+b|0]=E[D[g>>2]+f|0];B[(D[d>>2]+b|0)+1|0]=E[D[g>>2]+(f|1)|0];f=f+2|0;b=b+2|0;e=e+2|0;if((h|0)!=(e|0)){continue}break}}if(l){B[D[d>>2]+b|0]=E[D[g>>2]+f|0];b=b+1|0}a=a+1|0;e=k>>>0>a>>>0;if((a|0)!=(k|0)){continue}}break}a=D[g>>2]}if(a){ma(a)}a=e^1}$=g+16|0;a=a&1;break a}pa();T()}pa();T()}return a|0}function sf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;a=0;g=$-16|0;$=g;i=B[c+24|0];k=D[b+80>>2];b=J(i,k);a:{b:{c:{e=D[c+28>>2];d:{if(!(!E[c+84|0]|(e|0)!=1&(e|0)!=2)){a=D[c+48>>2];c=D[D[c>>2]>>2];D[g+8>>2]=0;D[g>>2]=0;D[g+4>>2]=0;e=0;if(b){if((b|0)<0){break b}e=na(b);f=oa(e,a+c|0,b)+b|0}a=D[d>>2];if(a){D[d+4>>2]=a;ma(a)}D[d+8>>2]=f;D[d+4>>2]=f;D[d>>2]=e;a=1;break d}D[g+8>>2]=0;D[g>>2]=0;D[g+4>>2]=0;if(i){if((i|0)<0){break b}a=na(i);D[g>>2]=a;f=a+i|0;D[g+8>>2]=f;qa(a,0,i);D[g+4>>2]=f}h=D[d+4>>2];f=D[d>>2];e=h-f|0;e:{if(e>>>0>>0){l=b-e|0;j=D[d+8>>2];if(l>>>0<=j-h>>>0){m=d,n=qa(h,0,l)+l|0,D[m+4>>2]=n;break e}if((b|0)<0){break c}h=j-f|0;j=h<<1;j=h>>>0<1073741823?b>>>0>>0?j:b:2147483647;h=na(j);qa(h+e|0,0,l);if((e|0)>0){oa(h,f,e)}D[d+8>>2]=h+j;D[d+4>>2]=b+h;D[d>>2]=h;if(!f){break e}ma(f);break e}if(b>>>0>=e>>>0){break e}D[d+4>>2]=b+f}f:{if(!k){e=0;break f}if(!i){b=0;e=1;while(1){if(!Cb(c,E[c+84|0]?b:D[D[c+68>>2]+(b<<2)>>2],B[c+24|0],a)){break f}b=b+1|0;e=k>>>0>b>>>0;if((b|0)!=(k|0)){continue}break}break f}h=i&-2;l=i&1;b=0;e=1;a=0;while(1){if(Cb(c,E[c+84|0]?a:D[D[c+68>>2]+(a<<2)>>2],B[c+24|0],D[g>>2])){f=0;e=0;if((i|0)!=1){while(1){B[D[d>>2]+b|0]=E[D[g>>2]+f|0];B[(D[d>>2]+b|0)+1|0]=E[D[g>>2]+(f|1)|0];f=f+2|0;b=b+2|0;e=e+2|0;if((h|0)!=(e|0)){continue}break}}if(l){B[D[d>>2]+b|0]=E[D[g>>2]+f|0];b=b+1|0}a=a+1|0;e=k>>>0>a>>>0;if((a|0)!=(k|0)){continue}}break}a=D[g>>2]}if(a){ma(a)}a=e^1}$=g+16|0;a=a&1;break a}pa();T()}pa();T()}return a|0}function Jb(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;k=D[b+16>>2];g=D[c+4>>2]-k|0;e=g;f=D[c>>2]-k|0;D[c>>2]=f;D[c+4>>2]=e;j=D[b+16>>2];e=e>>31;h=(e^g)-e|0;e=f>>31;l=(j|0)>=(h+((e^f)-e|0)|0);a:{if(l){e=g;break a}b:{c:{if((f|0)>=0){i=1;h=1;if((g|0)>=0){break b}e=1;i=-1;h=-1;if(f){break c}break b}e=-1;i=-1;h=-1;if((g|0)<=0){break b}}i=(g|0)<=0?-1:1;h=e}e=f<<1;f=J(h,j);e=e-f|0;h=(J(i,h)|0)>=0;i=J(i,j);e=((h?0-e|0:e)+i|0)/2|0;D[c+4>>2]=e;j=f;f=(g<<1)-i|0;f=(j+(h?0-f|0:f)|0)/2|0;D[c>>2]=f}d:{e:{f:{g:{h:{i:{j:{if(f){if((f|0)<0){break j}if((e|0)>=0){break i}break f}if(e){break h}i=1;g=0;e=0;h=0;break d}i=1;if((e|0)>0){break g}h=(e|0)>0?253:0;g=e;e=f;break d}g=0-e|0;e=0-f|0;h=254;break e}if((e|0)<=0){break f}}e=0-e|0;g=f;h=253;break e}g=0-f|0;h=255}D[c>>2]=e;D[c+4>>2]=g;i=0}c=D[d+4>>2]+g|0;f=D[d>>2]+e|0;g=D[b+16>>2];k:{if((f|0)>(g|0)){f=f-D[b+4>>2]|0;break k}if((0-g|0)<=(f|0)){break k}f=D[b+4>>2]+f|0}l:{if((c|0)>(g|0)){c=c-D[b+4>>2]|0;break l}if((0-g|0)<=(c|0)){break l}c=D[b+4>>2]+c|0}m:{if(i){b=c;break m}b=c;n:{switch((h&3)-1|0){case 0:b=0-f|0;f=c;break m;case 1:b=0-c|0;f=0-f|0;break m;case 2:break n;default:break m}}b=f;f=0-c|0}o:{if(l){c=b;break o}p:{q:{if((f|0)>=0){c=1;e=1;if((b|0)>=0){break p}d=1;c=-1;e=-1;if(f){break q}break p}d=-1;c=-1;e=-1;if((b|0)<=0){break p}}c=(b|0)<=0?-1:1;e=d}d=f<<1;f=J(e,g);d=d-f|0;D[a>>2]=d;j=0-d|0;h=d;d=(J(c,e)|0)>=0;e=J(c,g);c=((d?j:h)+e|0)/2|0;b=(b<<1)-e|0;f=(f+(d?0-b|0:b)|0)/2|0}D[a>>2]=f+k;D[a+4>>2]=c+k}function uf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;a=0;h=$-16|0;$=h;j=D[b+80>>2];b=E[c+24|0];D[h+8>>2]=0;D[h>>2]=0;D[h+4>>2]=0;e=b<<24>>24;a:{b:{c:{d:{if(b){if((e|0)<0){break d}b=e<<2;a=na(b);D[h>>2]=a;g=a+b|0;D[h+8>>2]=g;b=a;k=e&7;if(k){while(1){D[b>>2]=-1073741824;b=b+4|0;f=f+1|0;if((k|0)!=(f|0)){continue}break}}if((e-1&1073741823)>>>0>=7){while(1){D[b+24>>2]=-1073741824;D[b+28>>2]=-1073741824;D[b+16>>2]=-1073741824;D[b+20>>2]=-1073741824;D[b+8>>2]=-1073741824;D[b+12>>2]=-1073741824;D[b>>2]=-1073741824;D[b+4>>2]=-1073741824;b=b+32|0;if((g|0)!=(b|0)){continue}break}}D[h+4>>2]=g}b=J(e,j);g=D[d>>2];f=D[d+4>>2]-g>>2;e:{if(b>>>0>f>>>0){ra(d,b-f|0);break e}if(b>>>0>=f>>>0){break e}D[d+4>>2]=g+(b<<2)}if(!j){break c}i=1;if((e|0)<=0){b=0;while(1){if(!nb(c,E[c+84|0]?b:D[D[c+68>>2]+(b<<2)>>2],B[c+24|0],a)){break c}b=b+1|0;i=j>>>0>b>>>0;if((b|0)!=(j|0)){continue}break}break c}o=e&-4;k=e&3;f=0;p=e-1>>>0<3;while(1){if(!nb(c,E[c+84|0]?l:D[D[c+68>>2]+(l<<2)>>2],B[c+24|0],a)){break c}n=D[d>>2];m=0;b=0;i=0;if(!p){while(1){e=(f<<2)+n|0;g=b<<2;H[e>>2]=H[g+a>>2];H[e+4>>2]=H[(g|4)+a>>2];H[e+8>>2]=H[(g|8)+a>>2];H[e+12>>2]=H[(g|12)+a>>2];b=b+4|0;f=f+4|0;i=i+4|0;if((o|0)!=(i|0)){continue}break}}if(k){while(1){H[(f<<2)+n>>2]=H[(b<<2)+a>>2];b=b+1|0;f=f+1|0;m=m+1|0;if((k|0)!=(m|0)){continue}break}}l=l+1|0;i=l>>>0>>0;if((j|0)!=(l|0)){continue}break}break b}pa();T()}if(!a){break a}}ma(a)}$=h+16|0;return(i^-1)&1}function rb(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0,k=0;i=d-c|0;if((i|0)<=0){return}a:{g=D[a+8>>2];h=D[a+4>>2];if((g-h|0)>=(i|0)){j=h-b|0;if((j|0)>=(i|0)){f=h;g=d;break a}f=h;g=c+j|0;if((g|0)!=(d|0)){e=g;while(1){B[f|0]=E[e|0];f=f+1|0;e=e+1|0;if((e|0)!=(d|0)){continue}break}}D[a+4>>2]=f;if((j|0)>0){break a}return}f=D[a>>2];e=(h-f|0)+i|0;if((e|0)>=0){j=b-f|0;g=g-f|0;k=g<<1;k=g>>>0<1073741823?e>>>0>>0?k:e:2147483647;if(k){g=na(k)}else{g=0}e=j+g|0;if((c|0)!=(d|0)){e=oa(e,c,i)+i|0}if((j|0)>0){oa(g,f,j)}if((b|0)!=(h|0)){d=(b^-1)+h|0;f=h-b&7;if(f){c=0;while(1){B[e|0]=E[b|0];e=e+1|0;b=b+1|0;c=c+1|0;if((f|0)!=(c|0)){continue}break}}if(d>>>0>=7){while(1){B[e|0]=E[b|0];B[e+1|0]=E[b+1|0];B[e+2|0]=E[b+2|0];B[e+3|0]=E[b+3|0];B[e+4|0]=E[b+4|0];B[e+5|0]=E[b+5|0];B[e+6|0]=E[b+6|0];B[e+7|0]=E[b+7|0];e=e+8|0;b=b+8|0;if((h|0)!=(b|0)){continue}break}}f=D[a>>2]}D[a+8>>2]=g+k;D[a+4>>2]=e;D[a>>2]=g;if(f){ma(f)}return}pa();T()}e=f;d=e-i|0;if(h>>>0>d>>>0){while(1){B[e|0]=E[d|0];e=e+1|0;d=d+1|0;if(h>>>0>d>>>0){continue}break}}D[a+4>>2]=e;a=b+i|0;if((a|0)!=(f|0)){a=f-a|0;Ra(f-a|0,b,a)}if((c|0)==(g|0)){return}a=(c^-1)+g|0;f=g-c&7;b:{if(!f){e=b;break b}d=0;e=b;while(1){B[e|0]=E[c|0];e=e+1|0;c=c+1|0;d=d+1|0;if((f|0)!=(d|0)){continue}break}}if(a>>>0<7){return}while(1){B[e|0]=E[c|0];B[e+1|0]=E[c+1|0];B[e+2|0]=E[c+2|0];B[e+3|0]=E[c+3|0];B[e+4|0]=E[c+4|0];B[e+5|0]=E[c+5|0];B[e+6|0]=E[c+6|0];B[e+7|0]=E[c+7|0];e=e+8|0;c=c+8|0;if((g|0)!=(c|0)){continue}break}}function Qh(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;D[a+8>>2]=e;m=a+32|0;h=D[m>>2];g=D[a+36>>2]-h>>2;a:{if(g>>>0>>0){ra(m,e-g|0);f=D[a+8>>2];break a}f=e;if(f>>>0>=g>>>0){break a}D[a+36>>2]=h+(e<<2);f=e}g=(e&1073741823)!=(e|0)?-1:e<<2;n=qa(na(g),0,g);b:{if((f|0)<=0){break b}h=D[a+32>>2];while(1){f=i<<2;g=D[f+n>>2];j=D[a+16>>2];c:{if((g|0)>(j|0)){D[f+h>>2]=j;break c}f=f+h|0;j=D[a+12>>2];if((j|0)>(g|0)){D[f>>2]=j;break c}D[f>>2]=g}f=D[a+8>>2];i=i+1|0;if((f|0)>(i|0)){continue}break}if((f|0)<=0){break b}i=0;while(1){g=i<<2;f=g+c|0;g=D[b+g>>2]+D[g+h>>2]|0;D[f>>2]=g;d:{if((g|0)>D[a+16>>2]){g=g-D[a+20>>2]|0}else{if((g|0)>=D[a+12>>2]){break d}g=g+D[a+20>>2]|0}D[f>>2]=g}f=D[a+8>>2];i=i+1|0;if((f|0)>(i|0)){continue}break}}if(!((d|0)<=(e|0)|(f|0)<=0)){p=0-e<<2;g=e;while(1){e:{if((f|0)<=0){break e}l=g<<2;o=l+c|0;q=o+p|0;j=D[m>>2];i=0;while(1){f=i<<2;h=D[f+q>>2];k=D[a+16>>2];f:{if((h|0)>(k|0)){D[f+j>>2]=k;break f}f=f+j|0;k=D[a+12>>2];if((k|0)>(h|0)){D[f>>2]=k;break f}D[f>>2]=h}f=D[a+8>>2];i=i+1|0;if((f|0)>(i|0)){continue}break}i=0;if((f|0)<=0){break e}l=b+l|0;while(1){h=i<<2;f=h+o|0;h=D[h+l>>2]+D[h+j>>2]|0;D[f>>2]=h;g:{if((h|0)>D[a+16>>2]){h=h-D[a+20>>2]|0}else{if((h|0)>=D[a+12>>2]){break g}h=h+D[a+20>>2]|0}D[f>>2]=h}f=D[a+8>>2];i=i+1|0;if((f|0)>(i|0)){continue}break}}g=e+g|0;if((g|0)<(d|0)){continue}break}}ma(n);return 1}function pf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=$-16|0;$=g;j=D[b+80>>2];a=B[c+24|0];b=J(j,a);a:{b:{c:{d:{e=D[c+28>>2];if(!(!E[c+84|0]|(e|0)!=5&(e|0)!=6)){e=D[c+48>>2];c=D[D[c>>2]>>2];D[g+8>>2]=0;D[g>>2]=0;D[g+4>>2]=0;if(b){if((b|0)<0){break d}a=b<<2;f=na(a);i=oa(f,c+e|0,a)+a|0}a=D[d>>2];if(a){D[d+4>>2]=a;ma(a)}D[d+8>>2]=i;D[d+4>>2]=i;D[d>>2]=f;a=1;break a}D[g+8>>2]=0;D[g>>2]=0;D[g+4>>2]=0;if(a){if((a|0)<0){break d}e=a<<2;f=na(e);D[g>>2]=f;h=e+f|0;D[g+8>>2]=h;qa(f,0,e);D[g+4>>2]=h}h=D[d>>2];e=D[d+4>>2]-h>>2;e:{if(e>>>0>>0){ra(d,b-e|0);break e}if(b>>>0>=e>>>0){break e}D[d+4>>2]=h+(b<<2)}if(!j){b=0;break c}if(!a){a=0;b=1;while(1){if(!yb(c,E[c+84|0]?a:D[D[c+68>>2]+(a<<2)>>2],B[c+24|0],f)){break c}a=a+1|0;b=j>>>0>a>>>0;if((a|0)!=(j|0)){continue}break}break c}o=a&-4;m=a&3;p=a-1>>>0<3;b=1;e=0;while(1){if(!yb(c,E[c+84|0]?e:D[D[c+68>>2]+(e<<2)>>2],B[c+24|0],f)){break c}n=D[d>>2];l=0;a=0;b=0;if(!p){while(1){h=(i<<2)+n|0;k=a<<2;D[h>>2]=D[k+f>>2];D[h+4>>2]=D[(k|4)+f>>2];D[h+8>>2]=D[(k|8)+f>>2];D[h+12>>2]=D[(k|12)+f>>2];a=a+4|0;i=i+4|0;b=b+4|0;if((o|0)!=(b|0)){continue}break}}if(m){while(1){D[(i<<2)+n>>2]=D[(a<<2)+f>>2];a=a+1|0;i=i+1|0;l=l+1|0;if((l|0)!=(m|0)){continue}break}}e=e+1|0;b=j>>>0>e>>>0;if((e|0)!=(j|0)){continue}break}a=e>>>0>=j>>>0;break b}pa();T()}a=!b;if(!f){break a}}ma(f)}$=g+16|0;return a&1}function ad(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=$-16|0;$=g;j=D[b+80>>2];a=B[c+24|0];b=J(j,a);a:{b:{c:{d:{e=D[c+28>>2];if(!(!E[c+84|0]|(e|0)!=5&(e|0)!=6)){e=D[c+48>>2];c=D[D[c>>2]>>2];D[g+8>>2]=0;D[g>>2]=0;D[g+4>>2]=0;if(b){if((b|0)<0){break d}a=b<<2;f=na(a);i=oa(f,c+e|0,a)+a|0}a=D[d>>2];if(a){D[d+4>>2]=a;ma(a)}D[d+8>>2]=i;D[d+4>>2]=i;D[d>>2]=f;a=1;break a}D[g+8>>2]=0;D[g>>2]=0;D[g+4>>2]=0;if(a){if((a|0)<0){break d}e=a<<2;f=na(e);D[g>>2]=f;h=e+f|0;D[g+8>>2]=h;qa(f,0,e);D[g+4>>2]=h}h=D[d>>2];e=D[d+4>>2]-h>>2;e:{if(e>>>0>>0){ra(d,b-e|0);break e}if(b>>>0>=e>>>0){break e}D[d+4>>2]=h+(b<<2)}if(!j){b=0;break c}if(!a){a=0;b=1;while(1){if(!zb(c,E[c+84|0]?a:D[D[c+68>>2]+(a<<2)>>2],B[c+24|0],f)){break c}a=a+1|0;b=j>>>0>a>>>0;if((a|0)!=(j|0)){continue}break}break c}o=a&-4;m=a&3;p=a-1>>>0<3;b=1;e=0;while(1){if(!zb(c,E[c+84|0]?e:D[D[c+68>>2]+(e<<2)>>2],B[c+24|0],f)){break c}n=D[d>>2];l=0;a=0;b=0;if(!p){while(1){h=(i<<2)+n|0;k=a<<2;D[h>>2]=D[k+f>>2];D[h+4>>2]=D[(k|4)+f>>2];D[h+8>>2]=D[(k|8)+f>>2];D[h+12>>2]=D[(k|12)+f>>2];a=a+4|0;i=i+4|0;b=b+4|0;if((o|0)!=(b|0)){continue}break}}if(m){while(1){D[(i<<2)+n>>2]=D[(a<<2)+f>>2];a=a+1|0;i=i+1|0;l=l+1|0;if((l|0)!=(m|0)){continue}break}}e=e+1|0;b=j>>>0>e>>>0;if((e|0)!=(j|0)){continue}break}a=e>>>0>=j>>>0;break b}pa();T()}a=!b;if(!f){break a}}ma(f)}$=g+16|0;return a&1}function rf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=$-16|0;$=g;j=D[b+80>>2];a=B[c+24|0];b=J(j,a);a:{b:{c:{d:{e=D[c+28>>2];if(!(!E[c+84|0]|(e|0)!=3&(e|0)!=4)){e=D[c+48>>2];c=D[D[c>>2]>>2];D[g+8>>2]=0;D[g>>2]=0;D[g+4>>2]=0;if(b){if((b|0)<0){break d}a=b<<1;f=na(a);i=oa(f,c+e|0,a)+a|0}a=D[d>>2];if(a){D[d+4>>2]=a;ma(a)}D[d+8>>2]=i;D[d+4>>2]=i;D[d>>2]=f;a=1;break a}D[g+8>>2]=0;D[g>>2]=0;D[g+4>>2]=0;if(a){if((a|0)<0){break d}e=a<<1;f=na(e);D[g>>2]=f;h=e+f|0;D[g+8>>2]=h;qa(f,0,e);D[g+4>>2]=h}h=D[d>>2];e=D[d+4>>2]-h>>1;e:{if(e>>>0>>0){id(d,b-e|0);break e}if(b>>>0>=e>>>0){break e}D[d+4>>2]=h+(b<<1)}if(!j){b=0;break c}if(!a){a=0;b=1;while(1){if(!Bb(c,E[c+84|0]?a:D[D[c+68>>2]+(a<<2)>>2],B[c+24|0],f)){break c}a=a+1|0;b=j>>>0>a>>>0;if((a|0)!=(j|0)){continue}break}break c}o=a&-4;m=a&3;p=a-1>>>0<3;b=1;e=0;while(1){if(!Bb(c,E[c+84|0]?e:D[D[c+68>>2]+(e<<2)>>2],B[c+24|0],f)){break c}n=D[d>>2];l=0;a=0;b=0;if(!p){while(1){h=(i<<1)+n|0;k=a<<1;C[h>>1]=F[k+f>>1];C[h+2>>1]=F[(k|2)+f>>1];C[h+4>>1]=F[(k|4)+f>>1];C[h+6>>1]=F[(k|6)+f>>1];a=a+4|0;i=i+4|0;b=b+4|0;if((o|0)!=(b|0)){continue}break}}if(m){while(1){C[(i<<1)+n>>1]=F[(a<<1)+f>>1];a=a+1|0;i=i+1|0;l=l+1|0;if((l|0)!=(m|0)){continue}break}}e=e+1|0;b=j>>>0>e>>>0;if((e|0)!=(j|0)){continue}break}a=e>>>0>=j>>>0;break b}pa();T()}a=!b;if(!f){break a}}ma(f)}$=g+16|0;return a&1}function qf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=$-16|0;$=g;j=D[b+80>>2];a=B[c+24|0];b=J(j,a);a:{b:{c:{d:{e=D[c+28>>2];if(!(!E[c+84|0]|(e|0)!=3&(e|0)!=4)){e=D[c+48>>2];c=D[D[c>>2]>>2];D[g+8>>2]=0;D[g>>2]=0;D[g+4>>2]=0;if(b){if((b|0)<0){break d}a=b<<1;f=na(a);i=oa(f,c+e|0,a)+a|0}a=D[d>>2];if(a){D[d+4>>2]=a;ma(a)}D[d+8>>2]=i;D[d+4>>2]=i;D[d>>2]=f;a=1;break a}D[g+8>>2]=0;D[g>>2]=0;D[g+4>>2]=0;if(a){if((a|0)<0){break d}e=a<<1;f=na(e);D[g>>2]=f;h=e+f|0;D[g+8>>2]=h;qa(f,0,e);D[g+4>>2]=h}h=D[d>>2];e=D[d+4>>2]-h>>1;e:{if(e>>>0>>0){id(d,b-e|0);break e}if(b>>>0>=e>>>0){break e}D[d+4>>2]=h+(b<<1)}if(!j){b=0;break c}if(!a){a=0;b=1;while(1){if(!Ab(c,E[c+84|0]?a:D[D[c+68>>2]+(a<<2)>>2],B[c+24|0],f)){break c}a=a+1|0;b=j>>>0>a>>>0;if((a|0)!=(j|0)){continue}break}break c}o=a&-4;m=a&3;p=a-1>>>0<3;b=1;e=0;while(1){if(!Ab(c,E[c+84|0]?e:D[D[c+68>>2]+(e<<2)>>2],B[c+24|0],f)){break c}n=D[d>>2];l=0;a=0;b=0;if(!p){while(1){h=(i<<1)+n|0;k=a<<1;C[h>>1]=F[k+f>>1];C[h+2>>1]=F[(k|2)+f>>1];C[h+4>>1]=F[(k|4)+f>>1];C[h+6>>1]=F[(k|6)+f>>1];a=a+4|0;i=i+4|0;b=b+4|0;if((o|0)!=(b|0)){continue}break}}if(m){while(1){C[(i<<1)+n>>1]=F[(a<<1)+f>>1];a=a+1|0;i=i+1|0;l=l+1|0;if((l|0)!=(m|0)){continue}break}}e=e+1|0;b=j>>>0>e>>>0;if((e|0)!=(j|0)){continue}break}a=e>>>0>=j>>>0;break b}pa();T()}a=!b;if(!f){break a}}ma(f)}$=g+16|0;return a&1}function lc(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;j=$-16|0;$=j;c=D[b+20>>2];d=D[b+16>>2];g=d+4|0;c=g>>>0<4?c+1|0:c;e=D[b+12>>2];a:{if((e|0)<=(c|0)&g>>>0>G[b+8>>2]|(c|0)>(e|0)){break a}d=d+D[b>>2]|0;d=E[d|0]|E[d+1|0]<<8|(E[d+2|0]<<16|E[d+3|0]<<24);D[b+16>>2]=g;D[b+20>>2]=c;if((d|0)<0){break a}Oa(a+76|0,d);c=j;D[c>>2]=0;D[c+4>>2]=0;B[c+5|0]=0;B[c+6|0]=0;B[c+7|0]=0;B[c+8|0]=0;B[c+9|0]=0;B[c+10|0]=0;B[c+11|0]=0;B[c+12|0]=0;b:{if(!Da(c,b)){break b}if(d){e=1;while(1){f=1<>2]+(h>>>3&536870908)|0;e=e^i;if(e&1){f=D[g>>2]&(f^-1)}else{f=f|D[g>>2]}e=e^1;D[g>>2]=f;h=h+1|0;if((d|0)!=(h|0)){continue}break}}h=0;d=D[b+12>>2];g=d;c=D[b+20>>2];e=c;f=D[b+16>>2];i=f+4|0;c=i>>>0<4?c+1|0:c;k=D[b+8>>2];if(k>>>0>>0&(c|0)>=(d|0)|(c|0)>(d|0)){break b}l=D[b>>2];d=l+f|0;d=E[d|0]|E[d+1|0]<<8|(E[d+2|0]<<16|E[d+3|0]<<24);D[b+16>>2]=i;D[b+20>>2]=c;c=e;e=f+8|0;c=e>>>0<8?c+1|0:c;f=e;e=c;if(f>>>0>k>>>0&(c|0)>=(g|0)|(c|0)>(g|0)){break b}c=i+l|0;c=E[c|0]|E[c+1|0]<<8|(E[c+2|0]<<16|E[c+3|0]<<24);D[b+16>>2]=f;D[b+20>>2]=e;if((c|0)<(d|0)){break b}D[a+16>>2]=c;D[a+12>>2]=d;b=(c>>31)-((d>>31)+(c>>>0>>0)|0)|0;c=c-d|0;if(!b&c>>>0>2147483646|b){break b}h=1;b=c+1|0;D[a+20>>2]=b;c=b>>>1|0;D[a+24>>2]=c;D[a+28>>2]=0-c;if(b&1){break b}D[a+24>>2]=c-1}}$=j+16|0;return h|0}function hc(a,b){var c=0,d=0,e=0,f=0,g=0;f=-1;d=-1;a:{if((b|0)==-1){break a}d=b+1|0;f=(d>>>0)%3|0?d:b-2|0;d=b-1|0;if((b>>>0)%3|0){break a}d=b+2|0}b:{c:{d:{switch(D[a+168>>2]){case 0:case 1:e=D[a+148>>2];c=1;b=D[a+156>>2];g=b+(((f|0)!=-1?D[D[e>>2]+(f<<2)>>2]:-1)<<2)|0;D[g>>2]=D[g>>2]+1;b=(((d|0)!=-1?D[D[e>>2]+(d<<2)>>2]:-1)<<2)+b|0;break c;case 5:e=D[a+148>>2];c=-1;c=((b|0)!=-1?D[D[e>>2]+(b<<2)>>2]:c)<<2;b=D[a+156>>2];c=c+b|0;D[c>>2]=D[c>>2]+1;c=(((f|0)!=-1?D[D[e>>2]+(f<<2)>>2]:-1)<<2)+b|0;D[c>>2]=D[c>>2]+1;c=2;b=(((d|0)!=-1?D[D[e>>2]+(d<<2)>>2]:-1)<<2)+b|0;break c;case 3:e=D[a+148>>2];c=-1;c=((b|0)!=-1?D[D[e>>2]+(b<<2)>>2]:c)<<2;b=D[a+156>>2];c=c+b|0;D[c>>2]=D[c>>2]+1;c=(((f|0)!=-1?D[D[e>>2]+(f<<2)>>2]:-1)<<2)+b|0;D[c>>2]=D[c>>2]+2;c=1;b=(((d|0)!=-1?D[D[e>>2]+(d<<2)>>2]:-1)<<2)+b|0;break c;case 7:break d;default:break b}}e=D[a+148>>2];c=-1;c=((b|0)!=-1?D[D[e>>2]+(b<<2)>>2]:c)<<2;b=D[a+156>>2];c=c+b|0;D[c>>2]=D[c>>2]+2;c=(((f|0)!=-1?D[D[e>>2]+(f<<2)>>2]:-1)<<2)+b|0;D[c>>2]=D[c>>2]+2;c=2;b=(((d|0)!=-1?D[D[e>>2]+(d<<2)>>2]:-1)<<2)+b|0}D[b>>2]=D[b>>2]+c}c=a;b=D[D[a+156>>2]+(((f|0)!=-1?D[D[D[a+148>>2]>>2]+(f<<2)>>2]:-1)<<2)>>2];d=D[a+180>>2];a=D[a+176>>2];D[c+172>>2]=(a|0)>(b|0)?0:((b|0)<(d|0)?b:d)-a|0}function zg(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;a:{c=D[a+32>>2];e=D[c+8>>2];f=D[c+12>>2];d=D[c+20>>2];g=e;e=D[c+16>>2];b=0;b:{if((f|0)<=(d|0)&g>>>0<=e>>>0|(d|0)>(f|0)){break b}g=E[e+D[c>>2]|0];f=e+1|0;d=f?d:d+1|0;D[c+16>>2]=f;D[c+20>>2]=d;c:{if(!g){break c}while(1){if(ba[D[D[a>>2]+16>>2]](a,b)|0){b=b+1|0;if((g|0)!=(b|0)){continue}break c}break}return 0}b=D[a+8>>2];d=D[a+12>>2];if((b|0)!=(d|0)){while(1){c=D[b>>2];if(!(ba[D[D[c>>2]+8>>2]](c,a,D[a+4>>2])|0)){break a}b=b+4|0;if((d|0)!=(b|0)){continue}break}}d:{if(!g){break d}b=0;while(1){c=D[D[a+8>>2]+(b<<2)>>2];if(!(ba[D[D[c>>2]+12>>2]](c,D[a+32>>2])|0)){break a}b=b+1|0;if((g|0)!=(b|0)){continue}break}if(!g){break d}e=a+20|0;while(1){b=0;f=h<<2;c=D[f+D[a+8>>2]>>2];d=ba[D[D[c>>2]+24>>2]](c)|0;if((d|0)>0){while(1){c=D[D[a+8>>2]+f>>2];k=ba[D[D[c>>2]+20>>2]](c,b)|0;i=D[a+20>>2];j=D[a+24>>2]-i>>2;e:{if(k>>>0>>0){break e}c=k+1|0;if(c>>>0>j>>>0){ra(e,c-j|0);i=D[e>>2];break e}if(c>>>0>=j>>>0){break e}D[a+24>>2]=(c<<2)+i}D[(k<<2)+i>>2]=h;b=b+1|0;if((d|0)!=(b|0)){continue}break}}h=h+1|0;if((g|0)!=(h|0)){continue}break}}b=0;if(!(ba[D[D[a>>2]+28>>2]](a)|0)){break b}b=ba[D[D[a>>2]+32>>2]](a)|0}return b|0}return 0}function Vb(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;d=D[a+8>>2];e=D[a>>2];if(d-e>>2>>>0>=b>>>0){g=D[a+4>>2];h=g-e>>2;f=b>>>0>h>>>0?h:b;a:{if(!f){break a}k=f-1|0;i=f&7;b:{if(!i){d=e;break b}d=e;while(1){D[d>>2]=D[c>>2];f=f-1|0;d=d+4|0;j=j+1|0;if((j|0)!=(i|0)){continue}break}}if(k>>>0<7){break a}while(1){D[d>>2]=D[c>>2];D[d+4>>2]=D[c>>2];D[d+8>>2]=D[c>>2];D[d+12>>2]=D[c>>2];D[d+16>>2]=D[c>>2];D[d+20>>2]=D[c>>2];D[d+24>>2]=D[c>>2];D[d+28>>2]=D[c>>2];d=d+32|0;f=f-8|0;if(f){continue}break}}if(b>>>0>h>>>0){b=(b-h<<2)+g|0;while(1){D[g>>2]=D[c>>2];g=g+4|0;if((b|0)!=(g|0)){continue}break}D[a+4>>2]=b;return}D[a+4>>2]=e+(b<<2);return}if(e){D[a+4>>2]=e;ma(e);D[a+8>>2]=0;D[a>>2]=0;D[a+4>>2]=0;d=0}c:{if(b>>>0>=1073741824){break c}e=d>>1;d=d>>>0<2147483644?b>>>0>>0?e:b:1073741823;if(d>>>0>=1073741824){break c}d=d<<2;e=na(d);D[a>>2]=e;D[a+8>>2]=d+e;c=D[c>>2];d=e;f=b&7;if(f){while(1){D[d>>2]=c;d=d+4|0;g=g+1|0;if((f|0)!=(g|0)){continue}break}}e=e+(b<<2)|0;if((b-1&1073741823)>>>0>=7){while(1){D[d+28>>2]=c;D[d+24>>2]=c;D[d+20>>2]=c;D[d+16>>2]=c;D[d+12>>2]=c;D[d+8>>2]=c;D[d+4>>2]=c;D[d>>2]=c;d=d+32|0;if((e|0)!=(d|0)){continue}break}}D[a+4>>2]=e;return}pa();T()}function Ue(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0;Mc(a,b,c);c=D[a+84>>2];d=D[a+88>>2]-c>>2;a:{if((d|0)>(b|0)){break a}b=b+1|0;if(b>>>0>d>>>0){b:{d=b-d|0;e=D[a+92>>2];c=D[a+88>>2];if(d>>>0<=e-c>>2>>>0){c:{if(!d){break c}b=c;f=d&7;if(f){while(1){D[b>>2]=1;b=b+4|0;g=g+1|0;if((f|0)!=(g|0)){continue}break}}c=(d<<2)+c|0;if((d-1&1073741823)>>>0<7){break c}while(1){D[b+24>>2]=1;D[b+28>>2]=1;D[b+16>>2]=1;D[b+20>>2]=1;D[b+8>>2]=1;D[b+12>>2]=1;D[b>>2]=1;D[b+4>>2]=1;b=b+32|0;if((c|0)!=(b|0)){continue}break}}D[a+88>>2]=c;break b}d:{f=D[a+84>>2];j=c-f|0;c=j>>2;b=c+d|0;if(b>>>0<1073741824){e=e-f|0;h=e>>1;e=e>>>0<2147483644?b>>>0>>0?h:b:1073741823;if(e){if(e>>>0>=1073741824){break d}i=na(e<<2)}c=(c<<2)+i|0;b=c;h=d&7;if(h){b=c;while(1){D[b>>2]=1;b=b+4|0;g=g+1|0;if((h|0)!=(g|0)){continue}break}}c=c+(d<<2)|0;if((d-1&1073741823)>>>0>=7){while(1){D[b+24>>2]=1;D[b+28>>2]=1;D[b+16>>2]=1;D[b+20>>2]=1;D[b+8>>2]=1;D[b+12>>2]=1;D[b>>2]=1;D[b+4>>2]=1;b=b+32|0;if((c|0)!=(b|0)){continue}break}}if((j|0)>0){oa(i,f,j)}D[a+92>>2]=(e<<2)+i;D[a+88>>2]=c;D[a+84>>2]=i;if(f){ma(f)}break b}pa();T()}sa();T()}return}if(b>>>0>=d>>>0){break a}D[a+88>>2]=c+(b<<2)}}function oa(a,b,c){var d=0,e=0,f=0;if(c>>>0>=512){_(a|0,b|0,c|0);return a}e=a+c|0;a:{if(!((a^b)&3)){b:{if(!(a&3)){c=a;break b}if(!c){c=a;break b}c=a;while(1){B[c|0]=E[b|0];b=b+1|0;c=c+1|0;if(!(c&3)){break b}if(c>>>0>>0){continue}break}}d=e&-4;c:{if(d>>>0<64){break c}f=d+-64|0;if(f>>>0>>0){break c}while(1){D[c>>2]=D[b>>2];D[c+4>>2]=D[b+4>>2];D[c+8>>2]=D[b+8>>2];D[c+12>>2]=D[b+12>>2];D[c+16>>2]=D[b+16>>2];D[c+20>>2]=D[b+20>>2];D[c+24>>2]=D[b+24>>2];D[c+28>>2]=D[b+28>>2];D[c+32>>2]=D[b+32>>2];D[c+36>>2]=D[b+36>>2];D[c+40>>2]=D[b+40>>2];D[c+44>>2]=D[b+44>>2];D[c+48>>2]=D[b+48>>2];D[c+52>>2]=D[b+52>>2];D[c+56>>2]=D[b+56>>2];D[c+60>>2]=D[b+60>>2];b=b- -64|0;c=c- -64|0;if(f>>>0>=c>>>0){continue}break}}if(c>>>0>=d>>>0){break a}while(1){D[c>>2]=D[b>>2];b=b+4|0;c=c+4|0;if(d>>>0>c>>>0){continue}break}break a}if(e>>>0<4){c=a;break a}d=e-4|0;if(d>>>0>>0){c=a;break a}c=a;while(1){B[c|0]=E[b|0];B[c+1|0]=E[b+1|0];B[c+2|0]=E[b+2|0];B[c+3|0]=E[b+3|0];b=b+4|0;c=c+4|0;if(d>>>0>=c>>>0){continue}break}}if(c>>>0>>0){while(1){B[c|0]=E[b|0];b=b+1|0;c=c+1|0;if((e|0)!=(c|0)){continue}break}}return a}function xa(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;f=D[a+8>>2];e=D[a+4>>2];if(f-e>>2>>>0>=b>>>0){a:{if(!b){break a}d=e;g=b&7;if(g){while(1){D[d>>2]=D[c>>2];d=d+4|0;h=h+1|0;if((g|0)!=(h|0)){continue}break}}e=(b<<2)+e|0;if((b-1&1073741823)>>>0<7){break a}while(1){D[d>>2]=D[c>>2];D[d+4>>2]=D[c>>2];D[d+8>>2]=D[c>>2];D[d+12>>2]=D[c>>2];D[d+16>>2]=D[c>>2];D[d+20>>2]=D[c>>2];D[d+24>>2]=D[c>>2];D[d+28>>2]=D[c>>2];d=d+32|0;if((e|0)!=(d|0)){continue}break}}D[a+4>>2]=e;return}b:{g=D[a>>2];k=e-g|0;e=k>>2;d=e+b|0;if(d>>>0<1073741824){f=f-g|0;i=f>>1;f=f>>>0<2147483644?d>>>0>>0?i:d:1073741823;if(f){if(f>>>0>=1073741824){break b}j=na(f<<2)}e=(e<<2)+j|0;d=e;i=b&7;if(i){d=e;while(1){D[d>>2]=D[c>>2];d=d+4|0;h=h+1|0;if((i|0)!=(h|0)){continue}break}}e=e+(b<<2)|0;if((b-1&1073741823)>>>0>=7){while(1){D[d>>2]=D[c>>2];D[d+4>>2]=D[c>>2];D[d+8>>2]=D[c>>2];D[d+12>>2]=D[c>>2];D[d+16>>2]=D[c>>2];D[d+20>>2]=D[c>>2];D[d+24>>2]=D[c>>2];D[d+28>>2]=D[c>>2];d=d+32|0;if((e|0)!=(d|0)){continue}break}}if((k|0)>0){oa(j,g,k)}D[a+8>>2]=(f<<2)+j;D[a+4>>2]=e;D[a>>2]=j;if(g){ma(g)}return}pa();T()}sa();T()}function pd(a){a=a|0;var b=0,c=0,d=0,e=0,f=0;D[a>>2]=8336;d=a+232|0;b=D[d+196>>2];if(b){D[d+200>>2]=b;ma(b)}c=D[d+184>>2];if(c){b=c;e=D[d+188>>2];if((b|0)!=(e|0)){while(1){b=e-12|0;f=D[b>>2];if(f){D[e-8>>2]=f;ma(f)}e=b;if((b|0)!=(c|0)){continue}break}b=D[d+184>>2]}D[d+188>>2]=c;ma(b)}b=D[d+156>>2];if(b){D[d+160>>2]=b;ma(b)}c=D[d+136>>2];D[d+136>>2]=0;if(c){e=c-4|0;b=D[e>>2];if(b){b=c+(b<<4)|0;while(1){b=b-16|0;if((c|0)!=(b|0)){continue}break}}ma(e)}qd(a+216|0);b=D[a+196>>2];if(b){D[a+200>>2]=b;ma(b)}b=D[a+184>>2];if(b){D[a+188>>2]=b;ma(b)}b=D[a+172>>2];if(b){D[a+176>>2]=b;ma(b)}b=D[a+160>>2];if(b){D[a+164>>2]=b;ma(b)}b=D[a+144>>2];if(b){while(1){c=D[b>>2];ma(b);b=c;if(b){continue}break}}b=D[a+136>>2];D[a+136>>2]=0;if(b){ma(b)}b=D[a+120>>2];if(b){ma(b)}b=D[a+108>>2];if(b){ma(b)}b=D[a+96>>2];if(b){ma(b)}b=D[a+72>>2];if(b){D[a+76>>2]=b;ma(b)}b=D[a+60>>2];if(b){ma(b)}b=D[a+48>>2];if(b){D[a+52>>2]=b;ma(b)}b=D[a+36>>2];if(b){D[a+40>>2]=b;ma(b)}b=D[a+24>>2];if(b){D[a+28>>2]=b;ma(b)}b=D[a+12>>2];if(b){D[a+16>>2]=b;ma(b)}b=D[a+8>>2];D[a+8>>2]=0;if(b){cb(b)}return a|0}function hi(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;g=c;a:{b:{c:{d:{e:{f:{g:{h:{i:{j:{k:{if(b){if(!g){break k}if(!d){break j}c=M(d)-M(b)|0;if(c>>>0<=31){break i}break c}if((d|0)==1|d>>>0>1){break c}a=(a>>>0)/(g>>>0)|0;aa=0;break a}if(!a){break h}if(!d){break g}if(d-1&d){break g}a=b>>>ki(d)|0;aa=0;break a}if(!(g-1&g)){break f}h=(M(g)+33|0)-M(b)|0;e=0-h|0;break d}h=c+1|0;e=63-c|0;break d}a=(b>>>0)/(d>>>0)|0;aa=0;break a}c=M(d)-M(b)|0;if(c>>>0<31){break e}break c}if((g|0)==1){break b}c=ki(g);d=c&31;if((c&63)>>>0>=32){c=0;a=b>>>d|0}else{c=b>>>d|0;a=((1<>>d}aa=c;break a}h=c+1|0;e=63-c|0}c=h&63;f=c&31;if(c>>>0>=32){c=0;i=b>>>f|0}else{c=b>>>f|0;i=((1<>>f}f=c;c=e&63;e=c&31;if(c>>>0>=32){c=a<>>32-e|b<>>31;f=f<<1|i>>>31;j=m-(f+(c>>>0>e>>>0)|0)>>31;k=g&j;i=c-k|0;f=f-((d&j)+(c>>>0>>0)|0)|0;b=b<<1|a>>>31;a=l|a<<1;l=j&1;h=h-1|0;if(h){continue}break}}aa=b<<1|a>>>31;a=l|a<<1;break a}a=0;b=0}aa=b}return a}function pb(a,b){var c=0,d=0,e=0;c=(a|0)==(b|0);B[b+12|0]=c;a:{if(c){break a}while(1){d=D[b+8>>2];if(E[d+12|0]){break a}b:{c=D[d+8>>2];e=D[c>>2];if((e|0)==(d|0)){e=D[c+4>>2];if(!(!e|E[e+12|0])){break b}c:{if(D[d>>2]==(b|0)){b=d;break c}b=D[d+4>>2];a=D[b>>2];D[d+4>>2]=a;if(a){D[a+8>>2]=d;c=D[d+8>>2]}D[b+8>>2]=c;a=D[d+8>>2];D[((D[a>>2]!=(d|0))<<2)+a>>2]=b;D[b>>2]=d;D[d+8>>2]=b;c=D[b+8>>2];d=D[c>>2]}B[b+12|0]=1;B[c+12|0]=0;a=D[d+4>>2];D[c>>2]=a;if(a){D[a+8>>2]=c}D[d+8>>2]=D[c+8>>2];a=D[c+8>>2];D[((D[a>>2]!=(c|0))<<2)+a>>2]=d;D[d+4>>2]=c;D[c+8>>2]=d;return}if(!(E[e+12|0]|!e)){break b}d:{if(D[d>>2]!=(b|0)){b=d;break d}a=D[b+4>>2];D[d>>2]=a;if(a){D[a+8>>2]=d;c=D[d+8>>2]}D[b+8>>2]=c;a=D[d+8>>2];D[((D[a>>2]!=(d|0))<<2)+a>>2]=b;D[b+4>>2]=d;D[d+8>>2]=b;c=D[b+8>>2]}B[b+12|0]=1;B[c+12|0]=0;a=D[c+4>>2];b=D[a>>2];D[c+4>>2]=b;if(b){D[b+8>>2]=c}D[a+8>>2]=D[c+8>>2];b=D[c+8>>2];D[((D[b>>2]!=(c|0))<<2)+b>>2]=a;D[a>>2]=c;D[c+8>>2]=a;break a}B[d+12|0]=1;B[c+12|0]=(a|0)==(c|0);B[e+12|0]=1;b=c;if((c|0)!=(a|0)){continue}break}}}function kd(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0;a:{b:{c:{if(!b){if((d|0)<0){break a}e=D[a+4>>2];b=D[a>>2];d=e-b|0;if(c>>>0>d>>>0){g=c-d|0;f=D[a+8>>2];if(g>>>0<=f-e>>>0){i=a,j=qa(e,0,g)+g|0,D[i+4>>2]=j;break c}if((c|0)<0){break b}e=f-b|0;f=e<<1;f=e>>>0<1073741823?c>>>0>>0?f:c:2147483647;e=na(f);qa(e+d|0,0,g);if((d|0)>0){oa(e,b,d)}D[a+8>>2]=e+f;D[a+4>>2]=c+e;D[a>>2]=e;if(!b){break c}ma(b);break c}if(c>>>0>=d>>>0){break c}D[a+4>>2]=b+c;break c}if((d|0)<0){break a}h=D[a+4>>2];g=D[a>>2];e=h-g|0;d:{if((d|0)<=0&c>>>0<=e>>>0|(d|0)<0){break d}if(c>>>0>e>>>0){f=c-e|0;d=D[a+8>>2];if(f>>>0<=d-h>>>0){i=a,j=qa(h,0,f)+f|0,D[i+4>>2]=j;break d}if((c|0)<0){break b}d=d-g|0;h=d<<1;h=d>>>0<1073741823?c>>>0>>0?h:c:2147483647;d=na(h);qa(d+e|0,0,f);if((e|0)>0){oa(d,g,e)}D[a+8>>2]=d+h;D[a+4>>2]=c+d;D[a>>2]=d;if(!g){break d}ma(g);break d}if(c>>>0>=e>>>0){break d}D[a+4>>2]=c+g}if(!c){break c}Ra(D[a>>2],b,c)}b=D[a+28>>2];c=D[a+24>>2]+1|0;b=c?b:b+1|0;D[a+24>>2]=c;D[a+28>>2]=b;e=1;break a}pa();T()}return e}function uh(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;c=D[b+88>>2];if(!(!c|D[c>>2]!=1)){d=D[c+8>>2];D[a+4>>2]=E[d|0]|E[d+1|0]<<8|(E[d+2|0]<<16|E[d+3|0]<<24);e=a+8|0;d=B[b+24|0];f=D[a+8>>2];g=D[a+12>>2]-f>>2;a:{if(d>>>0>g>>>0){ra(e,d-g|0);d=B[b+24|0];break a}if(d>>>0>=g>>>0){break a}D[a+12>>2]=f+(d<<2)}k=1;g=D[c+8>>2];b:{if((d|0)<=0){b=4;break b}h=d&3;e=D[e>>2];c:{if(d-1>>>0<3){b=4;d=0;break c}l=d&-4;d=0;b=4;while(1){f=d<<2;c=b+g|0;D[f+e>>2]=E[c|0]|E[c+1|0]<<8|(E[c+2|0]<<16|E[c+3|0]<<24);D[e+(f|4)>>2]=E[c+4|0]|E[c+5|0]<<8|(E[c+6|0]<<16|E[c+7|0]<<24);D[e+(f|8)>>2]=E[c+8|0]|E[c+9|0]<<8|(E[c+10|0]<<16|E[c+11|0]<<24);D[e+(f|12)>>2]=E[c+12|0]|E[c+13|0]<<8|(E[c+14|0]<<16|E[c+15|0]<<24);d=d+4|0;b=b+16|0;i=i+4|0;if((l|0)!=(i|0)){continue}break}}if(!h){break b}while(1){c=b+g|0;D[e+(d<<2)>>2]=E[c|0]|E[c+1|0]<<8|(E[c+2|0]<<16|E[c+3|0]<<24);d=d+1|0;b=b+4|0;j=j+1|0;if((j|0)!=(h|0)){continue}break}}c=a;a=b+g|0;D[c+20>>2]=E[a|0]|E[a+1|0]<<8|(E[a+2|0]<<16|E[a+3|0]<<24)}return k|0}function ue(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;if(Zc(a,b)){i=a+36|0;g=ba[D[D[a>>2]+24>>2]](a)|0;d=D[a+40>>2];e=D[a+36>>2];c=d-e>>2;a:{if(g>>>0>c>>>0){Pb(i,g-c|0);break a}if(c>>>0<=g>>>0){break a}e=e+(g<<2)|0;if((e|0)!=(d|0)){while(1){d=d-4|0;c=D[d>>2];D[d>>2]=0;if(c){ba[D[D[c>>2]+4>>2]](c)}if((d|0)!=(e|0)){continue}break}}D[a+40>>2]=e}b:{if((g|0)<=0){e=0;break b}e=1;c=D[b+20>>2];d=D[b+12>>2];f=D[b+16>>2];if((c|0)>=(d|0)&f>>>0>=G[b+8>>2]|(c|0)>(d|0)){break b}d=0;while(1){h=E[f+D[b>>2]|0];f=f+1|0;c=f?c:c+1|0;D[b+16>>2]=f;D[b+20>>2]=c;f=ba[D[D[a>>2]+48>>2]](a,h)|0;h=d<<2;j=h+D[a+36>>2]|0;c=D[j>>2];D[j>>2]=f;if(c){ba[D[D[c>>2]+4>>2]](c)}c=D[D[i>>2]+h>>2];if(!c){break b}if(!(l=c,m=ba[D[D[a>>2]+28>>2]](a)|0,n=ba[D[D[a>>2]+20>>2]](a,d)|0,k=D[D[c>>2]+8>>2],ba[k](l|0,m|0,n|0)|0)){break b}d=d+1|0;e=(g|0)>(d|0);if((d|0)==(g|0)){break b}f=D[b+16>>2];c=D[b+20>>2];h=D[b+12>>2];if(f>>>0>2]&(c|0)<=(h|0)|(c|0)<(h|0)){continue}break}}a=!e}else{a=0}return a|0}function sd(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=K(0),j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;k=$-16|0;$=k;if(D[c+28>>2]==9){d=D[a+4>>2];g=B[c+24|0];e=g<<2;f=na((g&1073741823)!=(g|0)?-1:e);l=k+8|0;D[l>>2]=1065353216;i=H[a+20>>2];d=-1<0){H[l>>2]=i/K(d|0)}o=(d|0)>0;a:{if(!o){break a}j=D[c+80>>2];if(!j){break a}d=0;if((g|0)<=0){if((j|0)!=1){a=j&-2;b=0;while(1){oa(D[D[c+64>>2]>>2]+d|0,f,e);d=d+e|0;oa(d+D[D[c+64>>2]>>2]|0,f,e);d=d+e|0;b=b+2|0;if((a|0)!=(b|0)){continue}break}}if(!(j&1)){break a}oa(D[D[c+64>>2]>>2]+d|0,f,e);break a}p=D[D[b>>2]>>2]+D[b+48>>2]|0;t=g&-2;u=g&1;while(1){m=D[a+8>>2];i=H[l>>2];b=0;n=0;if((g|0)!=1){while(1){h=b<<2;q=(d<<2)+p|0;H[h+f>>2]=K(i*K(D[q>>2]))+H[h+m>>2];h=h|4;H[h+f>>2]=K(i*K(D[q+4>>2]))+H[h+m>>2];b=b+2|0;d=d+2|0;n=n+2|0;if((t|0)!=(n|0)){continue}break}}if(u){b=b<<2;H[b+f>>2]=K(i*K(D[(d<<2)+p>>2]))+H[b+m>>2];d=d+1|0}oa(D[D[c+64>>2]>>2]+r|0,f,e);r=e+r|0;s=s+1|0;if((s|0)!=(j|0)){continue}break}}ma(f)}$=k+16|0;return o|0}function Hg(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;k=D[a+12>>2];c=D[a+68>>2];d=D[c+80>>2];B[b+84|0]=0;m=b+68|0;i=D[b+68>>2];e=D[b+72>>2]-i>>2;a:{if(e>>>0>>0){xa(m,d-e|0,9124);c=D[a+68>>2];d=D[c+80>>2];break a}if(d>>>0>=e>>>0){break a}D[b+72>>2]=i+(d<<2)}b=D[c+100>>2];e=D[c+96>>2];i=(b-e|0)/12|0;b:{if((b|0)==(e|0)){break b}n=1;k=D[k+28>>2];f=D[k>>2];if((f|0)==-1){break b}o=i>>>0>1?i:1;c=e;b=0;while(1){g=D[c>>2];if(g>>>0>=d>>>0){break b}j=D[D[a+72>>2]+12>>2];h=D[j+(f<<2)>>2];if(h>>>0>=d>>>0){break b}f=D[m>>2];D[f+(g<<2)>>2]=h;g=k+(l<<2)|0;h=D[g+4>>2];if((h|0)==-1){break b}l=D[c+4>>2];if(l>>>0>=d>>>0){break b}h=D[(h<<2)+j>>2];if(h>>>0>=d>>>0){break b}D[f+(l<<2)>>2]=h;g=D[g+8>>2];if((g|0)==-1){break b}c=D[c+8>>2];if(c>>>0>=d>>>0){break b}j=D[(g<<2)+j>>2];if(j>>>0>=d>>>0){break b}D[f+(c<<2)>>2]=j;b=b+1|0;n=i>>>0>b>>>0;if((b|0)==(o|0)){break b}c=e+J(b,12)|0;l=J(b,3);f=D[k+(l<<2)>>2];if((f|0)!=-1){continue}break}}return(n^-1)&1}function Xf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;h=D[d+80>>2];e=$-48|0;$=e;a=D[a+4>>2];k=a-31|0;a:{if(k>>>0<4294967267){break a}i=D[D[d>>2]>>2]+D[d+48>>2]|0;D[e+16>>2]=a;a=-1<>2]=a^-1;a=-2-a|0;D[e+24>>2]=a;D[e+32>>2]=(a|0)/2;H[e+28>>2]=K(2)/K(a|0);f=D[c>>2];if((f|0)!=D[c+4>>2]){a=0;d=0;while(1){g=D[(d<<2)+f>>2];h=e+36|0;j=D[D[b>>2]>>2];m=D[b+48>>2];f=D[b+44>>2];l=D[b+40>>2];if(!E[b+84|0]){g=D[D[b+68>>2]+(g<<2)>>2]}g=fi(l,f,g,0)+m|0;oa(h,g+j|0,l);Gc(e+16|0,h,e+12|0,e+8|0);f=a<<2;D[f+i>>2]=D[e+12>>2];D[(f|4)+i>>2]=D[e+8>>2];a=a+2|0;d=d+1|0;f=D[c>>2];if(d>>>0>2]-f>>2>>>0){continue}break}break a}if(!h){break a}d=0;a=0;while(1){j=e+36|0;c=D[D[b>>2]>>2];g=D[b+40>>2];f=D[b+48>>2]+fi(g,D[b+44>>2],E[b+84|0]?a:D[D[b+68>>2]+(a<<2)>>2],0)|0;oa(j,c+f|0,g);Gc(e+16|0,j,e+12|0,e+8|0);c=d<<2;D[c+i>>2]=D[e+12>>2];D[(c|4)+i>>2]=D[e+8>>2];d=d+2|0;a=a+1|0;if((h|0)!=(a|0)){continue}break}}$=e+48|0;return k>>>0>4294967266|0}function Vg(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;j=D[a+12>>2];c=D[a+108>>2];d=D[c+80>>2];B[b+84|0]=0;m=b+68|0;h=D[b+68>>2];f=D[b+72>>2]-h>>2;a:{if(f>>>0>>0){xa(m,d-f|0,9124);c=D[a+108>>2];d=D[c+80>>2];break a}if(d>>>0>=f>>>0){break a}D[b+72>>2]=h+(d<<2)}b=D[c+100>>2];f=D[c+96>>2];h=(b-f|0)/12|0;b:{if((b|0)==(f|0)){j=0;break b}n=h>>>0>1?h:1;o=D[j>>2];c=f;b=0;j=1;while(1){e=(e<<2)+o|0;i=D[e>>2];if((i|0)==-1){break b}g=D[c>>2];if(g>>>0>=d>>>0){break b}l=D[D[a+112>>2]+12>>2];k=D[l+(i<<2)>>2];if(k>>>0>=d>>>0){break b}i=D[m>>2];D[i+(g<<2)>>2]=k;g=D[e+4>>2];if((g|0)==-1){break b}k=D[c+4>>2];if(k>>>0>=d>>>0){break b}g=D[(g<<2)+l>>2];if(g>>>0>=d>>>0){break b}D[i+(k<<2)>>2]=g;e=D[e+8>>2];if((e|0)==-1){break b}c=D[c+8>>2];if(c>>>0>=d>>>0){break b}e=D[(e<<2)+l>>2];if(e>>>0>=d>>>0){break b}D[i+(c<<2)>>2]=e;b=b+1|0;j=h>>>0>b>>>0;if((b|0)==(n|0)){break b}e=J(b,3);c=f+J(b,12)|0;if((b|0)!=1431655765){continue}break}}return(j^-1)&1}function Ng(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;j=D[a+12>>2];c=D[a+68>>2];d=D[c+80>>2];B[b+84|0]=0;m=b+68|0;h=D[b+68>>2];f=D[b+72>>2]-h>>2;a:{if(f>>>0>>0){xa(m,d-f|0,9124);c=D[a+68>>2];d=D[c+80>>2];break a}if(d>>>0>=f>>>0){break a}D[b+72>>2]=h+(d<<2)}b=D[c+100>>2];f=D[c+96>>2];h=(b-f|0)/12|0;b:{if((b|0)==(f|0)){j=0;break b}n=h>>>0>1?h:1;o=D[j>>2];c=f;b=0;j=1;while(1){e=(e<<2)+o|0;i=D[e>>2];if((i|0)==-1){break b}g=D[c>>2];if(g>>>0>=d>>>0){break b}l=D[D[a+72>>2]+12>>2];k=D[l+(i<<2)>>2];if(k>>>0>=d>>>0){break b}i=D[m>>2];D[i+(g<<2)>>2]=k;g=D[e+4>>2];if((g|0)==-1){break b}k=D[c+4>>2];if(k>>>0>=d>>>0){break b}g=D[(g<<2)+l>>2];if(g>>>0>=d>>>0){break b}D[i+(k<<2)>>2]=g;e=D[e+8>>2];if((e|0)==-1){break b}c=D[c+8>>2];if(c>>>0>=d>>>0){break b}e=D[(e<<2)+l>>2];if(e>>>0>=d>>>0){break b}D[i+(c<<2)>>2]=e;b=b+1|0;j=h>>>0>b>>>0;if((b|0)==(n|0)){break b}e=J(b,3);c=f+J(b,12)|0;if((b|0)!=1431655765){continue}break}}return(j^-1)&1}function Ma(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0;d=(c>>>0)/3|0;i=D[(D[D[a+8>>2]+96>>2]+J(d,12)|0)+(c-J(d,3)<<2)>>2];e=D[D[a+12>>2]+4>>2];d=D[e+4>>2];a:{if((d|0)!=D[e+8>>2]){D[d>>2]=i;D[e+4>>2]=d+4;break a}b:{h=D[e>>2];g=d-h|0;j=g>>2;d=j+1|0;if(d>>>0<1073741824){f=g>>1;f=g>>>0<2147483644?d>>>0>>0?f:d:1073741823;if(f){if(f>>>0>=1073741824){break b}d=na(f<<2)}else{d=0}j=d+(j<<2)|0;D[j>>2]=i;if((g|0)>0){oa(d,h,g)}D[e+8>>2]=d+(f<<2);D[e+4>>2]=j+4;D[e>>2]=d;if(h){ma(h)}break a}pa();T()}sa();T()}e=D[a+4>>2];d=D[e+4>>2];c:{d:{e:{if((d|0)!=D[e+8>>2]){D[d>>2]=c;D[e+4>>2]=d+4;break e}h=D[e>>2];g=d-h|0;i=g>>2;d=i+1|0;if(d>>>0>=1073741824){break d}f=g>>1;f=g>>>0<2147483644?d>>>0>>0?f:d:1073741823;if(f){if(f>>>0>=1073741824){break c}d=na(f<<2)}else{d=0}i=d+(i<<2)|0;D[i>>2]=c;if((g|0)>0){oa(d,h,g)}D[e+8>>2]=d+(f<<2);D[e+4>>2]=i+4;D[e>>2]=d;if(!h){break e}ma(h)}a=D[a+4>>2];D[D[a+12>>2]+(b<<2)>>2]=D[a+24>>2];D[a+24>>2]=D[a+24>>2]+1;return}pa();T()}sa();T()}function Vc(a,b){var c=0,d=0,e=0,f=0,g=0,h=0;h=D[a>>2];c=h+(b>>>3&536870908)|0;D[c>>2]=D[c>>2]|1<>2];e=(b|0)==-1;c=-1;a:{if(e){break a}d=b+1|0;d=(d>>>0)%3|0?d:b-2|0;c=-1;if((d|0)==-1){break a}c=D[D[f>>2]+(d<<2)>>2]}d=D[a+12>>2];g=(c>>>3&536870908)+d|0;D[g>>2]=D[g>>2]|1<>>0)%3|0){c=b-1|0;break f}c=b+2|0;if((c|0)==-1){break e}}e=D[D[f>>2]+(c<<2)>>2];c=1<>>3&536870908)|0;g=D[e>>2];break d}e=d+536870908|0;c=D[d+536870908>>2];g=-2147483648}D[e>>2]=c|g;c=-1;b=D[D[f+12>>2]+(b<<2)>>2];if((b|0)==-1){break b}B[a+24|0]=0;a=(b>>>3&536870908)+h|0;D[a>>2]=D[a>>2]|1<>>0)%3|0?a:b-2|0;if((a|0)!=-1){c=D[D[f>>2]+(a<<2)>>2]}a=d+(c>>>3&536870908)|0;D[a>>2]=D[a>>2]|1<>>0)%3|0){b=b-1|0;break h}b=b+2|0;a=-1;if((b|0)==-1){break g}}a=D[D[f>>2]+(b<<2)>>2]}b=1<>>3&536870908)|0;c=D[a>>2];break c}a=d+536870908|0;b=D[d+536870908>>2];c=-2147483648}D[a>>2]=b|c}}function Da(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;g=$-16|0;$=g;e=D[b+20>>2];c=D[b+12>>2];d=D[b+16>>2];a:{if((e|0)>=(c|0)&d>>>0>=G[b+8>>2]|(c|0)<(e|0)){break a}B[a+12|0]=E[d+D[b>>2]|0];e=D[b+20>>2];c=D[b+16>>2]+1|0;e=c?e:e+1|0;D[b+16>>2]=c;D[b+20>>2]=e;if(!Nd(1,g+12|0,b)){break a}e=D[b+8>>2];h=D[b+16>>2];c=h;d=e-c|0;c=c>>>0>e>>>0;e=D[b+20>>2];f=D[b+12>>2]-(c+e|0)|0;c=D[g+12>>2];if((f|0)<=0&d>>>0>>0|(f|0)<0|(c|0)<=0){break a}d=h+D[b>>2]|0;D[a>>2]=d;b:{c:{f=c-1|0;i=f+d|0;j=E[i|0];d:{if(j>>>0<=63){D[a+4>>2]=f;f=E[i|0]&63;break d}e:{switch((j>>>6|0)-1|0){case 1:break c;case 0:break e;default:break a}}if(c>>>0<2){break a}D[a+4>>2]=c-2;d=(c+d|0)-2|0;f=E[d+1|0]<<8&16128|E[d|0]}D[a+8>>2]=f+4096;break b}if(c>>>0<3){break a}D[a+4>>2]=c-3;f=a;a=(c+d|0)-3|0;a=E[a+1|0]<<8|E[a+2|0]<<16&4128768|E[a|0];D[f+8>>2]=a+4096;if(a>>>0>1044479){break a}}a=e;d=c+h|0;a=d>>>0>>0?a+1|0:a;D[b+16>>2]=d;D[b+20>>2]=a;k=1}$=g+16|0;return k}function Ug(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0,h=0;g=$-16|0;$=g;b=D[a+4>>2];d=D[b>>2];a:{c=D[a+12>>2];c=D[c+28>>2]-D[c+24>>2]|0;e=c>>2;b:{if(e>>>0<=D[b+8>>2]-d>>2>>>0){break b}if((c|0)<0){break a}f=D[b+4>>2];c=na(c);h=c+(e<<2)|0;e=f-d|0;f=e+c|0;if((e|0)>0){oa(c,d,e)}D[b+8>>2]=h;D[b+4>>2]=f;D[b>>2]=c;if(!d){break b}ma(d)}b=D[a+12>>2];d=D[b+28>>2];b=D[b+24>>2];D[g+12>>2]=0;b=d-b>>2;c=a+96|0;e=D[c>>2];d=D[a+100>>2]-e>>2;c:{if(b>>>0>d>>>0){xa(c,b-d|0,g+12|0);break c}if(b>>>0>=d>>>0){break c}D[a+100>>2]=e+(b<<2)}e=a+8|0;b=D[a+116>>2];d:{if(b){c=D[b>>2];if((c|0)==D[b+4>>2]){d=1;break d}b=0;while(1){d=od(e,D[(b<<2)+c>>2]);if(!d){break d}f=D[a+116>>2];c=D[f>>2];b=b+1|0;if(b>>>0>2]-c>>2>>>0){continue}break}break d}d=1;a=D[a+12>>2];a=D[a+4>>2]-D[a>>2]|0;if(a>>>0<12){break d}a=(a>>2>>>0)/3|0;b=0;while(1){d=od(e,J(b,3));if(!d){break d}b=b+1|0;if((a|0)!=(b|0)){continue}break}}$=g+16|0;return d|0}pa();T()}function Oa(a,b){var c=0,d=0,e=0,f=0,g=0,h=0;d=$-16|0;$=d;a:{e=D[a+4>>2];b:{if(e>>>0>>0){f=b-e|0;c=D[a+8>>2];g=c<<5;c:{if(!(f>>>0>g>>>0|e>>>0>g-f>>>0)){D[a+4>>2]=b;h=e&31;b=D[a>>2]+(e>>>3&536870908)|0;break c}D[d+8>>2]=0;D[d>>2]=0;D[d+4>>2]=0;if((b|0)<0){break a}if(g>>>0<=1073741822){c=c<<6;b=b+31&-32;b=b>>>0>>0?c:b}else{b=2147483647}Xa(d,b);c=D[a+4>>2];D[d+4>>2]=c+f;e=D[a>>2];b=D[d>>2];d:{if((c|0)<=0){break d}g=c>>>5<<2;b=Ra(b,e,g)+g|0;h=c&31;e:{if(!h){h=0;break e}c=-1>>>32-h|0;D[b>>2]=D[b>>2]&(c^-1)|D[e+g>>2]&c}e=D[a>>2]}D[a>>2]=D[d>>2];D[d>>2]=e;c=D[a+4>>2];D[a+4>>2]=D[d+4>>2];D[d+4>>2]=c;c=D[a+8>>2];D[a+8>>2]=D[d+8>>2];D[d+8>>2]=c;if(!e){break c}ma(e)}if(!f){break b}if(h){c=32-h|0;a=c>>>0>>0?c:f;D[b>>2]=D[b>>2]&(-1<>>c-a^-1);f=f-a|0;b=b+4|0}a=b;b=f>>>5<<2;a=qa(a,0,b);if((f&-32)==(f|0)){break b}a=a+b|0;D[a>>2]=D[a>>2]&(-1>>>32-(f&31)^-1);break b}D[a+4>>2]=b}$=d+16|0;return}pa();T()}function nd(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0;f=D[a+12>>2];h=D[a+8>>2];d=f-h>>2;b=B[b+24|0];a:{if(d>>>0>>0){ra(a+8|0,b-d|0);h=D[a+8>>2];f=D[a+12>>2];break a}if(b>>>0>=d>>>0){break a}f=(b<<2)+h|0;D[a+12>>2]=f}b=0;i=D[c+20>>2];e=D[c+16>>2];d=f-h|0;f=d;g=e+d|0;j=D[c+12>>2];i=d>>>0>g>>>0?i+1|0:i;b:{if(g>>>0>G[c+8>>2]&(j|0)<=(i|0)|(i|0)>(j|0)){break b}oa(h,e+D[c>>2]|0,d);d=D[c+20>>2];e=f+D[c+16>>2]|0;d=e>>>0>>0?d+1|0:d;g=e;D[c+16>>2]=e;D[c+20>>2]=d;e=D[c+12>>2];f=g+4|0;d=f>>>0<4?d+1|0:d;if(f>>>0>G[c+8>>2]&(d|0)>=(e|0)|(d|0)>(e|0)){break b}d=g+D[c>>2]|0;D[a+20>>2]=E[d|0]|E[d+1|0]<<8|(E[d+2|0]<<16|E[d+3|0]<<24);d=D[c+20>>2];g=D[c+16>>2];e=g+4|0;f=e>>>0<4?d+1|0:d;j=e;D[c+16>>2]=e;D[c+20>>2]=f;e=D[c+12>>2];if((f|0)>=(e|0)&j>>>0>=G[c+8>>2]|(f|0)>(e|0)){break b}e=E[j+D[c>>2]|0];f=g+5|0;d=f>>>0<5?d+1|0:d;D[c+16>>2]=f;D[c+20>>2]=d;if(e-1>>>0>29){break b}D[a+4>>2]=e;b=1}return b|0}function Rb(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;d=E[a+11|0]>>>7|0?D[a+4>>2]:E[a+11|0];if(d>>>0>>0){h=$-16|0;$=h;f=b-d|0;if(f){b=E[a+11|0]>>>7|0;g=b?D[a+4>>2]:E[a+11|0];i=g+f|0;b=b?(D[a+8>>2]&2147483647)-1|0:10;if(b-g>>>0>>0){a:{d=$-16|0;$=d;c=i-b|0;if(c>>>0<=-17-b>>>0){j=E[a+11|0]>>>7|0?D[a>>2]:a;b:{if(b>>>0<2147483623){D[d+8>>2]=b<<1;D[d+12>>2]=b+c;c=$-16|0;$=c;$=c+16|0;c=d+8|0;e=d+12|0;c=D[(G[e>>2]>2]?c:e)>>2];if(c>>>0>=11){e=c+16&-16;c=e-1|0;c=(c|0)==11?e:c}else{c=10}break b}c=-18}e=c+1|0;c=na(e);if(g){gb(c,j,g)}if((b|0)!=10){ma(j)}D[a>>2]=c;D[a+8>>2]=e|-2147483648;$=d+16|0;break a}Ca();T()}}b=E[a+11|0]>>>7|0?D[a>>2]:a;d=g+b|0;if(f){qa(d,0,f)}c:{if(E[a+11|0]>>>7|0){D[a+4>>2]=i;break c}B[a+11|0]=i}B[h+15|0]=0;B[b+i|0]=E[h+15|0]}$=h+16|0;return}c=E[a+11|0]>>>7|0;f=c?D[a>>2]:a;d=$-16|0;$=d;d:{if(c){D[a+4>>2]=b;break d}B[a+11|0]=b}B[d+15|0]=0;B[b+f|0]=E[d+15|0];$=d+16|0}function Gc(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;j=+H[b>>2];k=+H[b+4>>2];l=+H[b+8>>2];g=L(j)+L(k)+L(l);a:{if(!(g>1e-6)){j=1;k=0;e=0;break a}g=1/g;k=g*k;j=g*j;e=g*l<0}h=D[a+16>>2];l=+(h|0);g=P(j*l+.5);b:{if(L(g)<2147483648){m=~~g;break b}m=-2147483648}f=m>>31;i=(f^m)-f|0;g=P(k*l+.5);c:{if(L(g)<2147483648){f=~~g;break c}f=-2147483648}b=f>>31;b=h-(i+((f^b)-b|0)|0)|0;i=(b|0)>0?b:0;e=e?0-i|0:i;f=f+(b>>31&((f|0)>0?b:0-b|0))|0;d:{if((m|0)>=0){b=e+h|0;a=D[a+8>>2];e=h+f|0;break d}b=f>>31;b=(b^f)-b|0;a=D[a+8>>2];b=(e|0)<0?b:a-b|0;e=(f|0)<0?i:a-i|0}e:{if(!(b|e)){b=a;break e}if(!((a|0)!=(b|0)|e)){b=a;break e}if(!((a|0)!=(e|0)|b)){b=a;break e}if(!((b|0)<=(h|0)|e)){b=(h<<1)-b|0;a=0;break e}if(!((a|0)!=(e|0)|(b|0)>=(h|0))){b=(h<<1)-b|0;break e}if(!((a|0)!=(b|0)|(e|0)>=(h|0))){b=a;a=(h<<1)-e|0;break e}if(b){a=e;break e}b=0;if((e|0)<=(h|0)){a=e;break e}a=(h<<1)-e|0}D[c>>2]=a;D[d>>2]=b}function Xc(a,b){var c=0,d=0,e=0,f=0,g=0,h=0;g=$-16|0;$=g;a:{b:{if(b){D[a+88>>2]=0;D[a+92>>2]=0;c=D[a+84>>2];D[a+84>>2]=0;if(c){ma(c)}D[a+76>>2]=0;D[a+80>>2]=0;c=D[a+72>>2];D[a+72>>2]=0;if(c){ma(c)}c=D[b>>2];d=D[b+4>>2];B[g+15|0]=0;Ha(a,d-c>>2,g+15|0);c=D[b+28>>2];d=D[b+24>>2];B[g+14|0]=0;Ha(a+12|0,c-d>>2,g+14|0);Vb(a+28|0,D[b+4>>2]-D[b>>2]>>2,10284);d=D[b+28>>2]-D[b+24>>2]|0;e=d>>2;c=D[a+52>>2];c:{if(e>>>0<=D[a+60>>2]-c>>2>>>0){break c}if((d|0)<0){break b}f=D[a+56>>2];d=na(d);h=d+(e<<2)|0;e=f-c|0;f=e+d|0;if((e|0)>0){oa(d,c,e)}D[a+60>>2]=h;D[a+56>>2]=f;D[a+52>>2]=d;if(!c){break c}ma(c)}d=D[b+28>>2]-D[b+24>>2]|0;e=d>>2;c=D[a+40>>2];d:{if(e>>>0<=D[a+48>>2]-c>>2>>>0){break d}if((d|0)<0){break a}f=D[a+44>>2];d=na(d);h=d+(e<<2)|0;e=f-c|0;f=e+d|0;if((e|0)>0){oa(d,c,e)}D[a+48>>2]=h;D[a+44>>2]=f;D[a+40>>2]=d;if(!c){break d}ma(c)}B[a+24|0]=1;D[a+64>>2]=b}$=g+16|0;return}pa();T()}pa();T()}function xc(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=K(0),f=K(0),g=K(0),h=K(0),i=K(0),j=0,k=K(0),l=K(0),m=K(0),n=K(0),o=0;a:{if(D[c+28>>2]!=9|E[c+24|0]!=3){break a}a=D[a+4>>2];if(a-31>>>0<4294967267){break a}o=1;j=D[c+80>>2];if(!j){break a}k=K(K(2)/K((1<>2]>>2]+D[c+48>>2]|0;a=D[D[b>>2]>>2]+D[b+48>>2]|0;b=0;while(1){g=K(0);l=K(0);m=K(0);e=K(K(K(D[a>>2])*k)+K(-1));f=K(K(K(D[a+4>>2])*k)+K(-1));i=K(K(K(1)-K(L(e)))-K(L(f)));h=K(O(K(-i),K(0)));n=K(-h);f=K(f+(f>>8;B[c+10|0]=d>>>16;B[c+11|0]=d>>>24;d=(v(l),x(2));B[c+4|0]=d;B[c+5|0]=d>>>8;B[c+6|0]=d>>>16;B[c+7|0]=d>>>24;d=(v(g),x(2));B[c|0]=d;B[c+1|0]=d>>>8;B[c+2|0]=d>>>16;B[c+3|0]=d>>>24;c=c+12|0;b=b+1|0;if((j|0)!=(b|0)){continue}break}}return o|0}function Jd(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;g=$-16|0;$=g;a:{if(!Va(1,g+8|0,b)){break a}c=D[b+8>>2];e=D[b+16>>2];h=D[g+12>>2];d=D[b+20>>2];f=D[b+12>>2]-(d+(c>>>0>>0)|0)|0;i=c-e|0;c=D[g+8>>2];if((h|0)==(f|0)&i>>>0>>0|f>>>0>>0){break a}d=d+h|0;f=c+e|0;d=f>>>0>>0?d+1|0:d;D[b+16>>2]=f;D[b+20>>2]=d;if((c|0)<=0){break a}d=e+D[b>>2]|0;D[a+40>>2]=d;f=c-1|0;e=d+f|0;b=E[e|0];b:{if(b>>>0<=63){D[a+44>>2]=f;b=E[e|0]&63;break b}c:{switch((b>>>6|0)-1|0){case 0:if(c>>>0<2){break a}D[a+44>>2]=c-2;b=(c+d|0)-2|0;b=E[b+1|0]<<8&16128|E[b|0];break b;case 1:if(c>>>0<3){break a}D[a+44>>2]=c-3;b=(c+d|0)-3|0;b=E[b+1|0]<<8|E[b+2|0]<<16&4128768|E[b|0];break b;default:break c}}D[a+44>>2]=c-4;b=(c+d|0)-4|0;b=E[b+2|0]<<16|E[b+3|0]<<24&1056964608|E[b+1|0]<<8|E[b|0]}D[a+48>>2]=b+16384;j=b>>>0<4177920}$=g+16|0;return j}function rd(a){a=a|0;var b=0,c=0,d=0,e=0;D[a>>2]=8284;d=D[a+368>>2];D[a+368>>2]=0;if(d){e=d-4|0;b=D[e>>2];if(b){c=(b<<4)+d|0;while(1){c=c-16|0;if((d|0)!=(c|0)){continue}break}}ma(e)}qd(a+216|0);b=D[a+196>>2];if(b){D[a+200>>2]=b;ma(b)}b=D[a+184>>2];if(b){D[a+188>>2]=b;ma(b)}b=D[a+172>>2];if(b){D[a+176>>2]=b;ma(b)}b=D[a+160>>2];if(b){D[a+164>>2]=b;ma(b)}c=D[a+144>>2];if(c){while(1){b=D[c>>2];ma(c);c=b;if(b){continue}break}}b=D[a+136>>2];D[a+136>>2]=0;if(b){ma(b)}b=D[a+120>>2];if(b){ma(b)}b=D[a+108>>2];if(b){ma(b)}b=D[a+96>>2];if(b){ma(b)}b=D[a+72>>2];if(b){D[a+76>>2]=b;ma(b)}b=D[a+60>>2];if(b){ma(b)}b=D[a+48>>2];if(b){D[a+52>>2]=b;ma(b)}b=D[a+36>>2];if(b){D[a+40>>2]=b;ma(b)}b=D[a+24>>2];if(b){D[a+28>>2]=b;ma(b)}b=D[a+12>>2];if(b){D[a+16>>2]=b;ma(b)}b=D[a+8>>2];D[a+8>>2]=0;if(b){cb(b)}return a|0}function ic(a,b){var c=0,d=0;c=D[b+8>>2];D[a+4>>2]=D[b+4>>2];D[a+8>>2]=c;D[a+20>>2]=D[b+20>>2];c=D[b+16>>2];D[a+12>>2]=D[b+12>>2];D[a+16>>2]=c;a:{b:{if((a|0)!=(b|0)){c=D[b+28>>2];if(c){d=D[a+24>>2];if(D[a+32>>2]<<5>>>0>>0){if(d){ma(d);D[a+32>>2]=0;D[a+24>>2]=0;D[a+28>>2]=0;c=D[b+28>>2]}if((c|0)<0){break b}c=(c-1>>>5|0)+1|0;d=na(c<<2);D[a+32>>2]=c;D[a+28>>2]=0;D[a+24>>2]=d;c=D[b+28>>2]}Ra(d,D[b+24>>2],(c-1>>>3&536870908)+4|0);c=D[b+28>>2]}else{c=0}D[a+28>>2]=c;c=D[b+40>>2];if(c){d=D[a+36>>2];if(D[a+44>>2]<<5>>>0>>0){if(d){ma(d);D[a+44>>2]=0;D[a+36>>2]=0;D[a+40>>2]=0;c=D[b+40>>2]}if((c|0)<0){break a}c=(c-1>>>5|0)+1|0;d=na(c<<2);D[a+44>>2]=c;D[a+40>>2]=0;D[a+36>>2]=d;c=D[b+40>>2]}Ra(d,D[b+36>>2],(c-1>>>3&536870908)+4|0);b=D[b+40>>2]}else{b=0}D[a+40>>2]=b}return}pa();T()}pa();T()}function Pf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0;a:{a=$-32|0;$=a;e=Ba(c);if(e>>>0<4294967280){b:{c:{if(e>>>0>=11){g=e+16&-16;f=na(g);D[a+24>>2]=g|-2147483648;D[a+16>>2]=f;D[a+20>>2]=e;break c}B[a+27|0]=e;f=a+16|0;if(!e){break b}}oa(f,c,e)}B[e+f|0]=0;D[a+8>>2]=0;D[a>>2]=0;D[a+4>>2]=0;d:{c=bb(b,a+16|0);if((c|0)==(b+4|0)){break d}b=D[c+28>>2];f=D[c+32>>2];if((b|0)==(f|0)){break d}b=f-b|0;if(b&3){break d}e=b>>>2|0;f=D[a+4>>2];b=D[a>>2];g=f-b>>2;e:{if(e>>>0>g>>>0){ra(a,e-g|0);b=D[a>>2];f=D[a+4>>2];break e}if(e>>>0>=g>>>0){break e}f=(e<<2)+b|0;D[a+4>>2]=f}if((b|0)!=(f|0)){e=b;b=D[c+28>>2];oa(e,b,D[c+32>>2]-b|0);break d}va();T()}b=D[d>>2];if(b){D[d+4>>2]=b;ma(b)}D[d>>2]=D[a>>2];D[d+4>>2]=D[a+4>>2];D[d+8>>2]=D[a+8>>2];if(B[a+27|0]<0){ma(D[a+16>>2])}$=a+32|0;break a}Ca();T()}}function Rf(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0;d=$-16|0;$=d;a:{e=Ba(c);if(e>>>0<4294967280){b:{c:{if(e>>>0>=11){f=e+16&-16;a=na(f);D[d+8>>2]=f|-2147483648;D[d>>2]=a;D[d+4>>2]=e;break c}B[d+11|0]=e;a=d;if(!e){break b}}oa(a,c,e)}B[a+e|0]=0;c=E[d+11|0];e=c<<24>>24;b=D[b+4>>2];a=0;d:{if(!b){break d}a=c;c=(e|0)<0;a=c?D[d+4>>2]:a;f=c?D[d>>2]:d;while(1){c=E[b+27|0];g=c<<24>>24<0;c=g?D[b+20>>2]:c;j=c>>>0>>0;e:{f:{g:{h:{i:{j:{i=j?c:a;if(i){h=b+16|0;g=g?D[h>>2]:h;h=ua(f,g,i);if(h){break j}if(a>>>0>=c>>>0){break i}break e}if(a>>>0>=c>>>0){break h}break e}if((h|0)<0){break e}}c=ua(g,f,i);if(c){break g}}if(j){break f}a=1;break d}if((c|0)<0){break f}a=1;break d}b=b+4|0}b=D[b>>2];if(b){continue}break}a=0}if((e|0)<0){ma(D[d>>2])}$=d+16|0;break a}Ca();T()}return a|0}function kc(a){var b=0,c=0,d=0;b=D[a+8>>2];d=D[a>>2];a:{if(E[a+12|0]){b:{c:{d:{e:{if((b|0)==-1){break e}c=b+1|0;b=(c>>>0)%3|0?c:b-2|0;if((b|0)==-1){break e}b=D[D[d+12>>2]+(b<<2)>>2];if((b|0)!=-1){break d}}D[a+8>>2]=-1;break c}c=b+1|0;b=(c>>>0)%3|0?c:b-2|0;D[a+8>>2]=b;if((b|0)!=-1){break b}}c=D[a+4>>2];b=-1;f:{if((c|0)==-1){break f}g:{if((c>>>0)%3|0){c=c-1|0;break g}c=c+2|0;b=-1;if((c|0)==-1){break f}}c=D[D[d+12>>2]+(c<<2)>>2];b=-1;if((c|0)==-1){break f}b=c-1|0;if((c>>>0)%3|0){break f}b=c+2|0}B[a+12|0]=0;D[a+8>>2]=b;return}if((b|0)!=D[a+4>>2]){break a}D[a+8>>2]=-1;return}c=-1;h:{if((b|0)==-1){break h}i:{if((b>>>0)%3|0){b=b-1|0;break i}b=b+2|0;c=-1;if((b|0)==-1){break h}}b=D[D[d+12>>2]+(b<<2)>>2];c=-1;if((b|0)==-1){break h}c=b-1|0;if((b>>>0)%3|0){break h}c=b+2|0}D[a+8>>2]=c}}function Ld(a){var b=0,c=0,d=0;b=na(32);c=E[1475]|E[1476]<<8;B[b+24|0]=c;B[b+25|0]=c>>>8;c=E[1471]|E[1472]<<8|(E[1473]<<16|E[1474]<<24);d=E[1467]|E[1468]<<8|(E[1469]<<16|E[1470]<<24);B[b+16|0]=d;B[b+17|0]=d>>>8;B[b+18|0]=d>>>16;B[b+19|0]=d>>>24;B[b+20|0]=c;B[b+21|0]=c>>>8;B[b+22|0]=c>>>16;B[b+23|0]=c>>>24;c=E[1463]|E[1464]<<8|(E[1465]<<16|E[1466]<<24);d=E[1459]|E[1460]<<8|(E[1461]<<16|E[1462]<<24);B[b+8|0]=d;B[b+9|0]=d>>>8;B[b+10|0]=d>>>16;B[b+11|0]=d>>>24;B[b+12|0]=c;B[b+13|0]=c>>>8;B[b+14|0]=c>>>16;B[b+15|0]=c>>>24;c=E[1455]|E[1456]<<8|(E[1457]<<16|E[1458]<<24);d=E[1451]|E[1452]<<8|(E[1453]<<16|E[1454]<<24);B[b|0]=d;B[b+1|0]=d>>>8;B[b+2|0]=d>>>16;B[b+3|0]=d>>>24;B[b+4|0]=c;B[b+5|0]=c>>>8;B[b+6|0]=c>>>16;B[b+7|0]=c>>>24;B[b+26|0]=0;D[a>>2]=-1;ta(a+4|0,b,26);ma(b)}function Ra(a,b,c){var d=0,e=0;a:{if((a|0)==(b|0)){break a}e=a+c|0;if(b-e>>>0<=0-(c<<1)>>>0){return oa(a,b,c)}d=(a^b)&3;b:{c:{if(a>>>0>>0){if(d){d=a;break b}if(!(a&3)){d=a;break c}d=a;while(1){if(!c){break a}B[d|0]=E[b|0];b=b+1|0;c=c-1|0;d=d+1|0;if(d&3){continue}break}break c}d:{if(d){break d}if(e&3){while(1){if(!c){break a}c=c-1|0;d=c+a|0;B[d|0]=E[b+c|0];if(d&3){continue}break}}if(c>>>0<=3){break d}while(1){c=c-4|0;D[c+a>>2]=D[b+c>>2];if(c>>>0>3){continue}break}}if(!c){break a}while(1){c=c-1|0;B[c+a|0]=E[b+c|0];if(c){continue}break}break a}if(c>>>0<=3){break b}while(1){D[d>>2]=D[b>>2];b=b+4|0;d=d+4|0;c=c-4|0;if(c>>>0>3){continue}break}}if(!c){break a}while(1){B[d|0]=E[b|0];d=d+1|0;b=b+1|0;c=c-1|0;if(c){continue}break}}return a}function Pb(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0;d=D[a+8>>2];c=D[a+4>>2];if(d-c>>2>>>0>=b>>>0){if(b){b=b<<2;c=qa(c,0,b)+b|0}D[a+4>>2]=c;return}a:{b:{c:{g=D[a>>2];f=c-g>>2;e=f+b|0;if(e>>>0<1073741824){d=d-g|0;h=d>>1;e=d>>>0<2147483644?e>>>0>>0?h:e:1073741823;if(e){if(e>>>0>=1073741824){break c}i=na(e<<2)}d=(f<<2)+i|0;f=b<<2;b=qa(d,0,f);f=b+f|0;e=(e<<2)+i|0;if((c|0)==(g|0)){break b}while(1){c=c-4|0;b=D[c>>2];D[c>>2]=0;d=d-4|0;D[d>>2]=b;if((c|0)!=(g|0)){continue}break}D[a+8>>2]=e;b=D[a+4>>2];D[a+4>>2]=f;c=D[a>>2];D[a>>2]=d;if((b|0)==(c|0)){break a}while(1){b=b-4|0;a=D[b>>2];D[b>>2]=0;if(a){ba[D[D[a>>2]+4>>2]](a)}if((b|0)!=(c|0)){continue}break}break a}pa();T()}sa();T()}D[a+8>>2]=e;D[a+4>>2]=f;D[a>>2]=b}if(c){ma(c)}}function Dc(a,b){var c=0,d=0,e=0;c=$+-64|0;$=c;d=D[a>>2];e=D[d-4>>2];d=D[d-8>>2];D[c+32>>2]=0;D[c+36>>2]=0;D[c+40>>2]=0;D[c+44>>2]=0;D[c+48>>2]=0;D[c+52>>2]=0;B[c+55|0]=0;B[c+56|0]=0;B[c+57|0]=0;B[c+58|0]=0;B[c+59|0]=0;B[c+60|0]=0;B[c+61|0]=0;B[c+62|0]=0;D[c+24>>2]=0;D[c+28>>2]=0;D[c+20>>2]=0;D[c+16>>2]=11020;D[c+12>>2]=a;D[c+8>>2]=b;a=a+d|0;d=0;a:{if(Na(e,b,0)){D[c+56>>2]=1;ba[D[D[e>>2]+20>>2]](e,c+8|0,a,a,1,0);d=D[c+32>>2]==1?a:0;break a}ba[D[D[e>>2]+24>>2]](e,c+8|0,a,1,0);b:{switch(D[c+44>>2]){case 0:d=D[c+48>>2]==1?D[c+36>>2]==1?D[c+40>>2]==1?D[c+28>>2]:0:0:0;break a;case 1:break b;default:break a}}if(D[c+32>>2]!=1){if(D[c+48>>2]|D[c+36>>2]!=1|D[c+40>>2]!=1){break a}}d=D[c+24>>2]}$=c- -64|0;return d}function Vd(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;d=D[b+12>>2];g=d;c=D[b+20>>2];e=c;f=D[b+16>>2];h=f+4|0;c=h>>>0<4?c+1|0:c;i=D[b+8>>2];a:{if(i>>>0>>0&(c|0)>=(d|0)|(c|0)>(d|0)){break a}j=D[b>>2];d=j+f|0;d=E[d|0]|E[d+1|0]<<8|(E[d+2|0]<<16|E[d+3|0]<<24);D[b+16>>2]=h;D[b+20>>2]=c;c=e;e=f+8|0;c=e>>>0<8?c+1|0:c;f=e;e=c;if(f>>>0>i>>>0&(c|0)>=(g|0)|(c|0)>(g|0)){break a}c=h+j|0;c=E[c|0]|E[c+1|0]<<8|(E[c+2|0]<<16|E[c+3|0]<<24);D[b+16>>2]=f;D[b+20>>2]=e;if((c|0)<(d|0)){break a}D[a+16>>2]=c;D[a+12>>2]=d;g=(c>>31)-((d>>31)+(c>>>0>>0)|0)|0;c=c-d|0;if(!g&c>>>0>2147483646|g){break a}c=c+1|0;D[a+20>>2]=c;d=c>>>1|0;D[a+24>>2]=d;D[a+28>>2]=0-d;if(!(c&1)){D[a+24>>2]=d-1}k=Da(a+112|0,b)}return k|0}function Uc(a,b){var c=0,d=0,e=0,f=0;d=-1;e=-1;f=-1;a:{b:{if((b|0)==-1){break b}e=D[D[D[a+4>>2]+12>>2]+(b<<2)>>2];c=b+1|0;c=(c>>>0)%3|0?c:b-2|0;if((c|0)>=0){f=(c>>>0)/3|0;f=D[(D[D[a>>2]+96>>2]+J(f,12)|0)+(c-J(f,3)<<2)>>2]}c:{if((e|0)==-1){break c}c=((e>>>0)%3|0?-1:2)+e|0;if((c|0)<0){break c}d=(c>>>0)/3|0;d=D[(D[D[a>>2]+96>>2]+J(d,12)|0)+(c-J(d,3)<<2)>>2]}c=-1;if((d|0)!=(f|0)){break a}f=-1;d:{b=((b>>>0)%3|0?-1:2)+b|0;if((b|0)>=0){d=(b>>>0)/3|0;d=D[(D[D[a>>2]+96>>2]+J(d,12)|0)+(b-J(d,3)<<2)>>2];if((e|0)==-1){break b}break d}d=-1;if((e|0)!=-1){break d}break b}b=e+1|0;b=(b>>>0)%3|0?b:e-2|0;if((b|0)<0){break b}c=D[D[a>>2]+96>>2];a=(b>>>0)/3|0;f=D[(c+J(a,12)|0)+(b-J(a,3)<<2)>>2]}c=(d|0)==(f|0)?e:-1}return c}function qa(a,b,c){var d=0,e=0,f=0;a:{if(!c){break a}B[a|0]=b;e=a+c|0;B[e-1|0]=b;if(c>>>0<3){break a}B[a+2|0]=b;B[a+1|0]=b;B[e-3|0]=b;B[e-2|0]=b;if(c>>>0<7){break a}B[a+3|0]=b;B[e-4|0]=b;if(c>>>0<9){break a}e=0-a&3;f=e+a|0;d=J(b&255,16843009);D[f>>2]=d;b=c-e&-4;c=b+f|0;D[c-4>>2]=d;if(b>>>0<9){break a}D[f+8>>2]=d;D[f+4>>2]=d;D[c-8>>2]=d;D[c-12>>2]=d;if(b>>>0<25){break a}D[f+24>>2]=d;D[f+20>>2]=d;D[f+16>>2]=d;D[f+12>>2]=d;D[c-16>>2]=d;D[c-20>>2]=d;D[c-24>>2]=d;D[c-28>>2]=d;c=b;b=f&4|24;c=c-b|0;if(c>>>0<32){break a}d=fi(d,0,1,1);e=aa;b=b+f|0;while(1){D[b+24>>2]=d;D[b+28>>2]=e;D[b+16>>2]=d;D[b+20>>2]=e;D[b+8>>2]=d;D[b+12>>2]=e;D[b>>2]=d;D[b+4>>2]=e;b=b+32|0;c=c-32|0;if(c>>>0>31){continue}break}}return a}function ee(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;d=D[b+12>>2];h=d;c=D[b+20>>2];e=c;f=D[b+16>>2];g=f+4|0;c=g>>>0<4?c+1|0:c;i=D[b+8>>2];a:{if(i>>>0>>0&(c|0)>=(d|0)|(c|0)>(d|0)){break a}j=D[b>>2];d=j+f|0;d=E[d|0]|E[d+1|0]<<8|(E[d+2|0]<<16|E[d+3|0]<<24);D[b+16>>2]=g;D[b+20>>2]=c;c=e;e=f+8|0;c=e>>>0<8?c+1|0:c;f=e;e=c;if(f>>>0>i>>>0&(c|0)>=(h|0)|(c|0)>(h|0)){break a}c=g+j|0;c=E[c|0]|E[c+1|0]<<8|(E[c+2|0]<<16|E[c+3|0]<<24);D[b+16>>2]=f;D[b+20>>2]=e;if((c|0)<(d|0)){break a}D[a+16>>2]=c;D[a+12>>2]=d;b=(c>>31)-((d>>31)+(c>>>0>>0)|0)|0;c=c-d|0;if(!b&c>>>0>2147483646|b){break a}k=1;b=c+1|0;D[a+20>>2]=b;c=b>>>1|0;D[a+24>>2]=c;D[a+28>>2]=0-c;if(b&1){break a}D[a+24>>2]=c-1}return k|0}function Gg(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0;b=D[a+4>>2];d=D[b>>2];a:{c=D[a+12>>2];c=D[c+56>>2]-D[c+52>>2]|0;e=c>>2;b:{if(e>>>0<=D[b+8>>2]-d>>2>>>0){break b}if((c|0)<0){break a}f=D[b+4>>2];c=na(c);g=c+(e<<2)|0;e=f-d|0;f=e+c|0;if((e|0)>0){oa(c,d,e)}D[b+8>>2]=g;D[b+4>>2]=f;D[b>>2]=c;if(!d){break b}ma(d)}e=a+8|0;b=D[a+76>>2];c:{if(b){d=D[b>>2];if((d|0)==D[b+4>>2]){return 1}b=0;while(1){c=ld(e,D[(b<<2)+d>>2]);if(!c){break c}f=D[a+76>>2];d=D[f>>2];b=b+1|0;if(b>>>0>2]-d>>2>>>0){continue}break}break c}c=1;a=D[D[a+12>>2]+64>>2];a=D[a+4>>2]-D[a>>2]|0;if(a>>>0<12){break c}a=(a>>2>>>0)/3|0;b=0;while(1){c=ld(e,J(b,3));if(!c){break c}b=b+1|0;if((a|0)!=(b|0)){continue}break}}return c|0}pa();T()}function Mg(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0;b=D[a+4>>2];d=D[b>>2];a:{c=D[a+12>>2];c=D[c+28>>2]-D[c+24>>2]|0;e=c>>2;b:{if(e>>>0<=D[b+8>>2]-d>>2>>>0){break b}if((c|0)<0){break a}f=D[b+4>>2];c=na(c);g=c+(e<<2)|0;e=f-d|0;f=e+c|0;if((e|0)>0){oa(c,d,e)}D[b+8>>2]=g;D[b+4>>2]=f;D[b>>2]=c;if(!d){break b}ma(d)}e=a+8|0;b=D[a+76>>2];c:{if(b){d=D[b>>2];if((d|0)==D[b+4>>2]){return 1}b=0;while(1){c=md(e,D[(b<<2)+d>>2]);if(!c){break c}f=D[a+76>>2];d=D[f>>2];b=b+1|0;if(b>>>0>2]-d>>2>>>0){continue}break}break c}c=1;a=D[a+12>>2];a=D[a+4>>2]-D[a>>2]|0;if(a>>>0<12){break c}a=(a>>2>>>0)/3|0;b=0;while(1){c=md(e,J(b,3));if(!c){break c}b=b+1|0;if((a|0)!=(b|0)){continue}break}}return c|0}pa();T()}function Sc(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;d=$-16|0;$=d;f=D[a+24>>2];k=D[a+28>>2];a:{if((f|0)!=(k|0)){while(1){D[d+8>>2]=0;D[d>>2]=0;D[d+4>>2]=0;a=Qc(D[f>>2],b,d);g=E[d+11|0];h=g<<24>>24;i=3;b:{c:{d:{if(!a){break d}i=0;a=E[c+11|0];e=a<<24>>24;j=(h|0)<0?D[d+4>>2]:g;if((j|0)!=(((e|0)<0?D[c+4>>2]:a)|0)){break d}a=(e|0)<0?D[c>>2]:c;e=(h|0)<0;e:{if(!e){e=d;if(!h){break e}while(1){if(E[e|0]!=E[a|0]){break d}a=a+1|0;e=e+1|0;g=g-1|0;if(g){continue}break}break e}if(!j){break e}if(ua(e?D[d>>2]:d,a,j)){break c}}l=D[f>>2];i=1}if((h|0)>=0){break b}}ma(D[d>>2])}f:{switch(i|0){case 0:case 3:break f;default:break a}}f=f+4|0;if((k|0)!=(f|0)){continue}break}}l=0}$=d+16|0;return l}function Ha(a,b,c){var d=0,e=0,f=0;f=$-16|0;$=f;D[a+4>>2]=0;a:{b:{if(!b){break b}d=D[a+8>>2];e=d<<5;c:{if(e>>>0>=b>>>0){D[a+4>>2]=b;break c}D[f+8>>2]=0;D[f>>2]=0;D[f+4>>2]=0;if((b|0)<0){break a}if(e>>>0<=1073741822){d=d<<6;e=b+31&-32;d=d>>>0>e>>>0?d:e}else{d=2147483647}Xa(f,d);d=D[a>>2];D[a>>2]=D[f>>2];D[f>>2]=d;e=D[a+4>>2];D[a+4>>2]=b;D[f+4>>2]=e;e=D[a+8>>2];D[a+8>>2]=D[f+8>>2];D[f+8>>2]=e;if(!d){break c}ma(d)}d=b>>>5|0;e=d<<2;a=D[a>>2];if(E[c|0]){a=qa(a,255,e);if((b&-32)==(b|0)){break b}a=a+(d<<2)|0;D[a>>2]=D[a>>2]|-1>>>32-(b&31);break b}a=qa(a,0,e);if((b&-32)==(b|0)){break b}a=a+(d<<2)|0;D[a>>2]=D[a>>2]&(-1>>>32-(b&31)^-1)}$=f+16|0;return}pa();T()}function xe(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;d=D[b>>2];b=D[b+4>>2];f=D[D[a+8>>2]+40>>2];m=na((f|0)>=0?f:-1);g=1;h=b-d|0;a:{if((h|0)<=0){break a}b=0;g=0;d=0+D[c+20>>2]|0;i=D[c+16>>2];e=f+i|0;d=e>>>0>>0?d+1|0:d;j=e;e=D[c+12>>2];if(j>>>0>G[c+8>>2]&(e|0)<=(d|0)|(d|0)>(e|0)){break a}k=h>>2;g=(k|0)>1?k:1;while(1){b:{e=oa(m,i+D[c>>2]|0,f);D[c+16>>2]=j;D[c+20>>2]=d;oa(D[D[D[a+8>>2]+64>>2]>>2]+b|0,e,f);l=l+1|0;if((g|0)==(l|0)){break b}b=b+f|0;d=n+D[c+20>>2]|0;i=D[c+16>>2];e=f+i|0;d=e>>>0>>0?d+1|0:d;j=e;h=e;e=D[c+12>>2];if((e|0)>=(d|0)&G[c+8>>2]>=h>>>0|(d|0)<(e|0)){continue}}break}g=(l|0)>=(k|0)}ma(m);return g|0}function oe(a,b){a=a|0;b=b|0;a=0;a:{switch(b|0){case 0:a=na(20);D[a+12>>2]=-1;D[a+16>>2]=0;D[a+4>>2]=0;D[a+8>>2]=0;D[a>>2]=1920;return a|0;case 1:a=na(24);D[a+12>>2]=-1;D[a+16>>2]=0;D[a+4>>2]=0;D[a+8>>2]=0;D[a>>2]=1920;D[a+20>>2]=0;D[a>>2]=2136;return a|0;case 2:a=na(48);D[a+12>>2]=-1;D[a+16>>2]=0;D[a+4>>2]=0;D[a+8>>2]=0;D[a>>2]=1920;D[a+20>>2]=0;D[a>>2]=2136;D[a+24>>2]=1624;D[a>>2]=7948;D[a+32>>2]=0;D[a+36>>2]=0;D[a+28>>2]=-1;D[a+40>>2]=0;D[a+44>>2]=0;return a|0;case 3:a=na(32);D[a+12>>2]=-1;D[a+16>>2]=0;D[a+4>>2]=0;D[a+8>>2]=0;D[a>>2]=1920;D[a+20>>2]=0;D[a>>2]=2136;D[a+24>>2]=1032;D[a>>2]=5812;D[a+28>>2]=-1;break;default:break a}}return a|0}function ih(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0;D[b>>2]=1;f=b+8|0;c=D[b+8>>2];d=D[b+12>>2]-c|0;if(d>>>0<=4294967291){Eb(f,d+4|0);c=D[f>>2]}c=c+d|0;d=D[a+4>>2];B[c|0]=d;B[c+1|0]=d>>>8;B[c+2|0]=d>>>16;B[c+3|0]=d>>>24;c=D[a+8>>2];if((c|0)!=D[a+12>>2]){d=0;while(1){g=(d<<2)+c|0;c=D[b+8>>2];e=D[b+12>>2]-c|0;if(e>>>0<=4294967291){Eb(f,e+4|0);c=D[f>>2]}c=c+e|0;e=D[g>>2];B[c|0]=e;B[c+1|0]=e>>>8;B[c+2|0]=e>>>16;B[c+3|0]=e>>>24;d=d+1|0;c=D[a+8>>2];if(d>>>0>2]-c>>2>>>0){continue}break}}c=D[b+12>>2];b=D[b+8>>2];c=c-b|0;if(c>>>0<=4294967291){Eb(f,c+4|0);b=D[f>>2]}b=b+c|0;a=D[a+20>>2];B[b|0]=a;B[b+1|0]=a>>>8;B[b+2|0]=a>>>16;B[b+3|0]=a>>>24}function Ef(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0;e=$-32|0;$=e;a:{b:{f=Ba(c);if(f>>>0<4294967280){c:{d:{if(f>>>0>=11){g=f+16&-16;a=na(g);D[e+24>>2]=g|-2147483648;D[e+16>>2]=a;D[e+20>>2]=f;break d}B[e+27|0]=f;a=e+16|0;if(!f){break c}}oa(a,c,f)}B[a+f|0]=0;c=Ba(d);if(c>>>0>=4294967280){break b}e:{f:{if(c>>>0>=11){f=c+16&-16;a=na(f);D[e+8>>2]=f|-2147483648;D[e>>2]=a;D[e+4>>2]=c;break f}B[e+11|0]=c;a=e;if(!c){break e}}oa(a,d,c)}B[a+c|0]=0;c=D[b+4>>2];a=-1;g:{if(!c){break g}c=Sc(c,e+16|0,e);a=-1;if(!c){break g}a=Nc(b,D[c+24>>2])}if(B[e+11|0]<0){ma(D[e>>2])}if(B[e+27|0]<0){ma(D[e+16>>2])}$=e+32|0;break a}Ca();T()}Ca();T()}return a|0}function je(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;h=D[c+12>>2];d=h;e=D[c+20>>2];i=D[c+8>>2];f=D[c+16>>2];a:{if((d|0)<=(e|0)&i>>>0<=f>>>0|(d|0)<(e|0)){break a}j=D[c>>2];k=B[j+f|0];d=e;g=f+1|0;d=g?d:d+1|0;D[c+16>>2]=g;D[c+20>>2]=d;b:{if((k|0)==-2){break b}if((d|0)>=(h|0)&g>>>0>=i>>>0|(d|0)>(h|0)){break a}d=B[g+j|0];f=f+2|0;e=f>>>0<2?e+1|0:e;D[c+16>>2]=f;D[c+20>>2]=e;if((d-4&255)>>>0<251){break a}e=ba[D[D[a>>2]+40>>2]](a,k,d)|0;d=D[a+20>>2];D[a+20>>2]=e;if(!d){break b}ba[D[D[d>>2]+4>>2]](d)}d=D[a+20>>2];if(d){if(!(ba[D[D[a>>2]+28>>2]](a,d)|0)){break a}}l=ba[D[D[a>>2]+36>>2]](a,b,c)|0}return l|0}function Ch(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;f=$-32|0;$=f;h=(e&1073741823)!=(e|0)?-1:e<<2;h=qa(na(h),0,h);g=D[b>>2];i=D[b+4>>2];k=D[h+4>>2];D[f+16>>2]=D[h>>2];D[f+20>>2]=k;D[f+8>>2]=g;D[f+12>>2]=i;i=a+8|0;Jb(f+24|0,i,f+16|0,f+8|0);D[c>>2]=D[f+24>>2];D[c+4>>2]=D[f+28>>2];if((d|0)>(e|0)){k=0-e<<2;a=e;while(1){g=a<<2;j=g+b|0;m=D[j>>2];j=D[j+4>>2];g=c+g|0;l=g+k|0;n=D[l+4>>2];D[f+16>>2]=D[l>>2];D[f+20>>2]=n;D[f+8>>2]=m;D[f+12>>2]=j;Jb(f+24|0,i,f+16|0,f+8|0);D[g>>2]=D[f+24>>2];D[g+4>>2]=D[f+28>>2];a=a+e|0;if((d|0)>(a|0)){continue}break}}ma(h);$=f+32|0;return 1}function ib(a,b,c){var d=0,e=0,f=0,g=0,h=0;f=c-b|0;g=f>>2;d=D[a+8>>2];e=D[a>>2];if(g>>>0<=d-e>>2>>>0){d=D[a+4>>2];f=d-e|0;h=f>>2;f=g>>>0>h>>>0?b+f|0:c;if((f|0)!=(b|0)){while(1){D[e>>2]=D[b>>2];e=e+4|0;b=b+4|0;if((f|0)!=(b|0)){continue}break}}if(g>>>0>h>>>0){b=c-f|0;if((b|0)>0){d=oa(d,f,b)+b|0}D[a+4>>2]=d;return}D[a+4>>2]=e;return}if(e){D[a+4>>2]=e;ma(e);D[a+8>>2]=0;D[a>>2]=0;D[a+4>>2]=0;d=0}a:{if((f|0)<0){break a}e=d>>1;d=d>>>0<2147483644?e>>>0>g>>>0?e:g:1073741823;if(d>>>0>=1073741824){break a}e=d<<2;d=na(e);D[a>>2]=d;D[a+4>>2]=d;D[a+8>>2]=d+e;if((b|0)!=(c|0)){d=oa(d,b,f)+f|0}D[a+4>>2]=d;return}pa();T()}function xf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;a:{if(G[b+80>>2]>65535){break a}a=D[b+100>>2];b=D[b+96>>2];e=(a-b|0)/12|0;f=J(e,6);g=(f|0)==(c|0);if((a|0)==(b|0)|(c|0)!=(f|0)){break a}g=1;c=e>>>0>1?e:1;i=c&1;a=0;if(e>>>0>=2){j=c&-2;c=0;while(1){f=J(a,6);h=f+d|0;e=b+J(a,12)|0;C[h>>1]=D[e>>2];C[(f|2)+d>>1]=D[e+4>>2];C[h+4>>1]=D[e+8>>2];f=a|1;e=J(f,6)+d|0;f=b+J(f,12)|0;C[e>>1]=D[f>>2];C[e+2>>1]=D[f+4>>2];C[e+4>>1]=D[f+8>>2];a=a+2|0;c=c+2|0;if((j|0)!=(c|0)){continue}break}}if(!i){break a}c=J(a,6)+d|0;a=b+J(a,12)|0;C[c>>1]=D[a>>2];C[c+2>>1]=D[a+4>>2];C[c+4>>1]=D[a+8>>2]}return g|0}function Pd(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;e=D[b+12>>2];c=D[b+20>>2];f=c;g=D[b+16>>2];d=g+4|0;c=d>>>0<4?c+1|0:c;h=D[b+8>>2];i=d;a:{if(h>>>0>>0&(c|0)>=(e|0)|(c|0)>(e|0)){break a}d=g+D[b>>2]|0;d=E[d|0]|E[d+1|0]<<8|(E[d+2|0]<<16|E[d+3|0]<<24);D[b+16>>2]=i;D[b+20>>2]=c;c=f;f=g+8|0;c=f>>>0<8?c+1|0:c;if(f>>>0>h>>>0&(c|0)>=(e|0)|(c|0)>(e|0)){break a}D[b+16>>2]=f;D[b+20>>2]=c;if(!(d&1)){break a}c=M(d)^31;if(c-30>>>0<4294967267){break a}D[a+8>>2]=c+1;e=-2<>2]=c;D[a+12>>2]=e^-1;D[a+24>>2]=(c|0)/2;H[a+20>>2]=K(2)/K(c|0);j=Da(a+96|0,b)}return j|0}function vd(a){var b=0,c=0,d=0,e=0,f=0;f=1;c=D[a+140>>2];a:{if((c|0)<=0){break a}b=c<<4;d=na((c|0)!=(c&268435455)?-1:b|4);D[d>>2]=c;d=d+4|0;c=d+b|0;b=d;while(1){D[b>>2]=0;D[b+4>>2]=0;B[b+5|0]=0;B[b+6|0]=0;B[b+7|0]=0;B[b+8|0]=0;B[b+9|0]=0;B[b+10|0]=0;B[b+11|0]=0;B[b+12|0]=0;b=b+16|0;if((c|0)!=(b|0)){continue}break}e=D[a+136>>2];D[a+136>>2]=d;if(e){c=e-4|0;d=D[c>>2];if(d){b=(d<<4)+e|0;while(1){b=b-16|0;if((e|0)!=(b|0)){continue}break}}ma(c)}b=0;if(D[a+140>>2]<=0){break a}while(1){f=Da(D[a+136>>2]+(b<<4)|0,a);if(!f){break a}b=b+1|0;if((b|0)>2]){continue}break}}return f}function Of(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0;a=$-32|0;$=a;D[a+24>>2]=0;D[a+28>>2]=0;a:{d=Ba(c);if(d>>>0<4294967280){b:{c:{if(d>>>0>=11){f=d+16&-16;e=na(f);D[a+16>>2]=f|-2147483648;D[a+8>>2]=e;D[a+12>>2]=d;break c}B[a+19|0]=d;e=a+8|0;if(!d){break b}}oa(e,c,d)}B[d+e|0]=0;c=b+4|0;b=bb(b,a+8|0);d:{if((c|0)==(b|0)){break d}c=D[b+32>>2];b=D[b+28>>2];if((c-b|0)!=8){break d}c=E[b+4|0]|E[b+5|0]<<8|(E[b+6|0]<<16|E[b+7|0]<<24);D[a+24>>2]=E[b|0]|E[b+1|0]<<8|(E[b+2|0]<<16|E[b+3|0]<<24);D[a+28>>2]=c}g=I[a+24>>3];if(B[a+19|0]<0){ma(D[a+8>>2])}$=a+32|0;break a}Ca();T()}return+g}function Zb(a,b){var c=0,d=0,e=0,f=0,g=0;a:{if(D[a+64>>2]){break a}c=na(32);D[c+16>>2]=0;D[c+20>>2]=0;D[c+8>>2]=0;D[c>>2]=0;D[c+4>>2]=0;D[c+24>>2]=0;D[c+28>>2]=0;d=D[a+64>>2];D[a+64>>2]=c;if(!d){break a}c=D[d>>2];if(c){D[d+4>>2]=c;ma(c)}ma(d)}e=D[a+64>>2];c=D[a+28>>2]-1|0;if(c>>>0<=10){d=D[(c<<2)+10148>>2]}else{d=-1}c=J(d,B[a+24|0]);d=c;g=c>>31;e=kd(e,0,fi(c,g,b,0),aa);if(e){c=D[a+64>>2];D[a>>2]=c;f=D[c+20>>2];D[a+8>>2]=D[c+16>>2];D[a+12>>2]=f;f=D[c+24>>2];c=D[c+28>>2];D[a+48>>2]=0;D[a+52>>2]=0;D[a+40>>2]=d;D[a+44>>2]=g;D[a+16>>2]=f;D[a+20>>2]=c;D[a+80>>2]=b}return e}function Gh(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;f=D[b+12>>2];c=D[b+20>>2];e=c;g=D[b+16>>2];d=g+4|0;c=d>>>0<4?c+1|0:c;h=D[b+8>>2];i=d;a:{if(h>>>0>>0&(c|0)>=(f|0)|(c|0)>(f|0)){break a}d=g+D[b>>2]|0;d=E[d|0]|E[d+1|0]<<8|(E[d+2|0]<<16|E[d+3|0]<<24);D[b+16>>2]=i;D[b+20>>2]=c;c=e;e=g+8|0;c=e>>>0<8?c+1|0:c;if(e>>>0>h>>>0&(c|0)>=(f|0)|(c|0)>(f|0)){break a}D[b+16>>2]=e;D[b+20>>2]=c;if(!(d&1)){break a}b=M(d)^31;if(b-30>>>0<4294967267){break a}j=1;D[a+8>>2]=b+1;c=-2<>2]=b;D[a+12>>2]=c^-1;D[a+24>>2]=(b|0)/2;H[a+20>>2]=K(2)/K(b|0)}return j|0}function bb(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;h=a+4|0;a=D[a+4>>2];a:{b:{if(!a){break b}d=E[b+11|0];c=d<<24>>24<0;f=c?D[b>>2]:b;d=c?D[b+4>>2]:d;b=h;while(1){e=E[a+27|0];c=e<<24>>24<0;e=c?D[a+20>>2]:e;g=e>>>0>d>>>0;i=g?d:e;c:{if(i){j=a+16|0;c=ua(c?D[j>>2]:j,f,i);if(c){break c}}c=d>>>0>e>>>0?-1:g}c=(c|0)<0;b=c?b:a;a=D[(c?a+4|0:a)>>2];if(a){continue}break}if((b|0)==(h|0)){break b}c=E[b+27|0];a=c<<24>>24<0;d:{c=a?D[b+20>>2]:c;e=c>>>0>>0?c:d;if(e){g=f;f=b+16|0;a=ua(g,a?D[f>>2]:f,e);if(a){break d}}if(c>>>0>d>>>0){break b}break a}if((a|0)>=0){break a}}b=h}return b}function _b(a,b){var c=0;c=D[b+4>>2];D[a>>2]=D[b>>2];D[a+4>>2]=c;c=D[b+60>>2];D[a+56>>2]=D[b+56>>2];D[a+60>>2]=c;c=D[b+52>>2];D[a+48>>2]=D[b+48>>2];D[a+52>>2]=c;c=D[b+44>>2];D[a+40>>2]=D[b+40>>2];D[a+44>>2]=c;c=D[b+36>>2];D[a+32>>2]=D[b+32>>2];D[a+36>>2]=c;c=D[b+28>>2];D[a+24>>2]=D[b+24>>2];D[a+28>>2]=c;c=D[b+20>>2];D[a+16>>2]=D[b+16>>2];D[a+20>>2]=c;c=D[b+12>>2];D[a+8>>2]=D[b+8>>2];D[a+12>>2]=c;D[a+88>>2]=0;D[a+64>>2]=0;D[a+68>>2]=0;D[a+72>>2]=0;D[a+76>>2]=0;B[a+77|0]=0;B[a+78|0]=0;B[a+79|0]=0;B[a+80|0]=0;B[a+81|0]=0;B[a+82|0]=0;B[a+83|0]=0;B[a+84|0]=0;return a}function wf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0;a=D[b+100>>2];b=D[b+96>>2];h=a-b|0;a:{if((h|0)!=(c|0)|(a|0)==(b|0)){break a}g=(c|0)/12|0;e=g>>>0>1?g:1;j=e&1;a=0;if(g>>>0>=2){k=e&-2;g=0;while(1){e=J(a,12);i=e+d|0;f=b+e|0;D[i>>2]=D[f>>2];D[(e|4)+d>>2]=D[f+4>>2];D[i+8>>2]=D[f+8>>2];f=J(a|1,12);e=f+d|0;f=b+f|0;D[e>>2]=D[f>>2];D[e+4>>2]=D[f+4>>2];D[e+8>>2]=D[f+8>>2];a=a+2|0;g=g+2|0;if((k|0)!=(g|0)){continue}break}}if(!j){break a}e=d;d=J(a,12);a=e+d|0;b=b+d|0;D[a>>2]=D[b>>2];D[a+4>>2]=D[b+4>>2];D[a+8>>2]=D[b+8>>2]}return(c|0)==(h|0)|0}function Le(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;if(Na(a,D[b+8>>2],e)){if(!(D[b+28>>2]==1|D[b+4>>2]!=(c|0))){D[b+28>>2]=d}return}a:{if(Na(a,D[b>>2],e)){if(!(D[b+16>>2]!=(c|0)&D[b+20>>2]!=(c|0))){if((d|0)!=1){break a}D[b+32>>2]=1;return}D[b+32>>2]=d;b:{if(D[b+44>>2]==4){break b}C[b+52>>1]=0;a=D[a+8>>2];ba[D[D[a>>2]+20>>2]](a,b,c,c,1,e);if(E[b+53|0]){D[b+44>>2]=3;if(!E[b+52|0]){break b}break a}D[b+44>>2]=4}D[b+20>>2]=c;D[b+40>>2]=D[b+40>>2]+1;if(D[b+36>>2]!=1|D[b+24>>2]!=2){break a}B[b+54|0]=1;return}a=D[a+8>>2];ba[D[D[a>>2]+24>>2]](a,b,c,d,e)}}function Eg(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0;f=na(64);c=na(12);D[c+8>>2]=D[D[a+4>>2]+80>>2];D[c>>2]=9968;D[c+4>>2]=0;f=wc(f,c);a:{b:{if((b|0)<0){c=f;break b}h=a+8|0;c=D[a+12>>2];e=D[a+8>>2];g=c-e>>2;c:{if((g|0)>(b|0)){break c}d=b+1|0;if(b>>>0>=g>>>0){Pb(h,d-g|0);break c}if(d>>>0>=g>>>0){break c}e=e+(d<<2)|0;if((e|0)!=(c|0)){while(1){c=c-4|0;d=D[c>>2];D[c>>2]=0;if(d){ba[D[D[d>>2]+4>>2]](d)}if((c|0)!=(e|0)){continue}break}}D[a+12>>2]=e}a=D[h>>2]+(b<<2)|0;c=D[a>>2];D[a>>2]=f;if(!c){break a}}ba[D[D[c>>2]+4>>2]](c)}return(b^-1)>>>31|0}function Yc(a,b,c){var d=0,e=0,f=0,g=0;a:{if((b|c)>=0){b:{if(b>>>0>1431655765){break b}d=J(b,3);Vb(a,d,10224);Vb(a+12|0,d,10228);d=D[a+24>>2];c:{if(D[a+32>>2]-d>>2>>>0>=c>>>0){break c}if(c>>>0>=1073741824){break a}e=D[a+28>>2];f=c<<2;c=na(f);f=c+f|0;e=e-d|0;g=e+c|0;if((e|0)>0){oa(c,d,e)}D[a+32>>2]=f;D[a+28>>2]=g;D[a+24>>2]=c;if(!d){break c}ma(d)}D[a+80>>2]=0;D[a+84>>2]=0;c=D[a+76>>2];D[a+76>>2]=0;if(c){ma(c)}D[a+68>>2]=0;D[a+72>>2]=0;c=a- -64|0;a=D[c>>2];D[c>>2]=0;if(!a){break b}ma(a)}a=b>>>0<1431655766}else{a=0}return a}pa();T()}function se(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0;c=D[a+60>>2];a:{if(!c){break a}D[c+4>>2]=a+48;if(!(ba[D[D[c>>2]+12>>2]](c)|0)){break a}b:{c=ba[D[D[a>>2]+24>>2]](a)|0;if((c|0)<=0){break b}while(1){c:{f=D[(ba[D[D[a>>2]+28>>2]](a)|0)+4>>2];g=ba[D[D[a>>2]+20>>2]](a,d)|0;e=D[a+60>>2];if(!(ba[D[D[e>>2]+8>>2]](e,D[D[f+8>>2]+(g<<2)>>2])|0)){break c}d=d+1|0;if((c|0)!=(d|0)){continue}break b}break}return 0}d=0;if(!(ba[D[D[a>>2]+36>>2]](a,b)|0)){break a}if(!(ba[D[D[a>>2]+40>>2]](a,b)|0)){break a}d=ba[D[D[a>>2]+44>>2]](a)|0}return d|0}function ob(a,b){var c=0,d=0,e=0,f=0,g=0,h=0;c=D[a+4>>2];if((c|0)!=D[a+8>>2]){d=D[b+4>>2];D[c>>2]=D[b>>2];D[c+4>>2]=d;D[c+8>>2]=D[b+8>>2];D[a+4>>2]=c+12;return}a:{f=D[a>>2];g=c-f|0;d=(g|0)/12|0;c=d+1|0;if(c>>>0<357913942){e=d<<1;e=d>>>0<178956970?c>>>0>>0?e:c:357913941;if(e){if(e>>>0>=357913942){break a}c=na(J(e,12))}else{c=0}d=c+J(d,12)|0;h=D[b+4>>2];D[d>>2]=D[b>>2];D[d+4>>2]=h;D[d+8>>2]=D[b+8>>2];b=d+J((g|0)/-12|0,12)|0;if((g|0)>0){oa(b,f,g)}D[a+8>>2]=c+J(e,12);D[a+4>>2]=d+12;D[a>>2]=b;if(f){ma(f)}return}pa();T()}sa();T()}function Ec(a,b,c,d,e,f,g){var h=0,i=0,j=0;h=$-16|0;$=h;if((b^-1)-17>>>0>=c>>>0){if(E[a+11|0]>>>7|0){j=D[a>>2]}else{j=a}a:{if(b>>>0<2147483623){D[h+8>>2]=b<<1;D[h+12>>2]=b+c;c=$-16|0;$=c;$=c+16|0;c=h+8|0;i=h+12|0;c=D[(G[i>>2]>2]?c:i)>>2];if(c>>>0>=11){i=c+16&-16;c=i-1|0;c=(c|0)==11?i:c}else{c=10}break a}c=-18}i=c+1|0;c=na(i);if(f){gb(c,g,f)}g=d-e|0;if((d|0)!=(e|0)){gb(c+f|0,e+j|0,g)}if((b|0)!=10){ma(j)}D[a>>2]=c;D[a+8>>2]=i|-2147483648;b=a;a=f+g|0;D[b+4>>2]=a;B[h+7|0]=0;B[a+c|0]=E[h+7|0];$=h+16|0;return}Ca();T()}function Fd(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0;c=D[a+216>>2];if((c|0)!=D[a+220>>2]){while(1){a:{c=D[J(e,144)+c>>2];if((c|0)<0){break a}d=D[a+4>>2];f=D[d+8>>2];if((c|0)>=D[d+12>>2]-f>>2){break a}d=0;c=D[(c<<2)+f>>2];if((ba[D[D[c>>2]+24>>2]](c)|0)<=0){break a}while(1){if((ba[D[D[c>>2]+20>>2]](c,d)|0)!=(b|0)){d=d+1|0;if((ba[D[D[c>>2]+24>>2]](c)|0)>(d|0)){continue}break a}break}a=D[a+216>>2]+J(e,144)|0;return(E[a+100|0]?a+4|0:0)|0}e=e+1|0;c=D[a+216>>2];if(e>>>0<(D[a+220>>2]-c|0)/144>>>0){continue}break}}return 0}function eb(a){var b=0,c=0,d=0,e=0,f=0;d=D[a+8>>2];a:{if(E[d+84|0]){break a}b=D[a+16>>2];if(!b|!E[b+84|0]){break a}c=D[d+72>>2];e=D[d+68>>2];B[b+84|0]=0;c=c-e>>2;f=D[b+68>>2];e=D[b+72>>2]-f>>2;b:{if(c>>>0>e>>>0){xa(b+68|0,c-e|0,2004);d=D[a+8>>2];break b}if(c>>>0>=e>>>0){break b}D[b+72>>2]=f+(c<<2)}if(E[d+84|0]){break a}c=D[d+68>>2];if((c|0)==D[d+72>>2]){break a}e=D[D[a+16>>2]+68>>2];b=0;while(1){f=b<<2;D[f+e>>2]=D[c+f>>2];b=b+1|0;c=D[d+68>>2];if(b>>>0>2]-c>>2>>>0){continue}break}}return D[a+16>>2]}function Hf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0;e=$+-64|0;$=e;f=La(e+8|0);D[f+16>>2]=0;D[f+20>>2]=0;D[f>>2]=b;D[f+8>>2]=c;D[f+12>>2]=0;b=e+48|0;Md(b,a,f,d);D[a+24>>2]=D[e+48>>2];d=a+24|0;a:{if((d|0)==(b|0)){break a}b=e+48|4;f=E[e+63|0];c=f<<24>>24;a=a+28|0;if(B[a+11|0]>=0){if((c|0)>=0){c=D[b+4>>2];D[a>>2]=D[b>>2];D[a+4>>2]=c;D[a+8>>2]=D[b+8>>2];break a}sb(a,D[e+52>>2],D[e+56>>2]);break a}g=a;a=(c|0)<0;tb(g,a?D[e+52>>2]:b,a?D[e+56>>2]:f)}if(B[e+63|0]<0){ma(D[e+52>>2])}$=e- -64|0;return d|0}function Ed(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0;c=D[a+216>>2];if((c|0)!=D[a+220>>2]){while(1){a:{c=D[J(e,144)+c>>2];if((c|0)<0){break a}d=D[a+4>>2];f=D[d+8>>2];if((c|0)>=D[d+12>>2]-f>>2){break a}d=0;c=D[(c<<2)+f>>2];if((ba[D[D[c>>2]+24>>2]](c)|0)<=0){break a}while(1){if((ba[D[D[c>>2]+20>>2]](c,d)|0)!=(b|0)){d=d+1|0;if((ba[D[D[c>>2]+24>>2]](c)|0)>(d|0)){continue}break a}break}return(D[a+216>>2]+J(e,144)|0)+104|0}e=e+1|0;c=D[a+216>>2];if(e>>>0<(D[a+220>>2]-c|0)/144>>>0){continue}break}}return a+184|0}function Eb(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0;a:{c=D[a+4>>2];d=D[a>>2];f=c-d|0;b:{if(f>>>0>>0){g=b-f|0;e=D[a+8>>2];if(g>>>0<=e-c>>>0){h=a,i=qa(c,0,g)+g|0,D[h+4>>2]=i;break b}if((b|0)<0){break a}c=e-d|0;e=c<<1;e=c>>>0<1073741823?b>>>0>>0?e:b:2147483647;c=na(e);qa(c+f|0,0,g);if((f|0)>0){oa(c,d,f)}D[a+8>>2]=c+e;D[a+4>>2]=b+c;D[a>>2]=c;if(!d){break b}ma(d);break b}if(b>>>0>=f>>>0){break b}D[a+4>>2]=b+d}b=D[a+28>>2];c=b;d=b+1|0;b=D[a+24>>2]+1|0;d=b?c:d;D[a+24>>2]=b;D[a+28>>2]=d;return}pa();T()}function If(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0;d=$+-64|0;$=d;e=La(d+8|0);D[e+16>>2]=0;D[e+20>>2]=0;D[e>>2]=b;D[e+8>>2]=c;D[e+12>>2]=0;b=d+48|0;Ld(b);D[a+24>>2]=D[d+48>>2];e=a+24|0;a:{if((e|0)==(b|0)){break a}b=d+48|4;f=E[d+63|0];c=f<<24>>24;a=a+28|0;if(B[a+11|0]>=0){if((c|0)>=0){c=D[b+4>>2];D[a>>2]=D[b>>2];D[a+4>>2]=c;D[a+8>>2]=D[b+8>>2];break a}sb(a,D[d+52>>2],D[d+56>>2]);break a}g=a;a=(c|0)<0;tb(g,a?D[d+52>>2]:b,a?D[d+56>>2]:f)}if(B[d+63|0]<0){ma(D[d+52>>2])}$=d- -64|0;return e|0}function ye(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0;if((ba[D[D[b>>2]+20>>2]](b)|0)<=0){return 1}while(1){a:{g=0;d=Oc(D[D[a+4>>2]+4>>2],ba[D[D[b>>2]+24>>2]](b,e)|0);if((d|0)==-1){break a}f=D[a+4>>2];c=0;b:{if((d|0)<0){break b}h=D[f+4>>2];if((d|0)>=D[h+12>>2]-D[h+8>>2]>>2){break b}c=D[D[f+8>>2]+(D[D[f+20>>2]+(d<<2)>>2]<<2)>>2];c=ba[D[D[c>>2]+32>>2]](c,d)|0}if(!c){break a}if(!(ba[D[D[b>>2]+28>>2]](b,c)|0)){break a}g=1;e=e+1|0;if((ba[D[D[b>>2]+20>>2]](b)|0)>(e|0)){continue}}break}return g|0}function ya(a){D[a>>2]=-1;D[a+4>>2]=0;D[a+8>>2]=0;D[a+32>>2]=0;D[a+36>>2]=0;B[a+28|0]=1;D[a+20>>2]=0;D[a+24>>2]=0;D[a+12>>2]=0;D[a+16>>2]=0;D[a+40>>2]=0;D[a+44>>2]=0;D[a+48>>2]=0;D[a+52>>2]=0;D[a+56>>2]=0;D[a+60>>2]=0;D[a+64>>2]=0;D[a+68>>2]=0;D[a+76>>2]=0;D[a+80>>2]=0;D[a+84>>2]=0;D[a+88>>2]=0;D[a+92>>2]=0;D[a+96>>2]=0;D[a+72>>2]=a+4;D[a+104>>2]=0;D[a+108>>2]=0;B[a+100|0]=1;D[a+112>>2]=0;D[a+116>>2]=0;D[a+120>>2]=0;D[a+124>>2]=0;D[a+128>>2]=0;D[a+132>>2]=0;D[a+136>>2]=0;D[a+140>>2]=0}function Ff(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0;a=$-32|0;$=a;a:{d=Ba(c);if(d>>>0<4294967280){b:{c:{if(d>>>0>=11){f=d+16&-16;e=na(f);D[a+24>>2]=f|-2147483648;D[a+16>>2]=e;D[a+20>>2]=d;break c}B[a+27|0]=d;e=a+16|0;if(!d){break b}}oa(e,c,d)}B[d+e|0]=0;B[a+4|0]=0;D[a>>2]=1701667182;B[a+11|0]=4;d=D[b+4>>2];c=-1;d:{if(!d){break d}d=Sc(d,a,a+16|0);c=-1;if(!d){break d}c=Nc(b,D[d+24>>2])}b=c;if(B[a+11|0]<0){ma(D[a>>2])}if(B[a+27|0]<0){ma(D[a+16>>2])}$=a+32|0;break a}Ca();T()}return b|0}function Qf(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0;d=$-16|0;$=d;D[d+12>>2]=0;a:{e=Ba(c);if(e>>>0<4294967280){b:{c:{if(e>>>0>=11){f=e+16&-16;a=na(f);D[d+8>>2]=f|-2147483648;D[d>>2]=a;D[d+4>>2]=e;break c}B[d+11|0]=e;a=d;if(!e){break b}}oa(a,c,e)}B[a+e|0]=0;a=bb(b,d);d:{if((a|0)==(b+4|0)){break d}b=D[a+32>>2];a=D[a+28>>2];if((b-a|0)!=4){break d}D[d+12>>2]=E[a|0]|E[a+1|0]<<8|(E[a+2|0]<<16|E[a+3|0]<<24)}a=D[d+12>>2];if(B[d+11|0]<0){ma(D[d>>2])}$=d+16|0;break a}Ca();T()}return a|0}function ub(a){a=a|0;var b=0,c=0,d=0;D[a>>2]=10300;b=D[a+68>>2];if(b){D[a+72>>2]=b;ma(b)}b=D[a+56>>2];if(b){D[a+60>>2]=b;ma(b)}b=D[a+44>>2];if(b){D[a+48>>2]=b;ma(b)}b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}b=D[a+20>>2];if(b){D[a+24>>2]=b;ma(b)}b=D[a+8>>2];if(b){d=b;c=D[a+12>>2];if((b|0)!=(c|0)){while(1){c=c-4|0;d=D[c>>2];D[c>>2]=0;if(d){Aa(d)}if((b|0)!=(c|0)){continue}break}d=D[a+8>>2]}D[a+12>>2]=b;ma(d)}b=D[a+4>>2];D[a+4>>2]=0;if(b){fc(b)}return a|0}function ra(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0;e=D[a+8>>2];c=D[a+4>>2];if(e-c>>2>>>0>=b>>>0){if(b){b=b<<2;c=qa(c,0,b)+b|0}D[a+4>>2]=c;return}a:{f=D[a>>2];g=c-f|0;h=g>>2;d=h+b|0;if(d>>>0<1073741824){c=0;e=e-f|0;i=e>>1;d=e>>>0<2147483644?d>>>0>>0?i:d:1073741823;if(d){if(d>>>0>=1073741824){break a}c=na(d<<2)}b=b<<2;b=qa((h<<2)+c|0,0,b)+b|0;if((g|0)>0){oa(c,f,g)}D[a+8>>2]=(d<<2)+c;D[a+4>>2]=b;D[a>>2]=c;if(f){ma(f)}return}pa();T()}sa();T()}function db(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0;e=D[a+8>>2];c=D[a+4>>2];if(e-c>>3>>>0>=b>>>0){if(b){b=b<<3;c=qa(c,0,b)+b|0}D[a+4>>2]=c;return}a:{f=D[a>>2];g=c-f|0;h=g>>3;d=h+b|0;if(d>>>0<536870912){c=0;e=e-f|0;i=e>>2;d=e>>>0<2147483640?d>>>0>>0?i:d:536870911;if(d){if(d>>>0>=536870912){break a}c=na(d<<3)}b=b<<3;b=qa((h<<3)+c|0,0,b)+b|0;if((g|0)>0){oa(c,f,g)}D[a+8>>2]=(d<<3)+c;D[a+4>>2]=b;D[a>>2]=c;if(f){ma(f)}return}pa();T()}sa();T()}function Ta(a,b){var c=0,d=0,e=0,f=0,g=0,h=0;e=D[a>>2];a=D[e+4>>2];c=D[e+8>>2];if(a>>>0>>0){D[a>>2]=D[b>>2];D[e+4>>2]=a+4;return}a:{f=D[e>>2];g=a-f|0;d=g>>2;a=d+1|0;if(a>>>0<1073741824){h=d<<2;c=c-f|0;d=c>>1;c=c>>>0<2147483644?a>>>0>>0?d:a:1073741823;if(c){if(c>>>0>=1073741824){break a}a=na(c<<2)}else{a=0}d=h+a|0;D[d>>2]=D[b>>2];if((g|0)>0){oa(a,f,g)}D[e+8>>2]=a+(c<<2);D[e+4>>2]=d+4;D[e>>2]=a;if(f){ma(f)}return}pa();T()}sa();T()}function dc(a,b){var c=0,d=0,e=0,f=0;c=a+4|0;a=bb(a,b);a:{if((c|0)==(a|0)){break a}b=a+28|0;b=B[a+39|0]<0?D[b>>2]:b;while(1){a=b;b=a+1|0;c=B[a|0];if((c|0)==32|c-9>>>0<5){continue}break}b:{c:{d:{c=B[a|0];switch(c-43|0){case 0:break c;case 2:break d;default:break b}}e=1}c=B[b|0];a=b}if(c-48>>>0<10){while(1){d=(J(d,10)-B[a|0]|0)+48|0;b=B[a+1|0];a=a+1|0;if(b-48>>>0<10){continue}break}}a=e?d:0-d|0;if((a|0)==-1){break a}f=(a|0)!=0}return f}function ne(a){a=a|0;var b=0,c=0,d=0;D[a>>2]=2016;b=D[a+60>>2];D[a+60>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}b=D[a+48>>2];if(b){D[a+52>>2]=b;ma(b)}d=D[a+36>>2];if(d){c=D[a+40>>2];b=d;if((c|0)!=(b|0)){while(1){c=c-4|0;b=D[c>>2];D[c>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}if((c|0)!=(d|0)){continue}break}b=D[a+36>>2]}D[a+40>>2]=d;ma(b)}D[a>>2]=1776;b=D[a+16>>2];if(b){D[a+20>>2]=b;ma(b)}b=D[a+4>>2];if(b){D[a+8>>2]=b;ma(b)}return a|0}function me(a){a=a|0;var b=0,c=0,d=0;D[a>>2]=2016;b=D[a+60>>2];D[a+60>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}b=D[a+48>>2];if(b){D[a+52>>2]=b;ma(b)}d=D[a+36>>2];if(d){c=D[a+40>>2];b=d;if((c|0)!=(b|0)){while(1){c=c-4|0;b=D[c>>2];D[c>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}if((c|0)!=(d|0)){continue}break}b=D[a+36>>2]}D[a+40>>2]=d;ma(b)}D[a>>2]=1776;b=D[a+16>>2];if(b){D[a+20>>2]=b;ma(b)}b=D[a+4>>2];if(b){D[a+8>>2]=b;ma(b)}ma(a)}function id(a,b){var c=0,d=0,e=0,f=0,g=0,h=0;e=D[a+8>>2];c=D[a+4>>2];if(e-c>>1>>>0>=b>>>0){if(b){b=b<<1;c=qa(c,0,b)+b|0}D[a+4>>2]=c;return}a:{f=D[a>>2];g=c-f|0;h=g>>1;d=h+b|0;if((d|0)>=0){c=0;e=e-f|0;d=e>>>0<2147483646?d>>>0>>0?e:d:2147483647;if(d){if((d|0)<0){break a}c=na(d<<1)}b=b<<1;b=qa((h<<1)+c|0,0,b)+b|0;if((g|0)>0){oa(c,f,g)}D[a+8>>2]=(d<<1)+c;D[a+4>>2]=b;D[a>>2]=c;if(f){ma(f)}return}pa();T()}sa();T()}function Ag(a){a=a|0;var b=0,c=0,d=0,e=0,f=0;a:{b=D[a+8>>2];b:{if((b|0)<0){break b}c=D[a+4>>2];e=D[c>>2];d=D[c+4>>2]-e>>2;c:{if(d>>>0>>0){ra(c,b-d|0);f=D[a+8>>2];break c}f=b;if(b>>>0>=d>>>0){break c}D[c+4>>2]=e+(b<<2);f=b}d=f;if((d|0)<=0){break b}a=D[a+4>>2];c=D[a>>2];e=D[a+4>>2]-c>>2;a=0;while(1){if((a|0)==(e|0)){break a}D[c+(a<<2)>>2]=a;a=a+1|0;if((d|0)!=(a|0)){continue}break}}return(b^-1)>>>31|0}va();T()}function $g(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0;d=$-16|0;$=d;e=D[a+4>>2];a:{if((e|0)==-1){break a}c=D[b+20>>2];if(!!D[b+16>>2]&(c|0)>=0|(c|0)>0){break a}rb(b,D[b+4>>2],D[a+8>>2],D[a+12>>2]);c=D[b+20>>2];if(!!D[b+16>>2]&(c|0)>=0|(c|0)>0){break a}rb(b,D[b+4>>2],a+20|0,a+24|0);c=D[b+20>>2];f=D[b+16>>2];B[d+15|0]=D[a+4>>2];if(!!f&(c|0)>=0|(c|0)>0){break a}rb(b,D[b+4>>2],d+15|0,d+16|0)}$=d+16|0;return(e|0)!=-1|0}function kf(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0;d=$-16|0;$=d;Md(d,a,b,c);D[a+24>>2]=D[d>>2];e=a+24|0;a:{if((e|0)==(d|0)){break a}b=d|4;f=E[d+15|0];c=f<<24>>24;a=a+28|0;if(B[a+11|0]>=0){if((c|0)>=0){c=D[b+4>>2];D[a>>2]=D[b>>2];D[a+4>>2]=c;D[a+8>>2]=D[b+8>>2];break a}sb(a,D[d+4>>2],D[d+8>>2]);break a}g=a;a=(c|0)<0;tb(g,a?D[d+4>>2]:b,a?D[d+8>>2]:f)}if(B[d+15|0]<0){ma(D[d+4>>2])}$=d+16|0;return e|0}function vf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0;a=$-32|0;$=a;e=B[b+24|0];f=D[2555];D[a+24>>2]=D[2554];D[a+28>>2]=f;f=D[2553];D[a+16>>2]=D[2552];D[a+20>>2]=f;a:{b:{c=nb(b,c,e,a+16|0);if(c){D[a+8>>2]=0;D[a>>2]=0;D[a+4>>2]=0;b=0;if(e){if((e|0)<0){break b}e=e<<2;b=na(e);g=oa(b,a+16|0,e)+e|0}e=D[d>>2];if(e){D[d+4>>2]=e;ma(e)}D[d+8>>2]=g;D[d+4>>2]=g;D[d>>2]=b}$=a+32|0;break a}pa();T()}return c|0}function Ua(a){var b=0,c=0,d=0,e=0,f=0;b=D[a+4>>2];if((b|0)!=D[a+8>>2]){D[b>>2]=D[2081];D[a+4>>2]=b+4;return}a:{f=D[a>>2];d=b-f|0;e=d>>2;b=e+1|0;if(b>>>0<1073741824){c=d>>1;c=d>>>0<2147483644?b>>>0>>0?c:b:1073741823;if(c){if(c>>>0>=1073741824){break a}b=na(c<<2)}else{b=0}e=b+(e<<2)|0;D[e>>2]=D[2081];if((d|0)>0){oa(b,f,d)}D[a+8>>2]=b+(c<<2);D[a+4>>2]=e+4;D[a>>2]=b;if(f){ma(f)}return}pa();T()}sa();T()}function lf(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0;b=$-16|0;$=b;Ld(b);D[a+24>>2]=D[b>>2];e=a+24|0;a:{if((e|0)==(b|0)){break a}c=b|4;f=E[b+15|0];d=f<<24>>24;a=a+28|0;if(B[a+11|0]>=0){if((d|0)>=0){d=D[c+4>>2];D[a>>2]=D[c>>2];D[a+4>>2]=d;D[a+8>>2]=D[c+8>>2];break a}sb(a,D[b+4>>2],D[b+8>>2]);break a}g=a;a=(d|0)<0;tb(g,a?D[b+4>>2]:c,a?D[b+8>>2]:f)}if(B[b+15|0]<0){ma(D[b+4>>2])}$=b+16|0;return e|0}function Hb(a,b){var c=0,d=0,e=0,f=0;d=D[a+12>>2];c=D[a+16>>2]-d>>2;a:{if(c>>>0>>0){ra(a+12|0,b-c|0);break a}if(b>>>0>=c>>>0){break a}D[a+16>>2]=d+(b<<2)}b:{c=D[a>>2];c:{if(D[a+8>>2]-c>>2>>>0>=b>>>0){break c}if(b>>>0>=1073741824){break b}d=D[a+4>>2];e=b<<2;b=na(e);e=b+e|0;d=d-c|0;f=d+b|0;if((d|0)>0){oa(b,c,d)}D[a+8>>2]=e;D[a+4>>2]=f;D[a>>2]=b;if(!c){break c}ma(c)}return}pa();T()}function Nf(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0;d=$-16|0;$=d;a:{e=Ba(c);if(e>>>0<4294967280){b:{c:{if(e>>>0>=11){g=e+16&-16;f=na(g);D[d+8>>2]=g|-2147483648;D[d>>2]=f;D[d+4>>2]=e;break c}B[d+11|0]=e;f=d;if(!e){break b}}oa(f,c,e)}B[e+f|0]=0;f=a+16|0;c=Qc(b,d,f);b=B[a+27|0];a=D[a+16>>2];if(B[d+11|0]<0){ma(D[d>>2])}$=d+16|0;a=c?(b|0)<0?a:f:0;break a}Ca();T()}return a|0}function jd(a,b,c){var d=0,e=0,f=0,g=0;a:{if(a>>>0>10){break a}d=D[c+20>>2];e=D[c+12>>2];f=D[c+16>>2];if((d|0)>=(e|0)&f>>>0>=G[c+8>>2]|(d|0)>(e|0)){break a}e=B[f+D[c>>2]|0];f=f+1|0;d=f?d:d+1|0;D[c+16>>2]=f;D[c+20>>2]=d;b:{if((e|0)<0){if(!jd(a+1|0,b,c)){break a}c=D[b>>2];a=D[b+4>>2]<<7|c>>>25;c=e&127|c<<7;break b}a=0;c=e&255}D[b>>2]=c;D[b+4>>2]=a;g=1}return g}function dg(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0;d=$+-64|0;$=d;e=ba[D[D[a>>2]+44>>2]](a,b)|0;a=ba[D[D[a>>2]+40>>2]](a,b)|0;f=mb(d);g=D[b+56>>2];h=e<<24>>24;i=a;a=a-1|0;if(a>>>0<=10){a=D[(a<<2)+10148>>2]}else{a=-1}a=J(a,e);$b(f,g,h,i,0,a,a>>31);a=_b(na(96),f);Zb(a,c);B[a+84|0]=1;D[a+72>>2]=D[a+68>>2];D[a+60>>2]=D[b+60>>2];$=d- -64|0;return a|0}function Va(a,b,c){var d=0,e=0,f=0,g=0;a:{if(a>>>0>10){break a}d=D[c+20>>2];e=D[c+12>>2];f=D[c+16>>2];if((d|0)>=(e|0)&f>>>0>=G[c+8>>2]|(d|0)>(e|0)){break a}e=B[f+D[c>>2]|0];f=f+1|0;d=f?d:d+1|0;D[c+16>>2]=f;D[c+20>>2]=d;b:{if((e|0)<0){if(!Va(a+1|0,b,c)){break a}c=D[b>>2];a=D[b+4>>2]<<7|c>>>25;c=e&127|c<<7;break b}a=0;c=e&255}D[b>>2]=c;D[b+4>>2]=a;g=1}return g}function Ke(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;if(Na(a,D[b+8>>2],e)){if(!(D[b+28>>2]==1|D[b+4>>2]!=(c|0))){D[b+28>>2]=d}return}a:{if(!Na(a,D[b>>2],e)){break a}if(!(D[b+16>>2]!=(c|0)&D[b+20>>2]!=(c|0))){if((d|0)!=1){break a}D[b+32>>2]=1;return}D[b+20>>2]=c;D[b+32>>2]=d;D[b+40>>2]=D[b+40>>2]+1;if(!(D[b+36>>2]!=1|D[b+24>>2]!=2)){B[b+54|0]=1}D[b+44>>2]=4}}function nh(a){a=a|0;var b=0,c=0,d=0;D[a>>2]=8176;b=D[a+48>>2];D[a+48>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}D[a>>2]=10032;b=D[a+20>>2];if(b){D[a+24>>2]=b;ma(b)}d=D[a+8>>2];if(d){c=D[a+12>>2];b=d;if((c|0)!=(b|0)){while(1){c=c-4|0;b=D[c>>2];D[c>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}if((c|0)!=(d|0)){continue}break}b=D[a+8>>2]}D[a+12>>2]=d;ma(b)}return a|0}function Bc(a,b,c,d){B[a+53|0]=1;a:{if(D[a+4>>2]!=(c|0)){break a}B[a+52|0]=1;c=D[a+16>>2];b:{if(!c){D[a+36>>2]=1;D[a+24>>2]=d;D[a+16>>2]=b;if((d|0)!=1){break a}if(D[a+48>>2]==1){break b}break a}if((b|0)==(c|0)){c=D[a+24>>2];if((c|0)==2){D[a+24>>2]=d;c=d}if(D[a+48>>2]!=1){break a}if((c|0)==1){break b}break a}D[a+36>>2]=D[a+36>>2]+1}B[a+54|0]=1}}function mh(a){a=a|0;var b=0,c=0,d=0;D[a>>2]=8176;b=D[a+48>>2];D[a+48>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}D[a>>2]=10032;b=D[a+20>>2];if(b){D[a+24>>2]=b;ma(b)}d=D[a+8>>2];if(d){c=D[a+12>>2];b=d;if((c|0)!=(b|0)){while(1){c=c-4|0;b=D[c>>2];D[c>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}if((c|0)!=(d|0)){continue}break}b=D[a+8>>2]}D[a+12>>2]=d;ma(b)}ma(a)}function Oe(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;e=$+-64|0;$=e;d=1;a:{if(Na(a,b,0)){break a}d=0;if(!b){break a}b=Dc(b,11068);d=0;if(!b){break a}d=e+8|0;qa(d|4,0,52);D[e+56>>2]=1;D[e+20>>2]=-1;D[e+16>>2]=a;D[e+8>>2]=b;ba[D[D[b>>2]+28>>2]](b,d,D[c>>2],1);a=D[e+32>>2];if((a|0)==1){D[c>>2]=D[e+24>>2]}d=(a|0)==1}$=e- -64|0;return d|0}function Cd(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=$-16|0;$=d;D[a+4>>2]=b;b=D[b+64>>2];e=D[b>>2];b=D[b+4>>2];B[d+15|0]=0;Ha(a+24|0,(b-e>>2>>>0)/3|0,d+15|0);b=D[a+4>>2];e=D[b+56>>2];b=D[b+52>>2];B[d+14|0]=0;Ha(a+36|0,e-b>>2,d+14|0);b=D[c+12>>2];D[a+16>>2]=D[c+8>>2];D[a+20>>2]=b;b=D[c+4>>2];D[a+8>>2]=D[c>>2];D[a+12>>2]=b;$=d+16|0}function re(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0;f=ba[D[D[a>>2]+24>>2]](a)|0;c=1;a:{if((f|0)<=0){break a}d=D[D[a+36>>2]>>2];g=a+48|0;c=0;if(!(ba[D[D[d>>2]+16>>2]](d,g,b)|0)){break a}while(1){e=e+1|0;if((f|0)!=(e|0)){d=D[D[a+36>>2]+(e<<2)>>2];if(ba[D[D[d>>2]+16>>2]](d,g,b)|0){continue}}break}c=(e|0)>=(f|0)}return c|0}function qe(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0;f=ba[D[D[a>>2]+24>>2]](a)|0;c=1;a:{if((f|0)<=0){break a}d=D[D[a+36>>2]>>2];g=a+48|0;c=0;if(!(ba[D[D[d>>2]+20>>2]](d,g,b)|0)){break a}while(1){e=e+1|0;if((f|0)!=(e|0)){d=D[D[a+36>>2]+(e<<2)>>2];if(ba[D[D[d>>2]+20>>2]](d,g,b)|0){continue}}break}c=(e|0)>=(f|0)}return c|0}function Wb(a){var b=0;D[a>>2]=0;D[a+4>>2]=0;D[a+56>>2]=0;D[a+48>>2]=0;D[a+52>>2]=0;D[a+40>>2]=0;D[a+44>>2]=0;D[a+32>>2]=0;D[a+36>>2]=0;D[a+24>>2]=0;D[a+28>>2]=0;D[a+16>>2]=0;D[a+20>>2]=0;D[a+8>>2]=0;D[a+12>>2]=0;b=a- -64|0;D[b>>2]=0;D[b+4>>2]=0;D[a+72>>2]=0;D[a+76>>2]=0;D[a+80>>2]=0;D[a+84>>2]=0;D[a+60>>2]=a;return a}function Zg(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=$-16|0;$=d;D[a+4>>2]=b;e=D[b>>2];b=D[b+4>>2];B[d+15|0]=0;Ha(a+24|0,(b-e>>2>>>0)/3|0,d+15|0);b=D[a+4>>2];e=D[b+28>>2];b=D[b+24>>2];B[d+14|0]=0;Ha(a+36|0,e-b>>2,d+14|0);b=D[c+12>>2];D[a+16>>2]=D[c+8>>2];D[a+20>>2]=b;b=D[c+4>>2];D[a+8>>2]=D[c>>2];D[a+12>>2]=b;$=d+16|0}function jb(a,b,c){var d=0,e=0,f=0,g=0,h=0;a:{if(a>>>0>5){break a}f=D[c+20>>2];d=f;g=D[c+12>>2];e=D[c+16>>2];if((d|0)>=(g|0)&e>>>0>=G[c+8>>2]|(d|0)>(g|0)){break a}d=E[e+D[c>>2]|0];e=e+1|0;f=e?f:f+1|0;D[c+16>>2]=e;D[c+20>>2]=f;if(d&128){if(!jb(a+1|0,b,c)){break a}d=d&127|D[b>>2]<<7}D[b>>2]=d;h=1}return h}function hb(a,b,c){var d=0,e=0,f=0,g=0,h=0;a:{if(a>>>0>5){break a}f=D[c+20>>2];d=f;g=D[c+12>>2];e=D[c+16>>2];if((d|0)>=(g|0)&e>>>0>=G[c+8>>2]|(d|0)>(g|0)){break a}d=E[e+D[c>>2]|0];e=e+1|0;f=e?f:f+1|0;D[c+16>>2]=e;D[c+20>>2]=f;if(d&128){if(!hb(a+1|0,b,c)){break a}d=d&127|D[b>>2]<<7}D[b>>2]=d;h=1}return h}function Wa(a,b,c){var d=0,e=0,f=0,g=0,h=0;a:{if(a>>>0>5){break a}f=D[c+20>>2];d=f;g=D[c+12>>2];e=D[c+16>>2];if((d|0)>=(g|0)&e>>>0>=G[c+8>>2]|(d|0)>(g|0)){break a}d=E[e+D[c>>2]|0];e=e+1|0;f=e?f:f+1|0;D[c+16>>2]=e;D[c+20>>2]=f;if(d&128){if(!Wa(a+1|0,b,c)){break a}d=d&127|D[b>>2]<<7}D[b>>2]=d;h=1}return h}function Ub(a,b,c){var d=0,e=0,f=0,g=0,h=0;a:{if(a>>>0>5){break a}f=D[c+20>>2];d=f;g=D[c+12>>2];e=D[c+16>>2];if((d|0)>=(g|0)&e>>>0>=G[c+8>>2]|(d|0)>(g|0)){break a}d=E[e+D[c>>2]|0];e=e+1|0;f=e?f:f+1|0;D[c+16>>2]=e;D[c+20>>2]=f;if(d&128){if(!Ub(a+1|0,b,c)){break a}d=d&127|D[b>>2]<<7}D[b>>2]=d;h=1}return h}function Pa(a,b,c){var d=0,e=0,f=0,g=0,h=0;a:{if(a>>>0>5){break a}f=D[c+20>>2];d=f;g=D[c+12>>2];e=D[c+16>>2];if((d|0)>=(g|0)&e>>>0>=G[c+8>>2]|(d|0)>(g|0)){break a}d=E[e+D[c>>2]|0];e=e+1|0;f=e?f:f+1|0;D[c+16>>2]=e;D[c+20>>2]=f;if(d&128){if(!Pa(a+1|0,b,c)){break a}d=d&127|D[b>>2]<<7}D[b>>2]=d;h=1}return h}function Nd(a,b,c){var d=0,e=0,f=0,g=0,h=0;a:{if(a>>>0>5){break a}f=D[c+20>>2];d=f;g=D[c+12>>2];e=D[c+16>>2];if((d|0)>=(g|0)&e>>>0>=G[c+8>>2]|(d|0)>(g|0)){break a}d=E[e+D[c>>2]|0];e=e+1|0;f=e?f:f+1|0;D[c+16>>2]=e;D[c+20>>2]=f;if(d&128){if(!Nd(a+1|0,b,c)){break a}d=d&127|D[b>>2]<<7}D[b>>2]=d;h=1}return h}function Ga(a,b,c){var d=0,e=0,f=0,g=0,h=0;a:{if(a>>>0>5){break a}f=D[c+20>>2];d=f;g=D[c+12>>2];e=D[c+16>>2];if((d|0)>=(g|0)&e>>>0>=G[c+8>>2]|(d|0)>(g|0)){break a}d=E[e+D[c>>2]|0];e=e+1|0;f=e?f:f+1|0;D[c+16>>2]=e;D[c+20>>2]=f;if(d&128){if(!Ga(a+1|0,b,c)){break a}d=d&127|D[b>>2]<<7}D[b>>2]=d;h=1}return h}function ua(a,b,c){var d=0,e=0;a:{b:{if(c>>>0>=4){if((a|b)&3){break b}while(1){if(D[a>>2]!=D[b>>2]){break b}b=b+4|0;a=a+4|0;c=c-4|0;if(c>>>0>3){continue}break}}if(!c){break a}}while(1){d=E[a|0];e=E[b|0];if((d|0)==(e|0)){b=b+1|0;a=a+1|0;c=c-1|0;if(c){continue}break a}break}return d-e|0}return 0}function qd(a){var b=0,c=0,d=0,e=0;d=D[a>>2];if(d){e=d;c=D[a+4>>2];if((d|0)!=(c|0)){while(1){e=c-144|0;b=D[e+132>>2];if(b){D[c-8>>2]=b;ma(b)}b=D[c-28>>2];if(b){D[c-24>>2]=b;ma(b)}b=D[c-40>>2];if(b){D[c-36>>2]=b;ma(b)}Gb(c-140|0);c=e;if((d|0)!=(c|0)){continue}break}e=D[a>>2]}D[a+4>>2]=d;ma(e)}}function Af(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=D[b+4>>2];a:{if(!d){break a}b=D[D[D[b+8>>2]+(c<<2)>>2]+60>>2];if((b|0)<0){break a}a=D[d+24>>2];c=D[d+28>>2];if((a|0)==(c|0)){break a}b:{while(1){e=D[a>>2];if((b|0)==D[e+24>>2]){break b}a=a+4|0;if((c|0)!=(a|0)){continue}break}e=0}}return e|0}function fc(a){var b=0,c=0,d=0;if(a){d=D[a+24>>2];if(d){b=d;c=D[a+28>>2];if((b|0)!=(c|0)){while(1){c=c-4|0;b=D[c>>2];D[c>>2]=0;if(b){Fa(b+12|0,D[b+16>>2]);Ea(b,D[b+4>>2]);ma(b)}if((c|0)!=(d|0)){continue}break}b=D[a+24>>2]}D[a+28>>2]=d;ma(b)}Fa(a+12|0,D[a+16>>2]);Ea(a,D[a+4>>2]);ma(a)}}function Xg(a){a=a|0;var b=0;D[a+8>>2]=9136;D[a>>2]=8924;b=D[a+96>>2];if(b){D[a+100>>2]=b;ma(b)}b=D[a+80>>2];if(b){D[a+84>>2]=b;ma(b)}b=D[a+68>>2];if(b){D[a+72>>2]=b;ma(b)}b=D[a+56>>2];if(b){D[a+60>>2]=b;ma(b)}D[a+8>>2]=9372;b=D[a+44>>2];if(b){ma(b)}b=D[a+32>>2];if(b){ma(b)}return a|0}function sh(a){a=a|0;var b=0,c=0,d=0;D[a>>2]=10032;b=D[a+20>>2];if(b){D[a+24>>2]=b;ma(b)}d=D[a+8>>2];if(d){c=D[a+12>>2];b=d;if((c|0)!=(b|0)){while(1){c=c-4|0;b=D[c>>2];D[c>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}if((c|0)!=(d|0)){continue}break}b=D[a+8>>2]}D[a+12>>2]=d;ma(b)}return a|0}function Wg(a){a=a|0;var b=0;D[a+8>>2]=9136;D[a>>2]=8924;b=D[a+96>>2];if(b){D[a+100>>2]=b;ma(b)}b=D[a+80>>2];if(b){D[a+84>>2]=b;ma(b)}b=D[a+68>>2];if(b){D[a+72>>2]=b;ma(b)}b=D[a+56>>2];if(b){D[a+60>>2]=b;ma(b)}D[a+8>>2]=9372;b=D[a+44>>2];if(b){ma(b)}b=D[a+32>>2];if(b){ma(b)}ma(a)}function sc(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0;h=D[c+8>>2];e=D[c+16>>2];g=D[c+12>>2];f=g;d=D[c+20>>2];if(h>>>0>e>>>0&(f|0)>=(d|0)|(d|0)<(f|0)){b=E[e+D[c>>2]|0];i=e+1|0;f=i?d:d+1|0;D[c+16>>2]=i;D[c+20>>2]=f;D[a+4>>2]=b}return e>>>0>>0&(d|0)<=(g|0)|(d|0)<(g|0)}function Dg(a){a=a|0;var b=0,c=0,d=0;D[a>>2]=10032;b=D[a+20>>2];if(b){D[a+24>>2]=b;ma(b)}d=D[a+8>>2];if(d){c=D[a+12>>2];b=d;if((c|0)!=(b|0)){while(1){c=c-4|0;b=D[c>>2];D[c>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}if((c|0)!=(d|0)){continue}break}b=D[a+8>>2]}D[a+12>>2]=d;ma(b)}ma(a)}function Na(a,b,c){var d=0;if(!c){return D[a+4>>2]==D[b+4>>2]}if((a|0)==(b|0)){return 1}d=D[a+4>>2];a=E[d|0];c=D[b+4>>2];b=E[c|0];a:{if(!a|(b|0)!=(a|0)){break a}while(1){b=E[c+1|0];a=E[d+1|0];if(!a){break a}c=c+1|0;d=d+1|0;if((a|0)==(b|0)){continue}break}}return(a|0)==(b|0)}function Cf(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=D[b+12>>2];b=D[b+8>>2];a=0;a:{if((d|0)==(b|0)){break a}a=d-b>>2;d=a>>>0>1?a:1;a=0;b:{while(1){e=D[b+(a<<2)>>2];if(D[e+60>>2]==(c|0)){break b}a=a+1|0;if((d|0)!=(a|0)){continue}break}a=0;break a}a=(a|0)==-1?0:e}return a|0}function Yg(a){a=a|0;var b=0;D[a>>2]=9136;b=D[a+88>>2];if(b){D[a+92>>2]=b;ma(b)}b=D[a+72>>2];if(b){D[a+76>>2]=b;ma(b)}b=D[a+60>>2];if(b){D[a- -64>>2]=b;ma(b)}b=D[a+48>>2];if(b){D[a+52>>2]=b;ma(b)}D[a>>2]=9372;b=D[a+36>>2];if(b){ma(b)}b=D[a+24>>2];if(b){ma(b)}return a|0}function Rc(a,b){var c=0,d=0,e=0;D[a+8>>2]=0;D[a>>2]=0;D[a+4>>2]=0;a:{c=D[b+4>>2];d=D[b>>2];b:{if((c|0)==(d|0)){a=c;break b}c=c-d|0;if((c|0)<0){break a}d=c;e=na(c);c=qa(e,0,c);d=d+c|0;D[a+8>>2]=d;D[a+4>>2]=d;D[a>>2]=c;c=D[b>>2];a=D[b+4>>2]}oa(e,c,a-c|0);return}pa();T()}function Ad(a){var b=0,c=0,d=0,e=0;c=D[a+4>>2];d=D[a>>2];if((c|0)!=(d|0)){while(1){e=c-144|0;b=D[e+132>>2];if(b){D[c-8>>2]=b;ma(b)}b=D[c-28>>2];if(b){D[c-24>>2]=b;ma(b)}b=D[c-40>>2];if(b){D[c-36>>2]=b;ma(b)}Gb(c-140|0);c=e;if((d|0)!=(c|0)){continue}break}}D[a+4>>2]=d}function Tg(a){a=a|0;var b=0;D[a>>2]=9136;b=D[a+88>>2];if(b){D[a+92>>2]=b;ma(b)}b=D[a+72>>2];if(b){D[a+76>>2]=b;ma(b)}b=D[a+60>>2];if(b){D[a- -64>>2]=b;ma(b)}b=D[a+48>>2];if(b){D[a+52>>2]=b;ma(b)}D[a>>2]=9372;b=D[a+36>>2];if(b){ma(b)}b=D[a+24>>2];if(b){ma(b)}ma(a)}function Ib(a,b){var c=0,d=0,e=0,f=0;a:{c=D[a>>2];b:{if(D[a+8>>2]-c>>2>>>0>=b>>>0){break b}if(b>>>0>=1073741824){break a}d=D[a+4>>2];e=b<<2;b=na(e);e=b+e|0;d=d-c|0;f=d+b|0;if((d|0)>0){oa(b,c,d)}D[a+8>>2]=e;D[a+4>>2]=f;D[a>>2]=b;if(!c){break b}ma(c)}return}pa();T()}function cb(a){var b=0;if(a){b=D[a+76>>2];if(b){D[a+80>>2]=b;ma(b)}b=D[a- -64>>2];if(b){D[a+68>>2]=b;ma(b)}b=D[a+48>>2];if(b){D[a+52>>2]=b;ma(b)}b=D[a+24>>2];if(b){D[a+28>>2]=b;ma(b)}b=D[a+12>>2];if(b){D[a+16>>2]=b;ma(b)}b=D[a>>2];if(b){D[a+4>>2]=b;ma(b)}ma(a)}}function Gb(a){var b=0;b=D[a+84>>2];if(b){D[a+88>>2]=b;ma(b)}b=D[a+72>>2];if(b){D[a+76>>2]=b;ma(b)}b=D[a+52>>2];if(b){D[a+56>>2]=b;ma(b)}b=D[a+40>>2];if(b){D[a+44>>2]=b;ma(b)}b=D[a+28>>2];if(b){D[a+32>>2]=b;ma(b)}b=D[a+12>>2];if(b){ma(b)}a=D[a>>2];if(a){ma(a)}}function Jc(a,b,c){var d=0,e=0,f=0,g=0,h=0;f=$-16|0;$=f;d=$-16|0;$=d;b=b-a>>2;while(1){if(b){D[d+12>>2]=a;e=b>>>1|0;D[d+12>>2]=D[d+12>>2]+(e<<2);h=(e^-1)+b|0;b=e;e=D[d+12>>2];g=G[e>>2]>2];b=g?h:b;a=g?e+4|0:a;continue}break}$=d+16|0;$=f+16|0;return a}function ta(a,b,c){var d=0,e=0;a:{b:{if(c>>>0<11){d=a;B[d+11|0]=c;break b}if(c>>>0>4294967279){break a}if(c>>>0>=11){e=c+16&-16;d=e-1|0;d=(d|0)==11?e:d}else{d=10}e=d+1|0;d=na(e);D[a>>2]=d;D[a+8>>2]=e|-2147483648;D[a+4>>2]=c}gb(d,b,c+1|0);return}Ca();T()}function gd(a,b){var c=0,d=0;d=na(40);D[d>>2]=-1;c=d+8|0;D[c+16>>2]=0;D[c+20>>2]=0;D[c+8>>2]=0;D[c>>2]=0;D[c+4>>2]=0;D[c+24>>2]=0;D[c+28>>2]=0;ba[D[D[a>>2]+16>>2]](a,d);a=D[b+88>>2];D[b+88>>2]=d;if(a){b=D[a+8>>2];if(b){D[a+12>>2]=b;ma(b)}ma(a)}return 1}function Ba(a){var b=0,c=0,d=0;b=a;a:{if(b&3){while(1){if(!E[b|0]){break a}b=b+1|0;if(b&3){continue}break}}while(1){c=b;b=b+4|0;d=D[c>>2];if(!((d^-1)&d-16843009&-2139062144)){continue}break}while(1){b=c;c=b+1|0;if(E[b|0]){continue}break}}return b-a|0}function za(a){var b=0,c=0,d=0,e=0,f=0;d=E[a+12|0];c=D[a+8>>2];a:{if(c>>>0>4095){break a}b=D[a+4>>2];if((b|0)<=0){break a}b=b-1|0;D[a+4>>2]=b;c=E[b+D[a>>2]|0]|c<<8}d=0-d&255;b=J(d,c>>>8|0);e=c&255;f=e>>>0>>0;D[a+8>>2]=f?b+e|0:c-(b+d|0)|0;return f}function wc(a,b){D[a+4>>2]=0;D[a+8>>2]=0;D[a>>2]=1776;D[a+12>>2]=0;D[a+16>>2]=0;D[a+20>>2]=0;D[a+24>>2]=0;D[a+28>>2]=0;D[a+32>>2]=0;D[a+36>>2]=0;D[a+40>>2]=0;D[a>>2]=2016;D[a+60>>2]=b;D[a+44>>2]=0;D[a+48>>2]=0;D[a+52>>2]=0;D[a+56>>2]=0;return a}function Kf(a){a=a|0;var b=0,c=0,d=0;if(a){if(B[a+27|0]<0){ma(D[a+16>>2])}c=D[a>>2];if(c){d=c;b=D[a+4>>2];if((b|0)!=(c|0)){while(1){b=b-12|0;if(B[b+11|0]<0){ma(D[b>>2])}if((c|0)!=(b|0)){continue}break}d=D[a>>2]}D[a+4>>2]=c;ma(d)}ma(a)}}function Aa(a){a=a|0;var b=0,c=0;if(a){b=D[a+88>>2];D[a+88>>2]=0;if(b){c=D[b+8>>2];if(c){D[b+12>>2]=c;ma(c)}ma(b)}b=D[a+68>>2];if(b){D[a+72>>2]=b;ma(b)}b=D[a+64>>2];D[a+64>>2]=0;if(b){c=D[b>>2];if(c){D[b+4>>2]=c;ma(c)}ma(b)}ma(a)}}function zf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;b=D[b+96>>2];a=na(12);b=b+J(c,12)|0;c=D[b+4>>2];D[a>>2]=D[b>>2];D[a+4>>2]=c;D[a+8>>2]=D[b+8>>2];b=D[d>>2];if(b){D[d+4>>2]=b;ma(b)}D[d>>2]=a;a=a+12|0;D[d+8>>2]=a;D[d+4>>2]=a;return 1}function wh(a){a=a|0;var b=0;D[a+24>>2]=1624;D[a>>2]=7948;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}D[a>>2]=2136;b=D[a+20>>2];D[a+20>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}D[a>>2]=1920;b=D[a+16>>2];D[a+16>>2]=0;if(b){Aa(b)}return a|0}function Fb(a,b){var c=0,d=0,e=0;c=Ba(b);if(c>>>0<4294967280){a:{b:{if(c>>>0>=11){e=c+16&-16;d=na(e);D[a+8>>2]=e|-2147483648;D[a>>2]=d;D[a+4>>2]=c;break b}B[a+11|0]=c;d=a;if(!c){break a}}oa(d,b,c)}B[c+d|0]=0;return a}Ca();T()}function gi(a,b,c,d){var e=0,f=0,g=0,h=0;f=b^d;g=f>>31;e=b>>31;a=a^e;h=a-e|0;e=(b^e)-((a>>>0>>0)+e|0)|0;a=d>>31;b=c^a;f=f>>31;a=hi(h,e,b-a|0,(a^d)-((a>>>0>b>>>0)+a|0)|0)^f;b=a-f|0;aa=(g^aa)-((a>>>0>>0)+g|0)|0;return b}function vh(a){a=a|0;var b=0;D[a+24>>2]=1624;D[a>>2]=7948;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}D[a>>2]=2136;b=D[a+20>>2];D[a+20>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}D[a>>2]=1920;b=D[a+16>>2];D[a+16>>2]=0;if(b){Aa(b)}ma(a)}function tb(a,b,c){var d=0,e=0,f=0;e=$-16|0;$=e;d=D[a+8>>2]&2147483647;a:{if(d>>>0>c>>>0){d=D[a>>2];D[a+4>>2]=c;gb(d,b,c);B[e+15|0]=0;B[c+d|0]=E[e+15|0];break a}f=a;a=D[a+4>>2];Ec(f,d-1|0,(c-d|0)+1|0,a,a,c,b)}$=e+16|0}function fi(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0;e=c>>>16|0;f=a>>>16|0;j=J(e,f);g=c&65535;h=a&65535;i=J(g,h);f=(i>>>16|0)+J(f,g)|0;e=(f&65535)+J(e,h)|0;aa=(J(b,c)+j|0)+J(a,d)+(f>>>16)+(e>>>16)|0;return i&65535|e<<16}function te(a,b){a=a|0;b=b|0;var c=0,d=0;c=$-16|0;$=c;a=D[a+4>>2];a:{if((a|0)==-1){break a}B[c+15|0]=a;d=D[b+20>>2];if(!!D[b+16>>2]&(d|0)>=0|(d|0)>0){break a}rb(b,D[b+4>>2],c+15|0,c+16|0)}$=c+16|0;return(a|0)!=-1|0}function Cc(a,b,c){var d=0;d=D[a+16>>2];if(!d){D[a+36>>2]=1;D[a+24>>2]=c;D[a+16>>2]=b;return}a:{if((b|0)==(d|0)){if(D[a+24>>2]!=2){break a}D[a+24>>2]=c;return}B[a+54|0]=1;D[a+24>>2]=2;D[a+36>>2]=D[a+36>>2]+1}}function rg(){var a=0;a=mb(na(96));D[a+64>>2]=0;D[a+68>>2]=0;D[a+88>>2]=0;D[a+72>>2]=0;D[a+76>>2]=0;B[a+77|0]=0;B[a+78|0]=0;B[a+79|0]=0;B[a+80|0]=0;B[a+81|0]=0;B[a+82|0]=0;B[a+83|0]=0;B[a+84|0]=0;return a|0}function fh(a,b){a=a|0;b=b|0;var c=0,d=0;D[b>>2]=2;c=D[b+8>>2];d=D[b+12>>2]-c|0;if(d>>>0<=4294967291){Eb(b+8|0,d+4|0);c=D[b+8>>2]}b=c+d|0;a=D[a+4>>2];B[b|0]=a;B[b+1|0]=a>>>8;B[b+2|0]=a>>>16;B[b+3|0]=a>>>24}function yg(a){a=a|0;var b=0,c=0,d=0;b=D[a+8>>2];d=D[a+12>>2];if((b|0)==(d|0)){return 1}while(1){c=D[b>>2];c=ba[D[D[c>>2]+16>>2]](c,D[a+32>>2])|0;if(c){b=b+4|0;if((d|0)!=(b|0)){continue}}break}return c|0}function ce(a){a=a|0;var b=0;D[a>>2]=3016;b=D[a+96>>2];if(b){ma(b)}b=D[a+84>>2];if(b){ma(b)}b=D[a+72>>2];if(b){ma(b)}b=D[a+60>>2];if(b){ma(b)}D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}return a|0}function _h(a){a=a|0;var b=0;D[a>>2]=4580;b=D[a+96>>2];if(b){ma(b)}b=D[a+84>>2];if(b){ma(b)}b=D[a+72>>2];if(b){ma(b)}b=D[a+60>>2];if(b){ma(b)}D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}return a|0}function Nc(a,b){var c=0,d=0;c=D[a+8>>2];a=D[a+12>>2];if((c|0)!=(a|0)){a=a-c>>2;d=a>>>0>1?a:1;a=0;while(1){if(D[D[(a<<2)+c>>2]+60>>2]==(b|0)){return a}a=a+1|0;if((d|0)!=(a|0)){continue}break}}return-1}function Te(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;Lc(a,b);a:{if((b|0)<0){break a}d=D[a+88>>2];c=D[a+84>>2];if(d-c>>2<=(b|0)){break a}b=c+(b<<2)|0;c=b+4|0;e=d-c|0;if((c|0)!=(d|0)){Ra(b,c,e)}D[a+88>>2]=b+e}}function be(a){a=a|0;var b=0;D[a>>2]=3016;b=D[a+96>>2];if(b){ma(b)}b=D[a+84>>2];if(b){ma(b)}b=D[a+72>>2];if(b){ma(b)}b=D[a+60>>2];if(b){ma(b)}D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}ma(a)}function Zh(a){a=a|0;var b=0;D[a>>2]=4580;b=D[a+96>>2];if(b){ma(b)}b=D[a+84>>2];if(b){ma(b)}b=D[a+72>>2];if(b){ma(b)}b=D[a+60>>2];if(b){ma(b)}D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}ma(a)}function Qc(a,b,c){var d=0,e=0;d=a+4|0;a=bb(a,b);if((d|0)==(a|0)){return 0}b=D[a+32>>2];d=D[a+28>>2];if((b|0)!=(d|0)){Rb(c,b-d|0);e=Sb(c);c=D[a+28>>2];oa(e,c,D[a+32>>2]-c|0)}return(b|0)!=(d|0)}function Hd(a){D[a+40>>2]=0;D[a+4>>2]=0;D[a+8>>2]=0;D[a>>2]=10032;D[a+12>>2]=0;D[a+16>>2]=0;D[a+20>>2]=0;D[a+24>>2]=0;D[a+28>>2]=0;D[a+32>>2]=0;C[a+36>>1]=0;D[a+44>>2]=0;D[a>>2]=8080;return a}function mb(a){D[a+8>>2]=0;D[a+12>>2]=0;D[a>>2]=0;D[a+40>>2]=0;D[a+44>>2]=0;D[a+28>>2]=9;B[a+24|0]=1;D[a+56>>2]=-1;D[a+60>>2]=0;D[a+16>>2]=0;D[a+20>>2]=0;D[a+48>>2]=0;D[a+52>>2]=0;return a}function ec(a,b,c){var d=0;a:{if(b){b=0;if(!jd(1,c,a)){break a}}B[a+36|0]=1;D[a+32>>2]=0;b=D[a+16>>2];c=b+D[a>>2]|0;D[a+24>>2]=c;d=a;a=D[a+8>>2];D[d+28>>2]=c+(a-b|0);b=1}return b}function le(a,b){a=a|0;b=b|0;var c=0,d=0;d=D[a+16>>2];c=0;a:{if(D[a+20>>2]-d>>2<=(b|0)){break a}b=D[(b<<2)+d>>2];c=0;if((b|0)<0){break a}c=eb(D[D[a+36>>2]+(b<<2)>>2])}return c|0}function _a(a){var b=0,c=0;b=D[2909];c=a+3&-4;a=b+c|0;a:{if(a>>>0<=b>>>0?c:0){break a}if(a>>>0>ca()<<16>>>0){if(!(Z(a|0)|0)){break a}}D[2909]=a;return b}D[2935]=48;return-1}function Jf(){var a=0;a=na(40);D[a+4>>2]=0;D[a+8>>2]=0;D[a>>2]=a+4;D[a+24>>2]=0;D[a+28>>2]=0;D[a+12>>2]=a+16;D[a+16>>2]=0;D[a+20>>2]=0;D[a+32>>2]=0;D[a+36>>2]=0;return a|0}function Ae(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=D[a+8>>2];a:{if(B[d+24|0]<=0){break a}if(!Zb(d,D[b+4>>2]-D[b>>2]>>2)){break a}e=ba[D[D[a>>2]+32>>2]](a,b,c)|0}return e|0}function sb(a,b,c){var d=0,e=0;d=$-16|0;$=d;a:{if(c>>>0<=10){B[a+11|0]=c;gb(a,b,c);B[d+15|0]=0;B[a+c|0]=E[d+15|0];break a}e=a;a=E[a+11|0];Ec(e,10,c-10|0,a,a,c,b)}$=d+16|0}function Ph(a,b,c){a=a|0;b=b|0;c=c|0;var d=0;D[a+4>>2]=b;b=D[D[D[b+4>>2]+8>>2]+(c<<2)>>2];D[a+12>>2]=c;D[a+8>>2]=b;a=D[a+8>>2];if(E[a+24|0]==3){d=D[a+28>>2]==9}return d|0}function Pg(a){a=a|0;var b=0;D[a+8>>2]=9556;D[a>>2]=9392;b=D[a+56>>2];if(b){D[a+60>>2]=b;ma(b)}D[a+8>>2]=9372;b=D[a+44>>2];if(b){ma(b)}b=D[a+32>>2];if(b){ma(b)}return a|0}function Kg(a){a=a|0;var b=0;D[a+8>>2]=8624;D[a>>2]=9684;b=D[a+56>>2];if(b){D[a+60>>2]=b;ma(b)}D[a+8>>2]=8876;b=D[a+44>>2];if(b){ma(b)}b=D[a+32>>2];if(b){ma(b)}return a|0}function Fa(a,b){if(b){Fa(a,D[b>>2]);Fa(a,D[b+4>>2]);a=D[b+28>>2];D[b+28>>2]=0;if(a){Fa(a+12|0,D[a+16>>2]);Ea(a,D[a+4>>2]);ma(a)}if(B[b+27|0]<0){ma(D[b+16>>2])}ma(b)}}function Bh(a,b,c){a=a|0;b=b|0;c=c|0;var d=0;D[a+4>>2]=b;d=D[D[D[b+4>>2]+8>>2]+(c<<2)>>2];D[a+12>>2]=c;D[a+8>>2]=d;return D[D[D[D[b+4>>2]+8>>2]+(c<<2)>>2]+28>>2]==9|0}function Og(a){a=a|0;var b=0;D[a+8>>2]=9556;D[a>>2]=9392;b=D[a+56>>2];if(b){D[a+60>>2]=b;ma(b)}D[a+8>>2]=9372;b=D[a+44>>2];if(b){ma(b)}b=D[a+32>>2];if(b){ma(b)}ma(a)}function Ig(a){a=a|0;var b=0;D[a+8>>2]=8624;D[a>>2]=9684;b=D[a+56>>2];if(b){D[a+60>>2]=b;ma(b)}D[a+8>>2]=8876;b=D[a+44>>2];if(b){ma(b)}b=D[a+32>>2];if(b){ma(b)}ma(a)}function Fc(a,b){var c=0,d=0,e=0,f=0;D[a>>2]=11356;D[a>>2]=11468;c=Ba(b);d=na(c+13|0);D[d+8>>2]=0;D[d+4>>2]=c;D[d>>2]=c;e=a,f=oa(d+12|0,b,c+1|0),D[e+4>>2]=f;return a}function Qe(a,b){a=a|0;b=b|0;var c=0;a:{if(!(ba[D[D[a>>2]+36>>2]](a,b)|0)){break a}if(!(ba[D[D[a>>2]+40>>2]](a,b)|0)){break a}c=ba[D[D[a>>2]+44>>2]](a)|0}return c|0}function Xd(a){a=a|0;var b=0;a:{if(!D[a- -64>>2]|!D[a+68>>2]|(!D[a+44>>2]|!D[a+48>>2])){break a}if(!D[a+52>>2]|!D[a+56>>2]){break a}b=D[a+92>>2]!=-1}return b|0}function uc(a){a=a|0;var b=0;D[a>>2]=2136;b=D[a+20>>2];D[a+20>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}D[a>>2]=1920;b=D[a+16>>2];D[a+16>>2]=0;if(b){Aa(b)}return a|0}function ei(a,b){a=a|0;b=b|0;var c=0;b=D[b+88>>2];if(!(!b|D[b>>2]!=2)){c=a;a=D[b+8>>2];D[c+4>>2]=E[a|0]|E[a+1|0]<<8|(E[a+2|0]<<16|E[a+3|0]<<24);c=1}return c|0}function Rd(a){a=a|0;var b=0;a:{if(!D[a+48>>2]|!D[a+52>>2]|(!D[a+28>>2]|!D[a+32>>2])){break a}if(!D[a+36>>2]|!D[a+40>>2]){break a}b=D[a+76>>2]!=-1}return b|0}function tc(a){a=a|0;var b=0;D[a>>2]=2136;b=D[a+20>>2];D[a+20>>2]=0;if(b){ba[D[D[b>>2]+4>>2]](b)}D[a>>2]=1920;b=D[a+16>>2];D[a+16>>2]=0;if(b){Aa(b)}ma(a)}function Qg(a){a=a|0;var b=0;D[a>>2]=9556;b=D[a+48>>2];if(b){D[a+52>>2]=b;ma(b)}D[a>>2]=9372;b=D[a+36>>2];if(b){ma(b)}b=D[a+24>>2];if(b){ma(b)}return a|0}function Bd(a){a=a|0;var b=0;D[a>>2]=8624;b=D[a+48>>2];if(b){D[a+52>>2]=b;ma(b)}D[a>>2]=8876;b=D[a+36>>2];if(b){ma(b)}b=D[a+24>>2];if(b){ma(b)}return a|0}function ug(){var a=0,b=0;b=na(40);D[b>>2]=-1;a=b+8|0;D[a+16>>2]=0;D[a+20>>2]=0;D[a+8>>2]=0;D[a>>2]=0;D[a+4>>2]=0;D[a+24>>2]=0;D[a+28>>2]=0;return b|0}function bh(a){a=a|0;var b=0;D[a>>2]=8624;b=D[a+48>>2];if(b){D[a+52>>2]=b;ma(b)}D[a>>2]=8876;b=D[a+36>>2];if(b){ma(b)}b=D[a+24>>2];if(b){ma(b)}ma(a)}function Lg(a){a=a|0;var b=0;D[a>>2]=9556;b=D[a+48>>2];if(b){D[a+52>>2]=b;ma(b)}D[a>>2]=9372;b=D[a+36>>2];if(b){ma(b)}b=D[a+24>>2];if(b){ma(b)}ma(a)}function La(a){D[a+8>>2]=0;D[a+12>>2]=0;D[a>>2]=0;D[a+16>>2]=0;D[a+20>>2]=0;D[a+32>>2]=0;D[a+24>>2]=0;D[a+28>>2]=0;C[a+38>>1]=0;B[a+36|0]=0;return a}function Ie(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;if(Na(a,D[b+8>>2],f)){Bc(b,c,d,e);return}a=D[a+8>>2];ba[D[D[a>>2]+20>>2]](a,b,c,d,e,f)}function Ah(a,b,c){a=a|0;b=b|0;c=c|0;a:{if(E[D[a+4>>2]+36|0]>=2){b=0;if(!(ba[D[D[a>>2]+52>>2]](a)|0)){break a}}b=gd(a+24|0,D[a+16>>2])}return b|0}function eg(){var a=0;a=Pc(na(108));D[a+84>>2]=0;D[a+88>>2]=0;D[a>>2]=10240;D[a+92>>2]=0;D[a+96>>2]=0;D[a+100>>2]=0;D[a+104>>2]=0;return a|0}function Oc(a,b){var c=0;c=-1;a:{if((b|0)==-1|(b|0)>4){break a}b=J(b,12)+a|0;a=D[b+20>>2];if((D[b+24>>2]-a|0)<=0){break a}c=D[a>>2]}return c}function $b(a,b,c,d,e,f,g){D[a>>2]=0;D[a+56>>2]=b;D[a+48>>2]=0;D[a+52>>2]=0;D[a+40>>2]=f;D[a+44>>2]=g;B[a+32|0]=e;D[a+28>>2]=d;B[a+24|0]=c}function Oh(a,b,c){a=a|0;b=b|0;c=c|0;a:{if(E[D[a+4>>2]+36|0]>=2){b=0;if(!sc(a+24|0,eb(a),c)){break a}}b=gd(a+24|0,D[a+16>>2])}return b|0}function We(a){a=a|0;var b=0;D[a>>2]=10240;b=D[a+96>>2];if(b){D[a+100>>2]=b;ma(b)}b=D[a+84>>2];if(b){D[a+88>>2]=b;ma(b)}return ub(a)|0}function Sb(a){var b=0;if(E[a+11|0]>>>7|0){b=D[a+4>>2]}else{b=E[a+11|0]}if(!b){qc(1222);T()}if(E[a+11|0]>>>7|0){a=D[a>>2]}return a}function Ve(a){a=a|0;var b=0;D[a>>2]=10240;b=D[a+96>>2];if(b){D[a+100>>2]=b;ma(b)}b=D[a+84>>2];if(b){D[a+88>>2]=b;ma(b)}ma(ub(a))}function _d(a){a=a|0;var b=0;D[a>>2]=3264;b=D[a+76>>2];if(b){ma(b)}D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}return a|0}function Wh(a){a=a|0;var b=0;D[a>>2]=4816;b=D[a+76>>2];if(b){ma(b)}D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}return a|0}function Ea(a,b){if(b){Ea(a,D[b>>2]);Ea(a,D[b+4>>2]);a=D[b+28>>2];if(a){D[b+32>>2]=a;ma(a)}if(B[b+27|0]<0){ma(D[b+16>>2])}ma(b)}}function Sf(){var a=0;a=na(28);D[a>>2]=0;D[a+4>>2]=0;D[a+24>>2]=0;D[a+16>>2]=0;D[a+20>>2]=0;D[a+8>>2]=0;D[a+12>>2]=0;return a|0}function Re(a){a=a|0;var b=0;D[a>>2]=1776;b=D[a+16>>2];if(b){D[a+20>>2]=b;ma(b)}b=D[a+4>>2];if(b){D[a+8>>2]=b;ma(b)}return a|0}function bg(){var a=0,b=0;a=na(24);D[a+4>>2]=0;D[a+8>>2]=0;b=a+16|0;D[b>>2]=0;D[b+4>>2]=0;D[a>>2]=a+4;D[a+12>>2]=b;return a|0}function Me(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;if(Na(a,D[b+8>>2],0)){Cc(b,c,d);return}a=D[a+8>>2];ba[D[D[a>>2]+28>>2]](a,b,c,d)}function Zd(a){a=a|0;var b=0;D[a>>2]=3264;b=D[a+76>>2];if(b){ma(b)}D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}ma(a)}function Vh(a){a=a|0;var b=0;D[a>>2]=4816;b=D[a+76>>2];if(b){ma(b)}D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}ma(a)}function na(a){var b=0;a=a?a:1;a:{while(1){b=Ic(a);if(b){break a}b=D[3060];if(b){ba[b|0]();continue}break}W();T()}return b}function kb(a,b){if(b){kb(a,D[b>>2]);kb(a,D[b+4>>2]);if(B[b+39|0]<0){ma(D[b+28>>2])}if(B[b+27|0]<0){ma(D[b+16>>2])}ma(b)}}function Ac(a){a=a|0;var b=0,c=0;D[a>>2]=11468;b=D[a+4>>2]-12|0;c=D[b+8>>2]-1|0;D[b+8>>2]=c;if((c|0)<0){ma(b)}return a|0}function jg(){var a=0;a=na(24);D[a+8>>2]=0;D[a+12>>2]=0;D[a+4>>2]=-1;D[a>>2]=1624;D[a+16>>2]=0;D[a+20>>2]=0;return a|0}function yc(a,b,c){a=a|0;b=b|0;c=c|0;D[a+4>>2]=b;b=D[D[D[b+4>>2]+8>>2]+(c<<2)>>2];D[a+12>>2]=c;D[a+8>>2]=b;return 1}function nc(a){a=a|0;var b=0;if(!(!D[a+60>>2]|!D[a+44>>2]|(!D[a+48>>2]|!D[a+52>>2]))){b=D[a+56>>2]!=0}return b|0}function ci(a){a=a|0;var b=0;D[a>>2]=3500;D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}return a|0}function Th(a){a=a|0;var b=0;D[a>>2]=5040;D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}return a|0}function jf(a){a=a|0;if(a){if(B[a+39|0]<0){ma(D[a+28>>2])}Yb(a+12|0,D[a+16>>2]);kb(a,D[a+4>>2]);ma(a)}}function ah(a){a=a|0;var b=0;D[a>>2]=8876;b=D[a+36>>2];if(b){ma(b)}b=D[a+24>>2];if(b){ma(b)}return a|0}function Sg(a){a=a|0;var b=0;D[a>>2]=9372;b=D[a+36>>2];if(b){ma(b)}b=D[a+24>>2];if(b){ma(b)}return a|0}function qb(a){a=a|0;var b=0;if(!(!D[a+52>>2]|(!D[a+44>>2]|!D[a+48>>2]))){b=D[a+56>>2]!=0}return b|0}function mc(a,b){a=a|0;b=b|0;var c=0;if(!(D[b+56>>2]|!b|E[b+24|0]!=3)){D[a+60>>2]=b;c=1}return c|0}function bi(a){a=a|0;var b=0;D[a>>2]=3500;D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}ma(a)}function Sh(a){a=a|0;var b=0;D[a>>2]=5040;D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}ma(a)}function vg(a,b,c){a=a|0;b=b|0;c=c|0;D[a+16>>2]=0;D[a+20>>2]=0;D[a>>2]=b;D[a+8>>2]=c;D[a+12>>2]=0}function _g(a){a=a|0;var b=0;D[a>>2]=8876;b=D[a+36>>2];if(b){ma(b)}b=D[a+24>>2];if(b){ma(b)}ma(a)}function Wd(a,b){a=a|0;b=b|0;var c=0;if(!(D[b+56>>2]|E[b+24|0]!=3)){D[a- -64>>2]=b;c=1}return c|0}function Rg(a){a=a|0;var b=0;D[a>>2]=9372;b=D[a+36>>2];if(b){ma(b)}b=D[a+24>>2];if(b){ma(b)}ma(a)}function Qd(a,b){a=a|0;b=b|0;var c=0;if(!(D[b+56>>2]|E[b+24|0]!=3)){D[a+48>>2]=b;c=1}return c|0}function He(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;if(Na(a,D[b+8>>2],f)){Bc(b,c,d,e)}}function sa(){var a=0;a=Y(4)|0;D[a>>2]=11356;D[a>>2]=11316;D[a>>2]=11336;X(a|0,11448,14);T()}function we(a){a=a|0;var b=0;D[a>>2]=1920;b=D[a+16>>2];D[a+16>>2]=0;if(b){Aa(b)}return a|0}function fe(a){a=a|0;var b=0;D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}return a|0}function yh(a){a=a|0;var b=0;b=eb(a);return nd(a+24|0,b?b:D[a+8>>2],D[D[a+4>>2]+32>>2])|0}function Jg(a){a=a|0;var b=0;D[a>>2]=1624;b=D[a+8>>2];if(b){D[a+12>>2]=b;ma(b)}return a|0}function ve(a){a=a|0;var b=0;D[a>>2]=1920;b=D[a+16>>2];D[a+16>>2]=0;if(b){Aa(b)}ma(a)}function Ob(a){a=a|0;var b=0;D[a>>2]=2960;b=D[a+32>>2];if(b){D[a+36>>2]=b;ma(b)}ma(a)}function Bg(a){a=a|0;var b=0;D[a>>2]=1624;b=D[a+8>>2];if(b){D[a+12>>2]=b;ma(b)}ma(a)}function ke(a,b){a=a|0;b=b|0;return ba[D[D[a>>2]+48>>2]](a,D[b+4>>2]-D[b>>2]>>2)|0}function Yb(a,b){if(b){Yb(a,D[b>>2]);Yb(a,D[b+4>>2]);kb(b+20|0,D[b+24>>2]);ma(b)}}function th(a){a=a|0;if(!D[a+44>>2]){return 0}return ba[D[D[a>>2]+48>>2]](a)|0}function tg(a){a=a|0;var b=0;if(a){b=D[a+8>>2];if(b){D[a+12>>2]=b;ma(b)}ma(a)}}function ii(a){var b=0;while(1){if(a){a=a-1&a;b=b+1|0;continue}break}return b}function Ne(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;if(Na(a,D[b+8>>2],0)){Cc(b,c,d)}}function rh(a,b){a=a|0;b=b|0;a=D[a+48>>2];return ba[D[D[a>>2]+20>>2]](a,b)|0}function kh(a,b){a=a|0;b=b|0;a=D[a+48>>2];return ba[D[D[a>>2]+12>>2]](a,b)|0}function jh(a,b){a=a|0;b=b|0;a=D[a+48>>2];return ba[D[D[a>>2]+16>>2]](a,b)|0}function ab(){var a=0;a=na(12);D[a>>2]=0;D[a+4>>2]=0;D[a+8>>2]=0;return a|0}function $a(a){a=a|0;var b=0;if(a){b=D[a>>2];if(b){D[a+4>>2]=b;ma(b)}ma(a)}}function ji(a){var b=0;b=a&31;a=0-a&31;return(-1>>>b&-2)<>>a}function hf(a,b,c){a=a|0;b=b|0;c=c|0;D[a+32>>2]=c;D[a+28>>2]=b;return 1}function ag(a){a=a|0;if(a){Fa(a+12|0,D[a+16>>2]);Ea(a,D[a+4>>2]);ma(a)}}function Lb(a,b){a=a|0;b=b|0;if(b>>>0<=1){D[a+28>>2]=b}return b>>>0<2|0}function Cg(a,b){a=a|0;b=b|0;B[b+84|0]=1;D[b+72>>2]=D[b+68>>2];return 1}function ph(a){a=a|0;a=D[a+48>>2];return ba[D[D[a>>2]+24>>2]](a)|0}function oh(a){a=a|0;a=D[a+48>>2];return ba[D[D[a>>2]+28>>2]](a)|0}function lh(a){a=a|0;a=D[a+48>>2];return ba[D[D[a>>2]+36>>2]](a)|0}function gg(){var a=0;a=na(8);D[a+4>>2]=-1;D[a>>2]=1032;return a|0}function Df(a,b,c){a=a|0;b=b|0;c=c|0;return D[D[b+8>>2]+(c<<2)>>2]}function xh(a,b){a=a|0;b=b|0;return sd(a+24|0,eb(a),D[a+8>>2])|0}function Nh(a,b){a=a|0;b=b|0;return xc(a+24|0,eb(a),D[a+8>>2])|0}function zh(a,b){a=a|0;b=b|0;return ba[D[D[a>>2]+56>>2]](a,b)|0}function fd(a,b){a=a|0;b=b|0;return ba[D[D[a>>2]+12>>2]](a,b)|0}function Zf(a){a=a|0;if(a){if(B[a+15|0]<0){ma(D[a+4>>2])}ma(a)}}function Ge(a){a=a|0;if(!a){return 0}return(Dc(a,11164)|0)!=0|0}function Be(a,b){a=a|0;b=b|0;D[a+12>>2]=-1;D[a+8>>2]=b;return 1}function qc(a){a=Fc(Y(8)|0,a);D[a>>2]=11568;X(a|0,11600,1);T()}function Od(a){a=Fc(Y(8)|0,a);D[a>>2]=11516;X(a|0,11548,1);T()}function ig(a,b){a=a|0;b=b|0;return K(H[D[a+8>>2]+(b<<2)>>2])}function Yf(a,b){a=a|0;b=b|0;return K(H[D[a>>2]+(b<<2)>>2])}function cg(a){a=a|0;return(D[a+100>>2]-D[a+96>>2]|0)/12|0}function _f(a){a=a|0;return(B[a+15|0]<0?D[a+4>>2]:a+4|0)|0}function Je(a,b){a=a|0;b=b|0;return D[D[a+4>>2]+(b<<2)>>2]}function bd(a,b){a=a|0;b=b|0;return D[D[a>>2]+(b<<2)>>2]}function Uf(a,b){a=a|0;b=b|0;return C[D[a>>2]+(b<<1)>>1]}function Tf(a,b){a=a|0;b=b|0;return F[D[a>>2]+(b<<1)>>1]}function Sd(a,b,c){a=a|0;b=b|0;c=c|0;return vc(a,b,c)|0}function Gf(a,b,c){a=a|0;b=b|0;c=c|0;return Oc(b,c)|0}function ki(a){if(a){return 31-M(a-1^a)|0}return 32} +function Pc(a){D[a>>2]=10300;qa(a+4|0,0,80);return a}function ed(a){a=a|0;return D[a+12>>2]-D[a+8>>2]>>2}function xb(a){a=a|0;if(a){ba[D[D[a>>2]+4>>2]](a)}}function Wf(a,b){a=a|0;b=b|0;return B[D[a>>2]+b|0]}function Vf(a,b){a=a|0;b=b|0;return E[D[a>>2]+b|0]}function Ce(a){a=a|0;return D[a+8>>2]-D[a+4>>2]>>2}function Gd(a,b){a=a|0;b=b|0;D[a+4>>2]=b;return 1}function cd(a){a=a|0;return D[a+4>>2]-D[a>>2]>>1}function ac(a){a=a|0;return D[a+4>>2]-D[a>>2]>>2}function dd(a){a=a|0;return D[a+4>>2]-D[a>>2]|0}function ze(a,b,c){a=a|0;b=b|0;c=c|0;return 1}function xg(a,b){a=a|0;b=b|0;return B[b+24|0]}function ge(a){a=a|0;return B[D[a+8>>2]+24|0]}function Mf(a,b){a=a|0;b=b|0;return D[b+8>>2]}function Bf(a,b){a=a|0;b=b|0;return D[b+4>>2]}function Kh(a){a=a|0;D[a>>2]=5928;return a|0}function Fh(a){a=a|0;D[a>>2]=6932;return a|0}function hg(a){a=a|0;return K(H[a+20>>2])}function Jh(a){a=a|0;D[a>>2]=5928;ma(a)}function Eh(a){a=a|0;D[a>>2]=6932;ma(a)}function qg(a){a=a|0;return D[a+88>>2]}function pg(a){a=a|0;return D[a+56>>2]}function mg(a){a=a|0;return D[a+40>>2]}function lg(a){a=a|0;return D[a+48>>2]}function kg(a){a=a|0;return D[a+60>>2]}function fb(a){a=a|0;return D[a+28>>2]}function bc(a){a=a|0;return D[a+80>>2]}function zc(a,b){a=a|0;b=b|0;return 1}function td(a){a=a|0;return D[a+8>>2]}function rc(a,b){a=a|0;b=b|0;return-1}function og(a){a=a|0;return B[a+24|0]}function ng(a){a=a|0;return E[a+32|0]}function Za(a){a=a|0;return D[a+4>>2]}function Td(a,b){a=a|0;b=b|0;return 6}function Lh(a,b){a=a|0;b=b|0;return 2}function Ka(a,b){a=a|0;b=b|0;return 0}function $f(a){a=a|0;return!D[a>>2]|0}function hd(a){a=a|0;return D[a>>2]}function gb(a,b,c){if(c){oa(a,b,c)}}function wg(){return La(na(40))|0}function sg(){return mb(na(64))|0}function fg(){return Pc(na(84))|0}function cc(a){a=a|0;if(a){ma(a)}}function Qb(a){a=a|0;Ac(a);ma(a)}function Fe(a){a=a|0;return 1161}function Ee(a){a=a|0;return 1235}function De(a){a=a|0;return 1201}function Qa(a){a=a|0;return a|0}function dh(a){a=a|0;ma(rd(a))}function ch(a){a=a|0;ma(pd(a))}function Se(a){a=a|0;ma(ub(a))}function wa(a){a=a|0;return 1}function pc(a){a=a|0;return 4}function oc(a){a=a|0;return 5}function Ya(a){a=a|0;return 0}function Ud(a){a=a|0;return 2}function Nb(a){a=a|0;return 6}function Ih(a){a=a|0;return 3}function va(){qc(1154);T()}function pa(){Od(1154);T()}function Ja(a){a=a|0;ma(a)}function Ca(){Od(1222);T()}function Sa(a){a=a|0;T()}function bf(){return 10}function af(){return 11}function $e(){return 12}function wb(){return-1}function vb(){return 1}function lb(){return 0}function gf(){return 5}function ff(){return 6}function ef(){return 7}function df(){return 8}function cf(){return 9}function _e(){return-2}function _c(){return 4}function Ze(){return-3}function Ye(){return-4}function Xe(){return-5}function Xb(){return 2}function $c(){return 3}function Pe(){W();T()}function Hc(a){a=a|0}function Yd(){} +// EMSCRIPTEN_END_FUNCS +e=E;p(ka);var ba=c([null,Ac,Qa,Ja,Ud,ei,fh,Xf,xc,te,sc,dg,Td,Lh,Qa,Jg,Bg,wa,uh,ih,gh,sd,$g,nd,Td,xg,Re,Sa,hf,Zc,Qe,Je,Ce,fb,Ka,Pe,zc,wa,we,ve,yc,Be,Ae,ze,zc,ye,xe,ne,me,ue,se,le,re,qe,pe,oe,uc,tc,yc,ke,je,vc,ie,ge,he,fe,Ob,wa,Za,qb,Ya,rc,Ka,Ya,wa,ee,de,Sa,Sa,ce,be,pc,qb,ae,$d,_d,Zd,oc,nc,wa,Ka,mc,lc,di,ci,bi,Nb,Xd,wa,Ka,Wd,Vd,ai,Qa,Ja,Lb,fb,Mb,Sa,Ob,wa,qb,$h,Sa,_h,Zh,pc,qb,Yh,Xh,Wh,Vh,oc,nc,wa,Ka,mc,lc,Uh,Th,Sh,Nb,Xd,wa,Ka,Wd,Vd,Rh,Qa,Ja,Lb,fb,Kb,Sa,Ob,Ya,wa,Qh,uc,tc,Ph,Oh,Sd,Mh,Ud,Nh,Kh,Jh,Nb,Za,Rd,wa,Ka,Qd,wa,Ih,Pd,Hh,Qa,Ja,Lb,fb,Mb,Fh,Eh,Nb,Rd,wa,Ka,Qd,Pd,Dh,Qa,Ja,Lb,fb,Kb,Qa,Ja,Ya,wa,Ya,rc,Ka,Gh,Ch,wh,vh,Bh,Ah,Sd,zh,yh,xh,sh,Sa,wa,wa,th,zg,yg,wa,Ya,Ka,Ka,nh,mh,qh,rh,oh,lh,kh,jh,ph,rd,dh,Gd,Fd,Ed,Dd,hh,wa,Za,td,pd,ch,Gd,Fd,Ed,Dd,eh,wa,Za,td,Bd,bh,Cd,ah,_g,Xg,Wg,Vg,Ug,Yg,Tg,Zg,Sg,Rg,Pg,Og,Ng,Mg,Qg,Lg,Kg,Ig,Hg,Gg,Dg,Eg,Fg,Qa,Ja,Cg,Ag,Sa,Ya,wa,We,Ve,Ue,Te,ub,Se,Mc,Lc,Qa,Ja,Hc,Hc,Oe,He,Ke,Ne,Ja,Ie,Le,Me,Ja,Ee,Ja,De,Ja,Fe,Qb,Za,Qb,Qb]);function ca(){return A.byteLength/65536|0}function ha(ia){ia=ia|0;var da=ca()|0;var ea=da+ia|0;if(da=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_MEMORY/65536,"maximum":2147483648/65536})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_MEMORY=buffer.byteLength;updateGlobalBufferAndViews(buffer);var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function keepRuntimeAlive(){return noExitRuntime}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){{if(Module["onAbort"]){Module["onAbort"](what)}}what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}function isFileURI(filename){return filename.startsWith("file://")}var wasmBinaryFile;wasmBinaryFile="draco_decoder_gltf.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(file){try{if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}var binary=tryParseAsDataURI(file);if(binary){return binary}if(readBinary){return readBinary(file)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"&&!isFileURI(wasmBinaryFile)){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary(wasmBinaryFile)})}else{if(readAsync){return new Promise(function(resolve,reject){readAsync(wasmBinaryFile,function(response){resolve(new Uint8Array(response))},reject)})}}}return Promise.resolve().then(function(){return getBinary(wasmBinaryFile)})}function createWasm(){var info={"a":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;wasmTable=Module["asm"]["h"];addOnInit(Module["asm"]["g"]);removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(function(instance){return instance}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(wasmBinaryFile)&&!isFileURI(wasmBinaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiationResult,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(receiveInstantiationResult)})})}else{return instantiateArrayBuffer(receiveInstantiationResult)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync().catch(readyPromiseReject);return{}}function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback(Module);continue}var func=callback.func;if(typeof func=="number"){if(callback.arg===undefined){getWasmTableEntry(func)()}else{getWasmTableEntry(func)(callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var wasmTableMirror=[];function getWasmTableEntry(funcPtr){var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func}function ___cxa_allocate_exception(size){return _malloc(size+24)+24}function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24;this.set_type=function(type){HEAPU32[this.ptr+4>>2]=type};this.get_type=function(){return HEAPU32[this.ptr+4>>2]};this.set_destructor=function(destructor){HEAPU32[this.ptr+8>>2]=destructor};this.get_destructor=function(){return HEAPU32[this.ptr+8>>2]};this.set_refcount=function(refcount){HEAP32[this.ptr>>2]=refcount};this.set_caught=function(caught){caught=caught?1:0;HEAP8[this.ptr+12>>0]=caught};this.get_caught=function(){return HEAP8[this.ptr+12>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>0]=rethrown};this.get_rethrown=function(){return HEAP8[this.ptr+13>>0]!=0};this.init=function(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor);this.set_refcount(0);this.set_caught(false);this.set_rethrown(false)};this.add_ref=function(){var value=HEAP32[this.ptr>>2];HEAP32[this.ptr>>2]=value+1};this.release_ref=function(){var prev=HEAP32[this.ptr>>2];HEAP32[this.ptr>>2]=prev-1;return prev===1};this.set_adjusted_ptr=function(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr};this.get_adjusted_ptr=function(){return HEAPU32[this.ptr+16>>2]};this.get_exception_ptr=function(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return HEAPU32[this.excPtr>>2]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}var exceptionLast=0;var uncaughtExceptionCount=0;function ___cxa_throw(ptr,type,destructor){var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw ptr}function _abort(){abort("")}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function getHeapMax(){return 2147483648}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){var oldSize=HEAPU8.length;requestedSize=requestedSize>>>0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}let alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}var ASSERTIONS=false;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}function intArrayToString(array){var ret=[];for(var i=0;i255){if(ASSERTIONS){assert(false,"Character code "+chr+" ("+String.fromCharCode(chr)+") at offset "+i+" not in 0x00-0xFF.")}chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}var decodeBase64=typeof atob=="function"?atob:function(input){var keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{enc1=keyStr.indexOf(input.charAt(i++));enc2=keyStr.indexOf(input.charAt(i++));enc3=keyStr.indexOf(input.charAt(i++));enc4=keyStr.indexOf(input.charAt(i++));chr1=enc1<<2|enc2>>4;chr2=(enc2&15)<<4|enc3>>2;chr3=(enc3&3)<<6|enc4;output=output+String.fromCharCode(chr1);if(enc3!==64){output=output+String.fromCharCode(chr2)}if(enc4!==64){output=output+String.fromCharCode(chr3)}}while(i0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run();function WrapperObject(){}WrapperObject.prototype=Object.create(WrapperObject.prototype);WrapperObject.prototype.constructor=WrapperObject;WrapperObject.prototype.__class__=WrapperObject;WrapperObject.__cache__={};Module["WrapperObject"]=WrapperObject;function getCache(__class__){return(__class__||WrapperObject).__cache__}Module["getCache"]=getCache;function wrapPointer(ptr,__class__){var cache=getCache(__class__);var ret=cache[ptr];if(ret)return ret;ret=Object.create((__class__||WrapperObject).prototype);ret.ptr=ptr;return cache[ptr]=ret}Module["wrapPointer"]=wrapPointer;function castObject(obj,__class__){return wrapPointer(obj.ptr,__class__)}Module["castObject"]=castObject;Module["NULL"]=wrapPointer(0);function destroy(obj){if(!obj["__destroy__"])throw"Error: Cannot destroy object. (Did you create it yourself?)";obj["__destroy__"]();delete getCache(obj.__class__)[obj.ptr]}Module["destroy"]=destroy;function compare(obj1,obj2){return obj1.ptr===obj2.ptr}Module["compare"]=compare;function getPointer(obj){return obj.ptr}Module["getPointer"]=getPointer;function getClass(obj){return obj.__class__}Module["getClass"]=getClass;var ensureCache={buffer:0,size:0,pos:0,temps:[],needed:0,prepare:function(){if(ensureCache.needed){for(var i=0;i=ensureCache.size){assert(len>0);ensureCache.needed+=len;ret=Module["_malloc"](len);ensureCache.temps.push(ret)}else{ret=ensureCache.buffer+ensureCache.pos;ensureCache.pos+=len}return ret},copy:function(array,view,offset){offset>>>=0;var bytes=view.BYTES_PER_ELEMENT;switch(bytes){case 2:offset>>>=1;break;case 4:offset>>>=2;break;case 8:offset>>>=3;break}for(var i=0;i=e*a`J^fA?ph*w^ocA!e6PU>CI!tC`G<_z?WF~hdgrK153EsLV zAwB5~fqydHAkiqOC_zQhMNoo3)J43kxEfc*%es2KEut~!%Q;gyyw)Zdg`g?UQboIx!Z2`&N=^DzwJi9?3Zs0%lg+ZyBm{byXAqq z(eW(hx8CWwyRoTX_S>FQWbn-0*syobD!Yq+kJsu9e)MygLal=_YBnm2_PzxIpPNOjkjgdbIJ@sij_J@CyroL?QU$YUoJ*$%>4OQ8k48n&?`1mQ4 z4b{vaP|;{LVi!T5qh)}K|Hf;J#~}olHXW$pC4W?qJ^^f!wAt^={!QbNE?)}T%e+~Xt_h9ggJU{9_82oMS8~u{|{orqR|0VciZjXP3`@P`raQ`{@ zSGwN~{#EXGf-l`~2fyDv#b4}xEBH&?k9mKo+vN|q4+MXi`_14Fx&!`@`;Fi)*Sjlt zcO_4*a=#w@)$Xm{Uqdt3^5m=Be+vGq-2=hDK##BE@e6r;z5CVRU*vuz_!|W0i`{<= z{%hPX2mkf%{lV{W&kJ*N?w3M1Jmf_k?i8oO^c&SI)V2g>coJ`^gZlo^$UE;hH&jUkKOExp#!{RdenqLip-A z_v0bFV9vcggzM(q+d_EZocpm5uAg&n4dF#}FN7NaJcJhmSqNV<=iU;+*YmFrJLcRE zhcI{8{SY`i?A{#0O^4kNhVZh(dixEB-4B4a!|wY-_@=||O(A^qVRvr`-*VW!5yTyK z-xtEdVfVcu969VR4L2Wl7ld05yGz2$4Dkg@_rpHiPJ5tD?_Z(! zcj)~qb@wXWl`6U4N?vRwFFEYK2do`--woCdyYB*Phu!PJ+F|!Puy)veCs;e|z5}cs zcK3iaRdtoBzxuHIc5rsseH%DC?Cu6xLd-#(ubx-oy@PEQj`F{vM>3_$6C_L(){f6*n z|9}0b{ondM&-_1rdFrqHU;5*JURBtM?S z58j@t$x2X98e(DF3 z-}K)fE5A2+V{(0b{G0y!;`h(m{@f`beN*zi$?KBuOx}=u57m5k@?FX6lW$9&JvH_1 z$sdOghpFd2^O>(sR+85ycPFn&PJ~Cpzl3j1?)U#3e%Zg@|C0X?{{M!lT|e#L?f+@; zxUi@TrryY9P_-<|NS@34aw=inohY-yfsi zWU0L8<8J=I*?For6Gd_$oh={!nA87MRvyp&D;D<#H<4r%N%n?`Jjv6&p*;~YeKFl{ z0+c~9QFt|E4J5f&QLiuB6FyU!a@%~73fKhrL)jbtDqY`GD4EUEek)IaYqY4RXdj4o zhMqpn@>c19D9f85Ko#!{+l#aeOXV9r;pU5kCh|Zx02ClV#iTF)oF4Ii>`^-CQM2ro z+wvwg^To`3RsPaR`sVZI-Y~7oX;t`BS9-C|Y3us7BGCxgi*3~ldXYDFhE%9sER)M7 zUHQq6F`j~>0n(3yOEAsI`lGr7(s_G3MU{Eu8Zc9R?ipT3?|c~+FJ(+V6UVZl@!>uX zR9XHF-Qs`sn4ViJ!@5H?{+CTA0>Y4{M|Lxn)zo1%@;KJ0g8aXJjibmf|nep7n3@R4=)nq1OSwlkbRAl(eAo!Z9t7DIJ&W%{WPgCP2qS$W>78^|KjK~P`aw_!p4Rs~qD_e4Jm)TOR8^vmsE-S3s#aXdA+RCMkd${q0ObRy zE}8;&v-3scib)si09;WUwSng-Jw+#7bryIp(3u6Vb5Z`d90_UsLN;@!TzVPCwvaBsMfp3N>;&t|2s8&|1E zyiTu~^kdLN1`z`(7|2ug+=jYL4~?J=Or#4%dd0}2RhTrK`U@P$6n4V}4)W1ma)C2q z8*QbACZUa!k4G*o1=KF`2;!j3W1IF+Q z3cJ8VWm3IP$}lL{8Wc>dk97qddtOq>0%TEu9ChM^Uo2n!n%B0E6sEu7fjnI>8WH)V z)GC5VOZ%D+L<)96vtl^K*P)yk6nuu7u@ckqQpwRuox@ROZ}8c+!QJ%WZhKvopkFMf zj~0wmD09{8@8AFGm6es=@qUBKHO%1J=Z*7|>3HeIOFLfppv>ba<*MTx2;H#%_Z|a~ zGVo`+Xy}p_VWAASo5;+4D(2MJ0b$(hpnDs6$Y6*mv##`k6Ie|?DOwnS3>9##h{8%Z z5XIFp zX_VbeQYh^;3uLLNH#IEXfl8~?7dix5p$$LZdp@u})n%{t!l(5(}@5ICw#dY zH|WXnZ>#=2p1A3j#$T?!=-f%EJ_~uyc%i^zFQcSwXO= z>3e+kO4%9kz(lkuB<_&;l7p4dE8Ug47YD)!CP2huVIGEIB-%?y`_U}R6A0Dg8tdt? zBjPFhjZZ~$c{0DCTCON$7Qx)vtKj0?fhCCShCW4PR^5PTg<}Lp&`o8IfydnIAIe^0 z_7bhAtM$X#x&pq56}VvqXrf^S+-2WFrvnX}V`y|E_Q%r%WN2LOqVxdtrOhWmW$)Kbo?w?w6yg4&YoAwD-StAM z3H6B8wG|CW&Lp)1W{P%sQB-L-*cj40Dlb~Z8Unm_*~FAz*uuxMz+$D$ehK)MH5bVSe2WphRUqpRM7x6Rno}m~=Ql0?Q8r`zBbQC)WyMq$K zNt%6vxsv5bWDT%mOqJT;i)@17Lfn;yHVhM>&ts))j)P=%rd#Ff) zwQRwxoJbDx!iJ`790SxK_syyXd60(${xS-K8YT}bZNhdj3GR6&EzCF zZxAYkAa=WIpv?F~6XU6^s{WvfB3im~(p;ehBot$&?;iY{#^n&0X#|v_Ildv?Uzg>~- zcQ2T14&ch76h1AWBu~Z|iW!1U0!5_qIY_0}>-z1yb+L2q>%VTY5$_&)sqXUDOSrUo zwX*!R+*M;6j@vW$^)E%RwSEe*yI-EK{aLR1bXo)`T{zY!Jl{?B3E$zlAiDGBemC!2 zLZA5a@Wn5iOozXI{U-g&JBPV+t0Ipq&+%*6zxw&Z7vDr5J3q5-A5UxCObd((LMf@u z5w={h$0U^fDtzPU%4%EcbL-nf{f927&z%(k|m-{c# zTcZM5P@hyZICyvak)iODPzr3WdY`-05Rcb;Z7pXq%4K8iXX5l8Q zIflYK9T_bYw)YS!X0_bZj>-E$w1u(+S(?}!_^SgCH5mk18kjX}JX9>9jBh$-7<6K* zNmSKM2tP6Bk01+Q0<}yRXePp>*o%N{iTc49frC20672(ZZk?XtT8;N?b-ye^Fo0BM z;OX~E6rtcz)vvbo3uU7=Pt~vXs(#5hQ^#UIG*TE@U_rkL@InoC$0!i(9Y&Xy6b6rR zY5FhoH9cVAY){ao^xW!^yb0I$kpvieeid;NHut#y$*k-@->3In^ai4(C0RAP$nwMz zv=|;Y*>|MASy{v8a#63Z@K0P<XhIB63&w z4)%&Jv*KThTMb3%N4;-YAIWGixfN4MUi)j3O2)9pJ$3i2jLkwIpKn*BRx>uT!>oH? z@^*$@7DzJanIGuIK+meu>KRd=H9aebEfXG*A4`9TP{o-CiNBNeEv4-E{drVF=n_@bSPKx?^I~C1K_MdRyYPR+M*0;UZ z1oi$C{##{)mQ}pu@e>Q@o>DBlx8pm~Mocv|ceu#tXdiS>?v-o;5)Y!#7?=e~K88z* zRZ~7#8c4Khau*n9a%7~rv9}oZK0yIJoQOr3L8$ZyGEv0Dhm6BeUqL1jg0O=awX$u} zf{zqUWG;^@*0C;a>?uVFpfrAw_5dYY%0nqaW!4eKSh$Tzw;4?}Q>0hD0CEcSp(qC5 z%tKNxcrBqa)S8U|u}E7%F>%s`Ff&?B#+Z^jG=H8(m4Vn{h$RW~L; z&)cTO^ip%bEqJI;OkR{oka5r;m1@qxm-)>w0$MZe?GWVvYGX;+3)Z|of?;F(WuAL< zrmu8n%XB6IN-!u&g4yF7wlWj=g(B1}cW01Iz(i&a%4E(G;p3g6ksyvM`3BfZ(gngW z8C0ltJ(@6Uf)BiqI(VSFHp9{}ya1Qp6paN24%f`!Bo5rlyFw2=Z(lJ}v=@$n!p4%R zR~gX4C^;L;Il&1~xX2fXriCSbgN21-`uEU`dMCK^HmXYF1KFt~9Vw0hHbn~Z<;jan zBjb-CEmg~m4ly2jOhp!bqYm&j!4wa;!-8I5l#nW*fe|ZsHJurN{kHW7CZ}Upg9QzB zzk@0;B+xw#dIu|pYk{;`sz8n|fuN#93RxhE8fw}?Z6oba@kLiK_S7#R5>p}?12}M` z4PlSJqNNsi6^7cQ$OO!mk>U^pFgT7i=xG#dL_!%akS(mKx!4;sjB2bAeqD<%frT-M z9*f-pUD$1bc{`Z6k^*ougr(s#Sz*#4mBniO8$|(9gZU*@Rz1gFm&D*Xfo@rEHlNb8 zilg2!hp%O=q}f+v(UhP5s9KZ;DwBC70uW_$f$>2AP{CC*RO2pUnq$dQCwj`uBfssV zJQZ|U`sK&TYa^cnlFSOrj$xc*rMii|j59mvzie9b(i6-PJIrfpaM9Ry*^dUzyV~q7 zd5?fV9cgqIq;qpb>3R5ZNjbe#PT!7jEy4_FkliQ)~oMegl#O;8x2bd+x(b-k{x7^CFaCend7_TDq(CgkI4?_T7F2 zxmOOS&905Z>`0dpJk{jM-f&6vd}r7_e7I-uaC-P~``{tDfc2P>T2Z-$BXt6{J=8#+ zB&i}DVp1V%m0iza?-FP6jgTW6%ja)7ffhuHj z9Umb-ltv)^M*;nF34%yZEG@~Gzv1R%p+B1H8OOufX67jANeqA@j7Hc&$~b4{j!vh*Cg)lc zhJd87)Z;fi`%XDLB~%e<1F6&dw?HXL%#GjW{uMpf&|oo0T<~PQNm^4zvvhlH^l>K` z#r9%`R>>4ZANOlca_anKUn~uG=%d}a%l_;s#*%?ShWE~J`mXeS3sA0#(OQm#gsGV& zkihsf9_-Wy{~|glX8|5Z)8sPpFjB6Z+#&)nqLXck1B09M-hIduC}HiK-qmB1+Z?`wd@-~ZVSz+KgMz_q?l ztnRz2q3_EVpF!W5orRyToE)2;RNp&KOyAc4{iXgi#+_)5w{Ztt>pQWsaq>|$7rRGK z95{8~2bC#|qrQ(#hpO-7Ha`(GzXs^%`O_HpQE;vAq-2fvUDaIdPAp$`27PBH-1w9N)-&GAX?{?q20Ru&TA5_N7yY+o+x>tQ~J~4e? z59m|#`zW~9_x3t{7r(DO?+p6ROuzMgY|OPNjLlhDu&y{gcq|$g4GU(!e?9_a)6=H{$S^Pp5N_^<01<;& z4?);A7DvP@k?U>9(V$%zN3ar81ogES!rmJfTbQ*$I_0Q=Myxlgs|u4`Ss( zxU%_UT!V9i#Sm;tz~-*><-|Hu0*!LwWcjmmF&$UHqBB&U=Bt#d)6qIZq{p2QXF0DVHHT1bHdAL&MOHt zn)t+mqO&zVNpP>N9P&9>Jy4L3KY^Xg9E?VwazQ8JLQOex#3Lbi zl27H7nA_(Rqz!Sh)53O4LFh}I82r`T;b8!bKvb>K#fbL>^dO=LmqiM+7*O<+gb zb0~w30ZP@{W9w5DqlUoaD(fI{(zE9h2@2qEXV|591J~Wvbx(EOSGvn$*yz!Q5;efw z0=X0lO&j|7gn4p(nKCtycNCi?pw3iAb*~jSeOrm#(k(1Xj_>DP)IITvicS{)s>ZBHK5QIbb1bPC+S3OY| zEMQ||i*aCvEpNni3Q5_DYZ69^>qCYHS5SAhV9f4p!I<5p7dS~5-Zn093Mg>byueB3 zaM!xPY2gI2o1a`5;8tu+$Wq)<;ooj0D+m)S7GUWp3L!Rdt)tsdry2z*D@?5r#;`6W z<6SbzN9U^;kAn9!sj*=EgdhdS9ifi}p1R%+1TS+SNC}265V9xk-*tw^;+EoK4G}t^8pcBp5iBS;^1xy!dB$Xl{k-OcR>z* z2CjHd1oXAMiTUc;F=FVk_Ed9#ycTE03~HvsG+%9F371QDNrc4))7T)$nHMJw8Wge? zsD}6!bDw;R1RH5KwdCdOVQ&jP%3ppkiV_6@2a#Jsix#Ba8TJhyvYxVfxNG=u_uyeZ ze7IxqaNF=96AIPmD4EzP7A#06K|PFQuzUhhtpu0>Wzw+s6j7211;dPF5~56VM|FkF zA%SN;fg(j!y?Kf#HO=dv3)-V(RN>|>1mAeB}{eg?Lf zMdnw1kSEp~wR<(G{rs0X{7h6lc_;UThc2JoyOOV~6#%-+`Uz&jD1)5@k@ z-@o59JTbl8=;zGfS>Na0G(4DIN~P|`@bC4Lnh1*Y)cwkU?3V64HM6bn6mJ?hOo=hz zn0z{!AF>$PqgIHJJM!Qird?rXk|JapYT_fp;E?U(5CI-V%kJLae}=&UD;CUQuEBDIJ$QX zo-t3FyhJ?dUz6gjS3G@Dabmg<%Ba_2eNl0qY@ON{vf^B2rIo{g-02yCtocP*%Bwv% zqM(%3b82~6`o5|1E0MzEyc?s|o0cV&2A!}~JMFvda_e;?a85jF6zPO%`PTK5Lq&Qf zz&*i=^mYAC)QUrG`oR%x+F3`L>Y2Mn3#Z!elx|V7?j27aJ=%S9KeI(q51>pRGG#hg z3iWGJrro?NWy+Fl`?Fe?*3Ta8%6;N_SPYWgivTCwk@N9l9F`)*W&xow3#|&8!s8e{O zLqv_uqzkae(<3!R;gOyeOc7CI9;x85+3ij13-X7fGGmW`D@dJ?B|3tx(=z|ZoKt~j zlh2z5ZJ=ijwCJjyDQII_R-oD3@TNf<@l%u9OBHC{uP|;rElD`$r3y5gy4^HrBVH9+9*^%?s5;(w3pzyax%J#2#9Jb@v#jxXio_&rqSH{jU z*T+1UGXvsr)m-(~i;wOfsIOliQD0+QFV=C+IDOa}nLhj+DX!5?79aR}(_VF)@<#lv zlW(%9o(w!Qn8yvebCu~T%iRs;_2}#f?3epuLNHo$fla7*uN3@HZ5UF#iMd~x z1v(?*JG^auu`^sZ%t&T$`6?s%;PBy*M4@VN#* zk_OShaC^ODlx^q50XKRT&r-0>jhd_sK!qq}A8e84uLT#-hq9GvqT0a{ghx!<(hKVl zNY;Xo;hLhA2>#~~f_F68HVc@w6i6OcujsP)_`ujjT=F7s%aM{Kg9sh;JL zN0ef_DxQ_(f^k2?s+30GmQ=R$>`1}785;FVth3;kczJ>460N*_gzDKzhK=*the|vJ z$5B>GS+p91Ex6ccF1}VekU%uqAW-R^?JpuOR|=~D#ZSr`2CvqZ0t!I7eydu%Yi!Ni ze_=-vyPu&u4dNXs{bwGNhYR{h^ZAYPQQ7z^W?i#)EI{G?zi5xkSc>H}KBE$3$NjmD zfe=rVEXvZ_Cc-QIP>%yKVU3SAMbhRDHh8pT%&cB_7OsZW7&1mki*fjlr8y!|Tb`#R z1F=LHFN%p4R8*Vs)C;%zzCsY2xGb_9VoT!KbG?GuQ%v%aY65$N#g0TE>=zHMZ4rjI zCL^wE!Z2#UeXa;2ff88Zq6JJfVGJKpYCssepV4BLxGu-&fke|II#9(#8=ZwXfG1fH zm*x$lj>LwaCP0nI0_tIX2YfuE*j2bWZq>==#Pj#_4gbOj8ief8R%kA_b;88MEX-l; ziey61_?~q#FQEwp)(!D;9T({DTJXpQXIk7x*=@!Zw*47T5k3~pus2$1ifYhiNo<`-+XUI zo!5d00D*VPD)g|i=+6OF-ta{Ifmki2iOLiQocm5bb^NaWWWFWO@*b6R@(Dg-rA+ytoA13`Qsf5h!>83*6xy=?qHixccjukE z`UIHjKdztA%B0>++?`JV&d9sF`%_SQmwh5Z+jfy9ZC*baVsfJzyb~zMUeo8<-PVIU zrC>TaowUST#$)4K!iygBqk2v zk}+|BC}^;M?pjeW_LY9D5e0;`jPrFERweg*?5`;`sj+CYU85s#B=@XNlaMusRs9{~ z{JOS5e|N`j?~E65J{85z8t2zwupw;}zb6C3Mn;Di!JahbS;@EM(3Y{#Z+W;?x%C^+xZq4eF8r18lz(? z@zJD~$ms+qF4x*IROpVEL`T60Q5s5yf)oOgWl=y=6d;+P7aATO5BI0E-)x|&vzd80 zJJ_RK<7k4!Lw`Do>joJZkp9}L?JO$E9PGqp_VxofdOT33M_`8O|#Y^z&F|x1NCzSB`5=#Bf@$h zk=u9Y?YsKz5mAbuo5&|d#O=ttyZc+faA!nXLpVce4b|KUDY0-zpLg#zGBj!3Mu6AC z`h-dA_PDfe52Ur#=pfe7x+=*(RtF?xg}Nisx@*$9y&UO%*(jP{wslq~N^A1aC9M(K zvL@D%)~r-*X3sV+wS2?Vny6ph5Uywau{W0V3-qF$$A#L2eTG&{nqT8XdF}p z70h&#O@$;iPun(v#%R}udA85B;swKfuG7J8&|1M;eG+#~w0(&&`jPw+Rc6M*08838 zkx&KZ84K#8G=;MXN^l-80(!XW7lSvh`c1VE*wha8c{~6yhn>wa#q8p1TnGz4z`dB$ z;L{dL44Vo2}*7CFU%5TJ>cNfhcOJ=s4BNp`%t%hD(5$w zpn~3tKiiJI_#V%y?OgwBS$EkwrUs~6(nC+OLcV-ZtF*Mx`>bc7{p!+jeR$SS;_`1c zVAco2`qbwt(1Bvseq3?IH^P}c3ge1zp6M*A>?_!}ZuHwxSTJvN=p3h0t}atSkiEU@ zGi})6ZBG*0SeVT;CXh)wmV2lDB@ygMTO z;~spt)OmNQXrTjePemxudEU})!Ff8+CV~Z`e*H!_^8gK7gB;tE!8~j$v(HykvsDjgRee=6RbL6i zj(m;j3aCRsa|~B~#c9_1WI)Z1>wv?rl91LB*zJcITS+j5Q<`4#2CwE82M}vFe)lFNZR9kSIs=QJ_<+M z*%mnEw5%Oe190-cHXw%*V=Q1_UmU1GXe;L1E{}7}1y8!kY;N+Bx{J028?sTrs}0YO z=UD_?W!q(X)Jh_AhF!#eid}5SlA>7}$) zbKz3L!C)9^3vM*oMHj}+RYGW#y0uFTQ7Z#r`oSy(zRTKn+%)NXV zry*#_c8@`N$ON=QL1ms<;S%s-t|4-VJ$fX-IcMm{KjIeYVB0p6!kw za>ZW}`b5N=f{=2VqREZytGrH*5oMNq zh+X4)Kf&he_~5F@&YlwjbNUmzrPFsgN=5{r5#a+1YTk7pY);~8mfhoRuOwkg$8=P? z7j4I)O-{9Ykxk}dRB|-1kKDmA#G+TejRK7t`!b>8h{gFreMM7i4iwIQr)zwK!>~I> z^po}!Y4$l_6;^A4Mjt>w?aO+gN7J~q+F$}CYI`JVo20-2Ghr)10H z#%j_#bbA*LRI~^c0FLrXu@Y_PXI7U5P6|p&xJ-yzqrEDrlXFfo77;rYIgMOeZSn=K z8C7~$7{7+{Pdg>&BR~=oJih#JcAm0xIiaBZeZ-hM-+__x1Myar#>=gcOFWz%KzX#4 zwi%x23J8ZU{=CPWAp!S4V#`<9;=vbA?_^dOEqp=t&TKzX`Z~RfTzz%lL&u{GhwvRR zoIf{I31t2>{Wz9vEeKcrChN#VrSlwnFQ<>%(C_~$FI@CyY%usAZnFGT{ zHU!AJBFjuk4#RKO0A|S%|33j1gsB0JPXU-RG&X}VYmDBX4#tLnof>1DdL-ij6{p@* zVOjp!96wd}1840UHNbOQw!qW8*-oR5l$6IM>;9I$p<)FBzO$l1C21#^IAbk&>VY z4F-bToOp7bEb%I-3p>)aoWW!R{yejB-0`;C4jd zcC8QGt_a)?`(yx|f;}ezjt>N!jA?)yerLe#I4N*DBXB$G0~+zb-f~IUhTD@ng>NJaUv7kdVhjxoD?#w*==EcIr>%p10(U5G4UNix|&h_b_*x z3RIFMqMKqDCg$`jkC#q~ z-L#jE7HFM)+^($nxV3DWpOtUp!3hqVa}rk~@5y-dppexrCypJ-Ip+upNEi5+*1Kwk zw)!CSJh$UgNN=*tuh2#Dk7_QubomzLHWKT=xsV+KnIg!^Th=58QxmFctT@J1Y3P)9#BL-!F_8{6Op{2 zvP{#XOL_BXe}b=?`LLp`3W;o04Fp0)YG7izt^vzNH4s-j+TY5B5SP+#wl3upNBOFw zU{@!9YK-SpD9E3tF!V?}ohx|IQ9D{rJ%qF~Xh&2HkViQ!+cq9b)Eg#+%zJ4`xpecV z&lgY6r{eep+0Jl@QFJPk@q;38*I1WJEnDnP`wBWM_ z&4C6HY9sQQU3SJ_dAv-=OD|s9G{ON;+FddcaL@B!Lb$P%2FAAwJq`y&x@gj&RW^^2 zxFvf@p@+L(IO+I6zE1Re5K_cZF$PTPViPzrL+w-2`pj``aU?IqOZZIeLRbVZJ8#M3 zwHo_)fG|!UsZ1mNX9#Da=X^SU#)~Hdg~VZQN_N9?G>I#h%*HmA>Rrh^*lnaWn*dlUn@5*& zceHP5kP4qoL>jKDRtO4`G)oP98V*HzptffYr8rqxY3%k@yI3*cS6@I4*)Oy zsxxenJxm=6g>rADx3@`B^JPw*L_Z)yN6uZzDRY|KF?s~lh2FoBq*LD*2i}Nh<2cx1 zaNt6t05Pc$HaEr~vKuUL?4^dP(CG*;o@VTI@Fy8gl94GnO&ncC_th?(sA&p-=1@Pt z0#1_cs7NeM*l~+RP9%V+F;0a#SagWJEfISisk>%8y}2q)Z!D&1m+ka`Uz{nci_Vng z(u)@zCd)6&?h|}Y+hYSrteL4|a8yYIgY-bZN9I;08t;M=QhiLNsP}QMv!%ICQE5~~ z9L@`YL!FgoG`cOGahFn~ppX0+X3S6DheD8`N1&VDd&A%vhWq_e69Aj_(xirBG~L{~nO#81?4^=(GS zBV`irO&t*p+V^zu;Xw8T-edWXp($hTK({DqN zBnwMV+e|IT$O=L*$DZwUnHHs|P5c=cQO+xDfKyYRxM&d>R_Wq-@1VuApUw9D|^Qq+oYUX?_g7SbHO7K}++$UoQ zWu^CdBf)!Ll;BT<1Q%sS3I4zdw`mc6(PI|j54hDbeClK}{H)KF3|CU!7o#X&cryHi ztF7>SwGdyi?Clr_Ur~C%lTwN^vFAT80^uw97p3?UA;pa}qZnT~;WsVDHUiDGdZA%I3{Acaca{uf8a}t?fW>jX%{ACV+w&? z$j{I(Y(8C>+T@dw6aq!;nT(HF1J#?DPZ0AS`f(#0O-c~B)uaUI(xe30YnqfuZBjye z5n1v8&-U0_5S!KaOfzVnw&-e7f*B(w?=>kAY*K>B9W9X=BoAl`Lzx{K2Bj?2OGB!; zHr^m_b70O=(hslU(DZgaEdw1}2yWlM;e^_^_Ik;9;DU zu#(lJgpZRFhJtz+vOWtKrm{~4ODpCpW@&7WP*cUs1hMhRV74``-38&mG@6$d7Zx-5 z!~Cbjc^OPHws?j*FA6K#9YW97*Xr)HG1*xjGrSpXHY zk1u3Oj6q~F?Y{Y)&N9^VOmrWr1!v{&k$1utDmKSYIi&%R^v8r%0YZCE(?ncQs*lch zEt%F`g2vmuvzX%r#aC*Ycd$swb|zpB_cpENT2z_}L&+@YQO)4RTaHa$)aE)AxQ*#v zk}fnWTuryy`c<1$HrNZOVA!1(R6QY4V|8CxX1Kq7XVFy=7JS8?YSy}IJ)zC||Za-N$mHL0xXSZ7lDzH-U3FN;M%;e{&A_0)%!vz)q- z@lTqa!~A8B+?L+mo@vyd`6ygW9p!@`r5io(RA@Q7z>}t>{D=baAv`886bEQTSQ>!9 z>3hjg+s4cmYbebE{G~6*t^qpg`$*5~MGjKbNu+Mm8Uzq4l7hi>>M$=>rmAwix*T#< z<#f=oCO5BoJnPGTvKcy%J(zYTW5C^3rpIl<7c2vp!DmS(EIN!@p@~*#_P!ik066ov zO3<2KDyMHRNrNfh_d%YLh;`&Wy_b~_yB@g#y_>XP`~s)_LP&|YWG_pGv^wYT*<4~B z7uv!hvN4pb7jp}25xKhEtWtWEtAS*`R->%s2mUK;cH2f~OB|Vr7x9*v>Lbt~t0++< z^GcGkviU?DEKOcdC*xFs>ESH*%@ZF zd@|Y&%3v%GIE^F9 zBN+MoF8e-D??297G9>~;Sv*RcV2<93u~&vts%^JhEw0sUx>4!cc8UoxbRrf7SW{-P zM&u-z-KKRcaB55jCf5bB&>|UHQ<|YvQ5v%?7+EERrb?FU00`^Z)ODuz$$2pii-JBz zRa_PqZWDR)f`yr*MOv{4m#PSL#69Sc>q))rkfs)G@M9CKa|e;u1pQDGT;lh@$zoN2 zj9t-341@_zGDEj|2j*DDYDB-S5JZqE<1c2^H~hD2Yg?tXCJDimWmob7fzE)t@{vj7 zQvF1A>4J>Y1zoSp4$3?nIoU*2e7Y-MNbkr#7((YRqdbOZd#PoW%1x~08)StrI%lE0 zi9i4VpiH6rLhE=hcFsw8xFs@B-uou9Bs9PRn=7<#HkAFQFZ_0lmQQB&8N(JYcJu;9 zo_d}A@Lsea z3&HQTd~_wo(V@J%kCitp9p2}Zcb4pPJS0O-oiyE&Pev)I~}uI~cl)>&EzH>~O?6!+LKmJnwwyD2RzW&49U_Z%phQtLT zt1(D(H>yp7WHRmtd4{vH9#Q1ZqS>=0I4Gd*CK5maDlrdrWll^rQLy>)`I zreaF&s?xi--5$T)sc+*g*sX6hR8@_!eu+Eoc7r-DloS%V<8w2wxg{Z9Y3`Panq>C} z-w^IFElF)tN3q??t=gEC)HF=`;T|FNt{)xctd)Nyi%J=V_(E*%C-i7dkCG54VtpEm z7A#R%R+SRwiY^0jsITTN|Er5w%VsoOL96z(>NT#~Gm3)Bd5|5LX_Vbe#{4Y^JZiHQ zebS2BAhywazF9Nu{)iaWMg%-&XLd3*k@9-!%dVbwj7#FmW94F#uU0JwlumAv6(|m6 zgN6&7(n159I-KWP+M_ontHs?|uZW!a@sChi;~H5M7Sx`wlk+UmOGH7dmpV)QlRXQ1 z=s^!-7)hP|ZpwCM>7BynbAo$+(Rs6O()SnHo8PLt_WO&8H@~&$4&>9z;GIjH{dwe~ zey6&1P8piuXYeZTzMb{(+1o%g%i`aL^kR#mw+)Klgk?^nX4zx4{6f*G-#vWMTi;T2 z>pl3_o^6V$#P*{o_uF#(8Uw#uL&Grn%RKrt{j71oW5g za<*AmfErr1uO~(HP+OkDNte$olGLc>PSWezfkWE6@5SitejGj7CECeE;0ZW@)Y}5t zqTM^(L00}!Jp;d>nh(yf>jkVvSB{!MGG~nksU)VY*w4{T)T%=EOm@idnaZ(bM=727 zI7>nYkoGkUd;#;TGzBD|2LE$Pz8HLo@hv$+5y6W1JH9 zUs3lZ5InEtMkj2GRNnJ(?&)6n25!W?(n^ISx2grdI3%|9ghmCMSrXKg4e5=FvM^@i z1nS}+R^%c{;kT&Wu%q-uX9zUQPevd~6Zi5o!fZ*e^%eZNaFnmyl9pO9E(_W#6_^}h zlCsA`b%6Cd?L~x$Q_(=L%5bbq7Yk2vYL3r`oIX~DRlmt8s@}_M2SykBOErW38flI7 zm#sFm3$BeIiYDp|)Tmt3ZGZ@kfoY9`Hgln`l0c}Vf$EY5QyR4NsPM0PwFin5imhc3 zUjBJRcUJ}|AuP5dej>1n?Nh$t6OnLGN2y4!xd7Zj#$cFLKYE1%aJs_+mZd9hu1bPB z^)WqE_!+)}6mo7D9^+RSLn=;dLbzdn>PjOb3d%>Ue}`}))Mf2TAyLioMG)gQMq8w8 z?ee7{kb{Im>iaAK7R*_h6@!BCu;uMrCO^fM$d7X>BIs%%oEE(N>ar%<#9%ak$0GZ_ zRyb~BE`wq9JJ4tTvLXaRSs|UW zdojLLhAv^f_=fJcWkw4~KDl;jCBztN;R&yNx{oiRn~5TbIJsLzoE6_1adHIo2+fHp zC|?n0B)>?UG>u#wCC*5?;)04e(R(6JgupMXgyGt2HPC8Ef)Q90(y(bb{ ztS)sbnrB#R>>g2m6`4%Tl0MwmRWaF(50eZqfi<&s~iNV0M=AO+QIG0+C zWh5h(!2>yu0kbXXJQf*!F&s%7GE&+>4U$~|lgT`Qq9-w=WGVrw>?MnfUNPCIp%#iN zs9|VntK=#U4?$TRnj|%Pt^@~sQ42NG@j*4(_ziFj?g%g&8zR@WsS1KeQF?}C zH*qCa^Hf7YaXwoRbYTIZRe=QHgt661=$#kWhRd$kzBcxl;*Evgd1q@^I8i>c2Mw(& zM|9}yF%_bp_MBNG4I2N08iG3vr|gib>ri9wynYZO`w~Y0=_9OM@*vYgkRipI<<5D2 zW4$%%L(kn_t`|1FmG_l$}^}Fc!WJSiSA=mU&5@IxN~L+K#efc~Z{R|vRw+tGTZLJxTJCGDVtblMKtNOiL!$ux zfHJmE7tE@p&UM>o2qS)T?R7cCD?mVDK8{ixy!bDu^BNx~dCe7hZ2=NUFZRQNaW&s! zlZXes_|`sS7cgAY0q3F|T_zo4!^TBK5PJ=7*Wy{b5Z2<&^WIk&ktr>VXm5FWMC@nZ zmtUbMuc5E0!5Kl5taf2YMu1^R3=^e){76=zeI(Hxjc=L#;~xQVbKVGCI-bdAcF4E0 z3KY4KSHlR8up;vsFm1<5i75<^ypFChEG)AE_)>_#HpDtW{7`lG}s;t`<5kZiiJ_R zY>8QZL*&e_sLZsXnO%-#P}mD5XzCZlIqXOSGle_Y_L9qrc+0OEjC4L2G{(MOPC9Ti zP>_{B7)mcGfs^3|P6lnRb~41a5Q-dXE?Q&>w7NhlZBf-Z0>@0)n6iTfi=Z8~U~7AI zXu)c;I*>hL!9p%ruypk(h9Q=KELfTzv0$|)m#y$*5vZcuw(d9j7kwXQYja!ON~zxZ z#NdEMxnxy0%xiOI>|&N+>=NdXv5TPxBg^K^gB_e8SA}d*m>FXhtCiAL3bw_v6)6y5 zHIflpSV?Ml(ZbXUOTwANyNsI+<*NB+tK}+@Uz2Nqzn)x!^^@{nGbT#gAJ@$JEM%BGb?sm|<1Fsx!Y5Asn~H z0=-HTWav_%i=jtMR5VG`Ithd!vCbGF)1!(i5rCERtEu&hDj9eRh$_Q?Dn%6CNl_&Yh#Y|`ULel44zfH4`DiCc*?PQix_;HVR0)#+zLMJ&QaVIgA?Q!3K2#v(LC>_LJXqwDlS5Ar2O1b1T?dT7+42hry^i&*2^^AH91 zV9+GEK_1d>oI98~ued{cQxPvnjR3`Z+|h(P*e*{fMrI>~#Gr5o?nBKTY>-`ZM>BE< z)grSE7t93J2ok!~SViiFHp8Axz=<;Kiwc)`*GxExJ1i31iByR(v4$#bIt?b(&?XgC zb|Y0*G}$ql)Xv^{5KYFSW-j1HTFcTnqDi8~gsjGC67zjE zP2zr6G|8RWuoX>0&=pON$15#XAmPL;38NRIl}r%~gf@oiYKmk;B#w0MirEkhx(E~d zkcVcTTE8tEAvTaxC;T$+jXqs|gJqR^ zMhMt;vxx1n-`Q=NH_}Tp6@^82sAy{HfUW(pd2{YHuo`1)yUGc2+0Rd~CtGYerRAu3 zz_u&@&|)l)JV*l1ABcx1=6l}(DPdNKs9bp`ZbHvRg~881@Y-kl5B!lriAZgIR6g>D z`jB1ezr*Xd^{GLhl+2(9ios(N^h4R`yD*!~TEowiY5j-3?k4c`6v2JilI zgLi+u!MnfN;N2q|y!*@s?;hRY-D`+Kn1@f zo+TlXu}JSY&snjn9*>nqC6w~$s1k)#?mkes8QB_AnI~v+dv04l(nc2@NV%Bq}7!sgeHnjV=7r>1dkRUO`lUBRyIg_q(yzA2$l?gV2~{v zH}Pi%Oeb96bdWL>VZ95q4`_ITUnI zyGxrAPkT?VHd0rIDnyVgXC1OQ4G6C~6c6W#9jaP5MV)mo33HPYEGNNW#<#WJ(+4*A zC+CXq6`)^7;~rl{ORtp_S-s|4VVXuoI@R$2ii}nD;<~6-C|0=K8!lKw`FPBc&IgoliN7#=MfuR9 zD4#qurD(4qZ4Vo_jq;VSRy0NVY#g^f3n!ys{wCTS?Uj`UN_JyD2MEnTW3w=JwnZa9bYmC`&4 zo^pbEGS3GYLfL{M=11f83|k&Sa;mhqF0>T4#z#)}%QZKyv<1C>-%wMFEr% zq;l~SotPF6fa)_bOQ(wlkB~Rg zRrSuC^u}CSx@s!4EB8!YP-sgE$HZhjF%2Ic?5IjKNmV7#rc!d1bRw`da{5oKTIW?! zXAYv|uk(eDjj9tC3iyS*+ChIXPq8p^BRQ3H5I zJ!Hc}?pn~rpfrf3GrcAV%Alc+^^Cn6%|IyaAa#6nkfy^97O?b$i0#2{(sca*W4lBu4Z={T7#?gR%nNO?Y9?9%8=A6aq0EKkAZrutz!z~Un)CMJ zsKnFb_?Tp5i<~T!wp$}V7;rk9olQ5&Uw+UAUNLS0PY-fHA;~$})t1}LEb{I`ka6}1 zezyPs3j}?1$*VLZ0lLup8p!5r<6E$(y*fE(Pq>E!F3XPF(z*(tii|nPh};rcSXLb6 zsxHO@#U&lUgN{+Bt5nQkKX7A!5eYI%(CE1Z=wtYZdPKvjF6*1pRsppi2jJ(!Kv)q% z37}H6Y656`kws=mB6JDRC1&c;NjT^Yo(hxmAhK3mb3?jQ(nr!6ACOVw7%($ju}2XP zWMPsO0e@hT=qsVv*6J|Eykp$VVx(L4yDw<;Rgqd63@qOy7M8$2=Q+ORpUaqQfHq{u z!yqzoWw#V9j8*ZJf^lXbGY+XTkUG6d9a(Gwge4$4`ke-@)_k1g6m(9L?JcQG5~sON z1{YLhk)l|nK(T1Zce4*~XT$7Ni}dn^g7nLBf}vnh}V|HDd34li{V0?r)iCm*_=;{ zYlAQ^^QTp-zZ5ZJpuWaLULKONjp+Up4?wNowYy&;Rbc_U5llWD%Q)NuC+i} zIZYqiqET#asxE@jD;f?pioB?F-9$u+?VOrFMZH%~R2-Js!V_-0BI%YWwU?8eY!t(= zkQA1X*yvdSX;p(Ox2>beq1JL8RMurK||!tF8L2 z#PQ~#Vrr()SzOd2fb8(}UQU6nNXE&cXEc{Lub9*cdwEY}Vl2qFSBZ!M)F#-9WHQyv z$X067hlF-nGE2IER^90KgDPoDo>*4ua2HGG>M*35g(#YX!!A&zHa7>oYS9=o z78Z}TAI{bT_i!m0XVIFN62#MzSAlc*uXwI7WJzPjfv^#Y4%@`dzh;PRER;t9@19m^R9aZJL zK_Ia}TdJg0=8EHX^DUQYI+yh_EOe0Z#Zh=Y6-XyJm_mF&MVKh+8q{wzWaQu5%X12F z>bfwuRn8;;4ZNn;#weO@sRxEnA|6Ov#wzb3cS z+9-rAqG!f9BX#8Ika6m|OtDgzTB#UEQU()&KHxSISEfSs!3Goi&hAtK>r?RBa7x5O zsn7}IOi5S~32)|5C@InFz{55bK9C9=R^2Y1mUHQ`%Q-wfeP{6ut)4~MtD{e6g`aUX zmY;x|7FUBZPH5^dAhLbw;%?Yg{EX}eYsQqeim1^K$*e}2P=#s>j9#9|K8oU2FYS#@ ziEH*zX0`YnjMD|^!Yl$alOshS&}_wH(TX1`U;)9Q_@ba6tB*#BIhazx=M|k{`bPGE zWcyP9Ye9mxtvV@ex&`ys_<T>HcnH?36>8Vo*kun{mml1d#rM8=Nd@NRNQMs0uqlft0IzT?DR83DK&&o-slM94D z!O-A^aa6>!plL`L1+A^3invHU#zV{&77XJJ4iIAqVr>ZBg=8Z1h7n3c#PACT#lT`{ z(JX?^_!&beic`U(S7tW@p-o7M;|q;f!=6YW8ekN*&)abTY9US`T;+B(Cu zdA!lcX$=#!_;^r-6uTk72m=HhsJsd!gJtYR(m-R$vJW7^ES6k)j)w!i#cR`BEj{i; zLEedi9Q`db-r^4l$^R%R_*)|aJ5nJJBwFr=HYGzwb zfhj`Plf|}6c}Ka*{Mt5Revwu!I+O(~UaicpDQeP(W`6ZHG`}z|cFO#c%)p>gY&kW9 zi)6BBO))CMzK&F2gqXnvU*q;xEkD7Zw44BuydWFKn48}kE1}d3ty=TVQ|-8+wTlr$ z6z|lT#F55quqztt3}{SQ0Y+YGN~CDTRJ+mKZY(N>OD=UJwt%AaaR@OTOcHY1?9(_% zLx4rfu~2VSZ!;QY8go^0DM{d4FbuKRx0?GC%`llT%9S6OFo{gCiDL5pXkHC`3JwQh zw*u3-Tk@x3^SjH44T(x}pP!{jRGje7y-=+bF(u~kixt&0p;*wQ$j|3^N(51E#_I(d z&O;^ZN{Ni5^;ein#AB++2)t~;ne_o- z@Rx4Zd)d9E1x?tf!OSNNR9OLJ&-H zs80PI9)WD)$?Ri++y=rH3IE%PY-S-<0SxF2npG-8jDA=N@+gEFeEc#j(5HB4eLSbq zNb^QLyanl^lgqJy%4B$Qxp};_!|Xz-Y=KUye^AXR zbXF-YIM8_l0weu{)~QF*_P|V*-J6oN5h+!xn1@^3fISHlsM{~agq59PRx42XR=C$n zCk|KV9!M0f1rmS<62=MKaeO_W^C*r>2GKB9nD#>bU?UxZaZ&`d608-(F2sqXt0b`c zCeA2*+|5YsXe6{m0s4t;Sm2pj3byQ_TXb)v0a-!9SUe!wA|hx?1$L1I7EQb(BN{8S z$P#lDA5*nMk^;3F1hB}$Xxu+w7^y!J#1Kt}53w!y0Po-fGBS%*=x{ZeG776OF{mhF zq9g<;(J+DlS@?!=P+&0WSX{$0ty%1k2+~qtf>{a77QOZ)cu5wIp@3njQ9wd6e?S5K zgHkM^G|PS@^IfPyBeusj-PGMqJ22i9Bfn;4aB$?coMA2EN`Td(F{sZ98iHV=1bRXF zeUK}c3xx^@SE7vuEl9FYz}ee9r2Nn|qP+ygf1qth$Z6D}l(hw5IaZwn~20wap?4RH>8){$y zHyY603}YP7U2#Bn4hPgkXy2#~gwiEa^(1N(E{#S49Uh39h_Zp8F#!Z&m|QpgQkCSH z=6W0>W8)r#R53b(Q%lEjO5m4|tIYX;c}aa|Oj1pW;N%UN#NO^9FCtEfC{BeE8<2f9 zC4#p^G;i&ch^ER0rO7rNGD(y0hM0t)tHv=ct0@s=X%&`ddPF56lf>Ajn1q>R4YyA6>()=mT?$Q{lwR4cRS7vpne|ndk%&K7CP%Eh$1# zj0PTxVT>z^p-@E!67OQNaf(5{uAvy7#nZRsiGTuZ-=SR9l&G0Z!>J*eq90BMsg?xx zOd>0})5%o7LGWHDaV|6RI&EneEn<6nrQRN_-yR&k9hnrdz#giOT@=iP+|{5iButK%#cP(1zo~G-ZCwK#71B0xQ!zhs|a+)1n-xYHS(T*T~Whpa?xIFE$zgvfmrF zh+YEy2wL%x4}!{w_oV!^e((`J$n_7gX&Z^4#n#cnVST!FX1n58V6kW@hN@X==|RZc zuqjudvg(I?Pd}(te9q=s;wXGWv52v|k<_(n^var~t{jq-y}bl5XR90tY8izD78}aa|G-PqB#|M?)Ao4C{7HjuL-+QUGO?w3sUx0PLHcmup5xc!>f8#it zKt@b3=O^Etm6OU0LK=!a;B*CztD^&XDoR5p)#8948oL0^_a_XOcoJS)rct5VzzerM z8ndLu#TPSrtEOodS^PBHe2?GxSidaw_1j7@v%58KVKv^S zc7h%=Kq3Ns%>`CLESCSM?Q7%2g3|5T@eg+&Id1cZIer%oCZ(DD3uX5z#HB{Q{P7Q3 z9-q#kt~LP_azRXuTZtdSn0vz|aeKgS?$P5FsiAxt z`|LNX=_AUqb5LwUUn2Y!M59KvB6c_Hm&`(Czp!w^7Ac|Vn7=3UjVcv<*U;-9QsQhl zupq@acz0T99(MxH8@7o9NH?cLUqXZy*02rJw0j7iykPUPPYp9rpF`BJxugLkqF|^% zEK>WRHW{I~@B+0Qdm_# z%1MKvb9yHYHb*m401ALC*%VEpcR{p})fIFiKs~`aI2wN|bD}1`aMzoMrgoB z{b+FFP|CF_;NECKXQORZE!FL)@Ae&+W__w+oMDH&!~zj7TvVBu{2InR#L$+%ly9}w zByPPVYIUw8l`dvIC+2c-q=b|BfR6HG0Rt-&|7g(dLG{|ipRswimDdcu-ooQ-%$VJ* zbuEe&V#x?e0nt+=B0TM%XJlx+_ zw_Cjs$(KGuxTx*yFTA1@28cF!Y(o9odQD;m*|DS@8>~%Fn~a_& zGb;^>1zuUs5TA;QsZP$$l=>}c0()iaST0frI55GO!}PTkg>Qba+X zDtt6_LW&6_kS|P&p>D=aola)TbUKaONv7_E;QoI9|8vg0_uXB6%V6V?_C5EU^PK17 z|NOt7|MPz=_QmRZ6<*cd8{hxoa0J}_#rk_mj!Z$9n@8h+rb5}fT!MhR=I)A2sAzJ+ zI+e84Ym7xLMZiAuOgIF;g$z+KDP=A6@39IBw;y?x@ zS{sH&#y-e6hDH@P_jsa1qsJ4-x(rPookK%#LP!v|`j#_C&r;?A6w82#^g7fj=)?g> z%rsMo0yQNT=}hy4?|nz9{1zmldDWm1hB%bAud_yv`H>X z0?o6zN&~{#H+l!3P%BIxw8_6TMvN5i?Z&xhD^aZo0Di;@gU z>W&4kQGzdoBejup)7|ifNzFN?6I6+@y>NiVS`!4@k^5uwBFtjMT!50fnX-a~F%N5# z+Z^i&QFiIu5QnIOxIuH9GDVr7bcy<!8fTR+e>}#uLA!jPhNs5Au9+rVGz|-z^^|WdBXv$Hn0zfCB%+E?Us5FXE(@Bag zfsod;;K5@WxPbnZj^%JX*{>DI#C>sN@p5m!PbrdZ2Al&{*tG&mB);NdwhBrOZjx{u z;)<;u%qabe@eDZ9L8=;x28swLJ2Ze2zh~U<>tH|JDd<`|96axrk-D_vzJiv7c{tP( zByk>dK&rTVvMYMxV?OBzb8kPWCp_>kA5g3t&x7$&(W)~+7yaN)$h7$}!hurD2!m2} zxA$|vSH&0X@aP-9`fa!3fGhgyhM_X{_2u!Rw!=Bu7J)w#F1nq%LF{3Gi2J+IGG!*&P*=cm>ZM zKwEfrfEM9RuL4l^5U}xkfN9~`LeWDo*0eg%7v zs3V+b%j_NI-fbaFK~}PNG=C6Z%v8uOzD$qZn)2qgWb?t1ZMSFhssfR# z07fo^qh|oQu;&E`f+GnAp}vrDLxnMr!r~EL?9K1%$mJL{S6MuG*|Yfag3>#Qu1uV4 zwXpCW9;~lJ3x$R6dkA+4bb!GYbVznBOIJJP?UXT00knc37$*0HA%QYGLqDer-rSg5 zhOy$);x)W^K&uUr*QGjP1#=5*v>lp92;?%PwF4I;#0pDqdUh+z=4~Kj8+G|DlErS9 zb+yHJV^~hlOE=-Ap!A~i**UoBXt{^-Cll_FsZ`rc6S*G=j)TQWq8#kha$39=T4AS~ zeApyAMG;t<@?~~f3ivHUSYf9TR0H_rZ7OR$I}Jicvs+%DDXRkmJ4Mk^*%`K1EEe3Z z%}zlKp{=E0ldiuoO@*DR%=GM(iY=Jzrm)jqMbzheHFgRe`wgAi2ogoQy$A#So~CJ^ zYCgn_0i0p8QMgFa$ZMTDVa|jWn0^jR##S3XAU2ZO<9V-k2Sv&x$rf8pYcW9&q%q;H zF@`Vo6SECM#{qZvfx2~qOkH~b^)1$IJULs}UXBmfaqn3ciQm7c-dLG~$Omt_8gmGc56mHaU@yuTR=yd} zmYA?GIzc-t@dsghsL#U-Hncrj)n7uy79vJj3MaJN^wT?-ScIMErtRfcF%6jGg{+dC zmSxq-;HfQDQz0R9qbhl3X>QN%hO7>hR#v0DIfT^#gw0~B3?L<>9DJ!&>MN4*A$U*2 zej-H}vrO=b<_h|eY^la9;-NF)IYD{4LT?mJslHdKP&pnFBJkmcisb%w`C3-0qK*bj z5%$}pOblBp^oY4ytSH>?+sqFptZ%qXtdeRgVtOaH3D8$HI#yMRdKpU_Q=O}aab75!H~Cb|44#@UuYz; zzB!DU8)ExU<{^{}dJRDKcL6 zkSF~xB`d0L(FQ`<==Cj;$rU_M@-g!1Guu*R#1`~XJbbpKZS)_iZ9H{v@U8Z}#wHDV z68`cqS(lI;x&^`8%NLadc%uNueZ(cRp{Di;&h?$GG)Hg&g)eDmU6owAq8mu*W6L~j z;r&r5PyOn|YLF31*h23NnKd|z5Gg63fes*KjVypz&AFm6RS&Rbkxl@LP~0AR;6U(P zARf#DUU^10SrJ4VOs+bjAG6hv&wF#msB?26bGs_}(>c{AW-w zGDb^kVFND9Op8VWEijHB<5sXLhxrS ze#=rKDM@g1YKQCp?En4s5$C<2F?{q_Vws0Dugav8&9Bw548h>eM+Y*m|v5w$k ze*IF7AZlika*MzzI~MWQfhi=Xx}cvEM(KA^Qq44La5Cucom4T@`?00wKE8PTObyWi znLC?jAQ>q|87ay{@8mio!XRpTPJP8APmkmTCJyw4F;lC!5Ds z?jBjWJGbcN0|_(gy=$ciyN!WQjPJ})AY7eqR#rOXKoWN#r5XLq#2=4d&UV(rlaKRYLa1v*S01SYV^=L95$MIKFY26)Jtl1o{BK2L&318HQYi<%pl)(_4aRA*Y4Dj*kP^Nd<6v$E^R?XhrSz}1-r8)m| zGeQ8~L`2YmZuE0M`tKhDV_|3Da>9e``}fhQ_WnzD?ee9WXJT=%=8yf*Z0DP+>gjj> zd!5&+dPKPG{MWknDsz4?_Dl_BOg5?u;|h20S}G1}lfR_COegSd2kCSpSF~aDnQVl( zll4qOvGa4$!541P^_JBBX>RoA=e1rL8l891^q;$M+3CCgm~>&=V`dmaql?+1&L!N8 z{s;fxpeKXjgi^#51y2wS>~+zn?60U6dQ@h9n75+MhH*3yePjW0g0-mmmZf%Ols^F{ zp)M=;gu1NU6Y7%p>f^DXM2HK_B#DRk>5B$SfGbg7;89;5a#-Wx;^i$qa3bb2xU+u3A4G7Jl8aJv;1pkfBuZF5llzJZAo z8pO1>GO$=22@UnC10x!PF9@3BFaHk%iw7|5m&aw&(Nu_wd>s`yQcJ3%NiYMV=T<;aQOqEkD#F-J7G#L z&*Bk7mEvrvkk!>iRB>drmWdtKpyIa+A6+}Gr3*r$c;Tf&*>RU=o$9-?52e{=VUTG4 zvDLcwjztU->fV0MzhvN2#e}wNEBT1FV0z%Jkw&l<2&cNi+=SjDmrB7fkh-<;XOF0v zl)NnlK2i->b_!9x%iMWWS zK|-Hw-d&1dS@IS_<@?A;vxWITOE!-uzyQ*n_tH~2N@TiOpT^ExE!$s0D6BA|4- zsJ>)S)HY*v+>qtF-OLPpxjcnFpv7+O z=~Je_d(`=Js>fM?81Glwh@*(A{^GE+i`ly2$O-VD*+;@F$vQI``l-^ON#>XdFm z*hye59z!CPmtI$>zBndg>6=e!A&@(Y^e#XhjaHY1VnK4{y=mJ36Aq=ntV)OF;c~W1xLn%DXPm9a?)C2Q1x)kU6Rn71O1EkD5S#)%(k1Ro({c3SaCeA; ztXLpjCRU^o#_xLo(0Tr`y1Uw!QFuL-GiEn4;xR!9Za81fM`g1sdk2`CPz=kj%{W}u{{CCa)PEZvNK%OPRy z{R_36-13kpd8pei+F5|$JgPNoeke_3W(3KYmz{1`CbpBS0vqJ=Ldt=FM?&%j|LxZW zN8PSp19lVjy`)`fEAGOw^v68M3Pirsx^fp8L_}T*`30hh{0**PY;?PBP@z*UpyF3F zmljTj@GS%h!#)urK(R+NQH26xPihB=LIK7=*LMg_Ct@h8()KUaZ5k{VZ)VOGffKOABdaY%aR*;5lDe!Zi=X;5kN; z*$`ED%PfVJAge1}owMh!I!o|#oB(>co9Vj!ThFEcP10TY1dR@T$V$2Pz@RC?B(?)< zXwz8?V>MO%UG*m*}Xtjd*HrO(3@#Yq2oqlr`XDT-l47z0(6Jr`o-sK7^teBiU{Z%V#7Xk!zIaa(`^Rn1m$K5GZH~ zdQ<408h3~U!2S%1zu?CJh#g5_z1Xe~!=;L6O1L8>^Z;LA)fRHZa9i5bDg)$A5Speb z^f0WREC_97V=EA)w`KJNhnro;6&Fn-$K-z0*=+}1;jX)r*6Gtm=@UP7B=XUnblk;2 zu+rH{CL(M4Y+V=>Tjh|GZZ-{qOSZ-gytgxHM-QaFI9MGZq6U4;8X1$rRv&H5!*HG%Cf&_4A_@_GEYS~!??45>14rm^s z6C`35tHI#VNaxk$&)?huT-od$)rn~n`~pCX-dvwRS=qcygPTuW!lrL8&c8dnfK=H? z0ssz2fyrRGbfFTmUko^MdwdqD=24?1Aoc^w+!b741tP8krtK5h5RPZ#qROMr2}}d_ zL*Ad^F#2(W(rhG~@S}(cqJeNkQZF?vDuAqMf%;?N?F6(hG+BPXquQMR0f*MNv~=mM zm9ZW41m;l`JU4H%;vBnLyZW1&?(U5z?{1%ow5GN_F>g=qQ0{gXX#Dx{uoY`*Uy!_G z=24yJ|>v{eBMqZ!BItO#Ip&$T7QPL%o zCD{>+69dHiM%nrQ^NSx-2hN#ddr-VXIB79d{AYra|C=%l;uk;m!{!gy|F#z2nLd2Y z(O}E76IBKuBBt)au})EL_JM;*L`&&i4G9k5WNgS1IMQ~1Ex^(HbhEFf5e5z;;1u9M z({1QrE_yP-4B^6zX-@ZHOn8WGe}xheNPtqlLs<%O(G!MXx5PyKFMb_SZI54(xGl;a z&9W1-8y`nMgFs|V;Y#Z$yk=(B_@Rvs*{Fw$ZBoJtSTFYORF*pBX8kD7 zfqKRt&@1xZ5dWTK<4a1olO4lR1{I&5&7x-w0f~?9a-%ay5Csc7$_G(LDRvLLt8L?4 zKOW-U?9Kz!f($>Gl|680JfPfzC|vpMA!8k)S6s>`cIc6;;NdLwuzM?OTX@%CcyBtS4w;sjWM3_`x$=g)%5vC z_{}#_qgSh>T%l!!g}R}5I|XlZ-?Zqf9-L7=6wM_1iNP>El{W~mT3x;;o5iq3PlE2{ zHTr74SiZ03E6exQ{3Ee^U(ZUHmVH%y?@G6#Kj>w&9gF(rPVYPf9u-b93zlvqH)N+$ zO58_uRyQ%b|1YHN73++o=!?$gD>@ryS$UP6%~y1G`BmRppp(21ph3ms@%Psy_O#C>U6W0tkVT zOF+Y%K7ATuCp$bN{Iv2%I|ks<;U!NYS%y@l)>WnW)2mY76LxN-$Iv@?AiIx7N(bAB zUq?fE2N59H#VV@AC3f3rM8wUbewiV6`#>|V#<;!d{W$}2=D%38)0=ML;4K}FDSMQ= z->c4#m0N@l9B7&B&u2Q30IaJU8}l!ieW96uHc^JE#e%q8rc=s05$#NGu9Fy~&*<>kRF{%~I2oev+eYb=#@EhSra z%6f5!W=C>(e?tde$iR}7_7BeG^9OlOn-AyZ-T4r|lHagvx9?HhKhnj*CIOS;I~JDs zuD=m{{|oroNtsb>4W9jT{1DqD^}*4(qtpDj88y&Q`L2A>&QFm;HNU|cHD(0fL3TL7 zM}GyTCu$(vaLBpF$0)swChq|$QTz1+0CU3kkXWHW&(A_aef0R`EqwNC2A>cF#`N#W z;^HBhJbZZ0KM(lCA68<$2tXElxjY_|97+o9k*Y9;_qb|(e} z#KnLgvmTF*b%6o1xS*kgVS=;KbE!7Ev1^-D^QdUXN8v@oC@0zzvLJQ_pD^X|)w?W2 z5tg6P)E{+tYJ@y+MT3CBRXjkk+=^8s36Hf|J#&~xe7-p7WNYxu4H>;aG1N62hwh`N z=12MlY}iff;2AyJcBg^EV2y&=DZC@5+YPf?`&Cb&3?j8lZG4nFN&Jix0 z)Q&9&%AO)e4_T!o;!pnr>gAgyB7VT(s%bSTGayDt;U$tW;2szXoJ4p+yWpJ-(2g~o z?O4$kzc;jHgJirG*7nsTH&wmU1hGGrp2p4=Pkc0FQwVlAg4N2GW zj>6Wd@a(cOBh3I>cn1pXLr%B>R4tvF$-ii% zFgT$HXNyb6IF8~a^HIXJl||4TT-1j-ZSX@T*$FSbwORSuD9z{a}h5V zqg`Z9p zvM5;~dx&m3Gu_|`bG@Uoq_w^6&_N1!;m|KcG`uB4$K)TQ3zLWCJ^;_$S1hT9M-c_Q z*XZ0`EnHPQ1K80;S*ZOul))0kDo+stC*&oK>6@ez*z({_d|MZ_VMZPjTCG*9hHBXR z@V@zNPv~XXB-NA@zcc==Ue{#FB!>Rk>>0yk7@?9-g&>eKCU9(YCx;*GoU_NmG?%Lu zS8wh{0OE%#-er6Q6YZ4HpCcr;$qgFI<(O@4Zi4BdpTc%Z7t}2xAq54B&)8|Q&!I!< zZ{iEJlkx9-S&Rs;h9^3ONqFoDg5H?w{_K$RN zciggXt54)7r?`Cd?Gkl0{=4I5mz|o)sz#v0D7k98z&r`Z z3ZJGglsA$O8C!BSLFRRcbn70;NvD9+lnJ`4u1zpXo3)MmmW$T z7#+GhWCFQE4hGHRi79+o;?DngL?q0C-BDB5l`9r@iF7eDboI5HS(S0Q+UeuOIx@rI z@FK-b%X)Fc+IF@{{BYkIL1Ig-5h^z)f_VMX<*vO1pDA9#18D=6s>3NOor3TY9S00W zazIPIJotcvJpj=8al}9Dg*A$YMMTg3hLoOu`jg79=82L=EOy~EE{?fELDo-$1dgcn z@O4MM9EYv#;as%tHi@}#)6K?($v3Kg0#aESZ&br_E?QSQWaq(ef*G0gYn^{43p1El zE+xZ45|{^+FG%RV=IXY~)u=+)9=40@MCwPsaktYiM#&yvr-da={Fb|6jKg@WQZpX* zEyEo^*r)!|LuaZ%I#5dMl8=VGc&-o^m#w)B%hqwnc6=XdE^$HDEAr_`P7aaL04W{1 zKui$dJB4@;8hp@IKn1paB;*O>PkT3vOK^2lQC3e*S`zhQla+r_HL!Pf_=A6j$6!f! zIP9`R&(7Lln+OhBcz5_&qR4cWvE7z(jGG_<`f^8A%{Jz5PlcLQDz-`SX#Vz#%v3?; z4QP+zyG>Q269c^ai2!wE9`=q~4zTlcR^L(KPPjaO`VR=Jm`ijHaa_-jJn@*p0o*y-P^U5wMO3QnFSj5N z{)j{;`#cM*QF_D7)!6O&;vvktJltG7+$j%Jh1nke@Xgbr zU?U5B+bZ}5I}Lo>d{zmco9F`Hwi4gyQ{Y=8pxBhKjBhX!y|^!eZ)gPKTc|6b!zu8s zc>#Q5^+kNMxcF9zzXW{q3-PUd@iOtv^&H&LpxYPg``wjY&e$7`|6r|QC;x|1l$(^9+vQKTuTrFe^^{4Qq( zhk$un6AploZ}M3AD{G+N;kt;WY-qb1_fDRgBl{3=B%O;r$xlohzG;&uFdAgg#Tmy8 zHg%1FvrBF|X<#H#TM7M{8wL{#J53=BiWO?8RHd+!03*K=dat4B^Iy z9V!pPP1RHP1HuhH;YVGJOa<__>4d^9q#mQ< zR^hhUp)M;skai)XY?p*rE@VC3rDy|NnQ$iriHK+;xRMHS!G&nkzsFBR+ZC{b4tvp7 zN;8-!9~T`!-01+~q63Hv9w{$~LN6FqUYKx28>E)JsKhDfsj_zT-Z*V{{HO5&&pSg7 z=f66Bb5*^qI?6cz=J@uCkm?CPe=dK*UFJWNKP!G>8k&8siU=fON$!=hUN`+dU=cyel`nihDPdJ^iS9lg-_y#!jhd_XaY$pC!eO! z0jpEhK@1iq(&V+lK<}t-i)~G1EI&CuNz#uPz<;(Fz+YP#09cm;px<*&F0%Jw%iU3R z)Ai)GYjWHCuUk(MJ3l>HpZu*FZ|pPwD0FglWxyU6#|2hQAfx%2z8t04=sf>?sO48J zjSA`XwPf3Qb~dj7pVI@I%jm7Q54$-gM%ZL82@sPuEhZC7)q&7$frx!}#1wsyd7dfHJ!Dw)&0W!1~v7M2|R<^s`M+&I#cvjUYw5*d!Y@8h_Jq z?hN>fAvm)r5Hd5AI3HSnoVl5sJP8G+AUgKVx{NFUN>hAZ&5=-=rL2C(Yqlco%nr(T zo4t64x&*FsC??Q7PM4y6*(7~&^96O`ttfqoWeVL?R0DY&wYABQ;C`Wmjew$@IU3%L zawsYNU^y~J?VbnZFL6(aTYWJ)x;kZvp0yA=nvbv8f2T=S#E48&PGgXA8mC+BSaO-AtslAV&>R2 z4=S+!92ZJ`Z5WwN^0%3P-%epH&HP{Y#NN#RWzYMYE9Gw!^zN4LARM4+OWWCF zxLgJ5wt4(7W9(UB&jWYhf!bV%Hdx?4*}kJfxG+ug-%TbU$^PboOZ?phm-z2jxWsgs z*-e+3UGmx^*$%w=qdSvtpVobGvW6AW1e+>Cf?o?E5jRl2atA?O22%R~o-U8;hoVPP zid&!mC)=-a6D#v(C|5+}3S1l9iB2smCHu4R{sGw3R@_%`s!js9O zWC&ZAX28GkV@<>EGVrXL$0-)Ej*VEv2pp1HuPv6c*Gf`rO~$8573wN)jlu>l{;FG3+X$))>icu^+uk>8=C@v$ ze;4KgKv7XvttFm&{vk7U;mp9fG>KPFy-!)8qo{e0%%l3|s;c&K!@l|*Zg42!1_J}z z@f*-}0UKR9YtQbej?N8;;B$0|)AL$J*o?n9OED3r?GV>9<$AnayK+5IuHo~c+ylfv zPqie*+fgYH{)^*LHDC8nGydh8#CZ!)5j-iV)>c3TS7qwZU9lVpVGZN1TN7Ao0t+o? z0m`+2TW4MtVUZvKGKj6`y7svbQgx(U*Y$)TeO9&=OEH40enKM#fX(?7yBf>F83;6N zutIpJ!<~i0fM4Lk$!oz+y&e#XGy%eU3kZ2GaU>M)Dc4iwx*xh{%ky^)P<$KJ(1%an zBa#(r@)lp_AvxEnB7GA2@+%dYKh5ks7it zq{H>;&IX5jAc2nKRN&INy&&XV1r6x#ihu+>-t-=`_}kzFI7MMd(Sc5$YDJvK5JR&% zpU42B0_r?v#hy6j8rf<^gQp{orrHQ&4gg)P7Jvnfy>KmYqTR;)jN>Y`&XVlW;@3Cv);fiA4cLRy#Y3SyEDUh%J++xnldtb zs0S;b7H5$O33{<*+6rBTTUx@!q8<}F*N{lD;V7261sO=>_mgf-ArajRZATDL zc>B-Gfb~&Hu+gNOWWZ}3oVR*8&5<1>gqR&oO(HJFBdcU4;=~-$%&6D)oZZ+3<=Ib% zX@L8-I~=T)rfo{5ChjuE}B;;QMDs=1s@HZ#_2cxYqt-&()Ng z$vnaqJA<$}+tcg_GcKGma@>a(rZ;gR`Rv!gB5vW|j`LG=+nsKTSrQvSZ(D3K$^CT{ zJwP)A!(ZSJdu{O2vUg>+d2Dw5Wws+;Pv+O@bxeY}!>aq}q#F=VbO-7C^bH-kD4M-M zg*WhOb-N*Vabh4v_W-}+%k3?>m5urU|2B=W_H?VDShv>WGhNkLvj1SWWAa!l>QK0R zd7(RWY+sS>p~&1_QkztJjP<5{rPiYqlK>$zKaw%pu6x*6n*sCJADe2{Z$E~snZ=dI zriU0gj({m=?uLgc5gz-*&h)j%-FAPMFAw#%FnZQ2MDI(pQ2Hs&>9YN6?zR_qe#>FK z{mb|k3Nvi_1}Eo+?&egAkJo8RRD9t! zh<18Cze21}Z?GykZ#9J%hQInycgO)cd*anrcf&gmY%z@M4Kmx>2cJ0Ulfk+3MSstL z^9OpI*8&c1&ULrDDN?VrLMPZd`$Q%k8A1)a7)vA3W{c5-s|ln2y6!q(j=Raq%gq;h zxq}z&s?|o;WzVZ7sA#vFC7P=cuJmWO+uh$E1qV2r2;Cje51CK1B!#&OC9^Y;up5Q9 zP$0fNx5;-mk!w=Tivmh-SaVDkP75Xhal^tqJ38Gbb)g$Q7E?9u)J&FSprUKP4BQ@M z;5O5=Uk0);pYInhuatp`1gA%S4F0%4KyNmI#)0gct4RpCa$ea!QE1{HM)OKVq5DO5 zE0^LA=jiZsA8=zS$b=cdaw^zM@*RY+C#RQ(g;Plkh>>MZm9_X(nU}>w+!pO3cjP9x z_kp)`U`53k58zdh?*}iYYQA5*d{OYC-F^wd+wZ*Vj+~p`f`7J4q?OWVVW_HPAH~%W zdYex+T;Mz#ink9>MzMH!YIt~j@vs{nP8JU_*Q|E~?t+u$7K54Ui@8neM>d*`Ji-ts zaB<0pR^XYKlbMVI|AGhKfK;cE=X#=`5<0AE%Hl9Q2>u4XV#?0%LW`VCL0s4VQ-ktS zVfqqCfVl`I5?q3Xd>Q=Sm>f>c@-9r#1&5!B!#a|ToFLM}Y0jVY{GxLkmMaEbCQn)E zFB;7Y_Ls%$p|`(bJnk##?zyXUHyk6;Upu+z@}<|Xzn^}E{e9>UslU1iUI~03d6oSY z7hUW{p$tdBmX3gJPSgsY3A~6kdL03>)@@CFgtd-u0BOC!+y(6GOpN0acS^3|6Q+tE8~xj>k0Cx82X4?xJWVc73aNW zs+mu!j5PC=#nO+4w2S+!h9d2X@q7Zu8JvSMXVjh2UPD77iHIfm6WJgx!WxdvILT~| zvOL*}c&|3?S-$C%rj7D6V$f5dR6_F%-e#fZJ4$&jmO-H20S z0}s0eaLrXhT7P0jY8Rtwuqv+uPFR&kxL{RY59$U$=)@-ZB`MDmyatiNzL;)dG#35% zswaCaY08e(A<}wi%F$DF)W(3ZfJQm%K;$u^;n)!I7%HP`Unp`agsz~LnBqhTZ83Ktl)B=Mi%^=C-~Kgsq>t+Fd};d6QdNA*AXU-H0Kta*?nvqb*DH5lS!Xmr z&>C4kW7P!h6bB4uCLoRg3~+Hj-iPO9GAo+Z1`*~1-bd0@sA303TIgc&QVO^V-UCpC zeRiSN{j(1GXYe-OB9w7VjDr3fVLbHczx8U-A4aO`nvGX0)tjOpr3%JTZ#3?g-DIpPoy2=|R zWZSPQU|uvS16g$FT4f+ApAxdM2wSQ0t+Bw3Z&_tGh@V#}Al&~x1y60+$fWCfdn z$x`)x2}$vkkZX`ck&xC#e|dnnd}I7IDXd<|H62R>$PSLl8UG(g>H|yZz=}HzM-%U7 zVDxcn-d(S&wpkmowY~Ca9WwODExz3p#vrM}fRYcosss7(e~6p&u#7QUE9*Nl55;)o zCq}HxIBWT81IpV{xWD+!BOBvT9ZI`_fAMbR4VB3a5F<^_7tP5 zf0fQac6~9XIT4=+P_XG3|C;UqYAKyTizahJV0lIqzqR5K`g(mSqb~dVChs@<`!?@) zysuoLwu@ZoqUJg-tmtX9#R~Girhr*~h@Bp@nID3b@WCA7($H9YE?|N^8;cZ)=TPA+ z>8`3*HcQM8jlb@*1PNSimgx2$r&(fe0pubzA%H}6$o>A8LQn+yn_d?!nq$;r#+uig zu5kKZZN~5lHPRLCAL(k_J_TLvF45I)(p8WUn;6|tstAGGg7a^yB`y*mK|I`#`g`0a z-f#Bz>v_N9{Z)x8H#P)uZ3l5>dqZobEy(yv`YO5cmWDW9qOb9Jw7X0KROqXHRWoOJ z&zElIf;(TqT?tP4V>xrgL-sVM7K5bjZJZUU)o8AHnKQ>Q_tBhc zxHMO244XUe$qODd*WZ&D+$Ul}upk)bl3u`mC{bsT$3RKsb`VLwqdd$K}Q7PUn;!*ba{Uy2pvYlSNqkKh{i z27c2FOjMCHCg0^^;GWV2+(RCvE1idjDmXvM2>7riiN($Ip+xdt@s++59q{?plwQ(L z)XNJQ=R`gBxG!^pno)7xwv!*7V%I53lxK2u5p=S6b&^-JH8fvJo|4xXpp5dbv&Y6vDJ7QtVO z^d#ih4)bBy)!FHvK0d3xpx1|9&VFLz@7RjF#pgA()6I^b?mg%e0iTR}Od_%kxXebV z2tbKOakl%5M$gcpe|RW(07@xgJg-|%9q6mNj{L5hw}2SygW)# zChW1UVjYN`!>`-WAd6Q!G&@>)U&i7A#t*Zdh^fR5NLK)6x_Su zWI~Sfk9TJBs^-s;f0X-D`dt13VIO2}2}}O{_nH5yy8EfOGyvo7@8;3tky&g0dZnjp;&O;T<|{au7Y;_sUbetP;OkJ z5!k)npHGd=MDXt^lpZ_~^tXO;wt-u-+3VWW!Z^P6J7Dever7SlMAq+aVgoSSuSoJq zDuaJjlNwd7OF7+zEY=@tU1a3f5fwqz88#NGMD?0h2Bcdc&Q0+}etI0WinVeT5Y(9R z@Pzf@QCb_{BBLkT8eN5!T!}A5PV?RP9-O7IoyUrOfrB^7)Pz;Che(L(t>DwtiCklI zVXl8V`4i*u|4`R0*2(;H2Ls<&TbwdFr}VBaf`y}Lx)6z0`1~pB#x*|naz z0jm|PXk)6DxF}nzq)QZwO+S>)D)Bt)`HP-Su@D)s=oCqz37?MrGZda=3%)!8AJtDt z4U32F*YF{KKJ^tgr14*3<*b@ksY3g=t9M6LYS2g2bMAIE^q`5PDya}$oIjoOd2l>G z`oblg7qDmknb>B;M(NnY@&Z-v`(XYVtZWtYkNg{fLCFSUW9aeh&dJVN-H-P&YJDa) zjaBoXzawgOljd=zcl_UN^+yA-pN;K|00SZkI&|a8?0{=hJmDZ5f;;Oe?!16lU+6f6 zKvSvHg*?!e+Y><}T3}%6X!0jKnTQWcz2y@~9419@Z)ij@p4f1M4RL@?!lHcJAqJ1X-Xk_)TSK^rkZ z*|F0xY#4Hwl7ECiI-$Av&V6^l;Z&BN@-UoaFUk8YL)I1HM~h(~RiBFYJTZ zHsZ6+-C{huy*-)V@auF`V!24?8*ka=9Ts~uXv_+4GsUl+jh&KhaN4=)|L1fr1_3&I zd`phV3!}O4iOEm0)wGV(EL3zy_0U_ZhqB5@@5?i7>Nc_*(#}0Lc8(lwVu`;Wmi^98 zvXF)$O*>3U_&?Y+;m|=<0T)=ga0wm}{300zX=q>;;MviT-_%j^x*s@4m@Q{SDbZA6V!PvRM&gY> zK+;;|b=_5ku>`{!1;bKYi?_}eEXiZM09ec(w1`6B47PjDq06cY*z8o(OL%5$A4+ zc%-Vuz^Ie|O_YY)EgB%;14J2oXuwnB|Cs6SG!TZx+co3=`g$M-OZeF~Fswi!HVn zhlG+WWo__*fMe=nu)oAyz=aZKAicrK5lLwZ`Z;?VV_alPfZ*IMDGb3&28clI_e>IR zSN2TCj7JNqtndl(70n!YoghqvH>k{H(6T>~YPz6&_9vuQ1VD>D(sBzg z2F}(r6bsO6=jbwlK8Etkrc2KWaDY5U-{LYq%kSf_&A@}AH6cx>V1-NqX(4BrT$j4# z8(vDe@&8hjZ>arHK!x!+`_>0C!ry0G&#nX^a9r%1z7Z8SOQeSv%;|JFqOq`=Ej9`#r zEzIvcoh;1`t^M0U&NzI(eLTgDiu9|-zg_2n3r@NuSOF=Kgj_uKfxd(_1ZJsU1mmZi zymIox7zaruJi%{HS@FD4F8~90=ALh40No8+rcs;YIZ{uhq-S>vt_RLWH#+gl?9a2< zgw99;{0P}3;>6wZ%szwKjDC%5ieiF0OzZJp94{BZnvGcB4kiSVID_%2eVTk{@&ub; z6#U%1Fque(>#&es6sS%sA2QXDoMw9QR%V)3o&Pw=Z#-~}HDc}MBA2~GU93LN)E5vg+$fN@l+y|^9q>%E=lBXDfqbxUo*>eEV znSe?0j`1dM>9|nzBvSyR$rexK@&u2M&a>@#{nqMEKAa<$PmRaVG_RtgF|KR(lQ)Zg z+QID8DR)pYS`$Q`Sq3ZY1-w{*)!oqFM_>^~SdJdJN^nNk?#kd7Qj5>f3qYij6 z>MJKP+d6t^2hR14Js{>}=;;w-@;xTQqS#{U^PA&`wyN<>*Z5>S{&=0a=h?5@BFs`l zVZ@Uz-3Vw&;ZCUMzx2Cernyst1rhykR+@Q5rXJHf3c#~mz<)C<1@{ac8O>PD1snuw zjG1oPCn>i>YQ`a$LB~gt1Cl^}uiU21oeUMUGO4QZUGQFJh1n=@e>npC=i7R_NNhJH z%hW53qWQ)X8Tl2NA-}kBk@cyy`8L)C+InArqR>O=fqXKCW5$jo$JAaRsJYooRbY*Z z&CLyq`wLvy7reich%`2^j2EN%|BltZVe%2E#qxqwaWq@?5*5Z?xT z_fH1}VjJl>4vVmvkKd_wjAAi={9;&cc-}PN#`hj`ObYP#MzqxyDm(C|WkM!d_>^Ps*w|NL)P=igkD zb*lnxIJNR@3h0;ZHyUqJ!Q`76{=XXzF}nVPb+bn!A(=pchgHmt%U?LzR4OT1oXA!{hN!j_M8I=F7=PtloOF*3{>yF7hNhI4T7>>;nk~vhjD# zg6BM(eGtKbv(l)U!dA=KMJ-=QiZr9~Tmww%A}LkscBl@QiP{nYK=u+u(jQz@$BI$- zb%&p*K>bsVW|x#GVC`(XKB?(K1i_N1f*r4TB<0 zOFzDsHtMZ;9C@b(o(Fyg2e2iNxnW*3GXv)ziUj*8P-7#Q%L!~L6-nYs8K@?|15f@` zQ8RxF9?H9u%_9p>=cAyep3Z)Y2on*uY&;AME@>a0eg$8v21Uw^C;jz7|9r?lJN_B_ zXWKtp{@L`;hJPYI$J$us#}Rj2=o5NF2rA}>Si!G_ko*PfkDi(&h?~jeKcF-}Mw34Y z0g_VaZ`BZBvOmO;as(7%x79y)F*C&E->^m8=+ofgv*xD#9waE~Ar?oC5jQ9{V+V>w3$O;=LV5XR$3Lm0mz z4PpEW=NDMQG|$OI=!8u!G<(i9XRtXVA_;>@CdGhn%#i{wz5+CyGtV=F4w5Pgz!Rwe|Plr8960E$7MRDmCc}#2m<~A*Pc+QN5J+2(h>) z7&zXmSNWdE`nZ>>k;OnJvEAM9EVJ&U>>S5(nQbh$K<)Vjm%88oK8`O0qa)UOj}YL9 zie(_^UX1iKTfZ3nJ!&J4`^dA?#u4eJR5#gn`@&Yc7XvVAO|+>xY%`T%v{7CRfa$Ii zGz}}WONG`f6fUNO-cZP-rYIMPJoh-1RN&zsWsd`@$Z{puZ0Tk>a2pme(@@8*cof;3 zJHB#ki!KH}vdj1Z4;>X~GX{D;t`9CkD=IVATay%gSqBsgd?7rVR2YdfLmOA%$5I<; zgzev z;z!v9RE|k(3vLL8f+Akunbb$w_wnUMEIn_)AUVp4(X7yV5INo@m&k(dx0VThyD0?U z-Z!fu%%IMfPVgQn$uyih;8EY#Ab2w7GdRE-gsjE0gxEU+Vv|8XDr0^RQ77{|VJJAP z3O^tt$Fy$c2V|lY$G5@pnyq*MZXb>xDAX@HIJ-@EIA_3&<3fEa2Rn0KLESgD*KD6UQ$pt1c%cZT-Qr}LQYr5fg zWv(X+ULX?8U=o4vtaEH7p>M@LC5EyN1jI%VWd#rr(+)4L1jI{%)_!6yrT~o>VqXIJ zHCqZ|_po&dk!}t|cuhk8)+IvUNWH3$0>4a%9=a$*4@eHGDX8KN zL>~7&k+TOO?hS{Q=-Go1_tMu(A$r;hqEA{3yH9FQIsa9nKlddddfK=q(TfU6^q|6a zj|u~k7gWgm1uEqIwNT+&L@z2x^w&a#S3~scS4jF7*Xo;Br`417>00#uRjnTO-RpS> zsIO}Ey)M!V;&&|3{p+RG)5ce%R?o&2)R$!o{v~SlqgN;3*RD=N_ z*Xr+IBJ|fwtEY`?3V02?6z~{$U&dNJTe_}J^e?8>ufIB?_prJz4^v)MP90qZ>#JHl z&OIC-e@LeMeP05ir;Te8{a1=sPhN+C=(kVktH<>lZhCPXXMmpj^~Z1z>F+p>V|Y6~ z@Y~^m=i|Cx2q;@u^v)5-M?^qubi~DnCn5ahGfp6(Ms!u|7thpe$kTh?#pm>6SFvpS zWLmIc`IZIf;-uJ|ALn3#7KfA@7N7nI|Mp^U@A54XYsWLT!+$^eUSd*Q(y9R>Ox!T z_NG1R6TB^Vd)n|Z3o+r~nk;;sq%?s+8rl#Ha_jt?n(8cW51-(dzLfVYmc~7{ZoJpe z?0an8xF6geWNYA5Xj0PQ;F|Ql&Nx@7bH6-om6rN;idH1j@Le3#vs(^}2@7f2(+xa$ zM!K;+OjW#kF%M!rxl54S4k)yKKi_i+*D33AZF&&f-h;RR?*U-7;-Lhz;XNFnn?_62 zFL1XCaCaBp!ydSG0(aC8Ixt`bxFYm2aJ|14a7$L@ecr%pi59NT;5%V z`f_J(G=u?=e37UEd@00JGqrp9j8-pHuM(_|@Ph3Q5w=95D?v3BqhF@067t=d4 zTeB4z9X!AlLe5`e-EVH7ECF#G1WYSqhDE~>TtH^;2-_wm*0?VxeXSfn%rE0WjD`+p zv|o~nAsCwHeU}K)SP!dT0+Np=$h`r{H}9W<2jzGtD-+3gxwwAHCD%?5GHylX+H(CY z^#zg-t9^;&Q9n@zPR0)3NE`r%W)7yOTqnGYgp_48z?2M5GoP4aJe_DHYmEDa(=6|= zaGI42;;x|1IF?HEWN%R{nv}LmOTBZBVdY9B7gln`^#i@9JcEA;J)*;8kqlhts;9i* zdabvd4Mkvj1WIH`ny|V!{;ijb(5(nPdc_EhMe-#;Xj*wi2+fIUs|fuQZaxyX7Z{Co z_3AMi^X+xT=rBQF7^Afk6Qh@{#KhRe+E3mu)_(H-inX5?!D!kFjOM!PFwp<|Rg8WK zEc%Z;MzhTLx?*%JmHzR>=#Q_Hut}lR6xGASPjgW-RS$9>*J1P+RUV25QP}q(zMCug zG_CYs69NEhD6RBA{Ad9CW?{0u?WW=4QMXR)K!5&hsMCi@ndeE2+6Tk!dP zZlow1QB_@vc4GkY_^TB1$C*MRT<-OvklZu+Wltf$te!7t$ThUhB0Eb&re1I<_aIu5XOqvRa;xth%sp#TxqUx~gzf~u?e?|rJey+wmDb<5|Oc;U2{44fm4JC04D)b|vPk2{U1=Lfx zxB)<67I~=pL{H=IZrCMdS57vMBILL{GGi+n5#2ygh`H&bneV)Z?T3m^PEf>WgfNf5 zO&%EMPuC1`cAmivm23_P!$qST+oQGUo>b^YdF-@EhT{FUzamUO^zuu7wVufsxb$B| z8t@oHCIn9{jDe%oq$Dqi&m*l%X&fY=@8~x(Mih<5*rJ;FWwY)J*tmE6pEqo=P7pkZ zvemwW5wC(HhriC4NCJZ~$ol|GIF{!%PZq#w1P*Fmc2D3m0!MH)1vpluW$Qe8PMv81 zGJ`c!41C@={8hO=tYi&osB1GohItcNFmF&#_Ns2Mpfu^-f@Ma`QtJ-sZl!$F&V6zc&=FJ5dSx*-_YB_RPL=7D*03u;Q-&v6*WJ|ZD;BGR8eXjA>LmB^=<52V zsfy~esW4$GK^#q0(NtPMrRSir&c~o*drNv|&Ix1-3d}+>2uqd{8>}(^5|CZMQ<~yHc3zL05bte-Pt_Q zRlqd#?Ra|+kN04<^ln-MwV?E{5aG|D2xlsekg6W7IAhaiaIx0&3#pX&gTSzmv$b+o zUSA_;ul#Hph7kkj@Fa>snhsvsOC!v+7`0#l%pN-*qI!_Aut+xdT?`R83PcFNGWn7t z7qfE+Biy3FBDsfGRklFAUr~q-$E7k6mZ>gYc?9puD5Zv z^A3W=CvgPzhI7oV!~?C1TTPIpDmw%bjhCwB|&G zs?@leFoE&GB-;z!Bs=f^6o-$E$mf%3SlSd&S+j9qA;KIX)gaaIn|7c@P=%+=v$P>0 z4Pc|;*hLPN#2S#!0tXsAuko&#|7$n!!ovJrvu78Ge^D^Cm)#4V{pR?oWP^^1Cg6p% z|9;Q!V%*$|yWxdk;NenJ` zd9)zT!7jAV!pIb+jV9^Vzh_;GLcjfcLP5_5<6}?gAmFe7x4R4!N;gQWT5NP-*@{YyA z=uJMn;90MaA5&Dhw7tNj>0x|1^p|6uRWCe7S&8)&2O#qqo&qt^ta>QLAENdSg6`MnX=c z2#D;aH&S=FPyC7!@|KE*=!PdbgC;loV4Q7ta3FI`2X(|0XR|p+Yu(|+XhGmeMfd`v zr4goQ)I|npBo^HghEm?5?!qT;8YAC#g9IBBHS5CZj&+eB^B}bxRQ*@s4ozEv&s3>I zQpj{dKuuE9K1Onx*^Q&Ulq+b&*s!ecj?fpPYcZ8=eqSb!L~iGSdF^wvk7Xgh)VZ_O9Sjxx}$KR7v$ zyp<`3fY^bpZB48AQbZJmzzL`cOiF69W1?$fAsLt=<5%FGOHhXRMmuePe>3{-t4t`%I4To(+uNF;lXnamyoRi15kI$|@MlKDV5OJa} zksQHK4-Uk`iGaaJ*whY|aUhmF!b9g7l{z6G+Gre87k=*e!MG&@BqT$LjI@=a;VBr_Q-C(BklNglz4XBtz8;N>gqzuIwyfJLbdOJT zH-F;p?)yKi7V2SnG~|RShuI)?VK$z(q?iyaqX;}|-g$uItQC~XF8;kEvrFK>o`0ca zmpB45IntMI`H6H|N0AtVESv`fFG4k4ZrJWJZlbJoZ)^OF!@Yfg-+qn21Q*kl&ogH# z^WBBc$B?e)Gv@9>ng&dt>`6`s8;$MkJxUdn;W7`t`1mo|TG)1ATXL$LaCrdvoVo`2 zeyrQX5=*QcGpRs4Clx>xmL|;O;iA1@b=d)dH53JEQCYm7*VCI~L!l}j-;OAHP(?&m z#0lHtuqQ{y0!MI}pt?aRK9D@;RwY*jfj0b8HXlyzGnV_vqE4VUA3Z<4sptT-blm1h zBOO{#WV*Y_`Rvs*CPO|m4lX4+@J>BQmr+n?q>NoDMG%D$ryFt9Yhhn#$pib6VACkvuzezpHea5ACuSg%cMzt_u@(d3_(p^=Z#>v(L*MceT&^I4(vgdQ{<5 zyGS~$mLuX!2yV7YK81;SBw-ndwkz`taZPfxW)GqXqXf?c_P|V(1`SA*SOhs9(SzL) z$#}v4WJ9Cil`s<2$bnDH*4>zl<)-`zEt;YiXV;TrGjx8>1p&I9RDen$T)+zyF_1!B zsk@uR*-f*G!YYD)w80TZ@(M_Pv!yc9m&Qb6n1z4PrvOQ56P_Z& zz@9Q?Df%xf4!xn)Eqdf*aXH*Y=3vS}oXJ6)jX@|*7lSyHgJ6iKU&ldYn=dqov%?_H zSG3P;s&k)lvf=xf^&itt5mH+R4ZD=P!38^P5KdQ73wd^QRmz z?uxntxEN5l9mu*szW^04E;yh;+dvP6Aw+pvo{?M)vWZ-4%BXhGIL5O|*$aIjBN}*i zC4xXokJBIw?n3`yN$@Pyn^Fg?Q`6xKx>LTO=~Yn$G=a|o7A&B)9^OZ#v$=)3g6#Q!h6IAL-6QhaZRJ9OKRipZ<+{6FU1z)Z^qE z=mr6oUB263wlxT7D;!IafCWdPf*|5Fugh{`MU*1~PY~(wP6xD;KKX`x8ZM;Br5!%Z zI(?W`cgR$2JH+mt)g;C#y7L~M?VO+79L`PC^aoGXrWGR7**5~uZktt#55Tt!YC4#;3V$ORoLddS)dklc4l3)UcHq?ds z9VTt!yA%HDeCA}5zlnpfnTZw{TelH`|&wGYG7gK#1sqxVC!UEwF~(H@SwQJ zx|#0CH58|Kbx*v~iLC<)$GS=(&wypSVIR3vVt9KgH*y2PK5$R~_N8sb zc&|QOQtzn9+8-`ggZI!vjd}tg;N3ekRnVBa!>z=kU9zmTWF)bw(FEDcgKx2Gw?Ky^ zN8EXjOm++f$+jRh6HOoQIUR>W$dtlRINt5>Sg{ztf)T|p*eJO$$Z$8kO)+MvbY{@A z;cK2kM!~lL7OKmxFh zY-Idy6CIZ(cPM3Jp^<}Sg_nYDVx0T}ro%k8dknfq40ZmyIyik4vZ26_Xo${hD?N4Z zv9Z~PR|Ycvht1N8^eFJ7nH+%-ACF|0pv$_6Oub|xQ$mubR=5`Ww#i73TD`^@<_%h4 zC^{w+)rBz$$5~o=ng^kDBX7?uy67ZLt<4{QryfR{TFa)y>ByN{nreoo%6d_>&tzp& zYve6e1MD~^1nhKHQ@Q6!wi7B{%%=I{)#0dtMp)JRt94-V&BBton*30$&?eb5lVk!n zRVNXWC%Ea#lSw=Yb%2A)2v8>nYvf`5fA_EN3(Ix^%QgpSc0vazEP>q$ENNU=GKvCA zehEuM04QwYb$SCV+Y-<>DzK~ssT2Kw{q0})nJ`X3IY6@*yqUNiJdTX0&cVks2G6oy z4jwoRg9jopc%GEO^CSje<=_o0kAZK2S9m&qxE}v+^^m?8bOOwq=O?$$*1{{0T$u58 z%_lsNV&uUJG{}QCGfD#P(_mDSxJ^#U$S7$!76qm(gWgfS9gKN}NhPWMj5B(+PbwJ? zWE~Z(3w%{YLe51}NoM@*!;GKF8Q;6WklOKQ7h~*mGcv|ej=fngRk~6f|4$*U& zWmtmRnV^{bn?qpv&7bjqvqng9vxgbU#F0Qu?+m}-*+I6LU=iEXx-`#tOZAL5k-8V5 zF=3oDlClgo0oz7P%Rb;Yt@1Dq!O)tke-;5ZHR2q6vl56HLmnP*5#kl2g|;EJA>ZE7jveslb5b(}quhJzeLF)><* ziBXCPMU-Mq0${@iGygX-E)^KHG!YJ*R}Qw$Q^*LIEb>h!my4n)Z*iXm?IL+T zTBA$K*r!Y(TpjRVNh2kVE>i#&Rp&r?&Zp{m{y(Xk_Nn^G=E?LNSByhOKnUB*m3oRh z#vxiD^>zyVytTTH&f@5Q0jbxdpg_i)HdqOwl?lK>I{)BxyfAmYmWu1!EBgjzejTSm z5ukOdA_k~rc+EWPDbphE&7|s2x2i^ai_yK5SwgoNW=T#Np#?FzP>lFB2=f=3sH%{O z@T|%p2?5+U$a30pH;WY|=E#NnmTj7Tp^*vO5z!H8a+oyA*NtP5*4B+<@kL?)4jKW^ za|03p7~&bLBUX2$`B(sgCkI#)#6-fd-h>LUE9ONL)V)v7=5bNA=}Itg8x4~}^c&`2 zNw4TJ>~{xsig=%twA96(@fReQ)KK*gFOy5@#1-TMBnI^~$%Q9HZ4|j$fDSMUX3_J` z?jM)t!+8WjoviFtKw#$u$*3RK{}&OJOIfvFctFxWl(B?a#ai*<%NdY4x$#UE^=S*u zkdXy~s2K)RWa77&611TyPH^TisV^Pao?Rv&zQU5%v? z$5gwuWa*9rO~;>Un>C{$>BNK6H5kZg7V5*c;uGY~{5JD6d>3|k^wVl6$`OgI#S~LY z8-+Lx*4K5ckMN)qPZ?cRm1y2$TKCa6S5>vwRX_V8P!rr&!4vz0^@799B9iAZF|ZTXeKp=_v0_=n95uLYJHnS|7-^&G~n}V+jpt^G&pQ z3uque9TK@a!-Ix;eISW5M$}R%b1crbpugV&KIg}FlJ6#y(5k(DP@qa1<1^@PdyW$zLa@uj89;)3fwRqs!YEIGQ zZAc4%eiqP$l|?JI6sHDnyDlWS=RfhO2qB8NpV4E_O&-NDGhx~%-v!*7$#;f#%<~KR z7Gw&~s@2Bfh{e*V#-}94|C0|Vf4NR;gAeBYK?x4?T}hb?X}n#{Kb=L#H~F2JP@oSb zN;UUl zO3Z$Fezsg69^Y>L!T->(dFhxXkCoXy7q5lRuC0&mW6WnpUCw0qVQ-ay^+ zR3`tSAK8I89&mfEuV1m5t!J9&1fY_n&8{0UvM3Q z`v8Dk59Pt;G~5H>{vQba``lm>e1Y-n(GHwMOmXz9Zs*Vcqo}yCexv1^$&)0sXrqCpt#xA zCy04&Kjb~hj5s(mS=4TSWF~P4J&OXEo_!#5o3`0A4jD~IfE#jmH)^r=#Wo1wl3{Oz zt-v67%I1h|<`cWt&us5H$nx_5a&Ca2j_KoR0OO}*w|FLHvTm^eNaCIcV+=IipL=3b%8%==-8HN2rOd;%q}Hlb~NQ)UjgF|Efdj!ZboXZ zhf*zj{#OwMT3w(12cgI??6V7t=dNP$%%A%^SuCP^V8E##Dau2o>h0>Ud2wBD{BOSI z4UgZERet*K_d__n7{Zx;2p{`<{o4~uomS^q8N#nz!3K_trANQ)*uYP{JT~z1ctBQu z4Ic1Q3m$+A>RLPiU2BO4gvUwMR?{jd{l$0y9yO8s8azN%J9z-K?aF~#ng1YpcHBUU z3(AK@tiwc0(6noo9c_bcBPK0`hs zpS&<9U=g(ctZ)KTdHPvs?u8R<+>gXzZ=ak%P7VKFFoZhw@MHqSpf59lARL*%^8<}s zjR^z=g|>KViDs@~0)@a|!%D~Zzg7f3z9VaTiOk^ZUV7>A57k-t`Csq(%)<*V^sa$p zo?AS8V0cK-5@=t=d6A+|&t6{zAN!jv$sw?cSfC*Saz(G{85%gn-ZUw6w4~RBf}mbA zTGDIqf1}sn$PwwL_?Z>Ku*A@DQm;{`&d?X=EcF`H8}*vrx!Ba=2&l5S6$*d=(t{ul$kg)c6ONyAo~iTyAfBFRt@WgBnr}_}1o@1P-feM_g4?s(iS1Og|d(^c*BB9xv*K9Am zi@9Ykbr0R71GDOm#46v%P!@U3&Xkqcyga+?tL5d#Y_)wXTvS=pY{TUv{!C`K>LCnQ z@~!Fm!;jhBny%Ss;0(*r*)qunaHGuHaA<)xQqg&8jbf*-?8j+F6^WeaG^FJL>1LRj z{Ml*va5ksRXoua6=R~2-W*myKBM?O(zW6xQ{1cR!f1JHV>ytm7PoLxI^FDp9e~PwM z=EWsP7c`%GOH&p`Pu$s@%$SPMS8zR|XgURMW+y8%iX9Hl@an<+x-rMiDA5YTmYNeIs z`(6~h4zjb~yGn$kC(E{E$F_*=VA@b+Ev@a<&l?ih257ONdnF#WnRuwI&*nfF*N^4O z+W%E;MSvy0WL&e^xybkw^i!-p$JokK1D+W3KEU|!d7w}M&*kK*MI@pg#88H3vt=aM z0~MMMM;GP=<&m12N^HNT^i7=$?uE&n2cl{zwc~Ej0u54@qo77EtH_#i4`?4OtM9m4=e(l$83J3N#UVX zX?dyA*#my1>bvK?^MSL+c1;*503EFoLa;UXypXi6QPm=YR_C|CF-e&snU6y&LA$kXh`mfI;a0WKJj&DqbX@{?2nkf!b}%d210RAEnEOumiL z7=jZ6C-9bsotnNG)RFAOjfP>}7bzz@lvCrRCZeq!x`KND_Gm!?t>dXvgX! zjT=37JEVxfmRa%#0}wXomln6iJ<4wrm9d#(RpU+@iGB1uZ{R&=qvJs0Js_K_$6^%i z!#vEKC!U6o^2b&GJ0xEAadbf%H5&?%CFM`~m{7bo8%52ywm-2h4p&J_w@4Nj|z5hU= zBEbukwN;^p$K?aSE;F2*hw|sJ!U{*MH(5Ed?3AO9$dbp@MuciuSiwsX1qyYkTB%TN zx=mTEi0TWU@Tfq1{Wzs*cPnTmq6l?a32jns4^%dRI_(a}D7;Zsnnv07m0->^KZ9z1 z9$`lN0|`sQl*5)f)oXe*Zi*H7tJx6rp79{b#~j1-Artp;bC>2DS+Gqb#UdOnvzhBG zz)qe(Ge|}R1M)?`wLm)-*&JO`>k&tk0ijyf4(-V^r~|CfKz1v(IpsgBniTCo`f;o# z26CbfD=HQimDmIdjY^<4mHF0bt0n!U zkVfXTQHTN8n%CuM*<`Ie8mmQ+?@;~}8{lf&pFxg>4z7Wnwz-}_P{zJm&9;` zWu(^*QFOQF+9Li_NK5Zl71&n6%Fsz;48ITtql^x?xl+I^Y$)EyvP50oC%_F%*r~eD zA?=i0e@#M-um;vD;?R(Zm_potD~;xN1k<1>YTHI_Tm~>vYpnyhZWJ1LC`#C55u3bl z`arZw7vg^k&{!Les%G3!L{~ z`FlXH$3|I!9VwetqRpA$sGe9;D$hA)XswxR`fPrP=?*-YfS=uYOesR9<{a!+`1DNX z_i5)}80;Ogdsv_v?uKY*!J{oe*(c({99rc{C%lWe?jS?H4t96EXkDeTEsGquOzxoB zPK{%61-XLqn+aF4gCV;Rcb+gcu6DTcn0>!YjCM;&%%;HI=p%UncE*L{Y^EjF48ujP zxyko5)$7;yaNSnUm;wZJc~F{q8Y>d5j>9~;0T~MSB54SPS9hL=|8Eq>KdA|m|5`(+ zd+E-Sm>;bG(P|#vi1~pzR2{}JORCf=h9`DPmz{nE<5wII2?!huppCZi2IKP9 zBm6>$fGvrJBn!}mk}O(p?jp7{c;eVH7E@tRh+}wYL5(HnS9E|3VePi%wG&GKdVXO+ zH%@Zlb+Enp_=9B;9YHwi^1x-A0)Gpi!P7)~oT~G~n^nU_3tindWw2 z6FY*6W#pjoxp-4j7f~WJ!?oQZ7n|}Zni}OAF%pM17T$cg zhFa86vQaw_E9h9tuEQ*lDO8(giaw)0T0k~62E51QW&Hr4}l=ihl2j zx2S$1SPQZa;%~5XjR1`nS7%FH3>HNz&Lf#ySSE(sNqnPn{MVBXuR=P!dKg|k$?#I4 zX-J*W9!(mmkk8dK{R;0Pj#LQd}4ci>mzGjk6V1Yr^!umETdo`X<^9(zN!dO7pj=dK#W7 ze>-Caai6MoDmALs8zY7orG(ZO&Os5+l@a`@gEe!A+&AF9=ls(;IG=PGPQ>b9d2C=W zNjtd4KMQnlA<2yZrHP z#xUu((gN?m^AN>z*&&StqjV+4U4uwAaMf}KNGE36v*=+5T+!_ zu^n8L0vk*D9LP4YH!wTMiAP@!dMi@I+u<7DEI<71W=Ru+^1 zKR*E_G!UN>;VBX(Sqy^AHgs)FJZ;tI*rU)7j%*4tQ9=!g1o- zi)vx&l?))lR@PTxJJ(f9mlxKRsRbR`x;H_HZgwFW zpvy!B&LhdI*;-i;1eZ9^R8oO++pHQ$-RD%Do=I&s6>LF$sKF;w8!#uiZJyE-rUsXX zePI%E6J?y4OW!reTLiZ)O$bV=lQ%8cDFky0NFX|dT!wK*xNo*4Gs1n&h5IngD70UB z0}TzwQNittVrn%#bW-lL5_CWAl_EiYaWx>I; z;L^bAf|oVdB7;SW45nf0k-?4(+?pjViYcr8h*4Z>xD-PX zE<3?xZXGUj7sjQ^u4qI%RnpZkZ9ChLn6hkLE?rwB(^#dCB@M(>Ev-9Bx+HU zP9DwBB_jk@V08v0!Z}hT8dH_=Tu9vD-O3&O*^me=naJ%LFyRnQJftK7XB7xB+k{mA zOREtfhs-u0to3$^Ht_}8w?V};g4&%3T!OyMFIr1$+)=1tCm#<~n5nr?>zVn>X7bXK zrXNKLHK)0>tp+N}E`4U!eH+KJ`SHNk{Co}z@O5uaA@v9gBvzt4*)a|$MQmVio^)r~ zH<~t>@Qeq<`DGEUtN+Z0o=8jnWLxX4f^Y%k7>n-1>r5+@p0R=g{Qbqti|XJb4)K^qQCY zLUzW|2c-t3cgUvRvG*XKu2r7WhjLT`uOv9FD%QUOW1fmbh$v(W%o+(c2*nh{;}S#F zG8>K!=71pul>lz`cvN4;FvADC_0P0$LqAwi(3*#iwTCn(ZoPGoB7@47JSi|Jh-<*W z2!0_~CTJ1%APc-Q=w2&(u&RsYXbgc5*r~d&z#f(AcY5GT^woJ<{L#|w_6`w}(PGdw zO-51i3tff$nI86;xaygKDMuYKii1fsw{F>Wc@BZ`cv#CkFwFm25$ntzi4SbW>(opl z4R929R`7WxE;Iw?7i<$EyK><#K!VpUQn;yd3MXzE#6}_?BnvK@cb%|QTT%$IQ&AH) z?NL3djujePbjy9Z3|0D{Mv%VP`f5kUcQKTOeF z|0eR$*|_iY)94dRn5M{uATJw9a$;V)GZ-m&5m;1vJX1{VwIuQ6=6L|H3b;!XY0@&G7`vdG+=!6764d^jZP5;)YHjd0ju z@FApMGJMJB9m3(|etsSt28&YH8XN`~uN;S)wOeO%Jn#-<@tv@HKWtnZN!@gN{=r1$ z8cgijST~q3J2V(flE$G%*NbKblg2P~qB+*0_K?GkEgD#|n|B!Vp<~s#IOh^vKQq{j zv9dr|JJ?u+Xj44A!3S9(JIL}z7ZR@-WSFruJJ$wTS7wk&Nfa2pgfK}1$tW=bDH?%b z%DZF&Nj@)%KrZ+5wFF|znD*=-3s5#1WG$BrV=~AloP zNOdU9#QHRxT{3Qavv6N7a&TY?pTCm0)!7+LWSbzRuNiJpHfIK3@n^^JQ!2=b3qK`} z;(_p3!#)aYt@BetWPy$~a2SS&-f^Ll7p&?H|0Lt5-lzN=mS3`)eAs!iSlA>uz9&6FZ&8ALp*gv zTU*Ufi4k9F;HAW{B^H5sDV5fFDe-a|X(HWGN}V{TU{$K~QYuLDx|& z5R`580c~|$*h?wj&`ZgleidFyTjZsLqB-?af^H09g?cX~*<>?bN+??pMdayoelI0T zYUrb6xaJ>xlnS(;>i9o#VCqo6@Q-|yV9RUYhou44iz@T7>$4p-?l2#vNFHA}BpF=W zD;{jK!>2JFjes0yu0}(ChpQ2bR{7KO7;mGH0dJ#e&w#hlaDGpI51EFJLW)JTcaEO2 zf`-yB_RD9o#1u#@;L4iY@pnNWr%k{LZ0?)vA>Xy1dEnB9|_PzNNXL^!yDFT{43vxZGhCp$lq82 zxTEEb;4?Lu3b)CBaf?=9f>#LV<7e_Le7QcGH`N-86#Y7vuW%q1L?bBuY02?lfz={}dUIC~dQoeOnb-#^J*Fdt zVPfup_*s6LUK*K6vo5-IX3Tlk?9#WoB?>jQ7*t|q%G!)wPl)cL-m+)gR;4Pn($GA# z!2qofe9t-d0kQpFn3hJ86d%%0*uhn1>BXk644d5$NDGqK`UWd~Bz>@uDy@sT%n5wZ ziR|Z27zVQGL4dtjre~#)aGL?pf?YKe%|>d6^i~=qe8S16RI4Q?W@-hfwTnuXdd|Q# zhYMU)lRZu`;QD;!Xi;yfS!$7;>3s@?a#qJ;+y^~sm+MhC`4+1JmQ1YU)_FKe1_eVW zAR86|u$mJgELWRvu5{vUAuF12X??m`5SnX?bW*C`PFyoDYI$3*>{f|1WUaRa>qT!J zMZpudQ6U$?6HERD&y`-Ai`}HKiIsIyxV-j&iiRrk7ivG~RxcR^A|Sd+PHa3_=WUTS zJlog+Vo2WlP}VE^imTyKz$NIVkMXu}^vcwvah0t^1{b4BBing$2J-;~U;%pt4h7n> z6OR|QOn6TQjSK}05X}xK^;kH%i3Iik&PuaZ&~P)=$pblCgrhB>;1hB4oSZFm7V1_6 zHdb=xY{4DQ7OD4=ohKN|aIDt~g;HDf3+*)K_`)83v)Iup#f&+uuTRJ$2&@2u%%JpV z%z;j5D!eEuaP%&?V66FAdJd@nxT$y2a^xo$$^i%U<s1t*};scV;1SM zM4g_R5yk#6BWfCDifo_>&I3rA+w4Dy8Bs75!$3#n%nMbLS#XkZ$ccu*1*0`CP>*a!Hc+E3DYlKDF|6my5l*8# z@R4u}mIhN9W5v;P8@+@vcHgPmXhvfu9_vGb4`kNn0>2MtZIP1?VFf`cU1OcBK04|a zIsL9_#L28N;k=?QKVV%YEL|XfQjmv@lv%sWCRQdm;ZffGDnNr7aiBFdYr{J1g&DZa zIOFUbYy?(t6`zPT8a0}ThX|qWWSJP~5k-CQTd>(Vr7)H!jp(uFw@^oqgnj{(VBSG< zFSua*#(!$WD0?~!2!tE?1a&Y=`2NC%#ArUxqQ#C1tj2nBh$2BTrff#A?9Lmcau9WD z;8QE6YSU;to4JjY4|62-NI7l>O$%9JgCxL%Vs?zMYN z**P8sQ#NeOWEK|Gwet)xWgB(SYE6}*Pz7)`LBXbBy>`|rUPmT3Wz(RfU0P8=v^MQP z{wKPMo$cu46^4Olmb2uLkzEsp2@`w&QQ0EPB+ryLb|_*X>@^xpf|t` zUOELNEEM9Vi#SyTnV?%kwo3w1ooF8p&PqgkuqgD}5O#k`eQ`lUJfQ6H*X9NN89_w?<&(;#@eT)SW8G7@R7sFPLu_ zgQ-&mZ}(T~q`=IGhTwDnADZLz08f!$;*482{#{fGvu=i(@1^L;yBW*x{hLpq_3mzq+Uh2K0wMsFp5JBa27q1jgYa5`7Jr0}m*yNvCc+m)OujQh6v zMSBi3?x`YEYWAXXDtmaWECD96&%S zO`IwUa;o6tQ?##+E;y>YN*ChuWlhRZ42oNGsxa-OJ5~6td?;*@>Kuh39Gof~H4u(w zVJ2rmY|>d7t9|NJL3`?)DiE2`({ntS;ZUnrvptta;j(z zP8FI%m0-1|P#F{^2NS=Fyl&mE!ce%*ufnYFkt2m|I*ekO=Vteic>}8~e6t%b|HNSHyja=2wvyFox6=m|_+f zcmaMDTY~XNxbf%0xB0j*K9#4gs!-PHw;srxK-gE)*ixoTu34W zfE$kxpu89AA?Y)G^HrShE<}YK;_@SkteC65^g>vH=`08gD@1MeFsAQjn6RFD7r$&D zzr{9v(BB>R%PGG+0yT(1J{GQz`&Fhy6AI)u^h9{};cz_{t{)56=fm~m;rc0EiRk&2 zo~it2!!t&CPJ2pA+vSS>IOlQN4Q}FL-(zH110nECk*cxoXaN&Kv&t zZ~VX9aO)4ony!z8YZeiD{*<04@d2LDkB6rUY>Bmxo(b1yxoU-P6eb%Z1A91jC*Zn) zstlE!ramH=lRt2XHh7FIJ`LE9B7+ytzNQhWi-VC`wiA`A!EL|P5)H&Z%I7-Rv8aaJ z>$?@jtZ;DA!c=~8Z9@?>Bz1=-5_0loVBkp%PPzS5EC`<@H`}M~Zgo<*g!r4t53$W1 ziYHxVzo3t?FbdoRG!^D8l(ntjr6jEtEmikQHh%RrE_wnPPonsxZkT z^5SInrYOQ;kH_pW;p_^2HzmJuS8DL zp5)({X~A5}D}KP94y!5Xuo`hnJJkXmYo$ZKSr)JWx(+!QxzgWpem!qH2hrEEcsWqn zA5PWePXWAgg^m0BNci@3%w|7ZY5`ne| zNIBWW8~6#v_|>8>3yx?LxKwiPW+*-nb+r1TAa3ytTJsS6L$W`g*5FUu=I{d+pR48h zbuFh2!5bg&DA(kdD&Fd0C1bg^sA#JGXXKg5RJd5fG;=+2Jy-3g|=J1GInhZDtl`p&4c3|2> ziwY3PH)sy>Y%vgBuradA)T~2SG|bC6jWRoRP{%#OF|N&rh%+Dq1xq;U!ZAbl>$t}P zM;0U>ZibkW4?8_n4S6xc*FH2OA2BBRP)^&}X3_14Z;G9oS_9@_{6YYV`q_+W>jHjD zCkQKn?U!!gIk!@=QbaXZd`q+wo=OQr@X6rO0~?2$O_!3>a@2?q%CMskBXN0KrG}#q zgHpmg`B`Te^J)*D`Rrzelo+3Rna>p0AQWok#$&Y}C`D9WH?(dVk8*p_Co!=OCMi`y z+hq-6;;=0(FmkoiUU5VsCINb*$r&vl*_nC_P$8^MGf62-A!1p`AWV0TM$BkdPMJkA zm8jKuz=A@=n`AjF0~D`Hte$S*Ik&{r0*y?;8w6OXv`dqiI(V0+Hk}FOGbkQV+{ElZ z*b!*}SNo*P$yZ~9ii*y!r4}ZtLX5XmQ?*@!i%wX0;d8=MHFrDKJ|YlsSNgMDxlolm z1AJ7y#;izhluJJ2H8bP2+id5*@kgUN09LU}cqa)p)uPNbFcBRF39oZ`$_|v2iN+6< zlmj&yJ6(!5qhszsygFLZfl7vLFz^2S9PSJVBDE%Sy^Kq;nb45yA|#ARrI-VrE)g}! zZ_L6O7UJS{QIE2?BN^{>OfYIpi|N;*mdJb)#~eauG?lAj*fj2GUKLU^RPt7+1QAI+ zUDq*5XU>|-50;5OA;JgQYfh+(jVK$*-9=WYak$Bs$75kHCgX5RE>wd7;H)Vi+4*Pxkp@IMNC3qDcetiz|NQw8jd& zH?SDv!U>CUmMp$(EGAb+-_$gj-{I80jV?>6T{4HD6w^SoO_>IrA#5A9LkAhAA&OzR zLWklWHgNFblQ}rr8C?V8rzDEpW}1e$orU<6R9eb{@U{aI)zFB$(t}#nf6CltonKtd z<>cn2bGL8;tiJyS!9;bMcRJI8#^@P9X@nvb%50U%q^TSg)Zr07 zE3HS9D%hea|G#!USX)(nE#`S+wb-52Lh<6!1tR{zv=p6Fo0(~1uJ{wJc@CA9+dPXS zF)DD1R+A$etA}N)Fr2*|aL$5{!YU!x#5C{bImSc|YdokNc0l91;^@XGiuS|>9ng3$ zgeWt|xC$I{{T|H)_4Efg)C_0=6Wj89;qEVHD-+^0saAI?U>-$31T?6)Y#WQ_jnC_( z3viT_Yo#*cr7MlwU{&VRk_3dOE|7m0m7qkH-jSxAtTe4qqid+KQRqqY3d{1NAJwxG zhNosdYh8(3=ReBvCWt#B*`TQ>ok{|YxHK?8zF?;%7No0Cj}{#5Zz0~ z6bIi38B|f4L9!NZYYYV&os!4t=^b3ae9Wa=F6}Kiz%!e)FwXb~-!+YYMxpiRkmdlp z+bJd>0Tx~nv?wh$p=djq&Kd5exz!I$+N1$v@67xx{!}hsI4glds$mALE~QFd2Lv_g zI3-OQao!L0K^+=5iE|)6?&Vydyk&^<#!T>XLb#2aAE;ivf--nJV_)afaDYQhDL^OE z77HLe1G}p+ev16~z*vA7D|W_XHo-Xy$cY6YO1Aue!e8#84;Ug}=PzI9FMrPXOA}t^ z&SajszK+R+pG7j{i$Brq$6mN(1hJ!o4ji;ej((bI9o!S*A?5WkAE;UlE{Le_aS@ zUatq*=ckJR{oJk;Xco4vr_d#0tyDl8X~&eCa>J3Wg_a|`uol_X&$5}(*4K8*T%ov8 z(_(hgSVqug5?i6FwhGFDfpjovAt6bpP<*^OS7aHZ zC8*T)Hb!;;Bw7+v$ApuaZiCuU79)9-I;=ePCp2tFvT37WaKslu;bLn}eyj|TMr0K& zoUlbnt1U`eS(J1E71Evr8i0!x>7FN?%%s&svsObDCUS|m?b2Scox&q3s#g8*Xbhb) z&iH$U2J)A5JQxo_EUe|tT26%O5SLnz$#KK*ny5x*CJ7)amn-gElmIkBhd_v%wX|;5 zeeb;2!EGn%c6-FvXoeb9891yO>1{>s_2m;f@zCUe1dnV(NCD*Z?xSpYH%CSVG5}g& zkqn(;#x!{x;p{EPYg+Y(#;2IUv&i4qUJ6GIFr!M6&Oi;$q6P%9g)SgS3r9O7nX8?r zoFb^>t40v?W6Q;`;Oi=}FQNFpwtTy<^x)#Q(v!ftPspBbv_3~f(tVaS-kMV%rdN5nAu89dt9{!W_UvjjCIu`9WP5ZqGRCSZJd$e z>HE~=YYJ|qCol$Sth!X`&@gA#KB`?=#s>7m7lp*WF})4%YcHj26gy-sXH1R5C&eJC z2Shs**o>VGu>VZ8vL4j_8)pL=v&JV?5WuHwph3W56!>I8HQSoC&GkHC zS=otLB&`oqk2F5MtPBUXJ$nsxF?1id-Ah8udaWd@&Tn)*-lgO&{z_-Q`)rpMrFgyH zjI$E*qc0zke8Ln!MLT>hyh>A2K^lDvH^wF{efAKup@v*jl`Vq62e#T+gYFRL=UZb} z&RyiHXTA}>`lnF1Q@^l#va-FJi%GW*mapcy4oHnz(rS-VeHqj*)zOyQiIXI|#TL3o zJyGsOEA|=84SnG4;qqoG?=@fFxF7hp3P5gRVT)=n7+`5dg7*$~g0_n_xc8e-D+tIl3fSn{4Cs8TO#PE<=!T*C+EQYJT z+Z=Dv80qy3fzlZT>_?CqPRG;(20y8xsce=etIBH}lr+6H-lj``Jg6@0kI^P}%Bl)< zO*K3X#C@76_OrWY&%ExiqUkcNd~|OJ;6ye1Qpn1*kqGc{0nZq|n?70^^ipk`9iOph z#tIqs%aC8Um(GMQr?KR3IFo#|A3v7x%vHy_J^lja$yZVX3zE(?W*dE&m59TKD*od%Bvp?#;0lqEbHW zIvck?eEN+1KhRrZ>|;91JUWetvXO%7pS7Q@wCv5@tIeo(dQ#io-1kvp>)zIP!rfZ; z<{vA=_Te+KdiIO3;w}3b`wWa#f`Qr)jr*Yq)TfZo79KNJiW+DpdN_574k0kCb1J5# z()Ki~J5~maSfa;061Sb+n|ln&vh8f#!cq1xHF~bM(hGa!rli{D*%w-KQ5P8%fCui@ z%cU#cdM@5}t^x|XDI#t^dwQ>YahlG>gJ^O=EX_P)6a8idMZopvG|0LE-D*FAxKI-J z(77B5Bz!Q(pTQ%@v)~ef2h1%+>g!WriXDu5ID}MqtTdc&rE}31h8>&VITb_vue?=r zgvq0^F^eFno1FwX$mPwgzQ0IZr#ar5%A-y3pug9w;V&7hOhlRKpkk6bl`y3y6A`tG z6K)o}6)fIA7NjUsKmarC?m{4VKus0IqHU=V>ScK?RT2mOL4!xp!0Ko06vIw-C01%6E zR1ndLtZ6DvPXx0SK$$yL@K87zs!&%@+LE1K5V~(6s8K1jQ4xUxG8>mN?WK%oN&yJy zE{q^bD8YVs5SQ5q64re1Bhhj}#OoqhsnY3ET)PLfP_Y(!(8Q!p7<03~$2c2AJV_{c zA&O#Kt;UKiq8Lt+BYmL4-%NbNjWWB;H8Cz-#a-?)H#1&ce4};a!qp6)sm;gE!4o1 z3LOtO%OgR>Tysjqk}Fd(vCL4=F?P#?TnLL*;euQ0Ha(nY?pEdHHz056s2|LAsc_O6 zm+`7FtHsq8bHKaHcjd4ZrIQ&H-hiyAUCeML!6W^P zK@%a!Mp=6}Q%K?T^n4Q&s0Ev}Ox7lr8H({jscDQCiq6D%*2P^!M7*sRw*o5HZPF7DehRHJ;c;su(RS?!N;a}pozvaZF}GmR37LPLNQP(!b0+k z{XP8bPJXgfjqJ1Ba>b$;^O{|n$!mUbOi1!e-y$s}KkZv8)TzZBKtO=Mc&qdELBV@v zzz_+IM!I)!6}P~=D72Z`N89kRk|Ug}vrr1EvxMnz7Ew<7dNX|waVVh9`s^?Oij;^h zHkj!nO04yf6=v9^mlzNpI6&F$Qw0uC{-Sw1S$W!fCn#3{l)GLyvjrmekIj0mZ}aTL z7u03Ai8kPhh>>s5DM7CA7ub_Vu?FZHG(ef2MM#t)>L)Z0U+7%50;?Y+%8E6n6+?ael~J5V(&_bT^trS%Ce}f z8v$N>7^#IR1+a+5h^mFiZK|hea)atD;0Z;jM!5~^oJzec)xB)H(92E*d2CcHX8?%e zy5%m_9ao&43w2+8eWQ?YRT(mnA1QiH@Bzg zmOz$4ZvdbUy+MHkdOHAS?bMI@)zMpfc~SI6uPS=+{}8@AS7G3XJ$NAM_qOI+ zJ;G*U2F&k4C}_s{7tgbb_&(+^9e5_0#r*co^<07{@uXltFgHdO+lLgPvZ++&TWF@> zVvR15;&I~bt)PCnf=Wk@yMVNi}R|%|0 z&^%@^oyudTT^=(XccI;o#|-?Z-F;@nPVwlIt82S_X4;hnm9M|WavQhnZ6QX{3sK7r zNM140VPI=Ot#F2-6{Vr|om~*32%n-wkr)seXtG{EB;PGLhVmUk6~U}D9V@2&EM(cuE5VDGZCY`MdQo~qftQ@d#)s9~~}h+qh$ZPS_aX*X(Ldb2zb zsr{h}r{l3jo}+D8Q`icxS2TE{%&N~30ubz2)7r?^BMPXIu2;aY!ux4Ehqa})s`H&3 zG|Xbx$t3D4v~XcThlHX*!IUhyzQg2t4i_Lg0aIE>$VUaHFN7@0m_~p_D?@{wrIy_G z5ZfsLG`sZAB&OdXq!uzz+>V6Jr9&6h8CHtC0(lhJMn&>)uQRJNe$m<_v%V!DVDi(xRqGJZ zEofg?-0Si{pXS{w14auFq(;R$6l!H1>oC#T1YhV9oYaj0WC=7cZXst@&I+zI(-?SP zE4XSjG#CRKmSe*I$+RKaLLy{)F@v7lNJA4>{*a)1c zh^$_Hoq7!115qME^=g^$b&r9sdknbGIDF~r9s{q2$G|yRmk>TLVvq?Q1DBG!_+ziV z#{d>y>ANq}V*o3>yl4_*d$}+83-p@5fJguC3)(}3C}}p(rb`hh9bl8x>GS;Kr)u(s zJr(^mLw-zD?5qpGRx{xA>2a);E7ETeEGiO%i5-BcGkH?b6KUvO#-UtI=BBqafv7@Y zOlh3^{USAg>KHJHJkW1H8#)F^WfKp&W5DKkt1JqeQ^x>+t9c)ANN%sJ6Z;~0>7U2I`m#!P6A0ln@RV5KH)OG+K~!iW44UwV<|7+^($bNBS<^Fjvvf~8Yn z)2?+;*1iywpj_??z1m_l828FCfPZR^0sLswlep#>z%M>%uUdat+A zukvNQrbaw@GTI}_b@J^XMn^A~E_?va;~cPcjdMWX8s`8``@N`hK!0!!=uMmhP;fCK znYU8yCYtrtO24ASnpeOeGG_y?0G7Lw!Gl-8AQ}`HvSiNYcrfD?uvIdr2T=5v3{(?% zjSZ>VMqUBbuH|T-F%DpX$u!6PCWGSxWD5LBKLr7K>J`whBdj$-f*DK(9v=G#WV&-1rYruJ=qN(P^gX}&8->ITqVMB7U`1|i@i>i;d6@UJl z-rW>M`6!ACByOW-QVXe-)JAG2b&!grPEr@?j)^17Gl!Q(r>m>0%X9agT%Eo1@aoKi zvqzSf7Vlo3SzNh)Y5CYqQS{cz~FnbnyFuhN?Q{lSyV zv++Z7%d0167UKI)E*@5I#fN7WKvfyK(BH@C>mIHp5}Qk+jigPaUQ!>apR}1IdKw^Y zAq9FG8&2uzn@`RxuFic2omEd!PE(IjhiEE%H&Ua+EcHdvv(VoQMeb`xMu2;Cc;dh;%LKO(e2KJ4x4(t|uj9ZStr}Dci2M@>}iNP5LI%4Wze`_K*@97^~GQL_RRPyuP`@<@>2eIMm<1VuWTm ziuRIj)NhiIe>3S8(tgqb(ygT1NN*>F`o@QEXM7!8o;@;W)O^?B2WOAX9-LVgQ7903HGW=Zq7!ZX8rM!}O84K-eQ&s*;64ubKgqMbQLY$P7*H>E$Vtc zTGTuJsVseW2kCOYJIADaC*K?-eKSe*y@S-KzPosSH!0Bm#AGAFVsJB;&de>&9=ZMG z!s^`XV=P!-dTh{r#k* zt)q?l_!gIQ<__P1pffV`^*;gM_mm9tXfla*b9CX$s!Hqv%)ej3K@gwzvuKIfd!A`vD7-^9t zdR!tk;yJhR{5UD;zt?cS9T|C@OtB3BG5qJjYci)SfdBXNTYtI=-zP}w1L0fO^Wi(` zr{@vAm&vz6S|#bblcYx9J;d{GCxw1`J5&zgeG6(`QW_m)50lf-zgSQ-v!LyP5K^^+V?2wdr99%dM_zy-(%c= zKPhS7YdQxsXq|Y?=QC~l0t>^x47~3ny`S_~NIyVI;J++J`nBQt4O($U(0y&#d;{nt z&)xuDh3luFotL=RpRU6750bLdvc!pWydjBmF4p$4CLj zvC-Pv(gmM%?G@mpR@M13b!r`}zx`XH=t-_WPWlPbPm-P@{dLk$k$#%=Vbb3q{S4`8 zQbHM*JMJdetz{g{ns)8RnZ>2WIW#WlntWYUzwCT9SDmjbXfL=LeI+0jMT$0lbD*{c z?BjkI`q1-xq0Qag+uvXmJ;TjMNIy&Zo1}B3gf6a(pS=>TNVN{@M(gG2B(6}leO)xc zW!|x^-fze0voCS4zYlMVqK|U@Inv)EX{`gzhXkbaSrjP;Lk|4XE#PhXc~y}`T? z;Jvs~=~d~g1^|Lnji*0m3?*Z0ANNntH~QPNJ&Jyr>#vZWBmHgC-ytRa@H!q_4H|nz zP^U7)Yt==PEx!9I@25}EFVpmi{=UTZSGhh<`Zbcq&)+5eI_U+{Z;+Dl^Y^&_O;SRS z7ndJiiPqNSibsJ}^rgSkS4YvuxqgE5_eqId@mt)#m2@3xH|dk48%S>>{R7f(ll~zo zv|((zCSPO?7!9Nh$K8JFP2`N1xc?MoeVX(;q~9e;F8d7WACdks>7S53OZpt?pOW-G z)IBmHy+}=ru`%><%6#$~GV!-Rj-r3Y^+l4(|L3INBW26~eSW`0`WK{sN%~i$q<@UR z-E`!E+56C`%+D@osk^VjDWzv5jCH9IZ z`Q|_J`#+KXko2EPe?RCtUxW$H-bdFKqa%)^PsQD9m5`zc%H z>+gvQJdx|4kp7gE^!u)T7)>9%d2V@SH550yd=cY9%jH)izH%+?6mFlV-H&sxKVAO^*DsO&lo%zS zh>E}5n&U@-)J$q6>F)_f#Q)^_zexX^^kq`gIYz)K#(kt74!D}Wedbh6BHB0m!1C;D z+Eih)o^@YF%SH`>85B+&lp%Q~t)H%TqFMoVHT(~0?Bm=g1LLtBQS@iz`9GwukdpR% z?O?uWr(ZEPLdj;Vd?W3$j;5`TaIZhR(y=*`+N!@jZ^S`?-vv?=shO1E-~xR*a=w9a z#lWXs>2SXQ%<3ooy#S0Yz$K#0^wBF1LqMSL_HOD-@OJzgaMqyic2WnaNcw7Uv8KCDAWf#bF7C6_(c0;*JJTv-?X~GPosEp5C_9;o zwlV$n@Lh>S^vY;st&EY0w`1g*S*{z3`d&8qq-QmK3eHV@*Go#KJCb((1)6B?}F@PHvmQE&y&6_A+tnVy!QLLprSEZ(qq>WJ0 zZ(Vay^$&hGD!w=O0zc9uo}oXUMez{M78JLcG(g%y3NVtZ5kt9(| zD1S3)f+TV4n@Bg3ZXq2Y-ATHO^sS^B(k$r#(md%H=>+Lv()WOeHF)1cU29?fL7p{&`y)Kh!v3rLUJJiyad>!m zWO#IVYJqkcnI{KjUN zvtOwEQ=|ow{&sWS4)I-0ib-Wsh4co}4$>P*`ipmZzHi`nHs3Y;9wJ>!s)KhF+^ozs zYNFxfOVq2n_4hbscXNFcWqcz^f6s+yJNbQGcy=m0yPn@~Cf&8VtLC@IH{xRtl85It zFFc;B&5!V0-`}-5I^58cFXVfYJc37mFLPDZ!~8R1^^J_+mV?9J?D8_6gDUq$@~B+> zZKIEsf3%i=)cpj*2fWiaZRAtg`a2lD8OwaLbaM63(*1|>>0,$jscomp.propertyToPolyfillSymbol[l]=$jscomp.IS_SYMBOL_NATIVE? +$jscomp.global.Symbol(l):$jscomp.POLYFILL_PREFIX+k+"$"+l),$jscomp.defineProperty(p,$jscomp.propertyToPolyfillSymbol[l],{configurable:!0,writable:!0,value:n})))}; +$jscomp.polyfill("Promise",function(h){function n(){this.batch_=null}function k(f){return f instanceof l?f:new l(function(q,v){q(f)})}if(h&&(!($jscomp.FORCE_POLYFILL_PROMISE||$jscomp.FORCE_POLYFILL_PROMISE_WHEN_NO_UNHANDLED_REJECTION&&"undefined"===typeof $jscomp.global.PromiseRejectionEvent)||!$jscomp.global.Promise||-1===$jscomp.global.Promise.toString().indexOf("[native code]")))return h;n.prototype.asyncExecute=function(f){if(null==this.batch_){this.batch_=[];var q=this;this.asyncExecuteFunction(function(){q.executeBatch_()})}this.batch_.push(f)}; +var p=$jscomp.global.setTimeout;n.prototype.asyncExecuteFunction=function(f){p(f,0)};n.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var f=this.batch_;this.batch_=[];for(var q=0;q=y}},"es6","es3"); +$jscomp.polyfill("Array.prototype.copyWithin",function(h){function n(k){k=Number(k);return Infinity===k||-Infinity===k?k:k|0}return h?h:function(k,p,l){var y=this.length;k=n(k);p=n(p);l=void 0===l?y:n(l);k=0>k?Math.max(y+k,0):Math.min(k,y);p=0>p?Math.max(y+p,0):Math.min(p,y);l=0>l?Math.max(y+l,0):Math.min(l,y);if(kp;)--l in this?this[--k]=this[l]:delete this[--k];return this}},"es6","es3"); +$jscomp.typedArrayCopyWithin=function(h){return h?h:Array.prototype.copyWithin};$jscomp.polyfill("Int8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8ClampedArray.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5"); +$jscomp.polyfill("Uint16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float64Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5"); +var DracoDecoderModule=function(){var h="undefined"!==typeof document&&document.currentScript?document.currentScript.src:void 0;"undefined"!==typeof __filename&&(h=h||__filename);return function(n){function k(e){return a.locateFile?a.locateFile(e,U):U+e}function p(e,b){if(e){var c=ia;var d=e+b;for(b=e;c[b]&&!(b>=d);)++b;if(16g?d+=String.fromCharCode(g):(g-=65536,d+=String.fromCharCode(55296|g>>10,56320|g&1023))}}else d+=String.fromCharCode(g)}c=d}}else c="";return c}function l(e){va=e;a.HEAP8=W=new Int8Array(e);a.HEAP16=new Int16Array(e);a.HEAP32=ca=new Int32Array(e);a.HEAPU8=ia=new Uint8Array(e);a.HEAPU16=new Uint16Array(e);a.HEAPU32=Y=new Uint32Array(e);a.HEAPF32=new Float32Array(e);a.HEAPF64=new Float64Array(e)}function y(e){if(a.onAbort)a.onAbort(e); +e="Aborted("+e+")";da(e);wa=!0;e=new WebAssembly.RuntimeError(e+". Build with -sASSERTIONS for more info.");na(e);throw e;}function f(e){try{if(e==P&&ea)return new Uint8Array(ea);if(oa)return oa(e);throw"both async and sync fetching of the wasm failed";}catch(b){y(b)}}function q(){if(!ea&&(xa||fa)){if("function"==typeof fetch&&!P.startsWith("file://"))return fetch(P,{credentials:"same-origin"}).then(function(e){if(!e.ok)throw"failed to load wasm binary file at '"+P+"'";return e.arrayBuffer()}).catch(function(){return f(P)}); +if(pa)return new Promise(function(e,b){pa(P,function(c){e(new Uint8Array(c))},b)})}return Promise.resolve().then(function(){return f(P)})}function v(e){for(;0=ja.length&&(ja.length=e+1),ja[e]=b=ya.get(e));return b}function O(e){this.excPtr=e;this.ptr=e-24;this.set_type=function(b){Y[this.ptr+4>>2]=b};this.get_type= +function(){return Y[this.ptr+4>>2]};this.set_destructor=function(b){Y[this.ptr+8>>2]=b};this.get_destructor=function(){return Y[this.ptr+8>>2]};this.set_refcount=function(b){ca[this.ptr>>2]=b};this.set_caught=function(b){W[this.ptr+12>>0]=b?1:0};this.get_caught=function(){return 0!=W[this.ptr+12>>0]};this.set_rethrown=function(b){W[this.ptr+13>>0]=b?1:0};this.get_rethrown=function(){return 0!=W[this.ptr+13>>0]};this.init=function(b,c){this.set_adjusted_ptr(0);this.set_type(b);this.set_destructor(c); +this.set_refcount(0);this.set_caught(!1);this.set_rethrown(!1)};this.add_ref=function(){ca[this.ptr>>2]+=1};this.release_ref=function(){var b=ca[this.ptr>>2];ca[this.ptr>>2]=b-1;return 1===b};this.set_adjusted_ptr=function(b){Y[this.ptr+16>>2]=b};this.get_adjusted_ptr=function(){return Y[this.ptr+16>>2]};this.get_exception_ptr=function(){if(za(this.get_type()))return Y[this.excPtr>>2];var b=this.get_adjusted_ptr();return 0!==b?b:this.excPtr}}function Z(e){function b(){if(!ka&&(ka=!0,a.calledRun=!0, +!wa)){Aa=!0;v(qa);Ba(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)Ca.unshift(a.postRun.shift());v(Ca)}}if(!(0=d&&(d=65536+((d&1023)<<10)|e.charCodeAt(++c)&1023);127>=d?++b:b=2047>=d?b+2:65535>=d?b+3:b+4}b=Array(b+1);c=0;d=b.length;if(0=u){var aa=e.charCodeAt(++g);u=65536+((u&1023)<<10)|aa&1023}if(127>=u){if(c>=d)break; +b[c++]=u}else{if(2047>=u){if(c+1>=d)break;b[c++]=192|u>>6}else{if(65535>=u){if(c+2>=d)break;b[c++]=224|u>>12}else{if(c+3>=d)break;b[c++]=240|u>>18;b[c++]=128|u>>12&63}b[c++]=128|u>>6&63}b[c++]=128|u&63}}b[c]=0}e=r.alloc(b,W);r.copy(b,W,e);return e}return e}function ra(e){if("object"===typeof e){var b=r.alloc(e,W);r.copy(e,W,b);return b}return e}function X(){throw"cannot construct a VoidPtr, no constructor in IDL";}function S(){this.ptr=Ea();x(S)[this.ptr]=this}function Q(){this.ptr=Fa();x(Q)[this.ptr]= +this}function V(){this.ptr=Ga();x(V)[this.ptr]=this}function w(){this.ptr=Ha();x(w)[this.ptr]=this}function C(){this.ptr=Ia();x(C)[this.ptr]=this}function F(){this.ptr=Ja();x(F)[this.ptr]=this}function G(){this.ptr=Ka();x(G)[this.ptr]=this}function E(){this.ptr=La();x(E)[this.ptr]=this}function T(){this.ptr=Ma();x(T)[this.ptr]=this}function B(){throw"cannot construct a Status, no constructor in IDL";}function H(){this.ptr=Na();x(H)[this.ptr]=this}function I(){this.ptr=Oa();x(I)[this.ptr]=this}function J(){this.ptr= +Pa();x(J)[this.ptr]=this}function K(){this.ptr=Qa();x(K)[this.ptr]=this}function L(){this.ptr=Ra();x(L)[this.ptr]=this}function M(){this.ptr=Sa();x(M)[this.ptr]=this}function N(){this.ptr=Ta();x(N)[this.ptr]=this}function z(){this.ptr=Ua();x(z)[this.ptr]=this}function m(){this.ptr=Va();x(m)[this.ptr]=this}n=n||{};var a="undefined"!=typeof n?n:{},Ba,na;a.ready=new Promise(function(e,b){Ba=e;na=b});var Wa=!1,Xa=!1;a.onRuntimeInitialized=function(){Wa=!0;if(Xa&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)}; +a.onModuleParsed=function(){Xa=!0;if(Wa&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.isVersionSupported=function(e){if("string"!==typeof e)return!1;e=e.split(".");return 2>e.length||3=e[1]?!0:0!=e[0]||10>>=0;if(2147483648=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,e+100663296);var g=Math;d=Math.max(e,d);g=g.min.call(g,2147483648,d+(65536-d%65536)%65536);a:{try{ma.grow(g-va.byteLength+65535>>>16);l(ma.buffer);var u=1;break a}catch(aa){}u=void 0}if(u)return!0}return!1}}; +(function(){function e(g,u){a.asm=g.exports;ma=a.asm.f;l(ma.buffer);ya=a.asm.h;qa.unshift(a.asm.g);ba--;a.monitorRunDependencies&&a.monitorRunDependencies(ba);0==ba&&(null!==ta&&(clearInterval(ta),ta=null),ha&&(g=ha,ha=null,g()))}function b(g){e(g.instance)}function c(g){return q().then(function(u){return WebAssembly.instantiate(u,d)}).then(function(u){return u}).then(g,function(u){da("failed to asynchronously prepare wasm: "+u);y(u)})}var d={a:wd};ba++;a.monitorRunDependencies&&a.monitorRunDependencies(ba); +if(a.instantiateWasm)try{return a.instantiateWasm(d,e)}catch(g){return da("Module.instantiateWasm callback failed with error: "+g),!1}(function(){return ea||"function"!=typeof WebAssembly.instantiateStreaming||P.startsWith("data:application/octet-stream;base64,")||P.startsWith("file://")||Za||"function"!=typeof fetch?c(b):fetch(P,{credentials:"same-origin"}).then(function(g){return WebAssembly.instantiateStreaming(g,d).then(b,function(u){da("wasm streaming compile failed: "+u);da("falling back to ArrayBuffer instantiation"); +return c(b)})})})().catch(na);return{}})();a.___wasm_call_ctors=function(){return(a.___wasm_call_ctors=a.asm.g).apply(null,arguments)};var cb=a._emscripten_bind_VoidPtr___destroy___0=function(){return(cb=a._emscripten_bind_VoidPtr___destroy___0=a.asm.i).apply(null,arguments)},Ea=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=function(){return(Ea=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=a.asm.j).apply(null,arguments)},db=a._emscripten_bind_DecoderBuffer_Init_2=function(){return(db=a._emscripten_bind_DecoderBuffer_Init_2= +a.asm.k).apply(null,arguments)},eb=a._emscripten_bind_DecoderBuffer___destroy___0=function(){return(eb=a._emscripten_bind_DecoderBuffer___destroy___0=a.asm.l).apply(null,arguments)},Fa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=function(){return(Fa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=a.asm.m).apply(null,arguments)},fb=a._emscripten_bind_AttributeTransformData_transform_type_0=function(){return(fb=a._emscripten_bind_AttributeTransformData_transform_type_0= +a.asm.n).apply(null,arguments)},gb=a._emscripten_bind_AttributeTransformData___destroy___0=function(){return(gb=a._emscripten_bind_AttributeTransformData___destroy___0=a.asm.o).apply(null,arguments)},Ga=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=function(){return(Ga=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=a.asm.p).apply(null,arguments)},hb=a._emscripten_bind_GeometryAttribute___destroy___0=function(){return(hb=a._emscripten_bind_GeometryAttribute___destroy___0=a.asm.q).apply(null, +arguments)},Ha=a._emscripten_bind_PointAttribute_PointAttribute_0=function(){return(Ha=a._emscripten_bind_PointAttribute_PointAttribute_0=a.asm.r).apply(null,arguments)},ib=a._emscripten_bind_PointAttribute_size_0=function(){return(ib=a._emscripten_bind_PointAttribute_size_0=a.asm.s).apply(null,arguments)},jb=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=function(){return(jb=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=a.asm.t).apply(null,arguments)},kb=a._emscripten_bind_PointAttribute_attribute_type_0= +function(){return(kb=a._emscripten_bind_PointAttribute_attribute_type_0=a.asm.u).apply(null,arguments)},lb=a._emscripten_bind_PointAttribute_data_type_0=function(){return(lb=a._emscripten_bind_PointAttribute_data_type_0=a.asm.v).apply(null,arguments)},mb=a._emscripten_bind_PointAttribute_num_components_0=function(){return(mb=a._emscripten_bind_PointAttribute_num_components_0=a.asm.w).apply(null,arguments)},nb=a._emscripten_bind_PointAttribute_normalized_0=function(){return(nb=a._emscripten_bind_PointAttribute_normalized_0= +a.asm.x).apply(null,arguments)},ob=a._emscripten_bind_PointAttribute_byte_stride_0=function(){return(ob=a._emscripten_bind_PointAttribute_byte_stride_0=a.asm.y).apply(null,arguments)},pb=a._emscripten_bind_PointAttribute_byte_offset_0=function(){return(pb=a._emscripten_bind_PointAttribute_byte_offset_0=a.asm.z).apply(null,arguments)},qb=a._emscripten_bind_PointAttribute_unique_id_0=function(){return(qb=a._emscripten_bind_PointAttribute_unique_id_0=a.asm.A).apply(null,arguments)},rb=a._emscripten_bind_PointAttribute___destroy___0= +function(){return(rb=a._emscripten_bind_PointAttribute___destroy___0=a.asm.B).apply(null,arguments)},Ia=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=function(){return(Ia=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=a.asm.C).apply(null,arguments)},sb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=function(){return(sb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=a.asm.D).apply(null, +arguments)},tb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=function(){return(tb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=a.asm.E).apply(null,arguments)},ub=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=function(){return(ub=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=a.asm.F).apply(null,arguments)},vb=a._emscripten_bind_AttributeQuantizationTransform_range_0=function(){return(vb=a._emscripten_bind_AttributeQuantizationTransform_range_0= +a.asm.G).apply(null,arguments)},wb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=function(){return(wb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=a.asm.H).apply(null,arguments)},Ja=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=function(){return(Ja=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=a.asm.I).apply(null,arguments)},xb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1= +function(){return(xb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=a.asm.J).apply(null,arguments)},yb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=function(){return(yb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=a.asm.K).apply(null,arguments)},zb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=function(){return(zb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=a.asm.L).apply(null,arguments)},Ka=a._emscripten_bind_PointCloud_PointCloud_0= +function(){return(Ka=a._emscripten_bind_PointCloud_PointCloud_0=a.asm.M).apply(null,arguments)},Ab=a._emscripten_bind_PointCloud_num_attributes_0=function(){return(Ab=a._emscripten_bind_PointCloud_num_attributes_0=a.asm.N).apply(null,arguments)},Bb=a._emscripten_bind_PointCloud_num_points_0=function(){return(Bb=a._emscripten_bind_PointCloud_num_points_0=a.asm.O).apply(null,arguments)},Cb=a._emscripten_bind_PointCloud___destroy___0=function(){return(Cb=a._emscripten_bind_PointCloud___destroy___0=a.asm.P).apply(null, +arguments)},La=a._emscripten_bind_Mesh_Mesh_0=function(){return(La=a._emscripten_bind_Mesh_Mesh_0=a.asm.Q).apply(null,arguments)},Db=a._emscripten_bind_Mesh_num_faces_0=function(){return(Db=a._emscripten_bind_Mesh_num_faces_0=a.asm.R).apply(null,arguments)},Eb=a._emscripten_bind_Mesh_num_attributes_0=function(){return(Eb=a._emscripten_bind_Mesh_num_attributes_0=a.asm.S).apply(null,arguments)},Fb=a._emscripten_bind_Mesh_num_points_0=function(){return(Fb=a._emscripten_bind_Mesh_num_points_0=a.asm.T).apply(null, +arguments)},Gb=a._emscripten_bind_Mesh___destroy___0=function(){return(Gb=a._emscripten_bind_Mesh___destroy___0=a.asm.U).apply(null,arguments)},Ma=a._emscripten_bind_Metadata_Metadata_0=function(){return(Ma=a._emscripten_bind_Metadata_Metadata_0=a.asm.V).apply(null,arguments)},Hb=a._emscripten_bind_Metadata___destroy___0=function(){return(Hb=a._emscripten_bind_Metadata___destroy___0=a.asm.W).apply(null,arguments)},Ib=a._emscripten_bind_Status_code_0=function(){return(Ib=a._emscripten_bind_Status_code_0= +a.asm.X).apply(null,arguments)},Jb=a._emscripten_bind_Status_ok_0=function(){return(Jb=a._emscripten_bind_Status_ok_0=a.asm.Y).apply(null,arguments)},Kb=a._emscripten_bind_Status_error_msg_0=function(){return(Kb=a._emscripten_bind_Status_error_msg_0=a.asm.Z).apply(null,arguments)},Lb=a._emscripten_bind_Status___destroy___0=function(){return(Lb=a._emscripten_bind_Status___destroy___0=a.asm._).apply(null,arguments)},Na=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=function(){return(Na=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0= +a.asm.$).apply(null,arguments)},Mb=a._emscripten_bind_DracoFloat32Array_GetValue_1=function(){return(Mb=a._emscripten_bind_DracoFloat32Array_GetValue_1=a.asm.aa).apply(null,arguments)},Nb=a._emscripten_bind_DracoFloat32Array_size_0=function(){return(Nb=a._emscripten_bind_DracoFloat32Array_size_0=a.asm.ba).apply(null,arguments)},Ob=a._emscripten_bind_DracoFloat32Array___destroy___0=function(){return(Ob=a._emscripten_bind_DracoFloat32Array___destroy___0=a.asm.ca).apply(null,arguments)},Oa=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0= +function(){return(Oa=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=a.asm.da).apply(null,arguments)},Pb=a._emscripten_bind_DracoInt8Array_GetValue_1=function(){return(Pb=a._emscripten_bind_DracoInt8Array_GetValue_1=a.asm.ea).apply(null,arguments)},Qb=a._emscripten_bind_DracoInt8Array_size_0=function(){return(Qb=a._emscripten_bind_DracoInt8Array_size_0=a.asm.fa).apply(null,arguments)},Rb=a._emscripten_bind_DracoInt8Array___destroy___0=function(){return(Rb=a._emscripten_bind_DracoInt8Array___destroy___0= +a.asm.ga).apply(null,arguments)},Pa=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=function(){return(Pa=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=a.asm.ha).apply(null,arguments)},Sb=a._emscripten_bind_DracoUInt8Array_GetValue_1=function(){return(Sb=a._emscripten_bind_DracoUInt8Array_GetValue_1=a.asm.ia).apply(null,arguments)},Tb=a._emscripten_bind_DracoUInt8Array_size_0=function(){return(Tb=a._emscripten_bind_DracoUInt8Array_size_0=a.asm.ja).apply(null,arguments)},Ub=a._emscripten_bind_DracoUInt8Array___destroy___0= +function(){return(Ub=a._emscripten_bind_DracoUInt8Array___destroy___0=a.asm.ka).apply(null,arguments)},Qa=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=function(){return(Qa=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=a.asm.la).apply(null,arguments)},Vb=a._emscripten_bind_DracoInt16Array_GetValue_1=function(){return(Vb=a._emscripten_bind_DracoInt16Array_GetValue_1=a.asm.ma).apply(null,arguments)},Wb=a._emscripten_bind_DracoInt16Array_size_0=function(){return(Wb=a._emscripten_bind_DracoInt16Array_size_0= +a.asm.na).apply(null,arguments)},Xb=a._emscripten_bind_DracoInt16Array___destroy___0=function(){return(Xb=a._emscripten_bind_DracoInt16Array___destroy___0=a.asm.oa).apply(null,arguments)},Ra=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=function(){return(Ra=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=a.asm.pa).apply(null,arguments)},Yb=a._emscripten_bind_DracoUInt16Array_GetValue_1=function(){return(Yb=a._emscripten_bind_DracoUInt16Array_GetValue_1=a.asm.qa).apply(null,arguments)}, +Zb=a._emscripten_bind_DracoUInt16Array_size_0=function(){return(Zb=a._emscripten_bind_DracoUInt16Array_size_0=a.asm.ra).apply(null,arguments)},$b=a._emscripten_bind_DracoUInt16Array___destroy___0=function(){return($b=a._emscripten_bind_DracoUInt16Array___destroy___0=a.asm.sa).apply(null,arguments)},Sa=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=function(){return(Sa=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=a.asm.ta).apply(null,arguments)},ac=a._emscripten_bind_DracoInt32Array_GetValue_1= +function(){return(ac=a._emscripten_bind_DracoInt32Array_GetValue_1=a.asm.ua).apply(null,arguments)},bc=a._emscripten_bind_DracoInt32Array_size_0=function(){return(bc=a._emscripten_bind_DracoInt32Array_size_0=a.asm.va).apply(null,arguments)},cc=a._emscripten_bind_DracoInt32Array___destroy___0=function(){return(cc=a._emscripten_bind_DracoInt32Array___destroy___0=a.asm.wa).apply(null,arguments)},Ta=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=function(){return(Ta=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0= +a.asm.xa).apply(null,arguments)},dc=a._emscripten_bind_DracoUInt32Array_GetValue_1=function(){return(dc=a._emscripten_bind_DracoUInt32Array_GetValue_1=a.asm.ya).apply(null,arguments)},ec=a._emscripten_bind_DracoUInt32Array_size_0=function(){return(ec=a._emscripten_bind_DracoUInt32Array_size_0=a.asm.za).apply(null,arguments)},fc=a._emscripten_bind_DracoUInt32Array___destroy___0=function(){return(fc=a._emscripten_bind_DracoUInt32Array___destroy___0=a.asm.Aa).apply(null,arguments)},Ua=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0= +function(){return(Ua=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=a.asm.Ba).apply(null,arguments)},gc=a._emscripten_bind_MetadataQuerier_HasEntry_2=function(){return(gc=a._emscripten_bind_MetadataQuerier_HasEntry_2=a.asm.Ca).apply(null,arguments)},hc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=function(){return(hc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=a.asm.Da).apply(null,arguments)},ic=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=function(){return(ic=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3= +a.asm.Ea).apply(null,arguments)},jc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=function(){return(jc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=a.asm.Fa).apply(null,arguments)},kc=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=function(){return(kc=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=a.asm.Ga).apply(null,arguments)},lc=a._emscripten_bind_MetadataQuerier_NumEntries_1=function(){return(lc=a._emscripten_bind_MetadataQuerier_NumEntries_1=a.asm.Ha).apply(null,arguments)}, +mc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=function(){return(mc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=a.asm.Ia).apply(null,arguments)},nc=a._emscripten_bind_MetadataQuerier___destroy___0=function(){return(nc=a._emscripten_bind_MetadataQuerier___destroy___0=a.asm.Ja).apply(null,arguments)},Va=a._emscripten_bind_Decoder_Decoder_0=function(){return(Va=a._emscripten_bind_Decoder_Decoder_0=a.asm.Ka).apply(null,arguments)},oc=a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=function(){return(oc= +a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=a.asm.La).apply(null,arguments)},pc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=function(){return(pc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=a.asm.Ma).apply(null,arguments)},qc=a._emscripten_bind_Decoder_GetAttributeId_2=function(){return(qc=a._emscripten_bind_Decoder_GetAttributeId_2=a.asm.Na).apply(null,arguments)},rc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=function(){return(rc=a._emscripten_bind_Decoder_GetAttributeIdByName_2= +a.asm.Oa).apply(null,arguments)},sc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=function(){return(sc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=a.asm.Pa).apply(null,arguments)},tc=a._emscripten_bind_Decoder_GetAttribute_2=function(){return(tc=a._emscripten_bind_Decoder_GetAttribute_2=a.asm.Qa).apply(null,arguments)},uc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=function(){return(uc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=a.asm.Ra).apply(null,arguments)}, +vc=a._emscripten_bind_Decoder_GetMetadata_1=function(){return(vc=a._emscripten_bind_Decoder_GetMetadata_1=a.asm.Sa).apply(null,arguments)},wc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=function(){return(wc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=a.asm.Ta).apply(null,arguments)},xc=a._emscripten_bind_Decoder_GetFaceFromMesh_3=function(){return(xc=a._emscripten_bind_Decoder_GetFaceFromMesh_3=a.asm.Ua).apply(null,arguments)},yc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2= +function(){return(yc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=a.asm.Va).apply(null,arguments)},zc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=function(){return(zc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=a.asm.Wa).apply(null,arguments)},Ac=a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=function(){return(Ac=a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=a.asm.Xa).apply(null,arguments)},Bc=a._emscripten_bind_Decoder_GetAttributeFloat_3=function(){return(Bc= +a._emscripten_bind_Decoder_GetAttributeFloat_3=a.asm.Ya).apply(null,arguments)},Cc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=function(){return(Cc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=a.asm.Za).apply(null,arguments)},Dc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=function(){return(Dc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=a.asm._a).apply(null,arguments)},Ec=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=function(){return(Ec= +a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=a.asm.$a).apply(null,arguments)},Fc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=function(){return(Fc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=a.asm.ab).apply(null,arguments)},Gc=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=function(){return(Gc=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=a.asm.bb).apply(null,arguments)},Hc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3= +function(){return(Hc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=a.asm.cb).apply(null,arguments)},Ic=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=function(){return(Ic=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=a.asm.db).apply(null,arguments)},Jc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=function(){return(Jc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=a.asm.eb).apply(null,arguments)},Kc=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5= +function(){return(Kc=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=a.asm.fb).apply(null,arguments)},Lc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=function(){return(Lc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=a.asm.gb).apply(null,arguments)},Mc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1=function(){return(Mc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1=a.asm.hb).apply(null,arguments)},Nc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2= +function(){return(Nc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=a.asm.ib).apply(null,arguments)},Oc=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=function(){return(Oc=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=a.asm.jb).apply(null,arguments)},Pc=a._emscripten_bind_Decoder___destroy___0=function(){return(Pc=a._emscripten_bind_Decoder___destroy___0=a.asm.kb).apply(null,arguments)},Qc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=function(){return(Qc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM= +a.asm.lb).apply(null,arguments)},Rc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=function(){return(Rc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=a.asm.mb).apply(null,arguments)},Sc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=function(){return(Sc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=a.asm.nb).apply(null,arguments)},Tc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM= +function(){return(Tc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=a.asm.ob).apply(null,arguments)},Uc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=function(){return(Uc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=a.asm.pb).apply(null,arguments)},Vc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=function(){return(Vc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=a.asm.qb).apply(null,arguments)},Wc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL= +function(){return(Wc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=a.asm.rb).apply(null,arguments)},Xc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=function(){return(Xc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=a.asm.sb).apply(null,arguments)},Yc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=function(){return(Yc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=a.asm.tb).apply(null,arguments)},Zc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC= +function(){return(Zc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=a.asm.ub).apply(null,arguments)},$c=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=function(){return($c=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=a.asm.vb).apply(null,arguments)},ad=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=function(){return(ad=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=a.asm.wb).apply(null,arguments)},bd=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH= +function(){return(bd=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=a.asm.xb).apply(null,arguments)},cd=a._emscripten_enum_draco_DataType_DT_INVALID=function(){return(cd=a._emscripten_enum_draco_DataType_DT_INVALID=a.asm.yb).apply(null,arguments)},dd=a._emscripten_enum_draco_DataType_DT_INT8=function(){return(dd=a._emscripten_enum_draco_DataType_DT_INT8=a.asm.zb).apply(null,arguments)},ed=a._emscripten_enum_draco_DataType_DT_UINT8=function(){return(ed=a._emscripten_enum_draco_DataType_DT_UINT8= +a.asm.Ab).apply(null,arguments)},fd=a._emscripten_enum_draco_DataType_DT_INT16=function(){return(fd=a._emscripten_enum_draco_DataType_DT_INT16=a.asm.Bb).apply(null,arguments)},gd=a._emscripten_enum_draco_DataType_DT_UINT16=function(){return(gd=a._emscripten_enum_draco_DataType_DT_UINT16=a.asm.Cb).apply(null,arguments)},hd=a._emscripten_enum_draco_DataType_DT_INT32=function(){return(hd=a._emscripten_enum_draco_DataType_DT_INT32=a.asm.Db).apply(null,arguments)},id=a._emscripten_enum_draco_DataType_DT_UINT32= +function(){return(id=a._emscripten_enum_draco_DataType_DT_UINT32=a.asm.Eb).apply(null,arguments)},jd=a._emscripten_enum_draco_DataType_DT_INT64=function(){return(jd=a._emscripten_enum_draco_DataType_DT_INT64=a.asm.Fb).apply(null,arguments)},kd=a._emscripten_enum_draco_DataType_DT_UINT64=function(){return(kd=a._emscripten_enum_draco_DataType_DT_UINT64=a.asm.Gb).apply(null,arguments)},ld=a._emscripten_enum_draco_DataType_DT_FLOAT32=function(){return(ld=a._emscripten_enum_draco_DataType_DT_FLOAT32=a.asm.Hb).apply(null, +arguments)},md=a._emscripten_enum_draco_DataType_DT_FLOAT64=function(){return(md=a._emscripten_enum_draco_DataType_DT_FLOAT64=a.asm.Ib).apply(null,arguments)},nd=a._emscripten_enum_draco_DataType_DT_BOOL=function(){return(nd=a._emscripten_enum_draco_DataType_DT_BOOL=a.asm.Jb).apply(null,arguments)},od=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT=function(){return(od=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT=a.asm.Kb).apply(null,arguments)},pd=a._emscripten_enum_draco_StatusCode_OK=function(){return(pd= +a._emscripten_enum_draco_StatusCode_OK=a.asm.Lb).apply(null,arguments)},qd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=function(){return(qd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=a.asm.Mb).apply(null,arguments)},rd=a._emscripten_enum_draco_StatusCode_IO_ERROR=function(){return(rd=a._emscripten_enum_draco_StatusCode_IO_ERROR=a.asm.Nb).apply(null,arguments)},sd=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=function(){return(sd=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER= +a.asm.Ob).apply(null,arguments)},td=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=function(){return(td=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=a.asm.Pb).apply(null,arguments)},ud=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=function(){return(ud=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=a.asm.Qb).apply(null,arguments)},bb=a._malloc=function(){return(bb=a._malloc=a.asm.Rb).apply(null,arguments)};a._free=function(){return(a._free=a.asm.Sb).apply(null,arguments)}; +var za=a.___cxa_is_pointer_type=function(){return(za=a.___cxa_is_pointer_type=a.asm.Tb).apply(null,arguments)},ka;ha=function b(){ka||Z();ka||(ha=b)};a.run=Z;if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0=r.size?(0>>=0;switch(c.BYTES_PER_ELEMENT){case 2:d>>>=1;break;case 4:d>>>=2;break;case 8:d>>>=3}for(var g=0;gb.byteLength)return a.INVALID_GEOMETRY_TYPE;switch(b[7]){case 0:return a.POINT_CLOUD;case 1:return a.TRIANGULAR_MESH;default:return a.INVALID_GEOMETRY_TYPE}};return n.ready}}(); +"object"===typeof exports&&"object"===typeof module?module.exports=DracoDecoderModule:"function"===typeof define&&define.amd?define([],function(){return DracoDecoderModule}):"object"===typeof exports&&(exports.DracoDecoderModule=DracoDecoderModule); diff --git a/packages/media-extention/ChromaKeyMaterial.ts b/packages/media-extention/ChromaKeyMaterial.ts new file mode 100644 index 00000000..ce54f687 --- /dev/null +++ b/packages/media-extention/ChromaKeyMaterial.ts @@ -0,0 +1,166 @@ +import { Engine3D, MaterialBase, ShaderLib, Vector4, Color, BlendMode, registerMaterial } from "@orillusion/core"; +import ChromaKeyShader from "./ChromaKeyShader.wgsl?raw"; + +/** + * ChromaKey Material + * Do not compute light, only read pixel color from a video source with a background color filter + * @group Material + */ +export class ChromaKeyMaterial extends MaterialBase { + + /** + * Create new ChromaKey material + */ + constructor() { + super(); + ShaderLib.register("ChromaKeyShader", ChromaKeyShader); + let shader = this.setShader(`ChromaKeyShader`, `ChromaKeyShader`); + shader.setShaderEntry(`VertMain`, `FragMain`) + + shader.setUniformVector4(`transformUV1`, new Vector4(0, 0, 1, 1)); + shader.setUniformVector4(`transformUV2`, new Vector4(0, 0, 1, 1)); + shader.setUniformColor(`baseColor`, new Color()); + shader.setUniformVector4(`rectClip`, new Vector4(0, 0, 0, 0)); + shader.setUniformFloat(`alphaCutoff`, 0.5); + + shader.setUniformColor(`keyColor`, new Color(0, 1, 0, 0)); + shader.setUniformFloat(`colorCutoff`, 0.4); + shader.setUniformFloat(`colorFeathering`, 0.5); + shader.setUniformFloat(`maskFeathering`, 1); + shader.setUniformFloat(`sharpening`, 0.5); + shader.setUniformFloat(`despoil`, 0.6); + shader.setUniformFloat(`despoilLuminanceAdd`, 0); + + let shaderState = shader.shaderState; + shaderState.acceptShadow = false; + shaderState.receiveEnv = false; + shaderState.acceptGI = false; + shaderState.useLight = false; + shaderState.castShadow = false; + shaderState.useZ = false; + shaderState.blendMode = BlendMode.ALPHA; + + // default value + this.baseMap = Engine3D.res.whiteTexture; + } + + /** + * Set the clip rect area + */ + public set rectClip(value: Vector4) { + this.renderShader.uniforms[`rectClip`].vector4 = value; + } + + /** + * Get current clip rect area + */ + public get rectClip(): Vector4 { + return this.renderShader.uniforms[`rectClip`].vector4; + } + + /** + * Set the chromakey color + */ + public set keyColor(value: Color) { + this.renderShader.uniforms[`keyColor`].color = value; + } + + /** + * Get the chromakey color + */ + public get keyColor(): Color { + return this.renderShader.uniforms[`keyColor`].color; + } + + /** + * Set the color cutoff factor + */ + public set colorCutoff(value: number) { + this.renderShader.uniforms[`colorCutoff`].value = value; + } + + /** + * Get the color cutoff factor + */ + public get colorCutoff(): number { + return this.renderShader.uniforms[`colorCutoff`].value; + } + + /** + * Set the color feather factor + */ + public set colorFeathering(value: number) { + this.renderShader.uniforms[`colorFeathering`].value = value; + } + + /** + * Get the color feather factor + */ + public get colorFeathering(): number { + return this.renderShader.uniforms[`colorFeathering`].value; + } + + /** + * Set the mask feather factor + */ + public set maskFeathering(value: number) { + this.renderShader.uniforms[`maskFeathering`].value = value; + } + + /** + * Get the mask feather factor + */ + public get maskFeathering(): number { + return this.renderShader.uniforms[`maskFeathering`].value; + } + + /** + * Set the sharpen factor + */ + public set sharpening(value: number) { + this.renderShader.uniforms[`sharpening`].value = value; + } + + /** + * Get the sharpen factor + */ + public get sharpening(): number { + return this.renderShader.uniforms[`sharpening`].value; + } + + /** + * Set the despoil factor + */ + public set despoil(value: number) { + this.renderShader.uniforms[`despoil`].value = value; + } + + /** + * Get the despoil factor + */ + public get despoil(): number { + return this.renderShader.uniforms[`despoil`].value; + } + + /** + * Set the despoil luminance factor + */ + public set despoilLuminanceAdd(value: number) { + this.renderShader.uniforms[`despoilLuminanceAdd`].value = value; + } + + /** + * Get the despoil luminance factor + */ + public get despoilLuminanceAdd(): number { + return this.renderShader.uniforms[`despoilLuminanceAdd`].value; + } + + /** + * Show a debug GUI + */ + debug() { + } +} + +registerMaterial('ChromaKeyMaterial', ChromaKeyMaterial); \ No newline at end of file diff --git a/packages/media-extention/ChromaKeyShader.wgsl b/packages/media-extention/ChromaKeyShader.wgsl new file mode 100644 index 00000000..f2cf609d --- /dev/null +++ b/packages/media-extention/ChromaKeyShader.wgsl @@ -0,0 +1,108 @@ +#include "Common_vert" +#include "Common_frag" +#include "UnLit_frag" + +struct StandMaterial { + transformUV1:vec4, + transformUV2:vec4, + + baseColor: vec4, + rectClip: vec4, + + keyColor: vec4, + colorCutoff: f32, + colorFeathering: f32, + maskFeathering: f32, + sharpening: f32, + despoil: f32, + despoilLuminanceAdd: f32, +}; + +@group(1) @binding(auto) +var baseMapSampler: sampler; +@group(1) @binding(auto) +var baseMap: texture_external; + +@group(2) @binding(0) +var materialUniform: StandMaterial; + +fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; +} + +fn frag(){ + let baseColor = materialUniform.baseColor; + let transformUV1 = materialUniform.transformUV1; + let uv = transformUV1.zw * ORI_VertexVarying.fragUV0.xy + transformUV1.xy; + if(uv.x < materialUniform.rectClip.x || uv.x > (1.0-materialUniform.rectClip.z)) { + discard; + } + if(uv.y < materialUniform.rectClip.y || uv.y > (1.0-materialUniform.rectClip.w)) { + discard; + } + + let texSize = textureDimensions(baseMap).xy; + let color = textureLoad(baseMap, vec2( i32(uv.x * f32(texSize.x)), i32(uv.y * f32(texSize.y))) ); + + let key_cb = rgb2cb(materialUniform.keyColor.rgb); + let key_cr = rgb2cr(materialUniform.keyColor.rgb); + let pixelWidth: vec2 = vec2(1.0 / f32(texSize.x), 0); + let pixelHeight: vec2 = vec2(0, 1.0 / f32(texSize.y)); + + let c = maskedTex2D(uv, texSize, key_cb, key_cr); + let r = maskedTex2D(uv + pixelWidth, texSize, key_cb, key_cr); + let l = maskedTex2D(uv - pixelWidth, texSize, key_cb, key_cr); + let d = maskedTex2D(uv + pixelHeight, texSize, key_cb, key_cr); + let u = maskedTex2D(uv - pixelHeight, texSize, key_cb, key_cr); + let rd = maskedTex2D(uv + pixelWidth + pixelHeight, texSize, key_cb, key_cr) * 0.707; + let dl = maskedTex2D(uv - pixelWidth + pixelHeight, texSize, key_cb, key_cr) * 0.707; + let lu = maskedTex2D(uv - pixelHeight - pixelWidth, texSize, key_cb, key_cr) * 0.707; + let ur = maskedTex2D(uv + pixelWidth - pixelHeight, texSize, key_cb, key_cr) * 0.707; + let blurContribution = (r + l + d + u + rd + dl + lu + ur + c) * 0.12774655; + let smoothedMask = smoothstep(materialUniform.sharpening, 1, mix(c, blurContribution, materialUniform.maskFeathering)); + var result = color * smoothedMask; + + let v = (2 * result.b + result.r) / 4; + if(result.g > v) { + result.g = mix(result.g, v, materialUniform.despoil); + } + let dif = (color - result); + let desaturatedDif = rgb2y(dif.xyz); + result += mix(0, desaturatedDif, materialUniform.despoilLuminanceAdd); + + ORI_ShadingInput.BaseColor = result * baseColor ; + UnLit(); +} + +fn rgb2cr(color: vec3) -> f32 { + return 0.5 + color.r * 0.5 - color.g * 0.418688 - color.b * 0.081312; +} + +fn rgb2y(color: vec3) -> f32 { + return color.r * 0.299 + color.g * 0.587 + color.b * 0.114; +} + +fn rgb2cb(color: vec3) -> f32 { + return 0.5 + color.r * -0.168736 - color.g * 0.331264 + color.b * 0.5; +} + +fn colorclose(Cb_p: f32, Cr_p: f32, Cb_key: f32, Cr_key: f32, tola: f32, tolb: f32) -> f32 { + let temp = (Cb_key - Cb_p) * (Cb_key - Cb_p) + (Cr_key - Cr_p) * (Cr_key - Cr_p); + let tola2 = tola * tola; + let tolb2 = tolb * tolb; + if (temp < tola2) { + return 0; + } + if (temp < tolb2) { + return (temp - tola2) / (tolb2 - tola2); + } + return 1; +} + +fn maskedTex2D(uv: vec2, texSize: vec2, key_cb: f32, key_cr: f32) -> f32 { + let color = textureLoad(baseMap, vec2( i32(uv.x * f32(texSize.x)), i32(uv.y * f32(texSize.y))) ); + let pix_cb = rgb2cb(color.rgb); + let pix_cr = rgb2cr(color.rgb); + return colorclose(pix_cb, pix_cr, key_cb, key_cr, materialUniform.colorCutoff, materialUniform.colorFeathering); +} diff --git a/packages/media-extention/ImageMaterial.ts b/packages/media-extention/ImageMaterial.ts new file mode 100644 index 00000000..cd592259 --- /dev/null +++ b/packages/media-extention/ImageMaterial.ts @@ -0,0 +1,71 @@ +import { Engine3D, MaterialBase, ShaderLib, Vector4, Color, Texture } from "@orillusion/core"; +import ImageMaterialShader from "./ImageMaterialShader.wgsl?raw"; + + +/** + * ImageMaterial + * Do not compute light, only read pixel color from a Image source + * @group Material + */ +export class ImageMaterial extends MaterialBase { + + /** + * Create a new ImageMaterial + */ + constructor() { + super(); + ShaderLib.register("ImageShVideoShaderader", ImageMaterialShader); + let shader = this.setShader(`ImageShader`, `ImageShader`); + shader.setShaderEntry(`VertMain`, `FragMain`) + shader.setUniformVector4(`transformUV1`, new Vector4(0, 0, 1, 1)); + shader.setUniformVector4(`transformUV2`, new Vector4(0, 0, 1, 1)); + shader.setUniformColor(`baseColor`, new Color()); + shader.setUniformVector4(`rectClip`, new Vector4(0, 0, 0, 0)); + shader.setUniformFloat(`alphaCutoff`, 0.5); + + let shaderState = shader.shaderState; + shaderState.acceptShadow = false; + shaderState.receiveEnv = false; + shaderState.acceptGI = false; + shaderState.useLight = false; + shaderState.castShadow = false; + shaderState.useZ = false; + + // default value + this.baseMap = Engine3D.res.whiteTexture; + } + + /** + * Set the clip rect area + */ + public set rectClip(value: Vector4) { + this.renderShader.uniforms[`rectClip`].vector4 = value; + } + + /** + * Get the clip rect area + */ + public get rectClip(): Vector4 { + return this.renderShader.uniforms[`rectClip`].vector4; + } + + /** + * Set no env Map + */ + public set envMap(texture: Texture) { + //no need env texture + } + + /** + * Set no shadow Map + */ + public set shadowMap(texture: Texture) { + //not need shadowMap texture + } + + /** + * Start debug GUI + */ + debug() { + } +} \ No newline at end of file diff --git a/packages/media-extention/ImageMaterialShader.wgsl b/packages/media-extention/ImageMaterialShader.wgsl new file mode 100644 index 00000000..230f58db --- /dev/null +++ b/packages/media-extention/ImageMaterialShader.wgsl @@ -0,0 +1,33 @@ +#include "Common_vert" +#include "Common_frag" +#include "UnLit_frag" +#include "VideoUniform_frag" + +@group(1) @binding(auto) +var baseMapSampler: sampler; +@group(1) @binding(auto) +var baseMap: texture_2d; + +fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; +} + +fn frag(){ + let transformUV1 = materialUniform.transformUV1; + + let uv = transformUV1.zw * ORI_VertexVarying.fragUV0 + transformUV1.xy; + + if(uv.x < materialUniform.rectClip.x || uv.x > (1.0-materialUniform.rectClip.z)) { + discard; + } + + if(uv.y < materialUniform.rectClip.y || uv.y > (1.0-materialUniform.rectClip.w)) { + discard; + } + + let videoColor = textureSample(baseMap, baseMapSampler, uv); + + ORI_ShadingInput.BaseColor = videoColor * materialUniform.baseColor ; + UnLit(); +} \ No newline at end of file diff --git a/packages/media-extention/README.md b/packages/media-extention/README.md new file mode 100644 index 00000000..e62b1978 --- /dev/null +++ b/packages/media-extention/README.md @@ -0,0 +1,15 @@ +Add media components for [Orillusion](https://www.orillusion.com) + +## Install +```bash +npm install @orillusion/core --save +npm install @orillusion/media-extention --save +``` + +Or access Global build from CDN +```html + + +``` + +More doc from [Orillusion](https://www.orillusion.com/guide/media/Readme.html) \ No newline at end of file diff --git a/packages/media-extention/VideoMaterial.ts b/packages/media-extention/VideoMaterial.ts new file mode 100644 index 00000000..07da7914 --- /dev/null +++ b/packages/media-extention/VideoMaterial.ts @@ -0,0 +1,72 @@ + +import { Color, Engine3D, MaterialBase, ShaderLib, Texture, Vector4, registerMaterial } from '@orillusion/core'; +import VideoShader from './VideoShader.wgsl?raw' + +/** + * Video Material + * Do not compute light, only read pixel color from a Video source + * @group Material + */ +export class VideoMaterial extends MaterialBase { + + /** + * Create new VideoMaterial + */ + constructor() { + super(); + ShaderLib['VideoShader'] = VideoShader; + let shader = this.setShader(`VideoShader`, `VideoShader`); + shader.setShaderEntry(`VertMain`, `FragMain`) + shader.setUniformVector4(`transformUV1`, new Vector4(0, 0, 1, 1)); + shader.setUniformVector4(`transformUV2`, new Vector4(0, 0, 1, 1)); + shader.setUniformColor(`baseColor`, new Color()); + shader.setUniformVector4(`rectClip`, new Vector4(0, 0, 0, 0)); + shader.setUniformFloat(`alphaCutoff`, 0.5); + let shaderState = shader.shaderState; + shaderState.acceptShadow = false; + shaderState.receiveEnv = false; + shaderState.acceptGI = false; + shaderState.useLight = false; + shaderState.castShadow = false; + shaderState.useZ = false; + + // default value + this.baseMap = Engine3D.res.whiteTexture; + } + + /** + * Set the clip rect area + */ + public set rectClip(value: Vector4) { + this.renderShader.uniforms[`rectClip`].vector4 = value; + } + + /** + * Get the clip rect area + */ + public get rectClip(): Vector4 { + return this.renderShader.uniforms[`rectClip`].vector4; + } + + /** + * Set no envMap + */ + public set envMap(texture: Texture) { + //not need env texture + } + + /** + * Set no shadowMap + */ + public set shadowMap(texture: Texture) { + //not need shadowMap texture + } + + /** + * Start debug GUI + */ + debug() { + + } +} +registerMaterial('VideoMaterial', VideoMaterial); \ No newline at end of file diff --git a/packages/media-extention/VideoShader.wgsl b/packages/media-extention/VideoShader.wgsl new file mode 100644 index 00000000..192987f9 --- /dev/null +++ b/packages/media-extention/VideoShader.wgsl @@ -0,0 +1,35 @@ +#include "Common_vert" +#include "Common_frag" +#include "UnLit_frag" +#include "VideoUniform_frag" + +@group(1) @binding(auto) +var baseMapSampler: sampler; +@group(1) @binding(auto) +var baseMap: texture_external; + +fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; +} + +fn frag(){ + var transformUV1 = materialUniform.transformUV1; + var transformUV2 = materialUniform.transformUV2; + + var uv = transformUV1.zw * ORI_VertexVarying.fragUV0 + transformUV1.xy; + + if(uv.x < materialUniform.rectClip.x || uv.x > (1.0-materialUniform.rectClip.z)){ + discard; + } + if(uv.y < materialUniform.rectClip.y || uv.y > (1.0-materialUniform.rectClip.w)){ + discard; + } + + let size = textureDimensions(baseMap).xy - 1; + let iuv = vec2(uv * vec2(size)); + let videoColor = textureLoad(baseMap, iuv) ; + + ORI_ShadingInput.BaseColor = videoColor * materialUniform.baseColor ; + UnLit(); +} \ No newline at end of file diff --git a/packages/media-extention/VideoTexture.ts b/packages/media-extention/VideoTexture.ts new file mode 100644 index 00000000..22717da4 --- /dev/null +++ b/packages/media-extention/VideoTexture.ts @@ -0,0 +1,82 @@ +import { Texture, webGPUContext } from "@orillusion/core"; + +/** + * Video Texture + * @group Texture + */ +export class VideoTexture extends Texture { + public media: HTMLVideoElement; + private external: boolean = false; + private _des: GPUExternalTextureDescriptor; + constructor() { + super(); + this.useMipmap = false; + this.isVideoTexture = true; + this.samplerBindingLayout = null; + } + + /** + * load one Video Source + * @param video the url of a video source, or a MediaStream object, or a HTMLVideoElement + */ + public async load(video: string | MediaStream | HTMLVideoElement) { + let media: HTMLVideoElement, old: HTMLVideoElement + if (this.media && !this.external) + old = this.media + + if (typeof video === 'string') { + media = this.createVideo() + media.src = video + } else if (video.constructor.name === 'MediaStream') { + media = this.createVideo() + media.srcObject = video as MediaStream + } else if (video.constructor.name === 'HTMLVideoElement') { + this.external = true + media = video as HTMLVideoElement + } else + throw new Error('no video or src provided') + + await media.play() + this.media = media + this._des = { + source: this.media + } + if (old) { + old.pause() + old.src = old.srcObject = null + old.load() + } + } + + public getGPUTexture() { + return null; + } + + protected updateGPUTexture() {} + + private videoTexture: GPUExternalTexture; + public getGPUView() { + this.samplerBindingLayout = null; + this.videoTexture = webGPUContext.device.importExternalTexture(this._des) + this.noticeChange() + return this.videoTexture + } + + protected noticeChange() { + this.gpuSampler = webGPUContext.device.createSampler(this); + this._stateChangeRef.forEach((v, k) => { + v(); + }); + } + + private createVideo() { + let video = document.createElement(`video`) as HTMLVideoElement; + video.controls = false; + video.autoplay = false; + video.muted = true; + video.loop = true; + video.playsInline = true + video.crossOrigin = '' + return video + } +} \ No newline at end of file diff --git a/packages/media-extention/index.ts b/packages/media-extention/index.ts new file mode 100644 index 00000000..f031cc34 --- /dev/null +++ b/packages/media-extention/index.ts @@ -0,0 +1,6 @@ +import { ChromaKeyMaterial } from './ChromaKeyMaterial' +import { ImageMaterial } from './ImageMaterial' +import { VideoMaterial } from './VideoMaterial' +import { VideoTexture } from './VideoTexture' + +export {ChromaKeyMaterial, ImageMaterial, VideoMaterial, VideoTexture} \ No newline at end of file diff --git a/packages/media-extention/package.json b/packages/media-extention/package.json new file mode 100644 index 00000000..4eab7e8f --- /dev/null +++ b/packages/media-extention/package.json @@ -0,0 +1,26 @@ +{ + "name": "@orillusion/media-extention", + "version": "0.1.7", + "author": "Orillusion", + "description": "Orillusion Media Material Extention", + "main": "./dist/media.umd.js", + "module": "./dist/media.es.js", + "module:dev": "./index.ts", + "types": "./dist/index.d.ts", + "files": ["dist"], + "scripts": { + "build": "vite build && npm run build:types && npm run build:clean", + "build:types": "tsc --emitDeclarationOnly -p tsconfig.json", + "build:clean": "mv dist/packages/media-extention/* dist && rm -rf dist/src && rm -rf dist/packages", + "docs": "npm run docs:typedoc ../../docs/media-extention index.ts", + "docs:typedoc": "npx typedoc --plugin typedoc-plugin-markdown --plugin ../../script/typedoc-plugin-not-exported.js --tsconfig tsconfig.json --gitRevision main --hideBreadcrumbs true --allReflectionsHaveOwnDocument true --readme none --excludeInternal --excludePrivate --excludeProtected --sort source-order --out" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/Orillusion/orillusion.git" + }, + "dependencies": { + "@orillusion/core": "^0.6.0" + } +} diff --git a/packages/media-extention/tsconfig.json b/packages/media-extention/tsconfig.json new file mode 100644 index 00000000..07928127 --- /dev/null +++ b/packages/media-extention/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "Node", + "sourceMap": false, + "resolveJsonModule": true, + "esModuleInterop": true, + "types": ["vite/client", "@webgpu/types"], + // for build + // "noEmit": true, + "declaration": true, + "declarationDir": "dist", + "outDir": "dist", + "skipLibCheck": true, + "noImplicitAny": false, + "noUnusedLocals": false, + "noUnusedParameters":false, + "noImplicitReturns": false, + "strictPropertyInitialization": false, + "strictNullChecks": false, + "strict": false, + "paths": { + "@orillusion/core": ["../../src"], + } + } +} \ No newline at end of file diff --git a/packages/media-extention/vite.config.js b/packages/media-extention/vite.config.js new file mode 100644 index 00000000..63e820e8 --- /dev/null +++ b/packages/media-extention/vite.config.js @@ -0,0 +1,24 @@ +import { defineConfig } from 'vite' +const path = require('path') +export default defineConfig({ + resolve: { + alias: { + '@orillusion/core': path.resolve(__dirname, '../../src') + } + }, + build: { + lib: { + entry: path.resolve('index.ts'), + name: 'Media', + fileName: (format) => `media.${format}.js` + }, + rollupOptions: { + external: ['@orillusion/core'], + output: { + globals: { + '@orillusion/core': 'Orillusion' + } + } + } + } +}) \ No newline at end of file diff --git a/packages/physics/ClothSoftBody.ts b/packages/physics/ClothSoftBody.ts new file mode 100644 index 00000000..4d1b86a7 --- /dev/null +++ b/packages/physics/ClothSoftBody.ts @@ -0,0 +1,124 @@ +import Ammo from '@orillusion/ammo'; +import { ComponentBase, Vector3, PlaneGeometry } from '@orillusion/core' +import { Physics } from './Physics'; +/** + * @internal + * @group Plugin + */ +export class ClothSoftBody extends ComponentBase { + private _mass: number = 0.01; + + private _planeGeo: PlaneGeometry; + + private _clothCorner00: Vector3; + + private _clothCorner01: Vector3; + + private _clothCorner10: Vector3; + + private _clothCorner11: Vector3; + + private _softBody: Ammo.btSoftBody; + + // get setter clothcorner + public get clothCorner00(): Vector3 { + return this._clothCorner00; + } + + public set clothCorner00(value: Vector3) { + this._clothCorner00 = value; + } + + public set clothCorner01(value: Vector3) { + this._clothCorner01 = value; + } + + public set clothCorner10(value: Vector3) { + this._clothCorner10 = value; + } + + public get clothCorner11(): Vector3 { + return this._clothCorner11; + } + + public set clothCorner11(value: Vector3) { + this._clothCorner11 = value; + } + + public get planeGeometry(): PlaneGeometry { + return this._planeGeo; + } + + public set planeGeometry(value: PlaneGeometry) { + this._planeGeo = value; + } + + public get mass(): number { + return this._mass; + } + + public set mass(value: number) { + this._mass = value; + } + + start(): void { + if (!this._planeGeo) { + console.error('cloth need planeGeometry'); + return; + } + + if (!this._clothCorner00) { + console.error('cloth need clothCorner00'); + return; + } + + if (!this._clothCorner01) { + console.error('cloth need clothCorner01'); + return; + } + + if (!this._clothCorner10) { + console.error('cloth need clothCorner10'); + return; + } + + if (!this.clothCorner11) { + console.error('cloth need clothCorner11'); + return; + } + var cc00 = new Ammo.btVector3(this._clothCorner00.x, this._clothCorner00.y, this._clothCorner00.z); + var cc01 = new Ammo.btVector3(this._clothCorner01.x, this._clothCorner01.y, this._clothCorner01.z); + var cc10 = new Ammo.btVector3(this._clothCorner10.x, this._clothCorner10.y, this._clothCorner10.z); + var cc11 = new Ammo.btVector3(this._clothCorner11.x, this._clothCorner11.y, this._clothCorner11.z); + + var softBodyHelpers = new Ammo.btSoftBodyHelpers(); + var softBody = softBodyHelpers.CreatePatch( + (Physics.world as Ammo.btSoftRigidDynamicsWorld).getWorldInfo(), + //todo calc clothCorner; + cc00, + cc01, + cc10, + cc11, + this._planeGeo.width, + this._planeGeo.height, + 0, + true, + ); + var sbconfig = softBody.get_m_cfg(); + sbconfig.set_viterations(10); + sbconfig.set_piterations(10); + softBody.setTotalMass(0.9, false); + // Ammo.castObject(softBody, Ammo.btCollisionObject).getCollisionShape().setMargin(0.05); + (Physics.world as Ammo.btSoftRigidDynamicsWorld).addSoftBody(softBody, 1, -1); + this._softBody = softBody; + // this._planeGeo.indexBuffer.buffer + + // var c00 = new + + + } + + public onUpdate(): void { + //todo update geo vecs + } +} diff --git a/packages/physics/HingeConstraint.ts b/packages/physics/HingeConstraint.ts new file mode 100644 index 00000000..7257b19f --- /dev/null +++ b/packages/physics/HingeConstraint.ts @@ -0,0 +1,69 @@ +import Ammo from '@orillusion/ammo'; +import { ComponentBase, Vector3 } from '@orillusion/core' +import { Physics } from './Physics'; +import { Rigidbody } from './Rigidbody'; +/** + * @internal + * @group Plugin + */ +export class HingeConstraint extends ComponentBase { + private _targetRigidbody: Rigidbody; + public pivotSelf: Vector3 = new Vector3(); + public pivotTarget: Vector3 = new Vector3(); + public axisSelf: Vector3 = new Vector3(0, 1, 0); + public axisTarget: Vector3 = new Vector3(0, 1, 0); + private _hinge: Ammo.btHingeConstraint; + + start(): void { + var selfRb = this.object3D.getComponent(Rigidbody); + if (selfRb == null) { + console.error('HingeConstraint need rigidbody'); + return; + } + + if (this._targetRigidbody == null) { + console.error('HingeConstraint need target rigidbody'); + return; + } + + let canStart = true; + if (!selfRb.btRigidbodyInited) { + selfRb.addInitedFunction(this.start, this); + canStart = false; + } + if (!this._targetRigidbody.btRigidbodyInited) { + this._targetRigidbody.addInitedFunction(this.start, this); + canStart = false; + } + + // console.log("hinge true start init"); + + let axisSelf = new Ammo.btVector3(this.axisSelf.x, this.axisSelf.y, this.axisSelf.z); + let axisTarget = new Ammo.btVector3(this.axisTarget.x, this.axisTarget.y, this.axisTarget.z); + + if (!canStart) { + return; + } + let pa = new Ammo.btVector3(this.pivotSelf.x, this.pivotSelf.y, this.pivotSelf.z); + let pb = new Ammo.btVector3(this.pivotTarget.x, this.pivotTarget.y, this.pivotTarget.z); + let hinge = new Ammo.btHingeConstraint(selfRb.btRigidbody, this._targetRigidbody.btRigidbody, pa, pb, axisSelf, axisTarget, true); + this._hinge = hinge; + Physics.world.addConstraint(hinge, true); + } + + public get hinge(): Ammo.btHingeConstraint { + return this._hinge; + } + + public get targetRigidbody(): Rigidbody { + return this._targetRigidbody; + } + + public set targetRigidbody(value: Rigidbody) { + this._targetRigidbody = value; + } + + public destroy(): void { + super.destroy(); + } +} diff --git a/packages/physics/Physics.ts b/packages/physics/Physics.ts new file mode 100644 index 00000000..aeff78d3 --- /dev/null +++ b/packages/physics/Physics.ts @@ -0,0 +1,174 @@ +import Ammo from '@orillusion/ammo'; +import {BoundingBox, Vector3, Time} from '@orillusion/core' +import { Rigidbody } from './Rigidbody'; + +/** + * Physics Engine + * @group Plugin + * @notExported + */ +class _Physics { + private _world: Ammo.btDiscreteDynamicsWorld | Ammo.btSoftRigidDynamicsWorld; + private _isStop: boolean = false; + private _gravity: Vector3 = new Vector3(0, -9.8, 0); + private _gravityEnabled: boolean = true; + private _maxSubSteps: number = 10; + private _fixedTimeStep: number = 1 / 60; + private _maxVelocity: number = 1000; + private _maxAngularVelocity: number = 1000; + private _maxForce: number = 1000; + private _maxTorque: number = 1000; + private _maxLinearCorrection: number = 0.2; + private _maxAngularCorrection: number = 0.2; + private _maxTranslation: number = 1000; + private _maxRotation: number = 1000; + private _maxSolverIterations: number = 20; + private _enableFriction: boolean = true; + private _enableCollisionEvents: boolean = true; + private _enableContinuous: boolean = true; + private _enableCCD: boolean = true; + private _enableWarmStarting: boolean = true; + private _enableTOI: boolean = true; + private _enableSAT: boolean = true; + private _enableSATNormal: boolean = true; + + private physicBound: BoundingBox; + private _isInited: boolean = false; + + public TEMP_TRANSFORM: Ammo.btTransform; //Temp cache, save results from body.getWorldTransform() + + constructor() { } + + /** + * Init Physics Engine + */ + public async init() { + await Ammo(Ammo); + this.TEMP_TRANSFORM = new Ammo.btTransform(); + var collisionConfiguration = new Ammo.btDefaultCollisionConfiguration(); + var dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration); + var overlappingPairCache = new Ammo.btDbvtBroadphase(); + var solver = new Ammo.btSequentialImpulseConstraintSolver(); + this._world = new Ammo.btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration); + this._world.setGravity(new Ammo.btVector3(this._gravity.x, this._gravity.y, this._gravity.z)); + this._isInited = true; + + this.physicBound = new BoundingBox(new Vector3(), new Vector3(2000, 2000, 2000)); + } + + public get maxSubSteps(): number { + return this._maxSubSteps; + } + public set maxSubSteps(value: number) { + this._maxSubSteps = value; + } + + public get fixedTimeStep(): number { + return this._fixedTimeStep; + } + public set fixedTimeStep(value: number) { + this._fixedTimeStep = value; + } + + public get isStop(): boolean { + return this._isStop; + } + + public set isStop(value: boolean) { + this._isStop = value; + } + + public set gravity(gravity: Vector3) { + this._gravity = gravity; + } + + public get gravity(): Vector3 { + return this._gravity; + } + + public get world(): Ammo.btDiscreteDynamicsWorld { + return this._world; + } + + private initByDefault() { + var collisionConfiguration = new Ammo.btDefaultCollisionConfiguration(); + var dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration); + var overlappingPairCache = new Ammo.btDbvtBroadphase(); + var solver = new Ammo.btSequentialImpulseConstraintSolver(); + this._world = new Ammo.btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration); + this._world.setGravity(new Ammo.btVector3(this._gravity.x, this._gravity.y, this._gravity.z)); + this._isInited = true; + this.physicBound = new BoundingBox(new Vector3(), new Vector3(2000, 2000, 2000)); + } + + private initBySoft() { + var collisionConfiguration = new Ammo.btSoftBodyRigidBodyCollisionConfiguration(); + var dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration); + var broadphase = new Ammo.btDbvtBroadphase(); + var solver = new Ammo.btSequentialImpulseConstraintSolver(); + var softBodySolver = new Ammo.btDefaultSoftBodySolver(); + this._world = new Ammo.btSoftRigidDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration, softBodySolver); + this._world.setGravity(new Ammo.btVector3(this._gravity.x, this._gravity.y, this._gravity.z)); + this._isInited = true; + this.physicBound = new BoundingBox(new Vector3(), new Vector3(2000, 2000, 2000)); + } + + public get isInited(): boolean { + return this._isInited; + } + + private __updateWithDelta(time:number ) { + if(!this._isInited) return; + if(this.isStop) return; + this._world.stepSimulation(time); + } + + private __updateWithFixedTimeStep(time:number, maxSubSteps:number, fixedTimeStep:number ) { + if(!this._isInited) return; + if(this.isStop) return; + this.world.stepSimulation(time, maxSubSteps, fixedTimeStep); + } + + + public update() { + if (!this._isInited) { + return; + } + if (this.isStop) return; + + // let fix = Math.max(this._fixedTimeStep, Time.detail); + + this.__updateWithFixedTimeStep(Time.delta, 1, this._fixedTimeStep); + // this._world.stepSimulation(Time.delta, 1, this._fixedTimeStep); + } + + public addRigidbody(rigidBody: Rigidbody) { + this._world.addRigidBody(rigidBody.btRigidbody); + } + + public removeRigidbody(rigidBody: Rigidbody) { + this._world.removeRigidBody(rigidBody.btRigidbody); + } + + checkBound(body: Rigidbody) { + if (body) { + let wp = body.transform.worldPosition; + let inside = this.physicBound.containsPoint(wp); + if (!inside) { + body.btRigidbody.activate(false); + // this._world.removeRigidBody(body.btRigidbody); + body.destroy(); + } + } + } +} + +/** + * Only init one physics instance + * ```ts + * await Physics.init(); + * ``` + * @group Plugin + */ +export let Physics = new _Physics(); +export {Ammo} diff --git a/packages/physics/README.md b/packages/physics/README.md new file mode 100644 index 00000000..0e9422cc --- /dev/null +++ b/packages/physics/README.md @@ -0,0 +1,19 @@ +A physics component for [Orillusion](https://www.orillusion.com), powered by [Ammo.js](https://github.com/kripken/ammo.js/) + +## Usage +```bash +npm install @orillusion/core --save +npm install @orillusion/physics --save +``` +```ts +import { Scene3D } from "@orillusion/core" +import { Stats } from "@orillusion/physics" +``` + +Or access Global build from CDN +```html + + +``` + +More doc from [Orillusion](https://www.orillusion.com/guide/physics/Readme.html) \ No newline at end of file diff --git a/packages/physics/Rigidbody.ts b/packages/physics/Rigidbody.ts new file mode 100644 index 00000000..1059af08 --- /dev/null +++ b/packages/physics/Rigidbody.ts @@ -0,0 +1,286 @@ +import Ammo from '@orillusion/ammo'; +import { Vector3, BoxColliderShape, CapsuleColliderShape, ColliderComponent, ComponentBase, MeshColliderShape, Quaternion, SphereColliderShape } from '@orillusion/core' +import { Physics } from './Physics'; + +enum CollisionFlags { + STATIC_OBJECT = 1, + KINEMATIC_OBJECT = 2, + NO_CONTACT_RESPONSE = 4, + CUSTOM_MATERIAL_CALLBACK = 8, + CHARACTER_OBJECT = 16, + DISABLE_VISUALIZE_OBJECT = 32, + DISABLE_SPU_COLLISION_PROCESSING = 64, + HAS_CONTACT_STIFFNESS_DAMPING = 128, + HAS_CUSTOM_DEBUG_RENDERING_COLOR = 256, + HAS_FRICTION_ANCHOR = 512, + HAS_COLLISION_SOUND_TRIGGER = 1024 +} + +enum CollisionObjectTypes { + COLLISION_OBJECT = 1, + RIGID_BODY = 2, + GHOST_OBJECT = 4, + SOFT_BODY = 8, + HF_FLUID = 16, + USER_TYPE = 32, + FEATHERSTONE_LINK = 64 +} + +/** + * Rigidbody Component + * Rigid bodies can endow game objects with physical properties, allowing them to be controlled by the physics system and subjected to forces and torques, thus achieving realistic motion effects. + * @group Components + */ +export class Rigidbody extends ComponentBase { + private _mass: number = 0.01; + private _velocity: Vector3 = new Vector3(); + private _angularVelocity: Vector3 = new Vector3(); + private _force: Vector3 = new Vector3(); + private _useGravity: boolean = true; + private _isKinematic: boolean = false; + private _isStatic: boolean = false; + private _isTrigger: boolean = false; + private _btRigidbody: Ammo.btRigidBody; + private _btRigidbodyInited: boolean = false; + private _friction: number = 0.6; + private _rollingFriction: number = 0.1; + private _restitution: number = 0.8 + + private _initedFunctions: { fun: Function; thisObj: Object }[] = []; + + init(): void { + + } + + public start(): void { + if (!this.object3D.getComponent(ColliderComponent)) { + console.error('rigidbody need collider'); + return; + } + this.initRigidbody(); + } + + /** + * Get friction value + */ + public get friction() { + return this._friction; + } + /** + * Set friction value + */ + public set friction(value: number) { + this._friction = value; + if (this._btRigidbody) this._btRigidbody.setFriction(value); + } + /** + * Get rolling friction value + */ + public get rollingFriction(): number { + return this._rollingFriction; + } + /** + * Set rolling friction value + */ + public set rollingFriction(value: number) { + this._rollingFriction = value; + if (this._btRigidbody) this._btRigidbody.setRollingFriction(value); + } + /** + * Get restitution value + */ + public get restitution(): number { + return this._restitution; + } + /** + * Set restitution value + */ + public set restitution(value: number) { + this._restitution = value; + if (this._btRigidbody) this._btRigidbody.setRestitution(value); + } + /** + * Check if rigidbody inited + */ + public get btRigidbodyInited(): boolean { + return this._btRigidbodyInited; + } + + private addAmmoRigidbody(): void { + var shape = this.getPhysicShape(); + var btTransform = new Ammo.btTransform(); + btTransform.setIdentity(); + var localInertia = new Ammo.btVector3(0, 0, 0); + + shape.calculateLocalInertia(this.mass, localInertia); + + btTransform.setOrigin(new Ammo.btVector3(this.object3D.x, this.object3D.y, this.object3D.z)); + let t = this.object3D.transform; + + Quaternion.HELP_0.fromEulerAngles(t.rotationX, t.rotationY, t.rotationZ); + let btq = new Ammo.btQuaternion(Quaternion.HELP_0.x, Quaternion.HELP_0.y, Quaternion.HELP_0.z, Quaternion.HELP_0.w); + btTransform.setRotation(btq); + + var motionState = new Ammo.btDefaultMotionState(btTransform); + var rbInfo = new Ammo.btRigidBodyConstructionInfo(this.mass, motionState, shape, localInertia); + + this._btRigidbody = new Ammo.btRigidBody(rbInfo); + this._btRigidbody.setRestitution(this.restitution); + this.btRigidbody.setFriction(this.friction); + this.btRigidbody.setRollingFriction(this.rollingFriction); + Physics.addRigidbody(this); + } + private initRigidbody(): void { + this.addAmmoRigidbody(); + + for (let i = 0; i < this._initedFunctions.length; i++) { + let fun = this._initedFunctions[i]; + fun.fun.call(fun.thisObj); + } + this._btRigidbodyInited = true; + } + + /** + * Add init callback + * @param fun callback function + * @param thisObj this + */ + public addInitedFunction(fun: Function, thisObj: Object) { + this._initedFunctions.push({ fun: fun, thisObj: thisObj }); + } + /** + * Remove init callback + * @param fun callback function + * @param thisObj this + */ + public removeInitedFunction(fun: Function, thisObj: Object) { + for (let i = 0; i < this._initedFunctions.length; i++) { + let item = this._initedFunctions[i]; + if (item.fun === fun && item.thisObj === thisObj) { + this._initedFunctions.splice(i, 1); + break; + } + } + } + + private getPhysicShape() { + let collider = this.object3D.getComponent(ColliderComponent); + let colliderShape = collider.shape; + + var shape: Ammo.btCollisionShape; + + if (colliderShape instanceof BoxColliderShape) { + shape = new Ammo.btBoxShape(new Ammo.btVector3(colliderShape.halfSize.x, colliderShape.halfSize.y, colliderShape.halfSize.z)); + } else if (colliderShape instanceof CapsuleColliderShape) { + shape = new Ammo.btCapsuleShape(colliderShape.radius, colliderShape.height); + } else if (colliderShape instanceof MeshColliderShape) { + // let triangleMeshShape = new Ammo.btTriangleMeshShape(); + } else if (colliderShape instanceof SphereColliderShape) { + shape = new Ammo.btSphereShape(colliderShape.radius); + } + return shape; + } + + /** + * Return internal Ammo.btRigidBody + */ + public get btRigidbody(): Ammo.btRigidBody { + return this._btRigidbody; + } + + onUpdate(): void { + if (this._btRigidbody && this._btRigidbody.getMotionState()) { + this._btRigidbody.getMotionState().getWorldTransform(Physics.TEMP_TRANSFORM); + + this.transform.x = Physics.TEMP_TRANSFORM.getOrigin().x(); + this.transform.y = Physics.TEMP_TRANSFORM.getOrigin().y(); + this.transform.z = Physics.TEMP_TRANSFORM.getOrigin().z(); + + let q = Quaternion.HELP_0; + q.set(Physics.TEMP_TRANSFORM.getRotation().x(), Physics.TEMP_TRANSFORM.getRotation().y(), Physics.TEMP_TRANSFORM.getRotation().z(), Physics.TEMP_TRANSFORM.getRotation().w()); + + this.object3D.transform.localRotQuat = q; + + Physics.checkBound(this); + } + } + + public destroy(): void { + Physics.removeRigidbody(this); + this._initedFunctions = null; + super.destroy(); + } + + /** + * Get mass value。 + */ + public get mass(): number { + return this._mass; + } + /** + * Set mass value。 + */ + public set mass(value: number) { + this._mass = value; + if (this._btRigidbody) { + Physics.world.removeRigidBody(this._btRigidbody); + this.addAmmoRigidbody(); + // console.log("setMassProps", "mass: " + value, "flag: " + this._btRigidbody.getCollisionFlags()); + // this._btRigidbody.setMassProps(value, new Ammo.btVector3(0, 0, 0)); + // this._btRigidbody.setCollisionFlags(this._btRigidbody.getCollisionFlags()); + // console.log("setMassProps", "mass: " + value, "flag: " + this._btRigidbody.getCollisionFlags()); + // if(this.mass <= 0) { + // this._btRigidbody.setLinearVelocity(new Ammo.btVector3(0, 0, 0)); + // this._btRigidbody.setAngularVelocity(new Ammo.btVector3(0, 0, 0)); + // } + } + } + /** + * Get velocity value of current object + */ + public get velocity(): Vector3 { + return this._velocity; + } + /** + * Set velocity value of current object + */ + public set velocity(value: Vector3) { + this._velocity = value.clone(); + if (this._btRigidbody) { + this._btRigidbody.applyForce(new Ammo.btVector3(value.x, value.y, value.z), new Ammo.btVector3(0, 0, 0)); + } + } + /** + * Get the angular velocity value of current object + */ + public get angularVelocity(): Vector3 { + return this._angularVelocity; + } + + /** + * Set the angular velocity value of current object + */ + public set angularVelocity(value: Vector3) { + this._angularVelocity = value; + } + /** + * Check if the rigidbody affect physics system + */ + public get isKinematic(): boolean { + return this._isKinematic; + } + /** + * Set if the rigidbody affect physics system + */ + public set isKinematic(value: boolean) { + this._isKinematic = value; + } + + public get isTrigger(): boolean { + return this._isTrigger; + } + + public set isTrigger(value: boolean) { + this._isTrigger = value; + } +} diff --git a/packages/physics/index.ts b/packages/physics/index.ts new file mode 100644 index 00000000..190efb56 --- /dev/null +++ b/packages/physics/index.ts @@ -0,0 +1,4 @@ +export * from './Physics' +export * from './Rigidbody' +export * from './ClothSoftBody' +export * from './HingeConstraint' \ No newline at end of file diff --git a/packages/physics/package.json b/packages/physics/package.json new file mode 100644 index 00000000..ac357459 --- /dev/null +++ b/packages/physics/package.json @@ -0,0 +1,27 @@ +{ + "name": "@orillusion/physics", + "version": "0.1.8", + "author": "Orillusion", + "description": "Orillusion Physics Plugin, Powerd by Ammo.js", + "main": "./dist/physics.umd.js", + "module": "./dist/physics.es.js", + "module:dev": "./index.ts", + "types": "./dist/index.d.ts", + "files": ["dist"], + "scripts": { + "build": "vite build && npm run build:types && npm run build:clean", + "build:types": "tsc --emitDeclarationOnly -p tsconfig.json", + "build:clean": "mv dist/packages/physics/* dist && rm -rf dist/src & rm -rf dist/packages", + "docs": "npm run docs:typedoc ../../docs/physics index.ts", + "docs:typedoc": "npx typedoc --plugin typedoc-plugin-markdown --plugin ../../script/typedoc-plugin-not-exported.js --tsconfig tsconfig.json --gitRevision main --hideBreadcrumbs true --allReflectionsHaveOwnDocument true --readme none --excludeInternal --excludePrivate --excludeProtected --sort source-order --out" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/Orillusion/orillusion.git" + }, + "dependencies": { + "@orillusion/ammo": "^0.1.1", + "@orillusion/core": "^0.6.0" + } +} diff --git a/packages/physics/tsconfig.json b/packages/physics/tsconfig.json new file mode 100644 index 00000000..15244be5 --- /dev/null +++ b/packages/physics/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "Node", + "sourceMap": false, + "resolveJsonModule": true, + "esModuleInterop": true, + "types": ["vite/client", "@webgpu/types"], + // for build + // "noEmit": true, + "declaration": true, + "declarationDir": "dist", + "outDir": "dist", + "skipLibCheck": true, + "noImplicitAny": false, + "noUnusedLocals": false, + "noUnusedParameters":false, + "noImplicitReturns": false, + "strictPropertyInitialization": false, + "strictNullChecks": false, + "strict": false, + "paths": { + "@orillusion/core": ["../../src"], + "@orillusion/ammo" : ["../ammo"] + } + } +} \ No newline at end of file diff --git a/packages/physics/vite.config.js b/packages/physics/vite.config.js new file mode 100644 index 00000000..270a759e --- /dev/null +++ b/packages/physics/vite.config.js @@ -0,0 +1,25 @@ +import { defineConfig } from 'vite' +const path = require('path') +export default defineConfig({ + resolve: { + alias: { + '@orillusion/ammo': path.resolve(__dirname, '../ammo'), + '@orillusion/core': path.resolve(__dirname, '../../src') + } + }, + build: { + lib: { + entry: path.resolve('index.ts'), + name: 'Physics', + fileName: (format) => `physics.${format}.js` + }, + rollupOptions: { + external: ['@orillusion/core'], + output: { + globals: { + '@orillusion/core': 'Orillusion' + } + } + } + } +}) \ No newline at end of file diff --git a/packages/post/index.ts b/packages/post/index.ts new file mode 100644 index 00000000..3f04d0c3 --- /dev/null +++ b/packages/post/index.ts @@ -0,0 +1,6 @@ +/** + * PostEffects Plugins + * @group Plugin + * @notExported + */ +export {} \ No newline at end of file diff --git a/packages/post/package.json b/packages/post/package.json new file mode 100644 index 00000000..4b5abb5b --- /dev/null +++ b/packages/post/package.json @@ -0,0 +1,24 @@ +{ + "name": "@orillusion/post", + "version": "0.1.0", + "author": "Orillusion", + "description": "Orillusion Post Effects", + "main": "./dist/post.umd.js", + "module": "./dist/post.es.js", + "module:dev": "./index.ts", + "types": "./dist/index.d.ts", + "files": ["dist"], + "scripts": { + "build": "vite build && npm run build:types && npm run build:clean", + "build:types": "tsc --emitDeclarationOnly -p tsconfig.json", + "build:clean": "mv dist/packages/post/* dist && rm -rf dist/src && rm -rf dist/packages" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/Orillusion/orillusion.git" + }, + "dependencies": { + "@orillusion/core": "^0.6.0" + } +} diff --git a/packages/post/tsconfig.json b/packages/post/tsconfig.json new file mode 100644 index 00000000..07928127 --- /dev/null +++ b/packages/post/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "Node", + "sourceMap": false, + "resolveJsonModule": true, + "esModuleInterop": true, + "types": ["vite/client", "@webgpu/types"], + // for build + // "noEmit": true, + "declaration": true, + "declarationDir": "dist", + "outDir": "dist", + "skipLibCheck": true, + "noImplicitAny": false, + "noUnusedLocals": false, + "noUnusedParameters":false, + "noImplicitReturns": false, + "strictPropertyInitialization": false, + "strictNullChecks": false, + "strict": false, + "paths": { + "@orillusion/core": ["../../src"], + } + } +} \ No newline at end of file diff --git a/packages/post/vite.config.js b/packages/post/vite.config.js new file mode 100644 index 00000000..1e9b31a0 --- /dev/null +++ b/packages/post/vite.config.js @@ -0,0 +1,24 @@ +import { defineConfig } from 'vite' +const path = require('path') +export default defineConfig({ + resolve: { + alias: { + '@orillusion/core': path.resolve(__dirname, '../../src') + } + }, + build: { + lib: { + entry: path.resolve('index.ts'), + name: 'Post', + fileName: (format) => `post.${format}.js` + }, + rollupOptions: { + external: ['@orillusion/core'], + output: { + globals: { + '@orillusion/core': 'Orillusion' + } + } + } + } +}) \ No newline at end of file diff --git a/packages/stats/README.md b/packages/stats/README.md new file mode 100644 index 00000000..28e82f3f --- /dev/null +++ b/packages/stats/README.md @@ -0,0 +1,28 @@ +A simple performance monitor component for [Orillusion](https://www.orillusion.com) + +## Usage +```bash +npm install @orillusion/core --save +npm install @orillusion/stats --save +``` +```ts +import { Scene3D } from "@orillusion/core" +import { Stats } from "@orillusion/stats" + +let scene = new Scene3D(); +scene.addComponent(Stats); +``` + +Or access Global build from CDN +```html + + +``` +```js +const { Scene3D, Stats } = Orillusion + +let scene = new Scene3D(); +scene.addComponent(Stats); +``` + +More doc from [Orillusion](https://www.orillusion.com/guide/performance/Readme.html) \ No newline at end of file diff --git a/packages/stats/index.ts b/packages/stats/index.ts new file mode 100644 index 00000000..92f0b815 --- /dev/null +++ b/packages/stats/index.ts @@ -0,0 +1,154 @@ +import { ComponentBase } from "@orillusion/core" + +/** + * Performance info stats + * @group Plugin + */ +export class Stats extends ComponentBase { + /** + * Stats DOM container + * with default class="stats" + * could custom container style with css + */ + container: HTMLElement + private beginTime: number = performance.now() + private prevTime: number = this.beginTime + private frames: number = 0 + private fpsPanel: Panel + private memPanel: Panel + // private drawcallPanel:Panel + + /** + * @internal + */ + init() { + const container = this.container = document.createElement('div') + container.className = 'stats' + container.setAttribute('style', 'display:flex;flex-direction:column;gap:1px;position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000') + this.fpsPanel = new Panel(container, 'FPS', '#0ff', '#002') + this.memPanel = new Panel(container, 'MB', '#f08', '#201') + // this.drawcallPanel = new Panel( container, 'DC', '#0f0', '#020' ) + + + this.beginTime = (performance || Date).now() + document.body.appendChild(this.container) + } + /** + * @internal + */ + onDisable() { + this.container.style.display = 'none' + } + /** + * @internal + */ + onEnable() { + this.container.style.display = 'flex' + } + /** + * @internal + */ + stop() { + this.fpsPanel.destroy() + this.memPanel.destroy() + document.body.removeChild(this.container) + } + /** + * @internal + */ + onUpdate() { + this.frames++ + const time = this.beginTime = performance.now() + if (time >= this.prevTime + 1000) { + this.fpsPanel.update((this.frames * 1000) / (time - this.prevTime), 100) + this.memPanel.update((performance as any).memory.totalJSHeapSize / 1048576, 256) + // this.drawcallPanel.update( Engine3D.engineSetting.performance.drawCall, 512) + this.prevTime = time + this.frames = 0 + } + } +} + +/** + * @internal + */ +class Panel { + canvas: HTMLCanvasElement + private worker: Worker + private width = 80 + private height = 48 + constructor(parent: HTMLElement, name: string, fg: string, bg: string) { + const canvas = this.canvas = document.createElement('canvas') + canvas.width = this.width + canvas.height = this.height + parent.appendChild(canvas) + const offscreen = (canvas as any).transferControlToOffscreen() + const blob = new Blob([`(${worker})()`], { type: 'application/javascript' }) + this.worker = new Worker(URL.createObjectURL(blob)) + this.worker.postMessage({ type: 'init', offscreen, name, fg, bg }, [offscreen]) + } + + update(value: number, maxValue: number) { + this.worker.postMessage({ type: 'update', value, maxValue }) + } + destroy() { + this.worker.terminate() + } +} + + /** + * @internal + */ +function worker() { + let canvas: HTMLCanvasElement + let context: CanvasRenderingContext2D + let name: string + let bg: string + let fg: string + let WIDTH: number + let HEIGHT: number + let min: number = Infinity + let max: number = 0 + const PR = 1 + const TEXT_X = 3 + const TEXT_Y = 2 + const GRAPH_X = 3 + const GRAPH_Y = 15 + const GRAPH_WIDTH = 74 + const GRAPH_HEIGHT = 30 + + onmessage = e => { + if (e.data.type == 'update') { + min = Math.min(min, e.data.value) + max = Math.max(max, e.data.value) + context.fillStyle = bg + context.globalAlpha = 1 + context.fillRect(0, 0, WIDTH, GRAPH_Y) + context.fillStyle = fg + context.fillText(Math.round(e.data.value) + ' ' + name + ' (' + Math.round(min) + '-' + Math.round(max) + ')', TEXT_X, TEXT_Y) + context.drawImage(canvas, GRAPH_X + PR, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT, GRAPH_X, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT) + context.fillRect(GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, GRAPH_HEIGHT) + context.fillStyle = bg + context.globalAlpha = 0.9 + context.fillRect(GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, Math.round((1 - (e.data.value / e.data.maxValue)) * GRAPH_HEIGHT)) + } else if (e.data.type == 'init') { + canvas = e.data.offscreen + name = e.data.name + bg = e.data.bg + fg = e.data.fg + WIDTH = canvas.width + HEIGHT = canvas.height + context = canvas.getContext('2d') as CanvasRenderingContext2D + context.font = 'bold 9px Helvetica,Arial,sans-serif' + context.textBaseline = 'top' + context.fillStyle = bg + context.fillRect(0, 0, WIDTH, HEIGHT) + context.fillStyle = fg + context.fillText(name, TEXT_X, TEXT_Y) + context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT) + context.fillStyle = bg + context.globalAlpha = 0.9 + context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT) + } + } +} \ No newline at end of file diff --git a/packages/stats/package.json b/packages/stats/package.json new file mode 100644 index 00000000..8b108fb6 --- /dev/null +++ b/packages/stats/package.json @@ -0,0 +1,26 @@ +{ + "name": "@orillusion/stats", + "version": "0.1.5", + "author": "Orillusion", + "description": "Orillusion Stats Plugin", + "main": "./dist/stats.umd.js", + "module": "./dist/stats.es.js", + "module:dev": "./index.ts", + "types": "./dist/index.d.ts", + "files": ["dist"], + "scripts": { + "build": "vite build && npm run build:types && npm run build:clean", + "build:types": "tsc --emitDeclarationOnly -p tsconfig.json", + "build:clean": "mv dist/packages/stats/* dist && rm -rf dist/src && rm -rf dist/packages", + "docs": "npm run docs:typedoc ../../docs/stats index.ts", + "docs:typedoc": "npx typedoc --plugin typedoc-plugin-markdown --plugin ../../script/typedoc-plugin-not-exported.js --tsconfig tsconfig.json --gitRevision main --hideBreadcrumbs true --allReflectionsHaveOwnDocument true --readme none --excludeInternal --excludePrivate --excludeProtected --sort source-order --out" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/Orillusion/orillusion.git" + }, + "dependencies": { + "@orillusion/core": ">=0.4.0" + } +} diff --git a/packages/stats/tsconfig.json b/packages/stats/tsconfig.json new file mode 100644 index 00000000..07928127 --- /dev/null +++ b/packages/stats/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "Node", + "sourceMap": false, + "resolveJsonModule": true, + "esModuleInterop": true, + "types": ["vite/client", "@webgpu/types"], + // for build + // "noEmit": true, + "declaration": true, + "declarationDir": "dist", + "outDir": "dist", + "skipLibCheck": true, + "noImplicitAny": false, + "noUnusedLocals": false, + "noUnusedParameters":false, + "noImplicitReturns": false, + "strictPropertyInitialization": false, + "strictNullChecks": false, + "strict": false, + "paths": { + "@orillusion/core": ["../../src"], + } + } +} \ No newline at end of file diff --git a/packages/stats/vite.config.js b/packages/stats/vite.config.js new file mode 100644 index 00000000..07b7b104 --- /dev/null +++ b/packages/stats/vite.config.js @@ -0,0 +1,24 @@ +import { defineConfig } from 'vite' +const path = require('path') +export default defineConfig({ + resolve: { + alias: { + '@orillusion/core': path.resolve(__dirname, '../../src') + } + }, + build: { + lib: { + entry: path.resolve('index.ts'), + name: 'Stats', + fileName: (format) => `stats.${format}.js` + }, + rollupOptions: { + external: ['@orillusion/core'], + output: { + globals: { + '@orillusion/core': 'Orillusion' + } + } + } + } +}) \ No newline at end of file diff --git a/samples/base/Sample_Base_0.ts b/samples/base/Sample_Base_0.ts new file mode 100644 index 00000000..a903d180 --- /dev/null +++ b/samples/base/Sample_Base_0.ts @@ -0,0 +1,59 @@ +import { AtmosphericComponent, BoxGeometry, Camera3D, DirectLight, Engine3D, HoverCameraController, KelvinUtil, LitMaterial, MeshRenderer, Object3D, Scene3D, View3D } from '@orillusion/core'; +import { Stats } from '@orillusion/stats' + +// simple base demo +class Sample_Base_0 { + async run() { + // init engine + await Engine3D.init(); + // create new Scene + let scene = new Scene3D(); + + // add performance stats + scene.addComponent(Stats) + + // add an Atmospheric sky enviroment + let sky = scene.addComponent(AtmosphericComponent); + sky.sunY = 0.6 + + // add a camera object + let cameraObj = new Object3D(); + scene.addChild(cameraObj); + + // set main camera component with a perspective view + let mainCamera = cameraObj.addComponent(Camera3D); + mainCamera.perspective(60, Engine3D.aspect, 0.01, 5000.0); + + // add a basic camera controller + let hoverCameraController = cameraObj.addComponent(HoverCameraController); + hoverCameraController.setCamera(15, -15, 10); + + // create a basic cube + let cubeObj = new Object3D(); + let mr = cubeObj.addComponent(MeshRenderer); + mr.geometry = new BoxGeometry(); + let mat = new LitMaterial(); + mr.material = mat; + scene.addChild(cubeObj); + + // add a basic direct light + let lightObj = new Object3D(); + lightObj.rotationX = 45; + lightObj.rotationY = 60; + lightObj.rotationZ = 150; + let lc = lightObj.addComponent(DirectLight); + lc.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + lc.intensity = 10; + scene.addChild(lightObj); + + // create a view with target scene and camera + let view = new View3D(); + view.scene = scene; + view.camera = mainCamera; + + // start render + Engine3D.startRenderView(view); + } +} + +new Sample_Base_0().run() \ No newline at end of file diff --git a/samples/index.ts b/samples/index.ts new file mode 100644 index 00000000..a36e0213 --- /dev/null +++ b/samples/index.ts @@ -0,0 +1,69 @@ +/******** Load all samples in /src/sample/ ********/ +{ + // find all demos in /sample + const modules = import.meta.glob(['./*/*.ts', '!./*/_*.ts']) + // create menu + let title = '', list = '' + for (const path in modules) { + const arr = path.split('/') + const _title = arr[1] + const _demo = arr[2].replace(/Sample_|Sample|\.ts/g, '') + if (_title != title) { + list += `