From 42f52f4e0097d82ddb585e79f2a02ca5feaf2717 Mon Sep 17 00:00:00 2001 From: Cristian Vogel Date: Mon, 11 Mar 2024 18:20:12 +0100 Subject: [PATCH 01/13] extra null check on diff --- dsp/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsp/main.js b/dsp/main.js index 7057940..8fa577b 100644 --- a/dsp/main.js +++ b/dsp/main.js @@ -20,7 +20,7 @@ let refs = new RefMap(core); let prevState = null; function shouldRender(prevState, nextState) { - return (prevState === null) || (prevState.sampleRate !== nextState.sampleRate); + return (prevState === null) || (nextState ===null) || (prevState.sampleRate !== nextState.sampleRate); } // The important piece: here we register a state change callback with the native From 63364f0af0da0a2c09a7ac0f3b3423abecc950ab Mon Sep 17 00:00:00 2001 From: Cristian Vogel Date: Mon, 15 Jul 2024 17:29:31 +0200 Subject: [PATCH 02/13] First commit. Swap out to latest choc. --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index e1c24ee..aea7f80 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,4 +6,4 @@ url = https://github.com/juce-framework/JUCE.git [submodule "choc"] path = native/choc - url = https://github.com/nick-thompson/choc.git + url = https://github.com/cristianvogel/choc/tree/cristians-edits/ From 939e69b9cd8ac8e743d3179e964ef68ea9a7b208 Mon Sep 17 00:00:00 2001 From: Cristian Vogel Date: Mon, 15 Jul 2024 17:39:08 +0200 Subject: [PATCH 03/13] Locally updated choc with elementary edits --- .gitmodules | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index aea7f80..9f4b218 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,6 +4,3 @@ [submodule "juce"] path = native/juce url = https://github.com/juce-framework/JUCE.git -[submodule "choc"] - path = native/choc - url = https://github.com/cristianvogel/choc/tree/cristians-edits/ From 7c34d2d97e8461b968ba0daa829c8433a66b24f0 Mon Sep 17 00:00:00 2001 From: Cristian Vogel Date: Mon, 15 Jul 2024 17:46:21 +0200 Subject: [PATCH 04/13] Remove submodule dep from .git config --- .gitmodules | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitmodules b/.gitmodules index 9f4b218..6e9a43d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,4 @@ [submodule "juce"] path = native/juce url = https://github.com/juce-framework/JUCE.git + From 37abc9400c73a222603b884a62b064de3e2c910c Mon Sep 17 00:00:00 2001 From: Cristian Vogel Date: Mon, 15 Jul 2024 17:47:51 +0200 Subject: [PATCH 05/13] Removed choc submodule --- native/choc | 1 - 1 file changed, 1 deletion(-) delete mode 160000 native/choc diff --git a/native/choc b/native/choc deleted file mode 160000 index 090fd7c..0000000 --- a/native/choc +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 090fd7cf41ea2b5d317420af45097cc22a975656 From 8359bfb44067174887c5727d90364509e44cfb13 Mon Sep 17 00:00:00 2001 From: Cristian Vogel Date: Mon, 15 Jul 2024 17:55:31 +0200 Subject: [PATCH 06/13] Removing old choc --- .github/workflows/main.yml | 120 ++++++++++++++++++------------------- .gitmodules | 3 + 2 files changed, 63 insertions(+), 60 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 431fc60..bca7ce4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,68 +1,68 @@ -name: Build +# name: Build -on: - workflow_dispatch: - pull_request: - push: - branches: - - '**' +# on: +# workflow_dispatch: +# pull_request: +# push: +# branches: +# - '**' -jobs: - native: - strategy: - fail-fast: false - matrix: - # Disabling the linux build for now - # os: [ubuntu-latest, macos-latest, windows-latest] - os: [macos-latest, windows-latest] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v3 - with: - submodules: true +# jobs: +# native: +# strategy: +# fail-fast: false +# matrix: +# # Disabling the linux build for now +# # os: [ubuntu-latest, macos-latest, windows-latest] +# os: [macos-latest, windows-latest] +# runs-on: ${{ matrix.os }} +# steps: +# - uses: actions/checkout@v3 +# with: +# submodules: true - - uses: actions/setup-node@v3 - with: - node-version: 18 +# - uses: actions/setup-node@v3 +# with: +# node-version: 18 - - name: JUCE Linux Dependencies - shell: bash - if: ${{ matrix.os == 'ubuntu-latest' }} - run: | - sudo apt-get update - sudo apt-get install -y freeglut3-dev - sudo apt-get install -y g++ - sudo apt-get install -y libasound2-dev - sudo apt-get install -y libcurl4-openssl-dev - sudo apt-get install -y libfreetype6-dev - sudo apt-get install -y libjack-jackd2-dev - sudo apt-get install -y libx11-dev - sudo apt-get install -y libxcomposite-dev - sudo apt-get install -y libxcursor-dev - sudo apt-get install -y libxinerama-dev - sudo apt-get install -y libxrandr-dev - sudo apt-get install -y mesa-common-dev +# - name: JUCE Linux Dependencies +# shell: bash +# if: ${{ matrix.os == 'ubuntu-latest' }} +# run: | +# sudo apt-get update +# sudo apt-get install -y freeglut3-dev +# sudo apt-get install -y g++ +# sudo apt-get install -y libasound2-dev +# sudo apt-get install -y libcurl4-openssl-dev +# sudo apt-get install -y libfreetype6-dev +# sudo apt-get install -y libjack-jackd2-dev +# sudo apt-get install -y libx11-dev +# sudo apt-get install -y libxcomposite-dev +# sudo apt-get install -y libxcursor-dev +# sudo apt-get install -y libxinerama-dev +# sudo apt-get install -y libxrandr-dev +# sudo apt-get install -y mesa-common-dev - - name: Build - shell: bash - run: | - set -x - set -e +# - name: Build +# shell: bash +# run: | +# set -x +# set -e - npm install - npm run build +# npm install +# npm run build - - name: Artifact naming - shell: bash - run: | - echo "ARTIFACT_DATESTRING=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - echo "ARTIFACT_OS=$(echo $RUNNER_OS | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV +# - name: Artifact naming +# shell: bash +# run: | +# echo "ARTIFACT_DATESTRING=$(date +'%Y-%m-%d')" >> $GITHUB_ENV +# echo "ARTIFACT_OS=$(echo $RUNNER_OS | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV - - uses: actions/upload-artifact@v3 - with: - name: srvb-${{ env.ARTIFACT_OS }}-${{ env.ARTIFACT_DATESTRING }} - path: | - native/build/scripted/SRVB_artefacts/Release/VST3/ - native/build/scripted/SRVB_artefacts/Release/AU/ - !native/build/scripted/SRVB_artefacts/Release/VST3/*.lib - !native/build/scripted/SRVB_artefacts/Release/VST3/*.exp +# - uses: actions/upload-artifact@v3 +# with: +# name: srvb-${{ env.ARTIFACT_OS }}-${{ env.ARTIFACT_DATESTRING }} +# path: | +# native/build/scripted/SRVB_artefacts/Release/VST3/ +# native/build/scripted/SRVB_artefacts/Release/AU/ +# !native/build/scripted/SRVB_artefacts/Release/VST3/*.lib +# !native/build/scripted/SRVB_artefacts/Release/VST3/*.exp diff --git a/.gitmodules b/.gitmodules index 6e9a43d..f0f98f4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,4 +4,7 @@ [submodule "juce"] path = native/juce url = https://github.com/juce-framework/JUCE.git +[submodule "choc"] + path = native/choc + url = https://github.com/cristianvogel/choc/tree/cristians-edits From 44e5dc08cafd6dec603ca1165ac7615fb6f9faef Mon Sep 17 00:00:00 2001 From: Cristian Vogel Date: Mon, 15 Jul 2024 18:05:28 +0200 Subject: [PATCH 07/13] Correctly updating the main choc submodule --- .gitmodules | 3 +++ native/choc | 1 + 2 files changed, 4 insertions(+) create mode 160000 native/choc diff --git a/.gitmodules b/.gitmodules index f0f98f4..08d3922 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,3 +8,6 @@ path = native/choc url = https://github.com/cristianvogel/choc/tree/cristians-edits +[submodule "native/choc"] + path = native/choc + url = https://github.com/cristianvogel/choc diff --git a/native/choc b/native/choc new file mode 160000 index 0000000..b086c62 --- /dev/null +++ b/native/choc @@ -0,0 +1 @@ +Subproject commit b086c628c82f2e12c794ad2642b11b41ef6f50e1 From c2f67cee946cf2b9f2ea8d1658123db8418a7dd5 Mon Sep 17 00:00:00 2001 From: Cristian Vogel Date: Mon, 15 Jul 2024 18:06:50 +0200 Subject: [PATCH 08/13] updating choc submodule --- .gitmodules | 4 - how_to_update_choc.md | 166 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 how_to_update_choc.md diff --git a/.gitmodules b/.gitmodules index 08d3922..27490bf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,9 +5,5 @@ path = native/juce url = https://github.com/juce-framework/JUCE.git [submodule "choc"] - path = native/choc - url = https://github.com/cristianvogel/choc/tree/cristians-edits - -[submodule "native/choc"] path = native/choc url = https://github.com/cristianvogel/choc diff --git a/how_to_update_choc.md b/how_to_update_choc.md new file mode 100644 index 0000000..5d0769d --- /dev/null +++ b/how_to_update_choc.md @@ -0,0 +1,166 @@ +Important to update CHOC that is used in the native/choc submodule and also probably in Elementary submodule + +here is copilot guide. + + +cristianvogel: npm command to install everything including git submodules + +GitHub Copilot: ```bash +npm install && git submodule update --init --recursive +``` + +cristianvogel: remove all cache of git submodules + +GitHub Copilot: ```bash +git submodule deinit -f --all && git rm -rf .git/modules +``` + +cristianvogel: fatal: No url found for submodule path 'native/choc' in .gitmodules + + +There is no url registred in .gitmodules file + +GitHub Copilot: To resolve the issue of a missing URL for the submodule path 'native/choc' in the [`.gitmodules`](command:_github.copilot.openRelativePath?%5B%7B%22scheme%22%3A%22file%22%2C%22authority%22%3A%22%22%2C%22path%22%3A%22%2FUsers%2Fcristianvogel%2FDesktop%2FProgramming%2FSRVB-withCablesUI%2Fsrvb-fork%2F.gitmodules%22%2C%22query%22%3A%22%22%2C%22fragment%22%3A%22%22%7D%5D "/Users/cristianvogel/Desktop/Programming/SRVB-withCablesUI/srvb-fork/.gitmodules") file, you need to add the submodule information for 'native/choc' to the [`.gitmodules`](command:_github.copilot.openRelativePath?%5B%7B%22scheme%22%3A%22file%22%2C%22authority%22%3A%22%22%2C%22path%22%3A%22%2FUsers%2Fcristianvogel%2FDesktop%2FProgramming%2FSRVB-withCablesUI%2Fsrvb-fork%2F.gitmodules%22%2C%22query%22%3A%22%22%2C%22fragment%22%3A%22%22%7D%5D "/Users/cristianvogel/Desktop/Programming/SRVB-withCablesUI/srvb-fork/.gitmodules") file. This involves specifying the path and URL of the submodule. Here's how you can do it: + +1. Open the [`.gitmodules`](command:_github.copilot.openRelativePath?%5B%7B%22scheme%22%3A%22file%22%2C%22authority%22%3A%22%22%2C%22path%22%3A%22%2FUsers%2Fcristianvogel%2FDesktop%2FProgramming%2FSRVB-withCablesUI%2Fsrvb-fork%2F.gitmodules%22%2C%22query%22%3A%22%22%2C%22fragment%22%3A%22%22%7D%5D "/Users/cristianvogel/Desktop/Programming/SRVB-withCablesUI/srvb-fork/.gitmodules") file in your editor. +2. Add the following lines to register the 'native/choc' submodule: + +```properties +[submodule "choc"] + path = native/choc + url = +``` + +Replace `` with the actual URL of the 'choc' Git repository. + +3. Save the `.gitmodules` file. +4. Run the following commands in your terminal to synchronize your local configuration: + +```bash +git submodule init +git submodule update +``` + +This will initialize the new submodule and clone it into the specified path. + +cristianvogel: i am trying to remove this submodule referenence but it dosn't seem to de-install + +GitHub Copilot: To remove a submodule reference, such as `elementary` or `juce`, from your Git repository, you need to follow these steps. Let's use `elementary` as an example: + +1. **Delete the submodule entry from [`.gitmodules`](command:_github.copilot.openRelativePath?%5B%7B%22scheme%22%3A%22file%22%2C%22authority%22%3A%22%22%2C%22path%22%3A%22%2FUsers%2Fcristianvogel%2FDesktop%2FProgramming%2FSRVB-withCablesUI%2Fsrvb-fork%2F.gitmodules%22%2C%22query%22%3A%22%22%2C%22fragment%22%3A%22%22%7D%5D "/Users/cristianvogel/Desktop/Programming/SRVB-withCablesUI/srvb-fork/.gitmodules") file**: Open the [`.gitmodules`](command:_github.copilot.openRelativePath?%5B%7B%22scheme%22%3A%22file%22%2C%22authority%22%3A%22%22%2C%22path%22%3A%22%2FUsers%2Fcristianvogel%2FDesktop%2FProgramming%2FSRVB-withCablesUI%2Fsrvb-fork%2F.gitmodules%22%2C%22query%22%3A%22%22%2C%22fragment%22%3A%22%22%7D%5D "/Users/cristianvogel/Desktop/Programming/SRVB-withCablesUI/srvb-fork/.gitmodules") file and remove the section related to `elementary`. + + ```properties + [submodule "elementary"] + path = native/elementary + url = https://github.com/elemaudio/elementary.git + ``` + +2. **Stage the `.gitmodules` changes**: After editing the `.gitmodules` file, stage the changes for commit. + + ```bash + git add .gitmodules + ``` + +3. **Delete the submodule section from [`.git/config`](command:_github.copilot.openRelativePath?%5B%7B%22scheme%22%3A%22file%22%2C%22authority%22%3A%22%22%2C%22path%22%3A%22%2FUsers%2Fcristianvogel%2FDesktop%2FProgramming%2FSRVB-withCablesUI%2Fsrvb-fork%2F.git%2Fconfig%22%2C%22query%22%3A%22%22%2C%22fragment%22%3A%22%22%7D%5D "/Users/cristianvogel/Desktop/Programming/SRVB-withCablesUI/srvb-fork/.git/config")**: Open your [`.git/config`](command:_github.copilot.openRelativePath?%5B%7B%22scheme%22%3A%22file%22%2C%22authority%22%3A%22%22%2C%22path%22%3A%22%2FUsers%2Fcristianvogel%2FDesktop%2FProgramming%2FSRVB-withCablesUI%2Fsrvb-fork%2F.git%2Fconfig%22%2C%22query%22%3A%22%22%2C%22fragment%22%3A%22%22%7D%5D "/Users/cristianvogel/Desktop/Programming/SRVB-withCablesUI/srvb-fork/.git/config") file in a text editor and remove the submodule section related to `elementary`. + + ```ini + [submodule "elementary"] + url = https://github.com/elemaudio/elementary.git + ``` + +4. **Unstage and remove the submodule files**: Run the following commands to unstage the submodule path and then remove the submodule directory from your working directory. + + ```bash + git rm --cached native/elementary + rm -rf native/elementary + ``` + +5. **Remove the submodule's [`.git`](command:_github.copilot.openRelativePath?%5B%7B%22scheme%22%3A%22file%22%2C%22authority%22%3A%22%22%2C%22path%22%3A%22%2FUsers%2Fcristianvogel%2FDesktop%2FProgramming%2FSRVB-withCablesUI%2Fsrvb-fork%2F.git%22%2C%22query%22%3A%22%22%2C%22fragment%22%3A%22%22%7D%5D "/Users/cristianvogel/Desktop/Programming/SRVB-withCablesUI/srvb-fork/.git") directory**: Delete the [`.git`](command:_github.copilot.openRelativePath?%5B%7B%22scheme%22%3A%22file%22%2C%22authority%22%3A%22%22%2C%22path%22%3A%22%2FUsers%2Fcristianvogel%2FDesktop%2FProgramming%2FSRVB-withCablesUI%2Fsrvb-fork%2F.git%22%2C%22query%22%3A%22%22%2C%22fragment%22%3A%22%22%7D%5D "/Users/cristianvogel/Desktop/Programming/SRVB-withCablesUI/srvb-fork/.git") directory located in the submodule's directory. Since you've already removed the directory in the previous step, this is more of a general step if you need to manually remove any leftover [`.git`](command:_github.copilot.openRelativePath?%5B%7B%22scheme%22%3A%22file%22%2C%22authority%22%3A%22%22%2C%22path%22%3A%22%2FUsers%2Fcristianvogel%2FDesktop%2FProgramming%2FSRVB-withCablesUI%2Fsrvb-fork%2F.git%22%2C%22query%22%3A%22%22%2C%22fragment%22%3A%22%22%7D%5D "/Users/cristianvogel/Desktop/Programming/SRVB-withCablesUI/srvb-fork/.git") directories. + +6. **Commit your changes**: Commit the removal of the submodule. + + ```bash + git commit -m "Removed elementary submodule" + ``` + +7. **Delete the submodule's entry from the `.git/modules` directory**: Finally, remove the submodule's data from the `.git/modules` directory. + + ```bash + rm -rf .git/modules/native/elementary + ``` + +Repeat these steps for any other submodule you wish to remove, such as `juce`. Make sure to adjust the paths and names accordingly. + +cristianvogel: how do i specifiy a specific branch and commit for a submodule + +GitHub Copilot: To specify a specific branch and commit for a submodule in Git, follow these steps: + +1. **Navigate to the submodule directory**: First, change your current working directory to the submodule's directory. + + ```bash + cd path/to/submodule + ``` + + Replace `path/to/submodule` with the actual path to your submodule, such as `native/elementary`. + +2. **Checkout the specific branch**: Checkout the branch you want to track in the submodule. + + ```bash + git checkout branch-name + ``` + + Replace `branch-name` with the name of the branch you want to use. + +3. **Pull or reset to the specific commit**: If you want the latest commit from that branch, you can simply pull. However, if you need a specific commit, use `git reset` or `git checkout` to move to that commit. + + - To pull the latest changes (if you're tracking a branch): + + ```bash + git pull + ``` + + - To move to a specific commit: + + ```bash + git reset --hard commit-hash + ``` + + or + + ```bash + git checkout commit-hash + ``` + + Replace `commit-hash` with the hash of the commit you want to use. + +4. **Update the submodule reference in the main project**: After you have checked out the specific branch and commit in the submodule, navigate back to the root of your main project and stage the submodule changes. + + ```bash + cd ../.. + git add path/to/submodule + ``` + + This adds the new state of the submodule to your main project. + +5. **Commit the change**: Commit the update to the submodule reference in your main project. + + ```bash + git commit -m "Update submodule to specific branch and commit" + ``` + +6. **(Optional) Push the changes**: If you want these changes to be reflected in the remote repository, push them. + + ```bash + git push + ``` + +**Note**: If you want to ensure that the submodule is always checked out to a specific branch when others clone or pull from the main repository, you can add the `branch` option to the [`.gitmodules`](command:_github.copilot.openRelativePath?%5B%7B%22scheme%22%3A%22file%22%2C%22authority%22%3A%22%22%2C%22path%22%3A%22%2FUsers%2Fcristianvogel%2FDesktop%2FProgramming%2FSRVB-withCablesUI%2Fsrvb-fork%2F.gitmodules%22%2C%22query%22%3A%22%22%2C%22fragment%22%3A%22%22%7D%5D "/Users/cristianvogel/Desktop/Programming/SRVB-withCablesUI/srvb-fork/.gitmodules") file. This doesn't lock the submodule to a specific commit but ensures the specified branch is checked out. + +```properties +[submodule "submodule-name"] + path = path/to/submodule + url = https://example.com/submodule.git + branch = branch-name +``` + +Replace `submodule-name`, `path/to/submodule`, `https://example.com/submodule.git`, and `branch-name` with your submodule's name, path, URL, and branch name, respectively. After adding the branch to `.gitmodules`, remember to commit and push the `.gitmodules` file as well. \ No newline at end of file From d613ec113f2f8ea300fe9e4520a5cbeae9bc8f76 Mon Sep 17 00:00:00 2001 From: Cristian Vogel Date: Mon, 15 Jul 2024 19:13:23 +0200 Subject: [PATCH 09/13] added Cables patch --- .github/workflows/main.yml | 68 - index.html | 91 +- package.json | 1 + .../assets/65bbe44771656d76fa1e7e54_voro.png | Bin 0 -> 85230 bytes public/assets/ChivoMono-Medium-msdf.json | 1 + public/assets/ChivoMono-Medium.png | Bin 0 -> 65264 bytes public/assets/forkawesome-webfont.ttf | Bin 0 -> 188756 bytes .../lib_matcaps_Chrome_Blue_Tint-White.png | Bin 0 -> 81035 bytes src/cables-js/patch.js | 19212 ++++++++++++++++ src/cables-js/patch.js.map | 1 + 10 files changed, 19297 insertions(+), 77 deletions(-) delete mode 100644 .github/workflows/main.yml create mode 100644 public/assets/65bbe44771656d76fa1e7e54_voro.png create mode 100644 public/assets/ChivoMono-Medium-msdf.json create mode 100644 public/assets/ChivoMono-Medium.png create mode 100644 public/assets/forkawesome-webfont.ttf create mode 100644 public/assets/lib_matcaps_Chrome_Blue_Tint-White.png create mode 100644 src/cables-js/patch.js create mode 100644 src/cables-js/patch.js.map diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index bca7ce4..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,68 +0,0 @@ -# name: Build - -# on: -# workflow_dispatch: -# pull_request: -# push: -# branches: -# - '**' - -# jobs: -# native: -# strategy: -# fail-fast: false -# matrix: -# # Disabling the linux build for now -# # os: [ubuntu-latest, macos-latest, windows-latest] -# os: [macos-latest, windows-latest] -# runs-on: ${{ matrix.os }} -# steps: -# - uses: actions/checkout@v3 -# with: -# submodules: true - -# - uses: actions/setup-node@v3 -# with: -# node-version: 18 - -# - name: JUCE Linux Dependencies -# shell: bash -# if: ${{ matrix.os == 'ubuntu-latest' }} -# run: | -# sudo apt-get update -# sudo apt-get install -y freeglut3-dev -# sudo apt-get install -y g++ -# sudo apt-get install -y libasound2-dev -# sudo apt-get install -y libcurl4-openssl-dev -# sudo apt-get install -y libfreetype6-dev -# sudo apt-get install -y libjack-jackd2-dev -# sudo apt-get install -y libx11-dev -# sudo apt-get install -y libxcomposite-dev -# sudo apt-get install -y libxcursor-dev -# sudo apt-get install -y libxinerama-dev -# sudo apt-get install -y libxrandr-dev -# sudo apt-get install -y mesa-common-dev - -# - name: Build -# shell: bash -# run: | -# set -x -# set -e - -# npm install -# npm run build - -# - name: Artifact naming -# shell: bash -# run: | -# echo "ARTIFACT_DATESTRING=$(date +'%Y-%m-%d')" >> $GITHUB_ENV -# echo "ARTIFACT_OS=$(echo $RUNNER_OS | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV - -# - uses: actions/upload-artifact@v3 -# with: -# name: srvb-${{ env.ARTIFACT_OS }}-${{ env.ARTIFACT_DATESTRING }} -# path: | -# native/build/scripted/SRVB_artefacts/Release/VST3/ -# native/build/scripted/SRVB_artefacts/Release/AU/ -# !native/build/scripted/SRVB_artefacts/Release/VST3/*.lib -# !native/build/scripted/SRVB_artefacts/Release/VST3/*.exp diff --git a/index.html b/index.html index 6c396ed..483a97c 100644 --- a/index.html +++ b/index.html @@ -1,12 +1,85 @@ - - - - Elementary Effects Plugin - - -
- - + + Four GL Dials + + + + + + + + + + + + + + + + + + + diff --git a/package.json b/package.json index 0d3eed2..7520247 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "dev": "npm run dev-native && concurrently \"npm run dev-dsp\" \"vite\"", "dev-native": "zx scripts/build-native.mjs --dev", "dev-dsp": "esbuild dsp/main.js --watch --bundle --outfile=public/dsp.main.js", + "dev-ui": "vite", "build-native": "zx scripts/build-native.mjs", "build-dsp": "esbuild dsp/main.js --bundle --outfile=public/dsp.main.js", "build-ui": "vite build", diff --git a/public/assets/65bbe44771656d76fa1e7e54_voro.png b/public/assets/65bbe44771656d76fa1e7e54_voro.png new file mode 100644 index 0000000000000000000000000000000000000000..804cfe987069e49c0a881c3a04e97ec1f36f3b93 GIT binary patch literal 85230 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%0A(z$MqkF)S6n(qp@xOFPd5?P*& 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

PYY{WYzd#W>?eB62P}q} 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 UY-Mc+`xk6VXf=hR8~6PF2R3ca;{X5v literal 0 HcmV?d00001 diff --git a/public/assets/forkawesome-webfont.ttf b/public/assets/forkawesome-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6cf62efb89d1f27433c94d5540069a659c6af6e0 GIT binary patch literal 188756 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

io{Q%^r;{*=QF$i)wnWKXT!|hf0;|hnavZjUC;Y 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%0D<=Fd`oLbG;$obXcRe|7ySKx(oc{lA^!0^unw2 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

  • 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 literal 0 HcmV?d00001 diff --git a/public/assets/lib_matcaps_Chrome_Blue_Tint-White.png b/public/assets/lib_matcaps_Chrome_Blue_Tint-White.png new file mode 100644 index 0000000000000000000000000000000000000000..81e23e9b24418aa9835708905f0c1648e71876f3 GIT binary patch literal 81035 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%0Au|i5qV~!{;G92Q_zC2hzX^W-o37hG^zw(^ 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 literal 0 HcmV?d00001 diff --git a/src/cables-js/patch.js b/src/cables-js/patch.js new file mode 100644 index 0000000..598b070 --- /dev/null +++ b/src/cables-js/patch.js @@ -0,0 +1,19212 @@ +var CABLES; +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; + +// EXPORTS +__webpack_require__.d(__webpack_exports__, { + "default": () => (/* binding */ core) +}); + +// NAMESPACE OBJECT: ./src/core/base64.js +var base64_namespaceObject = {}; +__webpack_require__.r(base64_namespaceObject); +__webpack_require__.d(base64_namespaceObject, { + "b64decTypedArray": () => (b64decTypedArray), + "b64encTypesArray": () => (b64encTypesArray), + "base64Chars": () => (base64Chars), + "base64lookup": () => (base64lookup) +}); + +// NAMESPACE OBJECT: ./src/core/utils.js +var utils_namespaceObject = {}; +__webpack_require__.r(utils_namespaceObject); +__webpack_require__.d(utils_namespaceObject, { + "UTILS": () => (UTILS), + "ajax": () => (ajax), + "ajaxSync": () => (ajaxSync), + "basename": () => (basename), + "cacheBust": () => (cacheBust), + "clamp": () => (clamp), + "cleanJson": () => (cleanJson), + "copyArray": () => (copyArray), + "filename": () => (filename), + "generateUUID": () => (generateUUID), + "getShortOpName": () => (getShortOpName), + "keyCodeToName": () => (keyCodeToName), + "logStack": () => (logStack), + "map": () => (map), + "prefixedHash": () => (prefixedHash), + "request": () => (request), + "shortId": () => (shortId), + "shuffleArray": () => (shuffleArray), + "simpleId": () => (simpleId), + "smoothStep": () => (smoothStep), + "smootherStep": () => (smootherStep), + "uuid": () => (uuid) +}); + +// NAMESPACE OBJECT: ./src/core/anim.js +var anim_namespaceObject = {}; +__webpack_require__.r(anim_namespaceObject); +__webpack_require__.d(anim_namespaceObject, { + "ANIM": () => (ANIM), + "Anim": () => (Anim) +}); + +;// CONCATENATED MODULE: ./src/core/base64.js +const base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +// Use a lookup table to find the index. +const _base64lookup = new Uint8Array(256); +for (let i = 0; i < base64Chars.length; i++) _base64lookup[base64Chars.charCodeAt(i)] = i; + +const base64lookup = _base64lookup; + +const b64encTypesArray = function (arraybuffer) +{ + if (arraybuffer.buffer) arraybuffer = arraybuffer.buffer; + let bytes = new Uint8Array(arraybuffer), + i, + len = bytes.length, + base64 = ""; + + for (i = 0; i < len; i += 3) + { + base64 += base64Chars[bytes[i] >> 2]; + base64 += base64Chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; + base64 += base64Chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)]; + base64 += base64Chars[bytes[i + 2] & 63]; + } + + if (len % 3 === 2) base64 = base64.substring(0, base64.length - 1) + "="; + else if (len % 3 === 1) base64 = base64.substring(0, base64.length - 2) + "=="; + + return base64; +}; + +const b64decTypedArray = function (base64) +{ + let bufferLength = base64.length * 0.75, + len = base64.length, + i, + p = 0, + encoded1, + encoded2, + encoded3, + encoded4; + + if (base64[base64.length - 1] === "=") + { + bufferLength--; + if (base64[base64.length - 2] === "=") bufferLength--; + } + + let arraybuffer = new ArrayBuffer(bufferLength), + bytes = new Uint8Array(arraybuffer); + + for (i = 0; i < len; i += 4) + { + encoded1 = base64lookup[base64.charCodeAt(i)]; + encoded2 = base64lookup[base64.charCodeAt(i + 1)]; + encoded3 = base64lookup[base64.charCodeAt(i + 2)]; + encoded4 = base64lookup[base64.charCodeAt(i + 3)]; + + bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); + bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); + bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63); + } + + return arraybuffer; +}; + +;// CONCATENATED MODULE: ./src/core/constants.js +const CONSTANTS = { + "ANIM": { + "EASINGS": [ + "linear", + "absolute", + "smoothstep", + "smootherstep", + "Cubic In", + "Cubic Out", + "Cubic In Out", + "Expo In", + "Expo Out", + "Expo In Out", + "Sin In", + "Sin Out", + "Sin In Out", + "Quart In", + "Quart Out", + "Quart In Out", + "Quint In", + "Quint Out", + "Quint In Out", + "Back In", + "Back Out", + "Back In Out", + "Elastic In", + "Elastic Out", + "Bounce In", + "Bounce Out", + ], + "EASING_LINEAR": 0, + "EASING_ABSOLUTE": 1, + "EASING_SMOOTHSTEP": 2, + "EASING_SMOOTHERSTEP": 3, + "EASING_CUBICSPLINE": 4, + + "EASING_CUBIC_IN": 5, + "EASING_CUBIC_OUT": 6, + "EASING_CUBIC_INOUT": 7, + + "EASING_EXPO_IN": 8, + "EASING_EXPO_OUT": 9, + "EASING_EXPO_INOUT": 10, + + "EASING_SIN_IN": 11, + "EASING_SIN_OUT": 12, + "EASING_SIN_INOUT": 13, + + "EASING_BACK_IN": 14, + "EASING_BACK_OUT": 15, + "EASING_BACK_INOUT": 16, + + "EASING_ELASTIC_IN": 17, + "EASING_ELASTIC_OUT": 18, + + "EASING_BOUNCE_IN": 19, + "EASING_BOUNCE_OUT": 21, + + "EASING_QUART_IN": 22, + "EASING_QUART_OUT": 23, + "EASING_QUART_INOUT": 24, + + "EASING_QUINT_IN": 25, + "EASING_QUINT_OUT": 26, + "EASING_QUINT_INOUT": 27, + }, + + "OP": { + "OP_PORT_TYPE_VALUE": 0, + "OP_PORT_TYPE_NUMBER": 0, + "OP_PORT_TYPE_FUNCTION": 1, + "OP_PORT_TYPE_TRIGGER": 1, + "OP_PORT_TYPE_OBJECT": 2, + "OP_PORT_TYPE_TEXTURE": 2, + "OP_PORT_TYPE_ARRAY": 3, + "OP_PORT_TYPE_DYNAMIC": 4, + "OP_PORT_TYPE_STRING": 5, + + "OP_VERSION_PREFIX": "_v", + }, + + "PORT": { + "PORT_DIR_IN": 0, + "PORT_DIR_OUT": 1, + }, + + "PACO": { + "PACO_CLEAR": 0, + "PACO_VALUECHANGE": 1, + "PACO_OP_DELETE": 2, + "PACO_UNLINK": 3, + "PACO_LINK": 4, + "PACO_LOAD": 5, + "PACO_OP_CREATE": 6, + "PACO_OP_ENABLE": 7, + "PACO_OP_DISABLE": 8, + "PACO_UIATTRIBS": 9, + "PACO_VARIABLES": 10, + "PACO_TRIGGERS": 11, + "PACO_PORT_SETVARIABLE": 12, + "PACO_PORT_SETANIMATED": 13, + "PACO_PORT_ANIM_UPDATED": 14, + "PACO_DESERIALIZE": 15 + + }, +}; + +;// CONCATENATED MODULE: ./src/core/utils.js + +/** + * @external CABLES + * @namespace Utils + */ + + + +const UTILS = {}; +/** + * Merge two Float32Arrays. + * @function float32Concat + * @memberof Utils + * @param {Float32Array} first Left-hand side array + * @param {Float32Array} second Right-hand side array + * @return {Float32Array} + * @static + */ +UTILS.float32Concat = function (first, second) +{ + if (!(first instanceof Float32Array)) first = new Float32Array(first); + if (!(second instanceof Float32Array)) second = new Float32Array(second); + + const result = new Float32Array(first.length + second.length); + + result.set(first); + result.set(second, first.length); + + return result; +}; + +/** + * get op shortname: only last part of fullname and without version + * @function getShortOpName + * @memberof CABLES + * @param {String} full op name + * @static + */ +const getShortOpName = function (fullname) +{ + let name = fullname.split(".")[fullname.split(".").length - 1]; + + if (name.contains(CONSTANTS.OP.OP_VERSION_PREFIX)) + { + const n = name.split(CONSTANTS.OP.OP_VERSION_PREFIX)[1]; + name = name.substring(0, name.length - (CONSTANTS.OP.OP_VERSION_PREFIX + n).length); + } + return name; +}; + +/** + * randomize order of an array + * @function shuffleArray + * @memberof Utils + * @param {Array|Float32Array} array {Array} original + * @return {Array|Float32Array} shuffled array + * @static + */ +const shuffleArray = function (array) +{ + for (let i = array.length - 1; i > 0; i--) + { + const j = Math.floor(Math.seededRandom() * (i + 1)); + const temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + return array; +}; + + +/** + * generate a short "relativly unique" id + * @function shortId + * @memberof Utils + * @return {String} generated ID + * @static + */ + +const _shortIds = {}; +const _shortId = function () +{ + let str = Math.random().toString(36).substr(2, 9); + + if (_shortIds.hasOwnProperty(str)) str = _shortId(); + _shortIds[str] = true; + return str; +}; +const shortId = _shortId; + + +/** + * generate a UUID + * @function uuid + * @memberof Utils + * @return {String} generated UUID + * @static + */ +const _uuid = function () +{ + let d = new Date().getTime(); + const uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => + { + const r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c == "x" ? r : (r & 0x3) | 0x8).toString(16); + }); + return uuid; +}; +const uuid = _uuid; +const generateUUID = _uuid; + + + +function cleanJson(obj) +{ + for (const i in obj) + { + if (obj[i] && typeof objValue === "object" && obj[i].constructor === Object) obj[i] = cleanJson(obj[i]); + + if (obj[i] === null || obj[i] === undefined) delete obj[i]; + else if (Array.isArray(obj[i]) && obj[i].length == 0) delete obj[i]; + } + + return obj; +} + + +/** + * @see http://stackoverflow.com/q/7616461/940217 + * @return {string} + */ +const _prefixedHash = function (str, prefix = "id") +{ + let hash = 0; + if (Array.prototype.reduce) + { + hash = str.split("").reduce((a, b) => { a = ((a << 5) - a) + b.charCodeAt(0); return a & a; }, 0); + } + else + { + if (str.length > 0) + { + for (let i = 0; i < str.length; i++) + { + let character = str.charCodeAt(i); + hash = ((hash << 5) - hash) + character; + hash &= hash; // Convert to 32bit integer + } + } + } + return prefix + "" + hash; +}; +const prefixedHash = _prefixedHash; + +/** + * generate a simple ID + * @function simpleId + * @memberof Utils + * @return {Number} new id + * @static + */ +let simpleIdCounter = 0; +const simpleId = function () +{ + simpleIdCounter++; + return simpleIdCounter; +}; + +/** + * smoothStep a value + * @function smoothStep + * @memberof Utils + * @function + * @param {Number} value value to be smoothed [0-1] + * @return {Number} smoothed value + * @static + */ +const smoothStep = function (perc) +{ + const x = Math.max(0, Math.min(1, (perc - 0) / (1 - 0))); + perc = x * x * (3 - 2 * x); // smoothstep + return perc; +}; + +/** + * smootherstep a value + * @function smootherStep + * @memberof Utils + * @param value {Number} value to be smoothed [0-1] + * @return {Number} smoothed value + * @static + */ +const smootherStep = function (perc) +{ + const x = Math.max(0, Math.min(1, (perc - 0) / (1 - 0))); + perc = x * x * x * (x * (x * 6 - 15) + 10); // smootherstep + return perc; +}; + + +/** + * clamp number / make sure its between min/max + * @function clamp + * @memberof Utils + * @param {Number} value value to be mapped + * @param {Number} min minimum value + * @param {Number} max maximum value + * @static + */ +const clamp = function (value, min, max) +{ + return Math.min(Math.max(value, min), max); +}; + +/** + * map a value in a range to a value in another range + * @function map + * @memberof Utils + * @param {Number} value value to be mapped + * @param {Number} oldMin old range minimum value + * @param {Number} oldMax old range maximum value + * @param {Number} newMin new range minimum value + * @param {Number} newMax new range maximum value + * @return {Number} mapped value + * @static + */ +const map = function (x, _oldMin, _oldMax, _newMin, _newMax, _easing) +{ + if (x >= _oldMax) return _newMax; + if (x <= _oldMin) return _newMin; + + let reverseInput = false; + const oldMin = Math.min(_oldMin, _oldMax); + const oldMax = Math.max(_oldMin, _oldMax); + if (oldMin != _oldMin) reverseInput = true; + + let reverseOutput = false; + const newMin = Math.min(_newMin, _newMax); + const newMax = Math.max(_newMin, _newMax); + if (newMin != _newMin) reverseOutput = true; + + let portion = 0; + let r = 0; + + if (reverseInput) portion = ((oldMax - x) * (newMax - newMin)) / (oldMax - oldMin); + else portion = ((x - oldMin) * (newMax - newMin)) / (oldMax - oldMin); + + if (reverseOutput) r = newMax - portion; + else r = portion + newMin; + + if (!_easing) return r; + if (_easing == 1) + { + // smoothstep + x = Math.max(0, Math.min(1, (r - _newMin) / (_newMax - _newMin))); + return _newMin + x * x * (3 - 2 * x) * (_newMax - _newMin); + } + if (_easing == 2) + { + // smootherstep + x = Math.max(0, Math.min(1, (r - _newMin) / (_newMax - _newMin))); + return _newMin + x * x * x * (x * (x * 6 - 15) + 10) * (_newMax - _newMin); + } + + return r; +}; + +/** + * @namespace Math + */ +/** + * set random seed for seededRandom() + * @memberof Math + * @type Number + * @static + */ +Math.randomSeed = 1; + + +Math.setRandomSeed = function (seed) +{ + // https://github.com/cables-gl/cables_docs/issues/622 + Math.randomSeed = seed * 50728129; + if (seed != 0) + { + Math.randomSeed = Math.seededRandom() * 17624813; + Math.randomSeed = Math.seededRandom() * 9737333; + } +}; + + +/** + * generate a seeded random number + * @function seededRandom + * @memberof Math + * @param {Number} max minimum possible random number + * @param {Number} min maximum possible random number + * @return {Number} random value + * @static + */ +Math.seededRandom = function (max, min) +{ + if (Math.randomSeed === 0) Math.randomSeed = Math.random() * 999; + max = max || 1; + min = min || 0; + + Math.randomSeed = (Math.randomSeed * 9301 + 49297) % 233280; + const rnd = Math.randomSeed / 233280.0; + + return min + rnd * (max - min); +}; + + +// ---------------------------------------------------------------- + +/** + * returns true if parameter is a number + * @function isNumeric + * @memberof Utils + * @param {Any} value The value to check. + * @return {Boolean} + * @static + */ +UTILS.isNumeric = function (n) +{ + return !isNaN(parseFloat(n)) && isFinite(n); +}; + +/** + * returns true if parameter is array + * @function isArray + * @param {Any} value Value to check + * @memberof Utils + * @return {Boolean} + * @static + */ +UTILS.isArray = function (v) +{ + return Object.prototype.toString.call(v) === "[object Array]"; +}; + +/** + * @namespace String + */ + +/** + * append a linebreak to a string + * @function endl + * @memberof String + * @return {String} string with newline break appended ('\n') + */ +String.prototype.endl = function () +{ + return this + "\n"; +}; + +/** + * return true if string starts with prefix + * @function startsWith + * @memberof String + * @param {String} prefix The prefix to check. + * @return {Boolean} + */ +String.prototype.startsWith = function (prefix) +{ + return this.indexOf(prefix) === 0; +}; + +/** + * return true if string ends with suffix + * @function endsWith + * @memberof String + * @param {String} suffix + * @return {Boolean} + */ +String.prototype.endsWith = String.prototype.endsWith || function (suffix) +{ + return this.match(suffix + "$") == suffix; +}; + +/** + * return true if string contains string + * @function contains + * @memberof String + * @param {String} searchStr + * @return {Boolean} + */ +String.prototype.contains = String.prototype.contains || function (searchStr) +{ + return this.indexOf(searchStr) > -1; +}; + + + +// ---------------------------------------------------------------- + +/** + * append a unique/random parameter to a url, so the browser is forced to reload the file, even if its cached + * @function cacheBust + * @static + * @memberof Utils + * @param {String} url The url to append the cachebuster parameter to. + * @return {String} url with cachebuster parameter + */ +const cacheBust = function (url) +{ + if (url.contains("?")) url += "&"; + else url += "?"; + return url + "cache=" + CABLES.uuid(); +}; + +/** + * copy the content of an array + * @function copyArray + * @static + * @memberof Utils + * @param {Array} sourceArray + * @param {Array} dst optional + * @return {Array} dst + */ +const copyArray = function (src, dst) +{ + if (!src) return null; + dst = dst || []; + dst.length = src.length; + for (let i = 0; i < src.length; i++) + { + dst[i] = src[i]; + } + + return dst; +}; + + +/** + * return the filename part of a url without extension + * @function basename + * @static + * @memberof Utils + * @param {String} url + * @return {String} just the filename + */ +const basename = function (url) +{ + let name = CABLES.filename(url); + + const parts2 = name.split("."); + name = parts2[0]; + + return name; +}; + +/** + * output a stacktrace to the console + * @function logStack + * @static + * @memberof Utils + */ +const logStack = function () +{ + console.log("logstack", (new Error()).stack); +}; + +/** + * return the filename part of a url + * @function filename + * @static + * @memberof Utils + * @param {String} url + * @return {String} just the filename + */ +const filename = function (url) +{ + let name = ""; + if (!url) return ""; + + if (url.startsWith("data:") && url.contains(":")) + { + const parts = url.split(","); + return parts[0]; + } + + const parts = (url + "").split("/"); + if (parts.length > 0) + { + const str = parts[parts.length - 1]; + let parts2 = str.split("?"); + name = parts2[0]; + } + + return name || ""; +}; + + +const ajaxSync = function (url, cb, method, post, contenttype) +{ + request({ + "url": url, + "cb": cb, + "method": method, + "data": post, + "contenttype": contenttype, + "sync": true, + }); +}; + +/** + * make an ajax request + * @function ajax + * @static + */ +const ajax = function (url, cb, method, post, contenttype, jsonP, headers = {}, options = {}) +{ + const requestOptions = { + "url": url, + "cb": cb, + "method": method, + "data": post, + "contenttype": contenttype, + "sync": false, + "jsonP": jsonP, + "headers": headers, + }; + if (options && options.credentials) requestOptions.credentials = options.credentials; + request(requestOptions); +}; + +const request = function (options) +{ + if (!options.hasOwnProperty("asynch")) options.asynch = true; + + let xhr; + try + { + xhr = new XMLHttpRequest(); + } + catch (e) {} + + xhr.onreadystatechange = function () + { + if (xhr.readyState != 4) return; + + if (options.cb) + { + if (xhr.status == 200 || xhr.status == 0) options.cb(false, xhr.responseText, xhr); + else options.cb(true, xhr.responseText, xhr); + } + }; + + try + { + xhr.open(options.method ? options.method.toUpperCase() : "GET", options.url, !options.sync); + } + catch (e) + { + if (options.cb && e) options.cb(true, e.msg, xhr); + } + + if (typeof options.headers === "object") + { + const keys = Object.keys(options.headers); + for (let i = 0; i < keys.length; i++) + { + const name = keys[i]; + const value = options.headers[name]; + xhr.setRequestHeader(name, value); + } + } + + if (options.credentials && options.credentials !== "omit") + { + xhr.withCredentials = true; + } + + try + { + if (!options.post && !options.data) + { + xhr.send(); + } + else + { + xhr.setRequestHeader( + "Content-type", + options.contenttype ? options.contenttype : "application/x-www-form-urlencoded", + ); + xhr.send(options.data || options.post); + } + } + catch (e) + { + if (options.cb) options.cb(true, e.msg, xhr); + } +}; + + +const keyCodeToName = function (keyCode) +{ + if (!keyCode && keyCode !== 0) return "Unidentified"; + const keys = { + "8": "Backspace", + "9": "Tab", + "12": "Clear", + "13": "Enter", + "16": "Shift", + "17": "Control", + "18": "Alt", + "19": "Pause", + "20": "CapsLock", + "27": "Escape", + "32": "Space", + "33": "PageUp", + "34": "PageDown", + "35": "End", + "36": "Home", + "37": "ArrowLeft", + "38": "ArrowUp", + "39": "ArrowRight", + "40": "ArrowDown", + "45": "Insert", + "46": "Delete", + "112": "F1", + "113": "F2", + "114": "F3", + "115": "F4", + "116": "F5", + "117": "F6", + "118": "F7", + "119": "F8", + "120": "F9", + "121": "F10", + "122": "F11", + "123": "F12", + "144": "NumLock", + "145": "ScrollLock", + "224": "Meta" + }; + if (keys[keyCode]) + { + return keys[keyCode]; + } + else + { + return String.fromCharCode(keyCode); + } +}; +// ---------------------------------------------------------------- + +window.performance = window.performance || { + "offset": Date.now(), + "now": function now() + { + return Date.now() - this.offset; + }, +}; + + + +;// CONCATENATED MODULE: ../shared/client/src/logger.js +/* eslint-disable no-console */ + +class Logger +{ + constructor(initiator) + { + this._logs = []; + this.initiator = initiator; + } + + stack(t) + { + console.info("[" + this.initiator + "] ", t); + console.log((new Error()).stack); + } + + groupCollapsed(t) + { + console.groupCollapsed("[" + this.initiator + "] " + t); + } + + table(t) + { + console.table(t); + } + + groupEnd() + { + console.groupEnd(); + } + + error(args) + { + console.error("[" + this.initiator + "]", ...arguments); + if (window.gui) window.gui.emitEvent("coreLogEvent", this.initiator, "error", arguments); + } + + info(args) + { + console.error("[" + this.initiator + "]", ...arguments); + if (window.gui) window.gui.emitEvent("coreLogEvent", this.initiator, "info", arguments); + } + + warn(args) + { + console.warn("[" + this.initiator + "]", ...arguments); + // console.log((new Error()).stack); + if (window.gui) window.gui.emitEvent("coreLogEvent", this.initiator, "warn", arguments); + } + + verbose() + { + if ((CABLES.UI && CABLES.UI.logFilter.shouldPrint(this.initiator, ...arguments)) || !CABLES.logSilent) + console.log("[" + this.initiator + "]", ...arguments); + if (window.gui) window.gui.emitEvent("coreLogEvent", this.initiator, "verbose", arguments); + } + + log(args) + { + if ((CABLES.UI && CABLES.UI.logFilter.shouldPrint(this.initiator, ...arguments)) || !CABLES.logSilent) + console.log("[" + this.initiator + "]", ...arguments); + if (window.gui) window.gui.emitEvent("coreLogEvent", this.initiator, "log", arguments); + } + + userInteraction(text) + { + // this.log({ "initiator": "userinteraction", "text": text }); + } +} + +;// CONCATENATED MODULE: ./src/core/anim_key.js + + +const Key = function (obj) +{ + this.time = 0.0; + this.value = 0.0; + // this.ui = null; + this.onChange = null; + this._easing = 0; + // this.bezTangIn = 0; + // this.bezTangOut = 0; + // this.bezTime = 0.5; + // this.bezValue = 0; + // this.bezTimeIn = -0.5; + // this.bezValueIn = 0; + + this.cb = null; + this.cbTriggered = false; + + // const bezierAnim = null; + // this._updateBezier = false; + + this.setEasing(CONSTANTS.ANIM.EASING_LINEAR); + this.set(obj); +}; + +Key.cubicSpline = function (perc, key1, key2) +{ + let + previousPoint = key1.value, + previousTangent = key1.bezTangOut, + nextPoint = key2.value, + nextTangent = key2.bezTangIn; + let t = perc; + let t2 = t * t; + let t3 = t2 * t; + + return (2 * t3 - 3 * t2 + 1) * previousPoint + (t3 - 2 * t2 + t) * previousTangent + (-2 * t3 + 3 * t2) * nextPoint + (t3 - t2) * nextTangent; +}; + +Key.easeCubicSpline = function (perc, key2) +{ + return Key.cubicSpline(perc, this, key2); +}; + + +Key.linear = function (perc, key1, key2) +{ + return parseFloat(key1.value) + parseFloat(key2.value - key1.value) * perc; +}; + +Key.easeLinear = function (perc, key2) +{ + return Key.linear(perc, this, key2); +}; + +Key.easeAbsolute = function (perc, key2) +{ + return this.value; +}; + +const easeExpoIn = function (t) +{ + return (t = 2 ** (10 * (t - 1))); +}; + +Key.easeExpoIn = function (t, key2) +{ + t = easeExpoIn(t); + return Key.linear(t, this, key2); +}; + +const easeExpoOut = function (t) +{ + t = -(2 ** (-10 * t)) + 1; + return t; +}; + +Key.easeExpoOut = function (t, key2) +{ + t = easeExpoOut(t); + return Key.linear(t, this, key2); +}; + +const easeExpoInOut = function (t) +{ + t *= 2; + if (t < 1) + { + t = 0.5 * 2 ** (10 * (t - 1)); + } + else + { + t--; + t = 0.5 * (-(2 ** (-10 * t)) + 2); + } + return t; +}; + +Key.easeExpoInOut = function (t, key2) +{ + t = easeExpoInOut(t); + return Key.linear(t, this, key2); +}; + +Key.easeSinIn = function (t, key2) +{ + t = -1 * Math.cos((t * Math.PI) / 2) + 1; + return Key.linear(t, this, key2); +}; + +Key.easeSinOut = function (t, key2) +{ + t = Math.sin((t * Math.PI) / 2); + return Key.linear(t, this, key2); +}; + +Key.easeSinInOut = function (t, key2) +{ + t = -0.5 * (Math.cos(Math.PI * t) - 1.0); + return Key.linear(t, this, key2); +}; + +const easeCubicIn = function (t) +{ + t = t * t * t; + return t; +}; + +Key.easeCubicIn = function (t, key2) +{ + t = easeCubicIn(t); + return Key.linear(t, this, key2); +}; + + +// b 0 +// c 1/2 or 1 +// d always 1 +// easeOutCubic: function (x, t, b, c, d) { +// return c*((t=t/d-1)*t*t + 1) + b; + +Key.easeInQuint = function (t, key2) +{ + t = t * t * t * t * t; + return Key.linear(t, this, key2); +}; +Key.easeOutQuint = function (t, key2) +{ + t = (t -= 1) * t * t * t * t + 1; + return Key.linear(t, this, key2); +}; +Key.easeInOutQuint = function (t, key2) +{ + if ((t /= 0.5) < 1) t = 0.5 * t * t * t * t * t; + else t = 0.5 * ((t -= 2) * t * t * t * t + 2); + return Key.linear(t, this, key2); +}; + +Key.easeInQuart = function (t, key2) +{ + t = t * t * t * t; + return Key.linear(t, this, key2); +}; + +Key.easeOutQuart = function (t, key2) +{ + // return -c * ((t=t/d-1)*t*t*t - 1) + b; + t = -1 * ((t -= 1) * t * t * t - 1); + return Key.linear(t, this, key2); +}; + +Key.easeInOutQuart = function (t, key2) +{ + if ((t /= 0.5) < 1) t = 0.5 * t * t * t * t; + else t = -0.5 * ((t -= 2) * t * t * t - 2); + return Key.linear(t, this, key2); +}; + +Key.bounce = function (t) +{ + if ((t /= 1) < 1 / 2.75) t = 7.5625 * t * t; + else if (t < 2 / 2.75) t = 7.5625 * (t -= 1.5 / 2.75) * t + 0.75; + else if (t < 2.5 / 2.75) t = 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375; + else t = 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375; + return t; +}; + +Key.easeInBounce = function (t, key2) +{ + return Key.linear(Key.bounce(t), this, key2); + // return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d); +}; + +Key.easeOutBounce = function (t, key2) +{ + return Key.linear(Key.bounce(t), this, key2); +}; + +Key.easeInElastic = function (t, key2) +{ + let s = 1.70158; + let p = 0; + let a = 1; + + const b = 0; + const d = 1; + const c = 1; + + if (t === 0) t = b; + else if ((t /= d) == 1) t = b + c; + else + { + if (!p) p = d * 0.3; + if (a < Math.abs(c)) + { + a = c; + s = p / 4; + } + else s = (p / (2 * Math.PI)) * Math.asin(c / a); + t = -(a * 2 ** (10 * (t -= 1)) * Math.sin(((t * d - s) * (2 * Math.PI)) / p)) + b; + } + + return Key.linear(t, this, key2); +}; + + +Key.easeOutElastic = function (t, key2) +{ + let s = 1.70158; + let p = 0; + let a = 1; + + const b = 0; + const d = 1; + const c = 1; + + if (t === 0) t = b; + else if ((t /= d) == 1) t = b + c; + else + { + if (!p) p = d * 0.3; + if (a < Math.abs(c)) + { + a = c; + s = p / 4; + } + else s = (p / (2 * Math.PI)) * Math.asin(c / a); + t = a * 2 ** (-10 * t) * Math.sin(((t * d - s) * (2 * Math.PI)) / p) + c + b; + } + + return Key.linear(t, this, key2); +}; + +Key.easeInBack = function (t, key2) +{ + const s = 1.70158; + t = t * t * ((s + 1) * t - s); + + return Key.linear(t, this, key2); +}; + +Key.easeOutBack = function (t, key2) +{ + const s = 1.70158; + t = (t = t / 1 - 1) * t * ((s + 1) * t + s) + 1; + + return Key.linear(t, this, key2); +}; + +Key.easeInOutBack = function (t, key2) +{ + let s = 1.70158; + const c = 1 / 2; + if ((t /= 1 / 2) < 1) t = c * (t * t * (((s *= 1.525) + 1) * t - s)); + else t = c * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2); + + return Key.linear(t, this, key2); +}; + +const easeCubicOut = function (t) +{ + t--; + t = t * t * t + 1; + return t; +}; + +Key.easeCubicOut = function (t, key2) +{ + t = easeCubicOut(t); + return Key.linear(t, this, key2); +}; + +const easeCubicInOut = function (t) +{ + t *= 2; + if (t < 1) t = 0.5 * t * t * t; + else + { + t -= 2; + t = 0.5 * (t * t * t + 2); + } + return t; +}; + +Key.easeCubicInOut = function (t, key2) +{ + t = easeCubicInOut(t); + return Key.linear(t, this, key2); +}; + +Key.easeSmoothStep = function (perc, key2) +{ + // var x = Math.max(0, Math.min(1, (perc-0)/(1-0))); + const x = Math.max(0, Math.min(1, perc)); + perc = x * x * (3 - 2 * x); // smoothstep + return Key.linear(perc, this, key2); +}; + +Key.easeSmootherStep = function (perc, key2) +{ + const x = Math.max(0, Math.min(1, (perc - 0) / (1 - 0))); + perc = x * x * x * (x * (x * 6 - 15) + 10); // smootherstep + return Key.linear(perc, this, key2); +}; + +Key.prototype.setEasing = function (e) +{ + this._easing = e; + + if (this._easing == CONSTANTS.ANIM.EASING_LINEAR) this.ease = Key.easeLinear; + else if (this._easing == CONSTANTS.ANIM.EASING_ABSOLUTE) this.ease = Key.easeAbsolute; + else if (this._easing == CONSTANTS.ANIM.EASING_SMOOTHSTEP) this.ease = Key.easeSmoothStep; + else if (this._easing == CONSTANTS.ANIM.EASING_SMOOTHERSTEP) this.ease = Key.easeSmootherStep; + else if (this._easing == CONSTANTS.ANIM.EASING_CUBIC_IN) this.ease = Key.easeCubicIn; + else if (this._easing == CONSTANTS.ANIM.EASING_CUBIC_OUT) this.ease = Key.easeCubicOut; + else if (this._easing == CONSTANTS.ANIM.EASING_CUBIC_INOUT) this.ease = Key.easeCubicInOut; + else if (this._easing == CONSTANTS.ANIM.EASING_EXPO_IN) this.ease = Key.easeExpoIn; + else if (this._easing == CONSTANTS.ANIM.EASING_EXPO_OUT) this.ease = Key.easeExpoOut; + else if (this._easing == CONSTANTS.ANIM.EASING_EXPO_INOUT) this.ease = Key.easeExpoInOut; + else if (this._easing == CONSTANTS.ANIM.EASING_SIN_IN) this.ease = Key.easeSinIn; + else if (this._easing == CONSTANTS.ANIM.EASING_SIN_OUT) this.ease = Key.easeSinOut; + else if (this._easing == CONSTANTS.ANIM.EASING_SIN_INOUT) this.ease = Key.easeSinInOut; + else if (this._easing == CONSTANTS.ANIM.EASING_BACK_OUT) this.ease = Key.easeOutBack; + else if (this._easing == CONSTANTS.ANIM.EASING_BACK_IN) this.ease = Key.easeInBack; + else if (this._easing == CONSTANTS.ANIM.EASING_BACK_INOUT) this.ease = Key.easeInOutBack; + else if (this._easing == CONSTANTS.ANIM.EASING_ELASTIC_IN) this.ease = Key.easeInElastic; + else if (this._easing == CONSTANTS.ANIM.EASING_ELASTIC_OUT) this.ease = Key.easeOutElastic; + else if (this._easing == CONSTANTS.ANIM.EASING_ELASTIC_INOUT) this.ease = Key.easeElasticInOut; + else if (this._easing == CONSTANTS.ANIM.EASING_BOUNCE_IN) this.ease = Key.easeInBounce; + else if (this._easing == CONSTANTS.ANIM.EASING_BOUNCE_OUT) this.ease = Key.easeOutBounce; + else if (this._easing == CONSTANTS.ANIM.EASING_QUART_OUT) this.ease = Key.easeOutQuart; + else if (this._easing == CONSTANTS.ANIM.EASING_QUART_IN) this.ease = Key.easeInQuart; + else if (this._easing == CONSTANTS.ANIM.EASING_QUART_INOUT) this.ease = Key.easeInOutQuart; + else if (this._easing == CONSTANTS.ANIM.EASING_QUINT_OUT) this.ease = Key.easeOutQuint; + else if (this._easing == CONSTANTS.ANIM.EASING_QUINT_IN) this.ease = Key.easeInQuint; + else if (this._easing == CONSTANTS.ANIM.EASING_QUINT_INOUT) this.ease = Key.easeInOutQuint; + else if (this._easing == CONSTANTS.ANIM.EASING_CUBICSPLINE) + { + // this._updateBezier = true; + this.ease = Key.easeCubicSpline; + } + else + { + this._easing = CONSTANTS.ANIM.EASING_LINEAR; + this.ease = Key.easeLinear; + } +}; + +Key.prototype.trigger = function () +{ + this.cb(); + this.cbTriggered = true; +}; + +Key.prototype.setValue = function (v) +{ + this.value = v; + // this._updateBezier = true; + if (this.onChange !== null) this.onChange(); +}; + +Key.prototype.set = function (obj) +{ + if (obj) + { + if (obj.e) this.setEasing(obj.e); + if (obj.cb) + { + this.cb = obj.cb; + this.cbTriggered = false; + } + + if (obj.b) + { + // this.bezTime = obj.b[0]; + // this.bezValue = obj.b[1]; + // this.bezTimeIn = obj.b[2]; + // this.bezValueIn = obj.b[3]; + // this._updateBezier = true; + } + + if (obj.hasOwnProperty("t")) this.time = obj.t; + if (obj.hasOwnProperty("time")) this.time = obj.time; + if (obj.hasOwnProperty("v")) this.value = obj.v; + else if (obj.hasOwnProperty("value")) this.value = obj.value; + } + if (this.onChange !== null) this.onChange(); +}; + +Key.prototype.getSerialized = function () +{ + const obj = {}; + obj.t = this.time; + obj.v = this.value; + obj.e = this._easing; + // if (this._easing == CONSTANTS.ANIM.EASING_CUBICSPLINE) obj.b = [this.bezTime, this.bezValue, this.bezTimeIn, this.bezValueIn]; + + return obj; +}; + +Key.prototype.getEasing = function () +{ + return this._easing; +}; + + + +;// CONCATENATED MODULE: ./src/core/eventtarget.js + + +const EventTarget = function () +{ + this._log = new Logger("eventtarget"); + this._eventCallbacks = {}; + this._logName = ""; + this._logEvents = false; + this._listeners = {}; + + this.addEventListener = this.on = function (which, cb, idPrefix) + { + const event = + { + "id": (idPrefix || "") + CABLES.simpleId(), + "name": which, + "cb": cb, + }; + if (!this._eventCallbacks[which]) this._eventCallbacks[which] = [event]; + else this._eventCallbacks[which].push(event); + + this._listeners[event.id] = event; + + return event.id; + }; + + this.hasEventListener = function (which, cb) + { + if (which && !cb) + { + // check by id + if (this._listeners[which]) return true; + else return false; + } + else + { + this._log.warn("old eventtarget function haseventlistener!"); + if (which && cb) + { + if (this._eventCallbacks[which]) + { + const idx = this._eventCallbacks[which].indexOf(cb); + if (idx == -1) return false; + return true; + } + } + } + }; + + this.hasListenerForEventName = function (eventName) + { + return this._eventCallbacks[eventName] && this._eventCallbacks[eventName].length > 0; + }; + + this.removeEventListener = this.off = function (which, cb) + { + if (which === null || which === undefined) return; + + if (!cb) // new style, remove by id, not by name/callback + { + const event = this._listeners[which]; + if (!event) + { + this._log.log("could not find event..."); + return; + } + + let found = true; + while (found) + { + found = false; + let index = -1; + for (let i = 0; i < this._eventCallbacks[event.name].length; i++) + { + if (this._eventCallbacks[event.name][i].id.startsWith(which)) // this._eventCallbacks[event.name][i].id == which || + { + found = true; + index = i; + } + } + + if (index !== -1) + { + this._eventCallbacks[event.name].splice(index, 1); + delete this._listeners[which]; + } + } + + return; + } + + this._log.info("[eventtaget] ", "old function signature: removeEventListener! use listener id"); + this._log.log((new Error()).stack); + + let index = null; + for (let i = 0; i < this._eventCallbacks[which].length; i++) + if (this._eventCallbacks[which][i].cb == cb) + index = i; + + if (index !== null) + { + delete this._eventCallbacks[index]; + } + else this._log.warn("removeEventListener not found " + which); + }; + + this.logEvents = function (enabled, name) + { + this._logEvents = enabled; + this._logName = name; + }; + + this.emitEvent = function (which, param1, param2, param3, param4, param5, param6) + { + if (this._logEvents) this._log.log("[event] ", this._logName, which, this._eventCallbacks); + + if (this._eventCallbacks[which]) + { + for (let i = 0; i < this._eventCallbacks[which].length; i++) + { + if (this._eventCallbacks[which][i]) + { + this._eventCallbacks[which][i].cb(param1, param2, param3, param4, param5, param6); + } + } + } + else + { + if (this._logEvents) this._log.log("[event] has no event callback", which, this._eventCallbacks); + } + }; +}; + + + +;// CONCATENATED MODULE: ./src/core/anim.js + + + + + +/** + * Keyframed interpolated animation. + * + * Available Easings: + *
    + * CONSTANTS.ANIM.EASING_LINEAR
    + * CONSTANTS.ANIM.EASING_ABSOLUTE
    + * CONSTANTS.ANIM.EASING_SMOOTHSTEP
    + * CONSTANTS.ANIM.EASING_SMOOTHERSTEP
    + * CONSTANTS.ANIM.EASING_CUBICSPLINE
    +
    + * CONSTANTS.ANIM.EASING_CUBIC_IN
    + * CONSTANTS.ANIM.EASING_CUBIC_OUT
    + * CONSTANTS.ANIM.EASING_CUBIC_INOUT
    +
    + * CONSTANTS.ANIM.EASING_EXPO_IN
    + * CONSTANTS.ANIM.EASING_EXPO_OUT
    + * CONSTANTS.ANIM.EASING_EXPO_INOUT
    +
    + * CONSTANTS.ANIM.EASING_SIN_IN
    + * CONSTANTS.ANIM.EASING_SIN_OUT
    + * CONSTANTS.ANIM.EASING_SIN_INOUT
    +
    + * CONSTANTS.ANIM.EASING_BACK_IN
    + * CONSTANTS.ANIM.EASING_BACK_OUT
    + * CONSTANTS.ANIM.EASING_BACK_INOUT
    +
    + * CONSTANTS.ANIM.EASING_ELASTIC_IN
    + * CONSTANTS.ANIM.EASING_ELASTIC_OUT
    +
    + * CONSTANTS.ANIM.EASING_BOUNCE_IN
    + * CONSTANTS.ANIM.EASING_BOUNCE_OUT
    +
    + * CONSTANTS.ANIM.EASING_QUART_IN
    + * CONSTANTS.ANIM.EASING_QUART_OUT
    + * CONSTANTS.ANIM.EASING_QUART_INOUT
    +
    + * CONSTANTS.ANIM.EASING_QUINT_IN
    + * CONSTANTS.ANIM.EASING_QUINT_OUT
    + * CONSTANTS.ANIM.EASING_QUINT_INOUT
    + * 
    + * @hideconstructor + * @external CABLES + * @namespace Anim + * @class + * @example + * var anim=new CABLES.Anim(); + * anim.setValue(0,0); // set value 0 at 0 seconds + * anim.setValue(10,1); // set value 1 at 10 seconds + * anim.getValue(5); // get value at 5 seconds - this returns 0.5 + */ + +const Anim = function (cfg) +{ + EventTarget.apply(this); + + cfg = cfg || {}; + this.keys = []; + this.onChange = null; + this.stayInTimeline = false; + this.loop = false; + this._log = new Logger("Anim"); + this._lastKeyIndex = 0; + this._cachedIndex = 0; + this.name = cfg.name || null; + + /** + * @member defaultEasing + * @memberof Anim + * @instance + * @type {Number} + */ + this.defaultEasing = cfg.defaultEasing || CONSTANTS.ANIM.EASING_LINEAR; + this.onLooped = null; + + this._timesLooped = 0; + this._needsSort = false; +}; + +Anim.prototype.forceChangeCallback = function () +{ + if (this.onChange !== null) this.onChange(); + this.emitEvent("onChange", this); +}; + +Anim.prototype.getLoop = function () +{ + return this.loop; +}; + +Anim.prototype.setLoop = function (target) +{ + this.loop = target; + this.emitEvent("onChange", this); +}; + +/** + * returns true if animation has ended at @time + * checks if last key time is < time + * @param {Number} time + * @returns {Boolean} + * @memberof Anim + * @instance + * @function + */ +Anim.prototype.hasEnded = function (time) +{ + if (this.keys.length === 0) return true; + if (this.keys[this._lastKeyIndex].time <= time) return true; + return false; +}; + +Anim.prototype.isRising = function (time) +{ + if (this.hasEnded(time)) return false; + const ki = this.getKeyIndex(time); + if (this.keys[ki].value < this.keys[ki + 1].value) return true; + return false; +}; + +/** + * remove all keys from animation before time + * @param {Number} time + * @memberof Anim + * @instance + * @function + */ +Anim.prototype.clearBefore = function (time) +{ + const v = this.getValue(time); + const ki = this.getKeyIndex(time); + + this.setValue(time, v); + + if (ki > 1) this.keys.splice(0, ki); + this._updateLastIndex(); +}; +/** + * remove all keys from animation + * @param {Number} [time=0] set a new key at time with the old value at time + * @memberof Anim + * @instance + * @function + */ +Anim.prototype.clear = function (time) +{ + let v = 0; + if (time) v = this.getValue(time); + this.keys.length = 0; + this._updateLastIndex(); + if (time) this.setValue(time, v); + if (this.onChange !== null) this.onChange(); + this.emitEvent("onChange", this); +}; + +Anim.prototype.sortKeys = function () +{ + this.keys.sort((a, b) => { return parseFloat(a.time) - parseFloat(b.time); }); + this._updateLastIndex(); + this._needsSort = false; + if (this.keys.length % 1000 == 0)console.log(this.name, this.keys.length); +}; + +Anim.prototype.getLength = function () +{ + if (this.keys.length === 0) return 0; + return this.keys[this.keys.length - 1].time; +}; + +Anim.prototype.getKeyIndex = function (time) +{ + let index = 0; + let start = 0; + if (this._cachedIndex && this.keys.length > this._cachedIndex && time >= this.keys[this._cachedIndex].time) start = this._cachedIndex; + for (let i = start; i < this.keys.length; i++) + { + if (time >= this.keys[i].time) index = i; + if (this.keys[i].time > time) + { + if (time != 0) this._cachedIndex = index; + return index; + } + } + + return index; +}; + +/** + * set value at time + * @function setValue + * @memberof Anim + * @instance + * @param {Number} time + * @param {Number} value + * @param {Function} [callback] callback + */ +Anim.prototype.setValue = function (time, value, cb) +{ + let found = null; + + if (this.keys.length == 0 || time <= this.keys[this.keys.length - 1].time) + for (let i = 0; i < this.keys.length; i++) + if (this.keys[i].time == time) + { + found = this.keys[i]; + this.keys[i].setValue(value); + this.keys[i].cb = cb; + break; + } + + if (!found) + { + found = new Key( + { + "time": time, + "value": value, + "e": this.defaultEasing, + "cb": cb, + }); + this.keys.push(found); + + // if (this.keys.length % 1000 == 0)console.log(this.name, this.keys.length); + this._updateLastIndex(); + } + + if (this.onChange) this.onChange(); + this.emitEvent("onChange", this); + this._needsSort = true; + return found; +}; + +Anim.prototype.setKeyEasing = function (index, e) +{ + if (this.keys[index]) + { + this.keys[index].setEasing(e); + this.emitEvent("onChange", this); + } +}; + +Anim.prototype.getSerialized = function () +{ + const obj = {}; + obj.keys = []; + obj.loop = this.loop; + + for (let i = 0; i < this.keys.length; i++) + obj.keys.push(this.keys[i].getSerialized()); + + return obj; +}; + +Anim.prototype.getKey = function (time) +{ + const index = this.getKeyIndex(time); + return this.keys[index]; +}; + +Anim.prototype.getNextKey = function (time) +{ + let index = this.getKeyIndex(time) + 1; + if (index >= this.keys.length) index = this.keys.length - 1; + + return this.keys[index]; +}; + +Anim.prototype.isFinished = function (time) +{ + if (this.keys.length <= 0) return true; + return time > this.keys[this.keys.length - 1].time; +}; + +Anim.prototype.isStarted = function (time) +{ + if (this.keys.length <= 0) return false; + return time >= this.keys[0].time; +}; + +/** + * get value at time + * @function getValue + * @memberof Anim + * @instance + * @param {Number} [time] time + * @returns {Number} interpolated value at time + */ +Anim.prototype.getValue = function (time) +{ + if (this.keys.length === 0) + { + return 0; + } + if (this._needsSort) this.sortKeys(); + + if (!this.loop && time > this.keys[this._lastKeyIndex].time) + { + if (this.keys[this._lastKeyIndex].cb && !this.keys[this._lastKeyIndex].cbTriggered) this.keys[this._lastKeyIndex].trigger(); + + return this.keys[this._lastKeyIndex].value; + } + + if (time < this.keys[0].time) + { + // if (this.name)console.log("A"); + + return this.keys[0].value; + } + + if (this.loop && time > this.keys[this._lastKeyIndex].time) + { + const currentLoop = time / this.keys[this._lastKeyIndex].time; + if (currentLoop > this._timesLooped) + { + this._timesLooped++; + if (this.onLooped) this.onLooped(); + } + time = (time - this.keys[0].time) % (this.keys[this._lastKeyIndex].time - this.keys[0].time); + time += this.keys[0].time; + } + + const index = this.getKeyIndex(time); + if (index >= this._lastKeyIndex) + { + if (this.keys[this._lastKeyIndex].cb && !this.keys[this._lastKeyIndex].cbTriggered) this.keys[this._lastKeyIndex].trigger(); + + return this.keys[this._lastKeyIndex].value; + } + + + const index2 = index + 1; + const key1 = this.keys[index]; + const key2 = this.keys[index2]; + + if (key1.cb && !key1.cbTriggered) key1.trigger(); + + if (!key2) return -1; + + const perc = (time - key1.time) / (key2.time - key1.time); + + if (!key1.ease) this.log._warn("has no ease", key1, key2); + + return key1.ease(perc, key2); +}; + +Anim.prototype._updateLastIndex = function () +{ + this._lastKeyIndex = this.keys.length - 1; +}; + +Anim.prototype.addKey = function (k) +{ + if (k.time === undefined) + { + this.log.warn("key time undefined, ignoring!"); + } + else + { + this.keys.push(k); + if (this.onChange !== null) this.onChange(); + this.emitEvent("onChange", this); + } + this._updateLastIndex(); +}; + +Anim.prototype.easingFromString = function (str) +{ + if (str == "linear") return CONSTANTS.ANIM.EASING_LINEAR; + if (str == "absolute") return CONSTANTS.ANIM.EASING_ABSOLUTE; + if (str == "smoothstep") return CONSTANTS.ANIM.EASING_SMOOTHSTEP; + if (str == "smootherstep") return CONSTANTS.ANIM.EASING_SMOOTHERSTEP; + + if (str == "Cubic In") return CONSTANTS.ANIM.EASING_CUBIC_IN; + if (str == "Cubic Out") return CONSTANTS.ANIM.EASING_CUBIC_OUT; + if (str == "Cubic In Out") return CONSTANTS.ANIM.EASING_CUBIC_INOUT; + + if (str == "Expo In") return CONSTANTS.ANIM.EASING_EXPO_IN; + if (str == "Expo Out") return CONSTANTS.ANIM.EASING_EXPO_OUT; + if (str == "Expo In Out") return CONSTANTS.ANIM.EASING_EXPO_INOUT; + + if (str == "Sin In") return CONSTANTS.ANIM.EASING_SIN_IN; + if (str == "Sin Out") return CONSTANTS.ANIM.EASING_SIN_OUT; + if (str == "Sin In Out") return CONSTANTS.ANIM.EASING_SIN_INOUT; + + if (str == "Back In") return CONSTANTS.ANIM.EASING_BACK_IN; + if (str == "Back Out") return CONSTANTS.ANIM.EASING_BACK_OUT; + if (str == "Back In Out") return CONSTANTS.ANIM.EASING_BACK_INOUT; + + if (str == "Elastic In") return CONSTANTS.ANIM.EASING_ELASTIC_IN; + if (str == "Elastic Out") return CONSTANTS.ANIM.EASING_ELASTIC_OUT; + + if (str == "Bounce In") return CONSTANTS.ANIM.EASING_BOUNCE_IN; + if (str == "Bounce Out") return CONSTANTS.ANIM.EASING_BOUNCE_OUT; + + if (str == "Quart Out") return CONSTANTS.ANIM.EASING_QUART_OUT; + if (str == "Quart In") return CONSTANTS.ANIM.EASING_QUART_IN; + if (str == "Quart In Out") return CONSTANTS.ANIM.EASING_QUART_INOUT; + + if (str == "Quint Out") return CONSTANTS.ANIM.EASING_QUINT_OUT; + if (str == "Quint In") return CONSTANTS.ANIM.EASING_QUINT_IN; + if (str == "Quint In Out") return CONSTANTS.ANIM.EASING_QUINT_INOUT; +}; + +Anim.prototype.createPort = function (op, title, cb) +{ + const port = op.inDropDown(title, CONSTANTS.ANIM.EASINGS); + + // const port = op.addInPort( + // new Port(op, title, CONSTANTS.OP.OP_PORT_TYPE_VALUE, { + // "display": "dropdown", + // "values": CONSTANTS.ANIM.EASINGS, + // }), + // ); + + port.set("linear"); + port.defaultValue = "linear"; + + port.onChange = function () + { + this.defaultEasing = this.easingFromString(port.get()); + this.emitEvent("onChangeDefaultEasing", this); + + if (cb) cb(); + }.bind(this); + + return port; +}; + +// ------------------------------ + +Anim.slerpQuaternion = function (time, q, animx, animy, animz, animw) +{ + if (!Anim.slerpQuaternion.q1) + { + Anim.slerpQuaternion.q1 = quat.create(); + Anim.slerpQuaternion.q2 = quat.create(); + } + + const i1 = animx.getKeyIndex(time); + let i2 = i1 + 1; + if (i2 >= animx.keys.length) i2 = animx.keys.length - 1; + + if (i1 == i2) + { + quat.set(q, animx.keys[i1].value, animy.keys[i1].value, animz.keys[i1].value, animw.keys[i1].value); + } + else + { + const key1Time = animx.keys[i1].time; + const key2Time = animx.keys[i2].time; + const perc = (time - key1Time) / (key2Time - key1Time); + + quat.set(Anim.slerpQuaternion.q1, animx.keys[i1].value, animy.keys[i1].value, animz.keys[i1].value, animw.keys[i1].value); + + quat.set(Anim.slerpQuaternion.q2, animx.keys[i2].value, animy.keys[i2].value, animz.keys[i2].value, animw.keys[i2].value); + + quat.slerp(q, Anim.slerpQuaternion.q1, Anim.slerpQuaternion.q2, perc); + } + return q; +}; + +const ANIM = { "Key": Key }; + + + + +;// CONCATENATED MODULE: ./src/core/core_link.js + + + +/** + * @external CABLES + * @namespace Link + * @param {Object} patch The patch object + * @description a link is a connection between two ops/ports -> one input and one output port + * @hideconstructor + * @class + */ +const Link = function (scene) +{ + EventTarget.apply(this); + + this.id = CABLES.simpleId(); + this.portIn = null; + this.portOut = null; + this.scene = scene; // todo: make private and rename to patch + this.activityCounter = 0; + this.ignoreInSerialize = false; +}; + +Link.prototype.setValue = function (v) +{ + if (v === undefined) this._setValue(); + else this.portIn.set(v); +}; + +Link.prototype.activity = function () +{ + this.activityCounter++; + // if(Date.now()-this.lastTime>100) + // { + // // this.lastTime=Date.now(); + // // this.changesPerSecond=this.changesCounter*10; + // this.changesCounter=0; + // } +}; + +Link.prototype._setValue = function () +{ + if (!this.portOut) + { + this.remove(); + return; + } + const v = this.portOut.get(); + + if (v == v) // NaN is the only JavaScript value that is treated as unequal to itself + { + if (this.portIn.type != CONSTANTS.OP.OP_PORT_TYPE_FUNCTION) this.activity(); + + if (this.portIn.get() !== v) + { + this.portIn.set(v); + } + else + { + if (this.portIn.changeAlways) this.portIn.set(v); + if (this.portOut.forceRefChange) this.portIn.forceChange(); + } + } +}; + +/** + * @function getOtherPort + * @memberof Link + * @instance + * @param {Port} port + * @description returns the port of the link, which is not port + */ +Link.prototype.getOtherPort = function (p) +{ + if (p == this.portIn) return this.portOut; + return this.portIn; +}; + +/** + * @function remove + * @memberof Link + * @instance + * @description unlink/remove this link from all ports + */ +Link.prototype.remove = function () +{ + if (this.portIn) this.portIn.removeLink(this); + if (this.portOut) this.portOut.removeLink(this); + if (this.scene) + { + this.scene.emitEvent("onUnLink", this.portIn, this.portOut, this); + } + + if (this.portIn && (this.portIn.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT || this.portIn.type == CONSTANTS.OP.OP_PORT_TYPE_ARRAY)) + { + this.portIn.set(null); + if (this.portIn.links.length > 0) this.portIn.set(this.portIn.links[0].getOtherPort(this.portIn).get()); + } + + if (this.portIn) this.portIn.op._checkLinksNeededToWork(); + if (this.portOut) this.portOut.op._checkLinksNeededToWork(); + + this.portIn = null; + this.portOut = null; + this.scene = null; +}; + +/** + * @function link + * @memberof Link + * @instance + * @description link those two ports + * @param {Port} port1 + * @param {Port} port2 + */ +Link.prototype.link = function (p1, p2) +{ + if (!Link.canLink(p1, p2)) + { + console.warn("[core_link] cannot link ports!", p1, p2); + return false; + } + + if (p1.direction == CONSTANTS.PORT.PORT_DIR_IN) + { + this.portIn = p1; + this.portOut = p2; + } + else + { + this.portIn = p2; + this.portOut = p1; + } + + p1.addLink(this); + p2.addLink(this); + + this.setValue(); + + if (p1.onLink) p1.onLink(this); + if (p2.onLink) p2.onLink(this); + + p1.op._checkLinksNeededToWork(); + p2.op._checkLinksNeededToWork(); +}; + +Link.prototype.getSerialized = function () +{ + const obj = {}; + + obj.portIn = this.portIn.getName(); + obj.portOut = this.portOut.getName(); + obj.objIn = this.portIn.op.id; + obj.objOut = this.portOut.op.id; + + return obj; +}; + +// -------------------------------------------- + +/** + * @function canLinkText + * @memberof Link + * @instance + * @description return a text message with human readable reason if ports can not be linked, or can be + * @param {Port} port1 + * @param {Port} port2 + */ +Link.canLinkText = function (p1, p2) +{ + if (p1.direction == p2.direction) + { + let txt = "(out)"; + if (p2.direction == CONSTANTS.PORT.PORT_DIR_IN) txt = "(in)"; + return "can not link: same direction " + txt; + } + if (p1.op == p2.op) return "can not link: same op"; + if (p1.type != CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC && p2.type != CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC) + { + if (p1.type != p2.type) return "can not link: different type"; + } + + if (CABLES.UI && p1.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT && p2.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT) + { + if (p1.uiAttribs.objType && p2.uiAttribs.objType) + if (p1.uiAttribs.objType != p2.uiAttribs.objType) + return "incompatible objects"; + } + + + if (!p1) return "can not link: port 1 invalid"; + if (!p2) return "can not link: port 2 invalid"; + + if (p1.direction == CONSTANTS.PORT.PORT_DIR_IN && p1.isAnimated()) return "can not link: is animated"; + if (p2.direction == CONSTANTS.PORT.PORT_DIR_IN && p2.isAnimated()) return "can not link: is animated"; + + // if(p1.direction==CABLES.CONSTANTS.PORT.PORT_DIR_IN && p1.links.length>0)return 'input port already busy'; + // if(p2.direction==CABLES.CONSTANTS.PORT.PORT_DIR_IN && p2.links.length>0)return 'input port already busy'; + if (p1.isLinkedTo(p2)) return "ports already linked"; + + if ((p1.canLink && !p1.canLink(p2)) || (p2.canLink && !p2.canLink(p1))) return "Incompatible"; + + return "can link"; +}; + +/** + * @function canLink + * @memberof Link + * @instance + * @description return true if ports can be linked + * @param {Port} port1 + * @param {Port} port2 + * @returns {Boolean} + */ +Link.canLink = function (p1, p2) +{ + if (!p1) return false; + if (!p2) return false; + if (p1.direction == CONSTANTS.PORT.PORT_DIR_IN && p1.isAnimated()) return false; + if (p2.direction == CONSTANTS.PORT.PORT_DIR_IN && p2.isAnimated()) return false; + + if (p1.isHidden() || p2.isHidden()) return false; + + if (p1.isLinkedTo(p2)) return false; + + if (p1.direction == p2.direction) return false; + + if (CABLES.UI && p1.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT && p2.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT) + { + if (p1.uiAttribs.objType && p2.uiAttribs.objType) + { + if (p1.uiAttribs.objType.indexOf("sg_") == 0 && p2.uiAttribs.objType.indexOf("sg_") == 0) return true; + if (p1.uiAttribs.objType != p2.uiAttribs.objType) + return false; + } + } + + if (p1.type != p2.type && (p1.type != CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC && p2.type != CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC)) return false; + if (p1.type == CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC || p2.type == CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC) return true; + + if (p1.op == p2.op) return false; + + if (p1.canLink && !p1.canLink(p2)) return false; + if (p2.canLink && !p2.canLink(p1)) return false; + + return true; +}; + + + +;// CONCATENATED MODULE: ./src/core/core_port.js + + + + + + + +/** + * data is coming into and out of ops through input and output ports + * @external CABLES + * @namespace Port + * @class + * @hideconstructor + * @example + * const myPort=op.inString("String Port"); + */ +const Port = function (___op, name, type, uiAttribs) +{ + EventTarget.apply(this); + + this.data = {}; // UNUSED, DEPRECATED, only left in for backwards compatibility with userops + this._log = new Logger("core_port"); + /** + * @type {Number} + * @name direction + * @instance + * @memberof Port + * @description direction of port (input(0) or output(1)) + */ + this.direction = CONSTANTS.PORT.PORT_DIR_IN; + this.id = String(CABLES.simpleId()); + this._op = ___op; + + /** + * @type {Array} + * @name links + * @instance + * @memberof Port + * @description links of port + */ + this.links = []; + this.value = 0.0; + this.name = name; + this.type = type || CONSTANTS.OP.OP_PORT_TYPE_VALUE; + this.uiAttribs = uiAttribs || {}; + this.anim = null; + this._oldAnimVal = -5711; + this.defaultValue = null; + + + this._uiActiveState = true; + this.ignoreValueSerialize = false; + this.onLinkChanged = null; + this.crashed = false; + + this._valueBeforeLink = null; + this._lastAnimFrame = -1; + this._animated = false; + + this.onValueChanged = null; + this.onTriggered = null; + this.onUiActiveStateChange = null; + this.changeAlways = false; + this.forceRefChange = false; + + this._useVariableName = null; + + this.activityCounter = 0; + this.apf = 0; + this.activityCounterStartFrame = 0; + + this._tempLastUiValue = null; + + Object.defineProperty(this, "title", { + get() + { + return this.uiAttribs.title || this.name; + } }); + + + Object.defineProperty(this, "parent", { + get() + { + this._log.stack("use port.op, not .parent"); + return this._op; + } }); + + + + Object.defineProperty(this, "op", { + get() + { + return this._op; + } }); + + + Object.defineProperty(this, "val", { + get() + { + this._log.warn("val getter deprecated!", this); + this._log.stack("val getter deprecated"); + return this.get(); + }, + set(v) + { + this._log.warn("val setter deprecated!", this); + this._log.stack("val setter deprecated"); + this.setValue(v); + } + }); +}; + + +/** + * copy over a uiattrib from an external connected port to another port + * @function copyLinkedUiAttrib + * @memberof Port + * @param {which} attrib name + * @param {Port} source port + * @instance + * @example + +inArray.onLinkChanged=()=> +{ + if(inArray) inArray.copyLinkedUiAttrib("stride", outArray); +}; + + */ +Port.prototype.copyLinkedUiAttrib = function (which, port) +{ + if (!CABLES.UI) return; + if (!this.isLinked()) return; + + const attr = {}; + attr[which] = this.links[0].getOtherPort(this).getUiAttrib(which); + port.setUiAttribs(attr); +}; + + +// TODO make extend class for ports, like for ops only for ui +Port.prototype.getValueForDisplay = function () +{ + let str = this.value; + + if (typeof this.value === "string" || this.value instanceof String) + { + if (str.length > 1000) + { + str = str.substring(0, 999); + str += "..."; + } + if (this.uiAttribs && (this.uiAttribs.display == "boolnum")) + { + str += " - "; + + if (!this.value) str += "false"; + else str += "true"; + } + + str = str.replace(/[\u00A0-\u9999<>\&]/g, function (i) + { + return "&#" + i.charCodeAt(0) + ";"; + }); + + + if (str.length > 100) str = str.substring(0, 100); + } + else + { + str = this.value; + } + return str; +}; + +/** + * change listener for input value ports, overwrite to react to changes + * @function onChange + * @memberof Port + * @instance + * @example + * const myPort=op.inString("MyPort"); + * myPort.onChange=function() + * { + * console.log("was changed to: ",myPort.get()); + * } + * + */ +Port.prototype.onAnimToggle = function () {}; +Port.prototype._onAnimToggle = function () +{ + this.onAnimToggle(); +}; + + +/** + * @function remove + * @memberof Port + * @instance + * @description remove port + */ +Port.prototype.remove = function () +{ + // this.setUiAttribs({hidePort:true}); + this.removeLinks(); + this._op.removePort(this); +}; + +/** + * set ui attributes + * @function setUiAttribs + * @memberof Port + * @instance + * @param {Object} newAttribs + *
    + * title - overwrite title of port (by default this is portname)
    + * greyout - port paramater will appear greyed out, can not be
    + * hidePort - port will be hidden from op
    + * hideParam - port params will be hidden from parameter panel
    + * showIndex - only for dropdowns - show value index (e.g. `0 - normal` )
    + * editorSyntax - set syntax highlighting theme for editor port
    + * ignoreObjTypeErrors - do not auto check object types
    + * 
    + * @example + * myPort.setUiAttribs({greyout:true}); + */ +Port.prototype.setUiAttribs = function (newAttribs) +{ + let changed = false; + if (!this.uiAttribs) this.uiAttribs = {}; + + for (const p in newAttribs) + { + if (newAttribs[p] === undefined) + { + // delete newAttribs[p]; + delete this.uiAttribs[p]; + continue; + } + if (this.uiAttribs[p] != newAttribs[p]) changed = true; + this.uiAttribs[p] = newAttribs[p]; + + if (p == "group" && this.indexPort) this.indexPort.setUiAttribs({ "group": newAttribs[p] }); + } + + if (newAttribs.hasOwnProperty("expose")) this._op.patch.emitEvent("subpatchExpose", this._op.uiAttribs.subPatch); + + if (changed) this.emitEvent("onUiAttrChange", newAttribs, this); +}; + +/** + * get ui attributes + * @function getUiAttribs + * @memberof Port + * @example + * myPort.getUiAttribs(); + */ +Port.prototype.getUiAttribs = function () +{ + return this.uiAttribs; +}; + +/** + * get ui attribute + * @function getUiAttrib + * @memberof Port + * @instance + * @param {String} attribName + *
    + * attribName - return value of the ui-attribute, or null on unknown attribute
    + * 
    + * @example + * myPort.setUiAttribs("values"); + */ +Port.prototype.getUiAttrib = function (attribName) +{ + if (!this.uiAttribs || !this.uiAttribs.hasOwnProperty(attribName)) + { + return null; + } + return this.uiAttribs[attribName]; +}; + +/** + * @function get + * @memberof Port + * @instance + * @description get value of port + */ +Port.prototype.get = function () +{ + if (this._animated && this._lastAnimFrame != this._op.patch.getFrameNum()) + { + this._lastAnimFrame = this._op.patch.getFrameNum(); + this.value = this.anim.getValue(this._op.patch.timer.getTime()); + + this._oldAnimVal = this.value; + this.forceChange(); + } + + return this.value; +}; + +Port.prototype.setRef = function (v) +{ + this.forceRefChange = true; + this.set(v); +}; + +/** + * @function setValue + * @memberof Port + * @instance + * @description set value of port / will send value to all linked ports (only for output ports) + */ +Port.prototype.set = Port.prototype.setValue = function (v) +{ + if (v === undefined) v = null; + + if (this._op.enabled && !this.crashed) + { + if (v !== this.value || this.changeAlways || this.type == CONSTANTS.OP.OP_PORT_TYPE_TEXTURE || this.type == CONSTANTS.OP.OP_PORT_TYPE_ARRAY) + { + if (this._animated) + { + this.anim.setValue(this._op.patch.timer.getTime(), v); + } + else + { + try + { + this.value = v; + this.forceChange(); + } + catch (ex) + { + this.crashed = true; + this.op.crashed = true; + + console.log("crash", this.op.objName); + + this.setValue = function (_v) {}; + this.onTriggered = function () {}; + + this._log.error("onvaluechanged exception cought", ex); + this._log.error(ex.stack); + this._log.warn("exception in: " + this._op.name); + + if (this._op.patch.isEditorMode()) gui.showOpCrash(this._op); + + this._op.patch.emitEvent("exception", ex, this._op); + if (this._op.onError) this._op.onError(ex); + } + + if (this._op && this._op.patch && this._op.patch.isEditorMode() && this.type == CONSTANTS.OP.OP_PORT_TYPE_TEXTURE) gui.texturePreview().updateTexturePort(this); + } + + if (this.direction == CONSTANTS.PORT.PORT_DIR_OUT) for (let i = 0; i < this.links.length; ++i) this.links[i].setValue(); + } + } +}; + +Port.prototype.updateAnim = function () +{ + if (this._animated) + { + this.value = this.get(); + + if (this._oldAnimVal != this.value || this.changeAlways) + { + this._oldAnimVal = this.value; + this.forceChange(); + } + this._oldAnimVal = this.value; + } +}; + +Port.prototype.forceChange = function () +{ + if (this.onValueChanged || this.onChange) + { + // very temporary: deprecated warning!!!!!!!!! + // if(params.length>0) this._log.warn('TOM: port has onchange params!',this._op.objName,this.name); + } + this._activity(); + this.emitEvent("change", this.value, this); + + if (this.onChange) this.onChange(this, this.value); + else if (this.onValueChanged) this.onValueChanged(this, this.value); // deprecated +}; + +/** + * @function getTypeString + * @memberof Port + * @instance + * @description get port type as string, e.g. "Function","Value"... + * @return {String} type + */ +Port.prototype.getTypeString = function () +{ + if (this.type == CONSTANTS.OP.OP_PORT_TYPE_VALUE) return "Number"; + if (this.type == CONSTANTS.OP.OP_PORT_TYPE_FUNCTION) return "Trigger"; + if (this.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT) return "Object"; + if (this.type == CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC) return "Dynamic"; + if (this.type == CONSTANTS.OP.OP_PORT_TYPE_ARRAY) return "Array"; + if (this.type == CONSTANTS.OP.OP_PORT_TYPE_STRING) return "String"; + return "Unknown"; +}; + +Port.prototype.deSerializeSettings = function (objPort) +{ + if (!objPort) return; + if (objPort.animated) this.setAnimated(objPort.animated); + if (objPort.useVariable) this.setVariableName(objPort.useVariable); + if (objPort.title) this.setUiAttribs({ "title": objPort.title }); + if (objPort.expose) this.setUiAttribs({ "expose": true }); + if (objPort.order) this.setUiAttribs({ "order": objPort.order }); + if (objPort.multiPortNum) this.setUiAttribs({ "multiPortNum": objPort.multiPortNum }); + + if (objPort.anim) + { + if (!this.anim) this.anim = new Anim({ "name": "port " + this.name }); + this._op._hasAnimPort = true; + this.anim.addEventListener("onChange", () => + { + this._op.patch.emitEvent("portAnimUpdated", this._op, this, this.anim); + }); + if (objPort.anim.loop) this.anim.loop = objPort.anim.loop; + for (const ani in objPort.anim.keys) + { + this.anim.keys.push(new ANIM.Key(objPort.anim.keys[ani])); + } + this.anim.sortKeys(); + } +}; + +Port.prototype.setInitialValue = function (v) +{ + if (this.op.preservedPortLinks[this.name]) + { + for (let i = 0; i < this.op.preservedPortLinks[this.name].length; i++) + { + const lobj = this.op.preservedPortLinks[this.name][i]; + this.op.patch._addLink( + lobj.objIn, + lobj.objOut, + lobj.portIn, + lobj.portOut); + } + } + + if (this.op.preservedPortValues && this.op.preservedPortValues.hasOwnProperty(this.name) && this.op.preservedPortValues[this.name] !== undefined) + { + this.set(this.op.preservedPortValues[this.name]); + } + else + if (v !== undefined) this.set(v); + if (v !== undefined) this.defaultValue = v; +}; + +Port.prototype.getSerialized = function () +{ + let obj = { "name": this.getName() }; + + + if (!this.ignoreValueSerialize && this.links.length === 0) + { + if (this.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT && this.value && this.value.tex) {} + else obj.value = this.value; + } + if (this._useVariableName) obj.useVariable = this._useVariableName; + if (this._animated) obj.animated = true; + if (this.anim) obj.anim = this.anim.getSerialized(); + if (this.uiAttribs.multiPortNum) obj.multiPortNum = this.uiAttribs.multiPortNum; + if (this.uiAttribs.display == "file") obj.display = this.uiAttribs.display; + if (this.uiAttribs.expose) + { + obj.expose = true; + if (this.uiAttribs.hasOwnProperty("order")) obj.order = this.uiAttribs.order; + } + if (this.uiAttribs.title) obj.title = this.uiAttribs.title; + if ((this.preserveLinks || this.direction == CONSTANTS.PORT.PORT_DIR_OUT) && this.links.length > 0) + { + obj.links = []; + for (const i in this.links) + { + if (!this.links[i].ignoreInSerialize && (this.links[i].portIn && this.links[i].portOut)) obj.links.push(this.links[i].getSerialized()); + } + } + + if (this.direction == CONSTANTS.PORT.PORT_DIR_IN && this.links.length > 0) + { + for (const i in this.links) + { + if (!this.links[i].portIn || !this.links[i].portOut) continue; + + const otherp = this.links[i].getOtherPort(this); + // check if functions exist, are defined in core_extend_ops code in ui + if (otherp.op.isInBlueprint2 && this.op.isInBlueprint2) + { + if (otherp.op.isInBlueprint2() && !this.op.isInBlueprint2()) + { + obj.links = obj.links || []; + obj.links.push(this.links[i].getSerialized()); + } + } + } + } + + if (obj.links && obj.links.length == 0) delete obj.links; + if (this.type === CONSTANTS.OP.OP_PORT_TYPE_FUNCTION) delete obj.value; + if (this.type === CONSTANTS.OP.OP_PORT_TYPE_FUNCTION && this.links.length == 0) obj = null; + if (obj && Object.keys(obj).length == 1 && obj.name)obj = null; // obj is null if there is no real information other than name + cleanJson(obj); + + return obj; +}; + +Port.prototype.shouldLink = function () +{ + return true; +}; + +/** + * @function removeLinks + * @memberof Port + * @instance + * @description remove all links from port + */ +Port.prototype.removeLinks = function () +{ + let count = 0; + while (this.links.length > 0) + { + count++; + if (count > 5000) + { + this._log.warn("could not delete links... / infinite loop"); + this.links.length = 0; + break; + } + this.links[0].remove(); + } +}; + +/** + * @function removeLink + * @memberof Port + * @instance + * @description remove all link from port + * @param {CABLES.Link} link + */ +Port.prototype.removeLink = function (link) +{ + for (const i in this.links) + if (this.links[i] == link) + this.links.splice(i, 1); + + if (this.direction == CONSTANTS.PORT.PORT_DIR_IN) + { + if (this.type == CONSTANTS.OP.OP_PORT_TYPE_VALUE) this.setValue(this._valueBeforeLink || 0); + else this.setValue(this._valueBeforeLink || null); + } + + if (CABLES.UI && this._op.checkLinkTimeWarnings) this._op.checkLinkTimeWarnings(); + + if (this.onLinkChanged) this.onLinkChanged(); + this.emitEvent("onLinkChanged"); + this._op.emitEvent("onLinkChanged"); +}; + +/** + * @function getName + * @memberof Port + * @instance + * @description return port name + */ +Port.prototype.getName = function () +{ + return this.name; +}; + +/** + * @function getTitle + * @memberof Port + * @instance + * @description return port name or title + */ +Port.prototype.getTitle = function () +{ + if (this.uiAttribs.title) return this.uiAttribs.title; + return this.name; +}; + +Port.prototype.addLink = function (l) +{ + this._valueBeforeLink = this.value; + this.links.push(l); + if (CABLES.UI && this._op.checkLinkTimeWarnings) this._op.checkLinkTimeWarnings(); + + if (this.onLinkChanged) this.onLinkChanged(); + this.emitEvent("onLinkChanged"); + this._op.emitEvent("onLinkChanged"); +}; + +/** + * @function getLinkTo + * @memberof Port + * @instance + * @param {Port} otherPort + * @description return link, which is linked to otherPort + */ +Port.prototype.getLinkTo = function (p2) +{ + for (const i in this.links) if (this.links[i].portIn == p2 || this.links[i].portOut == p2) return this.links[i]; +}; + +/** + * @function removeLinkTo + * @memberof Port + * @instance + * @param {Port} otherPort + * @description removes link, which is linked to otherPort + */ +Port.prototype.removeLinkTo = function (p2) +{ + for (const i in this.links) + { + if (this.links[i].portIn == p2 || this.links[i].portOut == p2) + { + this.links[i].remove(); + if (CABLES.UI && this._op.checkLinkTimeWarnings) this._op.checkLinkTimeWarnings(); + + if (this.onLinkChanged) this.onLinkChanged(); + this.emitEvent("onLinkChanged"); + return; + } + } +}; + +/** + * @function isLinkedTo + * @memberof Port + * @instance + * @param {Port} otherPort + * @description returns true if port is linked to otherPort + */ +Port.prototype.isLinkedTo = function (p2) +{ + for (const i in this.links) if (this.links[i].portIn == p2 || this.links[i].portOut == p2) return true; + + return false; +}; + +Port.prototype._activity = function () +{ + this.activityCounter++; +}; + +/** + * @function trigger + * @memberof Port + * @instance + * @description trigger the linked port (usually invoked on an output function port) + */ +Port.prototype.trigger = function () +{ + const linksLength = this.links.length; + + this._activity(); + if (linksLength === 0) return; + if (!this._op.enabled) return; + + let portTriggered = null; + try + { + for (let i = 0; i < linksLength; ++i) + { + if (this.links[i].portIn) + { + portTriggered = this.links[i].portIn; + + portTriggered.op.patch.pushTriggerStack(portTriggered); + portTriggered._onTriggered(); + + portTriggered.op.patch.popTriggerStack(); + } + if (this.links[i]) this.links[i].activity(); + } + } + catch (ex) + { + portTriggered.op.enabled = false; + + if (this._op.patch.isEditorMode()) + { + this._op.patch.emitEvent("exception", ex, portTriggered.op); + this._op.patch.emitEvent("opcrash", portTriggered); + console.log("crash", portTriggered.op.objName); + + if (portTriggered.op.onError) portTriggered.op.onError(ex); + } + this._log.warn("exception!"); + this._log.error("ontriggered exception caught", ex); + this._log.error(ex.stack); + this._log.warn("exception in: " + portTriggered.op.name); + } +}; + +Port.prototype.call = function () +{ + this._log.warn("call deprecated - use trigger() "); + this.trigger(); +}; + +Port.prototype.execute = function () +{ + this._log.warn("### execute port: " + this.getName(), this.goals.length); +}; + +Port.prototype.setVariableName = function (n) +{ + this._useVariableName = n; + + + this._op.patch.on("variableRename", (oldname, newname) => + { + if (oldname != this._useVariableName) return; + this._useVariableName = newname; + }); +}; + +Port.prototype.getVariableName = function () +{ + return this._useVariableName; +}; + +Port.prototype.setVariable = function (v) +{ + this.setAnimated(false); + const attr = { "useVariable": false }; + + if (this._variableIn && this._varChangeListenerId) + { + this._variableIn.off(this._varChangeListenerId); + this._variableIn = null; + } + + if (v) + { + this._variableIn = this._op.patch.getVar(v); + + if (!this._variableIn) + { + this._log.warn("PORT VAR NOT FOUND!!!", v); + } + else + { + if (this.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT) + { + this._varChangeListenerId = this._variableIn.on("change", () => { this.set(null); this.set(this._variableIn.getValue()); }); + } + else + { + this._varChangeListenerId = this._variableIn.on("change", this.set.bind(this)); + } + this.set(this._variableIn.getValue()); + } + this._useVariableName = v; + attr.useVariable = true; + attr.variableName = this._useVariableName; + } + else + { + attr.variableName = this._useVariableName = null; + attr.useVariable = false; + } + + this.setUiAttribs(attr); + this._op.patch.emitEvent("portSetVariable", this._op, this, v); +}; + +Port.prototype._handleNoTriggerOpAnimUpdates = function (a) +{ + let hasTriggerPort = false; + for (let i = 0; i < this._op.portsIn.length; i++) + { + if (this._op.portsIn.type == CONSTANTS.OP.OP_PORT_TYPE_FUNCTION) + { + hasTriggerPort = true; + break; + } + } + + if (!hasTriggerPort) + { + if (a) this._notriggerAnimUpdate = this._op.patch.on("onRenderFrame", + () => + { + this.updateAnim(); + }); + else this._op.patch.removeEventListener(this._notriggerAnimUpdate); + } +}; + +Port.prototype.setAnimated = function (a) +{ + if (this._animated != a) + { + this._animated = a; + this._op._hasAnimPort = true; + + if (this._animated && !this.anim) + { + this.anim = new Anim({ "name": "port " + this.name }); + this.anim.addEventListener("onChange", () => + { + this._op.patch.emitEvent("portAnimUpdated", this._op, this, this.anim); + }); + } + this._onAnimToggle(); + } + + this._handleNoTriggerOpAnimUpdates(a); + if (!a) + { + this.anim = null; + } + + this.setUiAttribs({ "isAnimated": this._animated }); +}; + +Port.prototype.toggleAnim = function () +{ + this._animated = !this._animated; + if (this._animated && !this.anim) + { + this.anim = new Anim({ "name": "port " + this.name }); + this.anim.addEventListener("onChange", () => + { + this._op.patch.emitEvent("portAnimUpdated", this._op, this, this.anim); + }); + } + this.setAnimated(this._animated); + this._onAnimToggle(); + this.setUiAttribs({ "isAnimated": this._animated }); +}; + +/** + *
    + * CABLES.CONSTANTS.OP.OP_PORT_TYPE_VALUE = 0;
    + * CABLES.CONSTANTS.OP.OP_PORT_TYPE_FUNCTION = 1;
    + * CABLES.CONSTANTS.OP.OP_PORT_TYPE_OBJECT = 2;
    + * CABLES.CONSTANTS.OP.OP_PORT_TYPE_TEXTURE = 2;
    + * CABLES.CONSTANTS.OP.OP_PORT_TYPE_ARRAY = 3;
    + * CABLES.CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC = 4;
    + * CABLES.CONSTANTS.OP.OP_PORT_TYPE_STRING = 5;
    + * 
    + * @function getType + * @memberof Port + * @instance + * @return {Number} type of port + */ +Port.prototype.getType = function () +{ + return this.type; +}; + +/** + * @function isLinked + * @memberof Port + * @instance + * @return {Boolean} true if port is linked + */ +Port.prototype.isLinked = function () +{ + return this.links.length > 0 || this._animated || this._useVariableName != null; +}; + +Port.prototype.isBoundToVar = function () +{ + const b = this._useVariableName != null; + this.uiAttribs.boundToVar = b; + return b; +}; +/** + * @function isAnimated + * @memberof Port + * @instance + * @return {Boolean} true if port is animated + */ +Port.prototype.isAnimated = function () +{ + return this._animated; +}; + +/** + * @function isHidden + * @memberof Port + * @instance + * @return {Boolean} true if port is hidden + */ +Port.prototype.isHidden = function () +{ + return this.uiAttribs.hidePort; +}; + +/** + * @function onTriggered + * @memberof Port + * @instance + * @param {onTriggeredCallback} callback + * @description set callback, which will be executed when port was triggered (usually output port) + */ +Port.prototype._onTriggered = function (a) +{ + this._activity(); + this._op.updateAnims(); + if (this._op.enabled && this.onTriggered) this.onTriggered(a); +}; + +Port.prototype._onSetProfiling = function (v) +{ + this._op.patch.profiler.add("port", this); + this.setValue(v); + this._op.patch.profiler.add("port", null); +}; + +Port.prototype._onTriggeredProfiling = function () +{ + if (this._op.enabled && this.onTriggered) + { + this._op.patch.profiler.add("port", this); + this.onTriggered(); + this._op.patch.profiler.add("port", null); + } +}; + + + +Port.prototype.getUiActiveState = function () +{ + return this._uiActiveState; +}; + +Port.prototype.setUiActiveState = function (onoff) +{ + this._uiActiveState = onoff; + if (this.onUiActiveStateChange) this.onUiActiveStateChange(); +}; + +/** + * @deprecated + */ +Port.prototype.onValueChange = function (cb) +{ + this.onChange = cb; +}; + +/** + * @deprecated + */ +Port.prototype.hidePort = function () {}; + + +/** + * Returns the port type string, e.g. "value" based on the port type number + * @function portTypeNumberToString + * @instance + * @memberof Port + * @param {Number} type - The port type number + * @returns {String} - The port type as string + */ +Port.portTypeNumberToString = function (type) +{ + if (type == CONSTANTS.OP.OP_PORT_TYPE_VALUE) return "value"; + if (type == CONSTANTS.OP.OP_PORT_TYPE_FUNCTION) return "function"; + if (type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT) return "object"; + if (type == CONSTANTS.OP.OP_PORT_TYPE_ARRAY) return "array"; + if (type == CONSTANTS.OP.OP_PORT_TYPE_STRING) return "string"; + if (type == CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC) return "dynamic"; + return "unknown"; +}; + + + +;// CONCATENATED MODULE: ./src/core/core_port_switch.js + + + + +class SwitchPort extends Port +{ + constructor(__parent, name, type, uiAttribs, indexPort) + { + super(__parent, name, type, uiAttribs); + + this.get = () => + { + let s = super.get(); + + if (CABLES.UI) + { + if ( + s === "" || + s === null || + s === undefined || + (uiAttribs.values && uiAttribs.values.indexOf(String(s)) === -1) + ) + { + this.op.setUiError("invalidswitch", "Invalid Value [" + this.name + "]: \"" + s + "\""); + } + else this.op.setUiError("invalidswitch", null); + } + + if (s === null || s === undefined)s = ""; + + return s; + }; + + this.indexPort = indexPort; + this.indexPort.set = (value) => + { + const values = uiAttribs.values; + + if (!values) + { + // console.log("switch port has no values", this); + return; + } + + let intValue = Math.floor(value); + + intValue = Math.min(intValue, values.length - 1); + intValue = Math.max(intValue, 0); + + this.indexPort.setValue(intValue); + this.set(values[intValue]); + + if (this.op.patch.isEditorMode() && performance.now() - (this.lastTime || 0) > 100 && window.gui && gui.patchView.isCurrentOp(this.op)) + { + gui.opParams.show(this.op); + this.lastTime = performance.now(); + } + }; + } + + setUiAttribs(attribs) + { + const hidePort = attribs.hidePort; + attribs.hidePort = true; + super.setUiAttribs(attribs); + if (typeof hidePort !== "undefined") + { + this.indexPort.setUiAttribs({ hidePort }); + } + } +} + + + +;// CONCATENATED MODULE: ./src/core/core_port_select.js + + + + +class ValueSelectPort extends SwitchPort +{ + setUiAttribs(newAttribs) + { + // never unhide valuePort when indexPort is linked + if (this.indexPort.isLinked()) + { + for (const p in newAttribs) + { + if (p == "greyout" && !newAttribs[p]) newAttribs[p] = "true"; + } + } + super.setUiAttribs(newAttribs); + } +} + + + + + +;// CONCATENATED MODULE: ./src/core/core_port_multi.js + + + +const MIN_NUM_PORTS = 2; + +class MultiPort extends Port +{ + constructor(__parent, name, type, dir, uiAttribs) + { + super(__parent, name, CONSTANTS.OP.OP_PORT_TYPE_ARRAY, uiAttribs); + + this.uiAttribs.multiPortNum = this.uiAttribs.multiPortNum || MIN_NUM_PORTS; + this.setUiAttribs({ "multiPort": true, "group": this.name, "order": -1 }); + this.ports = []; + this.direction = dir; + + const updateArray = () => + { + const arr = []; + for (let i = 0; i < this.ports.length - 1; i++) + { + arr[i] = this.ports[i]; + } + + this.setRef(arr); + }; + + + + + + const updateUi = () => + { + for (let i = 0; i < this.ports.length; i++) + { + let lp; // undefined to remove/not set it + let opacity;// undefined to remove/not set it + let grey;// undefined to remove/not set it + + if (!this.uiAttribs.editable)grey = true; + if (i == 0) lp = this.ports.length; + if (i == this.ports.length - 1) + { + opacity = 0.2; + grey = true; + } + + this.ports[i].setUiAttribs({ "longPort": lp, "opacity": opacity, "greyout": grey, "group": this.name }); + } + }; + + this.removeInvalidPorts = () => + { + for (let i = 0; i < this.ports.length; i++) + { + if (!this.ports[i]) this.ports.splice(i, 1); + } + }; + + this.countPorts = () => + { + if (gui.patchView.patchRenderer.isDraggingPort()) + { + clearTimeout(this.retryTo); + this.retryTo = setTimeout(this.countPorts.bind(this)); + return; + } + this.retryTo = null; + + let redo = false; + this.removeListeners(); + this.removeInvalidPorts(); + + for (let i = 0; i < this.ports.length; i++) + { + if (this.ports[i] && this.ports[i].links.length > 1) + { + const po = this.ports[i + 1]; + const otherPort = this.ports[i].links[0].getOtherPort(this.ports[i]); + this.ports[i].links[0].remove(); + this.op.patch.link(this.op, po.name, otherPort.op, otherPort.name); + redo = true; + break; + } + } + + + let foundHole = true; + if (!this.uiAttribs.editable) + while (foundHole) + { + foundHole = false; + for (let i = this.ports.length - 1; i > 0; i--) + { + if (this.ports[i] && this.ports[i].links.length > 0 && this.ports[i - 1].links.length == 0) + { + console.log("found hole!"); + // found hole + + const otherPort = this.ports[i].links[0].getOtherPort(this.ports[i]); + this.ports[i].links[0].remove(); + + const po = this.ports[i - 1]; + + if (po && this.ports[i]) + { + console.log("move ", this.ports[i].name, "to", po.name); + + this.op.patch.link(this.op, po.name, otherPort.op, otherPort.name); + foundHole = true; + redo = true; + break; + } + } + } + } + + if (this.ports.length > 2) + { + let i = this.ports.length - 1; + if (!this.uiAttribs.editable) + { + if (this.ports[i].links.length == 0 && this.ports[i - 1].links.length == 0) + { + this.ports[i].remove(); + this.ports[i] = null; + } + } + } + this.removeInvalidPorts(); + + if (this.ports[this.ports.length - 1].isLinked()) this.newPort(); + + updateArray(); + updateUi(); + + if (redo) this.countPorts(); + else this.addListeners(); + }; + + this.removeListeners = () => + { + for (let i = 0; i < this.ports.length; i++) + { + const po = this.ports[i]; + po.multiPortChangeListener = po.off(po.multiPortChangeListener); + po.multiLinkChangeListener = po.off(po.multiLinkChangeListener); + } + }; + + this.addListeners = () => + { + for (let i = 0; i < this.ports.length; i++) + { + const po = this.ports[i]; + + if (po.multiPortChangeListener)po.multiPortChangeListener = po.off(po.multiPortChangeListener); + po.multiPortChangeListener = po.on("change", updateArray.bind(this)); + + if (po.multiPortTriggerListener)po.multiPortTriggerListener = po.off(po.multiPortTriggerListener); + po.multiPortTriggerListener = po.on("trigger", this.trigger()); + + + if (po.multiLinkChangeListener)po.multiLinkChangeListener = po.off(po.multiLinkChangeListener); + po.multiLinkChangeListener = po.on("onLinkChanged", this.countPorts.bind(this)); + } + }; + + this.newPort = () => + { + const attrs = {}; + if (type == CABLES.OP_PORT_TYPE_STRING) attrs.type = "string"; + const po = new Port(this.op, name + "_" + this.ports.length, type, attrs); + + po.direction = dir; + this.ports.push(po); + console.log("CONSTANTS.PORT_DIR_OUT", CONSTANTS.PORT.PORT_DIR_OUT, this.direction); + if (this.direction == CONSTANTS.PORT.PORT_DIR_OUT) this.op.addOutPort(po); + else this.op.addInPort(po); + + po.setInitialValue(""); + this.addListeners(); + + updateUi(); + return po; + }; + + this.initPorts = () => + { + for (let i = 0; i < 2; i++) this.newPort(); + updateArray(); + updateUi(); + }; + + this.checkNum = () => + { + if (MIN_NUM_PORTS != this.uiAttribs.multiPortNum) this.setUiAttribs({ "editable": true }); + + this.uiAttribs.multiPortNum = Math.max(MIN_NUM_PORTS, this.uiAttribs.multiPortNum); + + while (this.ports.length < this.uiAttribs.multiPortNum) this.newPort(); + while (this.ports.length > this.uiAttribs.multiPortNum) if (this.ports[this.ports.length - 1]) this.ports.pop().remove(); + + this.removeInvalidPorts(); + }; + + this.incDec = (incDir) => + { + this.setUiAttribs({ "multiPortNum": this.uiAttribs.multiPortNum + incDir }); + this.checkNum(); + this.setUiAttribs({ "editable": true }); + updateUi(); + }; + + this.on("onUiAttrChange", this.checkNum.bind(this)); + this.checkNum(); + } +} + + + + + +;// CONCATENATED MODULE: ./src/core/core_op.js + + + + + + + + + +/** + * op the class of all operators + * @external CABLES + * @namespace Op + * @hideconstructor + */ + +/** + * @type {Object} + * @name attachments + * @instance + * @memberof Op + * @description access file attachments as String values + * @example + * // set shader source to attached files (files are called shader.vert / shader.frag) + * shader.setSource(attachments.shader_vert,attachments.shader_frag); + */ + +const Ops = {}; + +const Op = function () +{ + EventTarget.apply(this); + + this._log = new Logger("core_op"); + this.data = {}; // UNUSED, DEPRECATED, only left in for backwards compatibility with userops + this.storage = {}; // op-specific data to be included in export + this._objName = ""; + this.portsOut = []; + this.portsIn = []; + this.portsInData = []; // original loaded patch data + this.opId = ""; // unique op id + this.uiAttribs = {}; + this.enabled = true; + this.patch = arguments[0]; + this.name = arguments[1]; + this.preservedPortValues = {}; + this.preservedPortLinks = {}; + + this._linkTimeRules = { + "needsLinkedToWork": [], + "needsParentOp": null + }; + + this.shouldWork = {}; + this.hasUiErrors = false; + this._uiErrors = {}; + this._hasAnimPort = false; + + if (arguments[1]) + { + this._shortOpName = CABLES.getShortOpName(arguments[1]); + this.getTitle(); + } + + this.id = arguments[2] || shortId(); // instance id + this.onAddPort = null; + this.onCreate = null; + this.onResize = null; + this.onLoaded = null; + this.onDelete = null; + this.onUiAttrChange = null; + this.onError = null; + + this._instances = null; + + /** + * overwrite this to prerender shader and meshes / will be called by op `loadingStatus` + * @function preRender + * @memberof Op + * @instance + */ + this.preRender = null; + + /** + * overwrite this to initialize your op + * @function init + * @memberof Op + * @instance + */ + this.init = null; + + Object.defineProperty(this, "objName", { get() { return this._objName; } }); + Object.defineProperty(this, "shortName", { get() { return this._shortOpName; } }); + + if (this.initUi) this.initUi(); +}; + +{ + Op.prototype.clearUiAttrib = function (name) + { + const obj = {}; + obj.name = null; + this.uiAttrib(obj); + }; + + Op.prototype.checkMainloopExists = function () + { + if (!CABLES.UI) return; + if (!this.patch.cgl.mainloopOp) this.setUiError("nomainloop", "patch should have a mainloop to use this op"); + else this.setUiError("nomainloop", null); + }; + + Op.prototype.getTitle = function () + { + if (!this.uiAttribs) return "nouiattribs" + this.name; + + if ((this.uiAttribs.title === undefined || this.uiAttribs.title === "") && this.objName.indexOf("Ops.Ui.") == -1) + this.uiAttribs.title = this._shortOpName; + + if (this.uiAttribs.title === undefined) this.uiAttribs.title = this._shortOpName; + + return this.uiAttribs.title; + }; + + Op.prototype.setTitle = function (name) + { + const doEmitEvent = this.name != name; + this.name = name; + + if (this.uiAttribs.title != name) this.uiAttr({ "title": name }); + if (doEmitEvent) this.emitEvent("onTitleChange", name); + }; + + Op.prototype.setStorage = function (newAttribs) + { + if (!newAttribs) return; + this.storage = this.storage || {}; + + let changed = false; + for (const p in newAttribs) + { + if (this.storage[p] != newAttribs[p]) changed = true; + this.storage[p] = newAttribs[p]; + } + + if (changed) this.emitEvent("onStorageChange", newAttribs); + }; + + Op.prototype.isSubPatchOp = function () + { + if (this.storage) return (this.storage.subPatchVer || 0); + }; + + const _setUiAttrib = function (newAttribs) + { + if (!newAttribs) return; + + if (newAttribs.error || newAttribs.warning || newAttribs.hint) + { + this._log.warn("old ui error/warning attribute in " + this.name + ", use op.setUiError !", newAttribs); + } + + + + if (typeof newAttribs != "object") this._log.error("op.uiAttrib attribs are not of type object"); + if (!this.uiAttribs) this.uiAttribs = {}; + + + let emitMove = false; + if ( + CABLES.UI && + newAttribs.hasOwnProperty("translate") && + ( + !this.uiAttribs.translate || + this.uiAttribs.translate.x != newAttribs.translate.x || + this.uiAttribs.translate.y != newAttribs.translate.y + )) emitMove = true; + + + if (newAttribs.hasOwnProperty("disabled")) + { + this.setEnabled(!newAttribs.disabled); + } + + let changed = false; + for (const p in newAttribs) + { + if (this.uiAttribs[p] != newAttribs[p]) changed = true; + this.uiAttribs[p] = newAttribs[p]; + } + + if (this.uiAttribs.hasOwnProperty("selected") && this.uiAttribs.selected == false) delete this.uiAttribs.selected; + if (newAttribs.title && newAttribs.title != this.name) this.setTitle(newAttribs.title); + + if (changed) + { + this.emitEvent("onUiAttribsChange", newAttribs); + this.patch.emitEvent("onUiAttribsChange", this, newAttribs); + } + + + if (emitMove) this.emitEvent("move"); + }; + /** + * setUiAttrib + * possible values: + *
    +     * warning - warning message - showing up in op parameter panel
    +     * error - error message - showing up in op parameter panel
    +     * extendTitle - op title extension, e.g. [ + ]
    +     * 
    + * @function setUiAttrib + * @param {Object} newAttribs, e.g. {"attrib":value} + * @memberof Op + * @instance + * @example + * op.setUiAttrib({"extendTitle":str}); + */ + Op.prototype.setUiAttribs = Op.prototype.setUiAttrib = Op.prototype.uiAttr = _setUiAttrib; + + Op.prototype.getName = function () + { + if (this.uiAttribs.name) return this.uiAttribs.name; + return this.name; + }; + + Op.prototype.addOutPort = function (p) + { + p.direction = CONSTANTS.PORT.PORT_DIR_OUT; + p._op = this; + this.portsOut.push(p); + this.emitEvent("onPortAdd", p); + return p; + }; + + Op.prototype.hasDynamicPort = function () + { + let i = 0; + for (i = 0; i < this.portsIn.length; i++) + { + if (this.portsIn[i].type == CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC) return true; + if (this.portsIn[i].getName() == "dyn") return true; + } + for (i = 0; i < this.portsOut.length; i++) + { + if (this.portsOut[i].type == CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC) return true; + if (this.portsOut[i].getName() == "dyn") return true; + } + + return false; + }; + + Op.prototype.addInPort = function (p) + { + if (!(p instanceof Port)) throw new Error("parameter is not a port!"); + + p.direction = CONSTANTS.PORT.PORT_DIR_IN; + p._op = this; + + this.portsIn.push(p); + this.emitEvent("onPortAdd", p); + + return p; + }; + + /** + * create a trigger input port + * @function inTrigger + * @instance + * @memberof Op + * @param {String} name + * @return {Port} created port + * + */ + Op.prototype.inFunction = Op.prototype.inTrigger = function (name, v) + { + const p = this.addInPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_FUNCTION)); + if (v !== undefined) p.set(v); + return p; + }; + + /** + * create multiple UI trigger buttons + * @function inTriggerButton + * @memberof Op + * @instance + * @param {String} name + * @param {Array} names + * @return {Port} created port + */ + Op.prototype.inFunctionButton = Op.prototype.inTriggerButton = function (name, v) + { + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_FUNCTION, { + "display": "button" + }) + ); + if (v !== undefined) p.set(v); + return p; + }; + + Op.prototype.inFunctionButton = Op.prototype.inUiTriggerButtons = function (name, v) + { + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_FUNCTION, { + "display": "buttons" + }) + ); + if (v !== undefined) p.set(v); + return p; + }; + + + + /** + * create a number value input port + * @function inFloat + * @memberof Op + * @instance + * @param {String} name + * @param {Number} value + * @return {Port} created port + */ + Op.prototype.inValueFloat = Op.prototype.inValue = Op.prototype.inFloat = function (name, v) + { + const p = this.addInPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE)); + + p.setInitialValue(v); + + return p; + }; + + /** + * create a boolean input port, displayed as a checkbox + * @function inBool + * @instance + * @memberof Op + * @param {String} name + * @param {Boolean} value + * @return {Port} created port + */ + Op.prototype.inValueBool = Op.prototype.inBool = function (name, v) + { + // old + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_NUMBER, { + "display": "bool" + }) + ); + // if (v !== undefined) + // { + p.setInitialValue(v); + // p.set(v); + // p.defaultValue = p.get(); + // } + + return p; + }; + + + Op.prototype.inMultiPort = function (name, type) + { + const p = new MultiPort( + this, + name, + type, + CONSTANTS.PORT_DIR_IN, + { + "display": "multiport", + "hidePort": true + } + ); + p.ignoreValueSerialize = true; + + this.addInPort(p); + p.initPorts(); + + return p; + }; + + Op.prototype.outMultiPort = function (name, type) + { + const p = new MultiPort( + this, + name, + type, + CONSTANTS.PORT.PORT_DIR_OUT, + { + "display": "multiport", + "hidePort": true + } + ); + p.ignoreValueSerialize = true; + + this.addOutPort(p); + p.initPorts(); + + return p; + }; + + + + Op.prototype.inValueString = function (name, v) + { + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, { + "type": "string" + }) + ); + p.value = ""; + + p.setInitialValue(v); + return p; + }; + + /** + * create a String value input port + * @function inString + * @instance + * @memberof Op + * @param {String} name + * @param {String} value default value + * @return {Port} created port + */ + Op.prototype.inString = function (name, v) + { + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_STRING, { + "type": "string" + }) + ); + v = v || ""; + // p.value = v; + + p.setInitialValue(v); + return p; + }; + + /** + * create a String value input port displayed as TextArea + * @function inValueText + * @instance + * @memberof Op + * @param {String} name + * @param {String} value default value + * @return {Port} created port + */ + Op.prototype.inValueText = function (name, v) + { + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, { + "type": "string", + "display": "text" + }) + ); + p.value = ""; + + p.setInitialValue(v); + // if (v !== undefined) + // { + // p.set(v); + // p.defaultValue = v; + // } + return p; + }; + + Op.prototype.inTextarea = function (name, v) + { + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_STRING, { + "type": "string", + "display": "text" + }) + ); + p.value = ""; + if (v !== undefined) + { + p.set(v); + p.defaultValue = v; + } + return p; + }; + + /** + * create a String value input port displayed as editor + * @function inStringEditor + * @instance + * @memberof Op + * @param {String} name + * @param {String} value default value + * @return {Port} created port + */ + // new string + Op.prototype.inStringEditor = function (name, v, syntax, hideFormatButton = true) + { + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_STRING, { + "type": "string", + "display": "editor", + "editShortcut": true, + "editorSyntax": syntax, + "hideFormatButton": hideFormatButton + })); + + p.value = ""; + if (v !== undefined) + { + p.set(v); + p.defaultValue = v; + } + return p; + }; + + // old + Op.prototype.inValueEditor = function (name, v, syntax, hideFormatButton = true) + { + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_NUMBER, { + "type": "string", + "display": "editor", + "editorSyntax": syntax, + "hideFormatButton": hideFormatButton + }) + ); + p.value = ""; + if (v !== undefined) + { + p.set(v); + p.defaultValue = v; + } + return p; + }; + + /** + * create a string select box + * @function inDropDown + * @instance + * @memberof Op + * @param {String} name + * @param {Array} values + * @param {String} value default value + * @return {Port} created port + */ + Op.prototype.inValueSelect = Op.prototype.inDropDown = function (name, values, v, noindex) + { + let p = null; + if (!noindex) + { + const indexPort = new Port(this, name + " index", CONSTANTS.OP.OP_PORT_TYPE_NUMBER, { + "increment": "integer", + "hideParam": true + }); + const n = this.addInPort(indexPort); + + if (values) for (let i = 0; i < values.length; i++) values[i] = String(values[i]); + + const valuePort = new ValueSelectPort( + this, + name, + CONSTANTS.OP.OP_PORT_TYPE_NUMBER, + { + "display": "dropdown", + "hidePort": true, + "type": "string", + "values": values + }, + n + ); + + valuePort.indexPort = indexPort; + + valuePort.on("change", (val, thePort) => + { + if (!thePort.indexPort.isLinked() && thePort.uiAttribs.values) + { + const idx = thePort.uiAttribs.values.indexOf(val); + if (idx > -1) thePort.indexPort.set(idx); + } + }); + + indexPort.onLinkChanged = function () + { + valuePort.setUiAttribs({ "greyout": indexPort.isLinked() }); + }; + + p = this.addInPort(valuePort); + + if (v !== undefined) + { + p.set(v); + const index = values.findIndex((item) => { return item == v; }); + n.setValue(index); + p.defaultValue = v; + n.defaultValue = index; + } + } + else + { + const valuePort = new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, { + "display": "dropdown", + "hidePort": true, + "type": "string", + values + }); + + p = this.addInPort(valuePort); + } + + return p; + }; + + /** + * create a string switch box + * @function inSwitch + * @instance + * @memberof Op + * @param {String} name + * @param {Array} values + * @param {String} value default value + * @return {Port} created port + */ + Op.prototype.inSwitch = function (name, values, v, noindex) + { + let p = null; + if (!noindex) + { + if (!v)v = values[0]; + const indexPort = new Port(this, name + " index", CONSTANTS.OP.OP_PORT_TYPE_VALUE, { + "increment": "integer", + "values": values, + "hideParam": true + }); + const n = this.addInPort(indexPort); + + if (values) for (let i = 0; i < values.length; i++) values[i] = String(values[i]); + + const switchPort = new SwitchPort( + this, + name, + CONSTANTS.OP.OP_PORT_TYPE_STRING, + { + "display": "switch", + "hidePort": true, + "type": "string", + "values": values + }, + n + ); + + switchPort.indexPort = indexPort; + + switchPort.on("change", (val, thePort) => + { + if (!thePort.indexPort.isLinked() && thePort.uiAttribs.values) + { + const idx = thePort.uiAttribs.values.indexOf(val); + if (idx > -1) thePort.indexPort.set(idx); + } + }); + + indexPort.onLinkChanged = function () + { + switchPort.setUiAttribs({ "greyout": indexPort.isLinked() }); + }; + p = this.addInPort(switchPort); + + if (v !== undefined) + { + p.set(v); + const index = values.findIndex((item) => { return item == v; }); + n.setValue(index); + p.defaultValue = v; + n.defaultValue = index; + } + } + else + { + const switchPort = new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_STRING, { + "display": "switch", + "hidePort": true, + "type": "string", + "values": values + }); + p = this.addInPort(switchPort); + } + + return p; + }; + + /** + * create a integer input port + * @function inInt + * @instance + * @memberof Op + * @param {String} name + * @param {number} value default value + * @return {Port} created port + */ + Op.prototype.inValueInt = Op.prototype.inInt = function (name, v) + { + // old + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, { + "increment": "integer" + }) + ); + if (v !== undefined) + { + p.set(v); + p.defaultValue = v; + } + return p; + }; + + /** + * create a file/URL input port + * @function inURL + * @instance + * @memberof Op + * @param {String} name + * @return {Port} created port + */ + Op.prototype.inFile = function (name, filter, v) + { + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, { + "display": "file", + "type": "string", + "filter": filter + }) + ); + if (v !== undefined) + { + p.set(v); + p.defaultValue = v; + } + return p; + }; + + Op.prototype.inUrl = function (name, filter, v) + { + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_STRING, { + "display": "file", + "type": "string", + "filter": filter + }) + ); + if (v !== undefined) + { + p.set(v); + p.defaultValue = v; + } + return p; + }; + + /** + * create a texture input port + * @function inTexture + * @instance + * @memberof Op + * @param {String} name + * @return {Port} created port + */ + Op.prototype.inTexture = function (name, v) + { + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_OBJECT, { + "display": "texture", + "objType": "texture", + "preview": true + }) + ); + p.ignoreValueSerialize = true; + if (v !== undefined) p.set(v); + return p; + }; + + + /** + * create a object input port + * @function inObject + * @instance + * @memberof Op + * @param {String} name + * @return {Port} created port + */ + Op.prototype.inObject = function (name, v, objType) + { + const p = this.addInPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_OBJECT, { "objType": objType })); + p.ignoreValueSerialize = true; + + if (v !== undefined) p.set(v); + return p; + }; + + Op.prototype.inGradient = function (name, v) + { + const p = this.addInPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, { + "display": "gradient" + // "hidePort": true + }) + ); + if (v !== undefined) p.set(v); + return p; + }; + + + Op.prototype.getPortVisibleIndex = function (p) + { + let ports = this.portsIn; + if (p.direction == CONSTANTS.PORT_DIR_OUT)ports = this.portsOut; + + let index = 0; + for (let i = 0; i < ports.length; i++) + { + if (ports[i].uiAttribs.hidePort) continue; + index++; + if (ports[i] == p) return index; + } + }; + + /** + * create a array input port + * @function inArray + * @instance + * @memberof Op + * @param {String} name + * @return {Port} created port + */ + Op.prototype.inArray = function (name, v, stride) + { + if (!stride && CABLES.UTILS.isNumeric(v))stride = v; + + const p = this.addInPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_ARRAY, { "stride": stride })); + + if (v !== undefined && (Array.isArray(v) || v == null)) p.set(v); + + // if (v !== undefined) p.set(v); + return p; + }; + + /** + * create a value slider input port + * @function inFloatSlider + * @instance + * @memberof Op + * @param {String} name + * @param {number} defaultvalue + * @param {number} min + * @param {number} max + * @return {Port} created port + */ + Op.prototype.inValueSlider = Op.prototype.inFloatSlider = function (name, v, min, max) + { + const uiattribs = { "display": "range" }; + + if (min != undefined && max != undefined) + { + uiattribs.min = min; + uiattribs.max = max; + } + + const p = this.addInPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, uiattribs)); + if (v !== undefined) + { + p.set(v); + p.defaultValue = v; + } + return p; + }; + + /** + * create output trigger port + * @function outTrigger + * @instance + * @memberof Op + * @param {String} name + * @return {Port} created port + */ + Op.prototype.outFunction = Op.prototype.outTrigger = function (name, v) + { + // old + const p = this.addOutPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_FUNCTION)); + if (v !== undefined) p.set(v); + return p; + }; + + /** + * create output value port + * @function outNumber + * @instance + * @memberof Op + * @param {String} name + * @param {number} default value + * @return {Port} created port + */ + Op.prototype.outValue = Op.prototype.outNumber = function (name, v) + { + // old + const p = this.addOutPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE)); + if (v !== undefined) p.set(v); + return p; + }; + + /** + * create output boolean port + * @function outBool + * @instance + * @memberof Op + * @param {String} name + * @return {Port} created port + */ + Op.prototype.outValueBool = Op.prototype.outBool = function (name, v) + { + // old + const p = this.addOutPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, { + "display": "bool" + }) + ); + if (v !== undefined) p.set(v); + else p.set(0); + return p; + }; + + /** + * create output boolean port,value will be converted to 0 or 1 + * @function outBool + * @instance + * @memberof Op + * @param {String} name + * @return {Port} created port + */ + Op.prototype.outBoolNum = function (name, v) + { + const p = this.addOutPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, { + "display": "boolnum" + }) + ); + + p.set = function (b) + { + this.setValue(b ? 1 : 0); + // console.log("bool set", b, this.get()); + }.bind(p); + + if (v !== undefined) p.set(v); + else p.set(0); + return p; + }; + + /** + * create output string port + * @function outString + * @instance + * @memberof Op + * @param {String} name + * @return {Port} created port + */ + Op.prototype.outValueString = function (name, v) + { + const p = this.addOutPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, { + "type": "string" + }) + ); + if (v !== undefined) p.set(v); + return p; + }; + Op.prototype.outString = function (name, v) + { + const p = this.addOutPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_STRING, { + "type": "string" + }) + ); + if (v !== undefined) p.set(v); + else p.set(""); + return p; + }; + + /** + * create output object port + * @function outObject + * @instance + * @memberof Op + * @param {String} name + * @return {Port} created port + */ + Op.prototype.outObject = function (name, v, objType) + { + const p = this.addOutPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_OBJECT, { "objType": objType || null })); + p.set(v || null); + p.ignoreValueSerialize = true; + return p; + }; + + /** + * create output array port + * @function outArray + * @instance + * @memberof Op + * @param {String} name + * @return {Port} created port + */ + Op.prototype.outArray = function (name, v, stride) + { + if (!stride && CABLES.UTILS.isNumeric(v))stride = v; + const p = this.addOutPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_ARRAY, { "stride": stride })); + if (v !== undefined && (Array.isArray(v) || v == null)) p.set(v); + + p.ignoreValueSerialize = true; + return p; + }; + + /** + * create output texture port + * @function outTexture + * @instance + * @memberof Op + * @param {String} name + * @return {Port} created port + */ + Op.prototype.outTexture = function (name, v) + { + const p = this.addOutPort( + new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_OBJECT, { + "preview": true, + "objType": "texture", + "display": "texture" + }) + ); + if (v !== undefined) p.set(v || CGL.Texture.getEmptyTexture(this.patch.cgl)); + + p.ignoreValueSerialize = true; + return p; + }; + + Op.prototype.inDynamic = function (name, filter, options, v) + { + const p = new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC, options); + + p.shouldLink = function (p1, p2) + { + if (filter && UTILS.isArray(filter)) + { + for (let i = 0; i < filter.length; i++) + { + if (p1 == this && p2.type === filter[i]) return true; + if (p2 == this && p1.type === filter[i]) return true; + } + return false; // types do not match + } + return true; // no filter set + }; + + this.addInPort(p); + if (v !== undefined) + { + p.set(v); + p.defaultValue = v; + } + return p; + }; + + Op.prototype.removeLinks = function () + { + for (let i = 0; i < this.portsIn.length; i++) this.portsIn[i].removeLinks(); + for (let ipo = 0; ipo < this.portsOut.length; ipo++) this.portsOut[ipo].removeLinks(); + }; + + Op.prototype.getSerialized = function () + { + const opObj = {}; + + if (this.opId) opObj.opId = this.opId; + if (this.patch.storeObjNames) opObj.objName = this.objName; + + + opObj.id = this.id; + opObj.uiAttribs = JSON.parse(JSON.stringify(this.uiAttribs)) || {}; + + if (this.storage && Object.keys(this.storage).length > 0) opObj.storage = JSON.parse(JSON.stringify(this.storage)); + if (this.uiAttribs.hasOwnProperty("working") && this.uiAttribs.working == true) delete this.uiAttribs.working; + if (opObj.uiAttribs.hasOwnProperty("uierrors")) delete opObj.uiAttribs.uierrors; + + if (opObj.uiAttribs.title == this._shortOpName) delete opObj.uiAttribs.title; + + opObj.portsIn = []; + opObj.portsOut = []; + + // console.log("this.portsIn", this.portsIn); + + for (let i = 0; i < this.portsIn.length; i++) + { + const s = this.portsIn[i].getSerialized(); + if (s)opObj.portsIn.push(s); + } + for (const ipo in this.portsOut) + { + const s = this.portsOut[ipo].getSerialized(); + if (s)opObj.portsOut.push(s); + } + + if (opObj.portsIn.length == 0) delete opObj.portsIn; + if (opObj.portsOut.length == 0) delete opObj.portsOut; + cleanJson(opObj); + + return opObj; + }; + + Op.prototype.getFirstOutPortByType = function (type) + { + for (const ipo in this.portsOut) if (this.portsOut[ipo].type == type) return this.portsOut[ipo]; + }; + + Op.prototype.getFirstInPortByType = function (type) + { + for (const ipo in this.portsIn) if (this.portsIn[ipo].type == type) return this.portsIn[ipo]; + }; + + /** + * return port by the name portName + * @function getPort + * @instance + * @memberof Op + * @param {String} portName + * @return {Port} + */ + Op.prototype.getPort = Op.prototype.getPortByName = function (name, lowerCase) + { + if (lowerCase) + { + for (let ipi = 0; ipi < this.portsIn.length; ipi++) + if (this.portsIn[ipi].getName().toLowerCase() == name || this.portsIn[ipi].id.toLowerCase() == name) + return this.portsIn[ipi]; + + for (let ipo = 0; ipo < this.portsOut.length; ipo++) + if (this.portsOut[ipo].getName().toLowerCase() == name || this.portsOut[ipo].id.toLowerCase() == name) + return this.portsOut[ipo]; + } + else + { + for (let ipi = 0; ipi < this.portsIn.length; ipi++) + if (this.portsIn[ipi].getName() == name || this.portsIn[ipi].id == name) + return this.portsIn[ipi]; + + for (let ipo = 0; ipo < this.portsOut.length; ipo++) + if (this.portsOut[ipo].getName() == name || this.portsOut[ipo].id == name) + return this.portsOut[ipo]; + } + }; + + + /** + * return port by the name id + * @function getPortById + * @instance + * @memberof Op + * @param {String} id + * @return {Port} + */ + Op.prototype.getPortById = function (id) + { + for (let ipi = 0; ipi < this.portsIn.length; ipi++) if (this.portsIn[ipi].id == id) return this.portsIn[ipi]; + for (let ipo = 0; ipo < this.portsOut.length; ipo++) if (this.portsOut[ipo].id == id) return this.portsOut[ipo]; + }; + + Op.prototype.updateAnims = function () + { + if (this._hasAnimPort) + for (let i = 0; i < this.portsIn.length; i++) this.portsIn[i].updateAnim(); + }; + + Op.prototype.log = function () + { + const initiator = "op " + this.objName; + if (CABLES.UI && !CABLES.UI.logFilter.shouldPrint(initiator, ...arguments)) return; + if (!CABLES.UI && this.patch.silent) return; + + const args = ["[op " + CABLES.getShortOpName(this.objName) + "]"]; + args.push.apply(args, arguments); + Function.prototype.apply.apply(console.log, [console, args]);// eslint-disable-line + }; + + Op.prototype.error = Op.prototype.logError = function () + { + if (!this) + { + console.log("no this...!!!"); + debugger; + return; + } + + // if (this.patch.silent) return; + const args = ["[op " + CABLES.getShortOpName(this.objName) + "]"]; + args.push.apply(args, arguments); + Function.prototype.apply.apply(console.error, [console, args]);// eslint-disable-line + if (window.gui) window.gui.emitEvent("opLogEvent", this.objName, "error", arguments); + }; + + Op.prototype.warn = Op.prototype.logWarn = function () + { + // if (this.patch.silent) return; + const args = ["[op " + CABLES.getShortOpName(this.objName) + "]"]; + args.push.apply(args, arguments); + Function.prototype.apply.apply(console.warn, [console, args]);// eslint-disable-line + }; + + Op.prototype.verbose = Op.prototype.logVerbose = function () + { + const initiator = "op " + CABLES.getShortOpName(this.objName); + if (CABLES.UI && !CABLES.UI.logFilter.shouldPrint(initiator, ...arguments)) return; + + if (!CABLES.UI && this.patch.silent) return; + + const args = ["[" + initiator + "]"]; + args.push.apply(args, arguments); + Function.prototype.apply.apply(console.info, [console, args]);// eslint-disable-line + }; + + + Op.prototype.profile = function (enable) + { + for (let ipi = 0; ipi < this.portsIn.length; ipi++) + { + this.portsIn[ipi]._onTriggered = this.portsIn[ipi]._onTriggeredProfiling; + this.portsIn[ipi].set = this.portsIn[ipi]._onSetProfiling; + } + }; + + Op.prototype.findParent = function (objName) + { + for (let ipi = 0; ipi < this.portsIn.length; ipi++) + { + if (this.portsIn[ipi].isLinked()) + { + if (this.portsIn[ipi].links[0].portOut.parent.objName == objName) + return this.portsIn[ipi].links[0].portOut.parent; + + let found = null; + found = this.portsIn[ipi].links[0].portOut.parent.findParent(objName); + if (found) return found; + } + } + return null; + }; + + + // todo: check instancing stuff? + Op.prototype.cleanUp = function () + { + if (this._instances) + { + for (let i = 0; i < this._instances.length; i++) + { + if (this._instances[i].onDelete) this._instances[i].onDelete(); + } + + + this._instances.length = 0; + } + for (let i = 0; i < this.portsIn.length; i++) + { + this.portsIn[i].setAnimated(false); + } + + if (this.onAnimFrame) this.patch.removeOnAnimFrame(this); + }; + + // todo: check instancing stuff? + Op.prototype.instanced = function (triggerPort) + { + console.log("instanced", this.patch.instancing.numCycles()); + if (this.patch.instancing.numCycles() === 0) return false; + + + let i = 0; + let ipi = 0; + if (!this._instances || this._instances.length != this.patch.instancing.numCycles()) + { + if (!this._instances) this._instances = []; + this._.log("creating instances of ", this.objName, this.patch.instancing.numCycles(), this._instances.length); + this._instances.length = this.patch.instancing.numCycles(); + + for (i = 0; i < this._instances.length; i++) + { + this._instances[i] = this.patch.createOp(this.objName, true); + this._instances[i].instanced = function () + { + return false; + }; + this._instances[i].uiAttr(this.uiAttribs); + + for (let ipo = 0; ipo < this.portsOut.length; ipo++) + { + if (this.portsOut[ipo].type == CONSTANTS.OP.OP_PORT_TYPE_FUNCTION) + { + this._instances[i].getPortByName(this.portsOut[ipo].name).trigger = this.portsOut[ipo].trigger.bind(this.portsOut[ipo]); + } + } + } + + for (ipi = 0; ipi < this.portsIn.length; ipi++) + { + this.portsIn[ipi].onChange = null; + this.portsIn[ipi].onValueChanged = null; + } + } + + const theTriggerPort = null; + for (ipi = 0; ipi < this.portsIn.length; ipi++) + { + if ( + this.portsIn[ipi].type == CONSTANTS.OP.OP_PORT_TYPE_VALUE || + this.portsIn[ipi].type == CONSTANTS.OP.OP_PORT_TYPE_ARRAY + ) + { + this._instances[this.patch.instancing.index()].portsIn[ipi].set(this.portsIn[ipi].get()); + } + if (this.portsIn[ipi].type == CONSTANTS.OP.OP_PORT_TYPE_FUNCTION) + { + // if(this._instances[ this.patch.instancing.index() ].portsIn[ipi].name==triggerPort.name) + // theTriggerPort=this._instances[ this.patch.instancing.index() ].portsIn[ipi]; + } + } + + if (theTriggerPort) theTriggerPort.onTriggered(); + + for (ipi = 0; ipi < this.portsOut.length; ipi++) + { + if (this.portsOut[ipi].type == CONSTANTS.OP.OP_PORT_TYPE_VALUE) + { + this.portsOut[ipi].set(this._instances[this.patch.instancing.index()].portsOut[ipi].get()); + } + } + + return true; + }; + + // todo: check instancing stuff? + Op.prototype.initInstancable = function () + { + // if(this.isInstanced) + // { + // console.log('cancel instancing'); + // return; + // } + // this._instances=[]; + // for(var ipi=0;ipi { cb(this._patch); this.emitEvent("finishedAll"); }, 100); + } + } + + if (!this._wasFinishedPrinted) + { + this._wasFinishedPrinted = true; + this.print(); + } + this.emitEvent("finishedAll"); + } +}; + +LoadingStatus.prototype.getList = function () +{ + let arr = []; + for (const i in this._loadingAssets) + { + arr.push(this._loadingAssets[i]); + } + + return arr; +}; + + +LoadingStatus.prototype.getListJobs = function () +{ + let arr = []; + for (const i in this._loadingAssets) + { + if (!this._loadingAssets[i].finished)arr.push(this._loadingAssets[i].name); + } + + return arr; +}; + +LoadingStatus.prototype.print = function () +{ + if (this._patch.config.silent) return; + + const rows = []; + + for (const i in this._loadingAssets) + { + rows.push([ + this._loadingAssets[i].order, + this._loadingAssets[i].type, + this._loadingAssets[i].name, + (this._loadingAssets[i].timeEnd - this._loadingAssets[i].timeStart) / 1000 + "s", + ]); + } + + this._log.groupCollapsed( + "finished loading " + this._order + " assets in " + (Date.now() - this._startTime) / 1000 + "s", + ); + this._log.table(rows); + this._log.groupEnd(); +}; + +LoadingStatus.prototype.finished = function (id) +{ + const l = this._loadingAssets[id]; + if (l) + { + if (l.finished) this._log.warn("loading job was already finished", l); + + if (l.op) l.op.setUiAttribs({ "loading": false }); + l.finished = true; + l.timeEnd = Date.now(); + } + + this.checkStatus(); + this.emitEvent("finishedTask"); +}; + +LoadingStatus.prototype._startAssetTasks = function () +{ + for (let i = 0; i < this._assetTasks.length; i++) this._assetTasks[i](); + this._assetTasks.length = 0; +}; + +/** + * delay an asset loading task, mainly to wait for ui to be finished loading and showing, and only then start loading assets + * @function addAssetLoadingTask + * @instance + * @memberof Op + * @param {function} callback + */ +LoadingStatus.prototype.addAssetLoadingTask = function (cb) +{ + if (this._patch.isEditorMode() && !CABLES.UI.loaded) + { + this._assetTasks.push(cb); + + if (!this._loadingAssetTaskCb)window.gui.addEventListener("uiloaded", this._startAssetTasks.bind(this)); + this._loadingAssetTaskCb = true; + } + else + { + cb(); + } + this.emitEvent("addAssetTask"); +}; + +LoadingStatus.prototype.existByName = function (name) +{ + for (let i in this._loadingAssets) + { + if (this._loadingAssets[i].name == name && !this._loadingAssets[i].finished) + { + return true; + } + } +}; + +LoadingStatus.prototype.start = function (type, name, op) +{ + if (this._startTime == 0) this._startTime = Date.now(); + const id = generateUUID(); + + if (op)op.setUiAttribs({ "loading": true }); + + this._loadingAssets[id] = { + "id": id, + "op": op, + "type": type, + "name": name, + "finished": false, + "timeStart": Date.now(), + "order": this._order, + }; + this._order++; + + this.emitEvent("startTask"); + + return id; +}; + + + +;// CONCATENATED MODULE: ./src/core/instancing.js +// todo: needs to be removed... + +const Instancing = function () +{ + this._loops = []; + this._indizes = []; + this._index = 0; +}; + +Instancing.prototype.pushLoop = function (maxNum) +{ + this._loops.push(Math.abs(Math.floor(maxNum))); + this._indizes.push(this._index); +}; + +Instancing.prototype.popLoop = function () +{ + this._loops.pop(); + // this._index--; + this._index = this._indizes.pop(); + if (this._loops.length === 0) this._index = 0; +}; + +Instancing.prototype.numLoops = function () +{ + return this._loops.length; +}; + +Instancing.prototype.numCycles = function () +{ + if (this._loops.length === 0) return 0; + let num = this._loops[0]; + for (let i = 1; i < this._loops.length; i++) num *= this._loops[i]; + + return num; +}; + +Instancing.prototype.inLoop = function () +{ + return this._loops.length > 0; +}; + +Instancing.prototype.increment = function () +{ + this._index++; +}; + +Instancing.prototype.index = function () +{ + return this._index; +}; + + + +;// CONCATENATED MODULE: ./src/core/timer.js + + +/** @namespace CABLES */ + +const internalNow = function () +{ + return window.performance.now(); +}; + +/** + * current time in milliseconds + * @memberof CABLES + * @function now + * @static + */ +const now = function () +{ + return internalNow(); +}; + +// ---------------------------- + +/** + * Measuring time + * @external CABLES + * @namespace Timer + * @hideconstructor + * @class + */ +const Timer = function () +{ + EventTarget.apply(this); + + this._timeStart = internalNow(); + this._timeOffset = 0; + + this._currentTime = 0; + this._lastTime = 0; + this._paused = true; + this._delay = 0; + this.overwriteTime = -1; +}; + + +Timer.prototype._internalNow = function () +{ + if (this._ts) return this._ts; + return internalNow(); +}; + +Timer.prototype._getTime = function () +{ + this._lastTime = (this._internalNow() - this._timeStart) / 1000; + return this._lastTime + this._timeOffset; +}; + +Timer.prototype.setDelay = function (d) +{ + this._delay = d; + this.emitEvent("timeChange"); +}; + +/** + * @function + * @memberof Timer + * @instance + * @description returns true if timer is playing + * @return {Boolean} value + */ +Timer.prototype.isPlaying = function () +{ + return !this._paused; +}; + +/** + * @function + * @memberof Timer + * @instance + * @description update timer + * @return {Number} time + */ +Timer.prototype.update = function (ts) +{ + if (ts) this._ts = ts; + if (this._paused) return; + this._currentTime = this._getTime(); + + return this._currentTime; +}; + +/** + * @function + * @memberof Timer + * @instance + * @return {Number} time in milliseconds + */ +Timer.prototype.getMillis = function () +{ + return this.get() * 1000; +}; + +/** + * @function + * @memberof Timer + * @instance + * @return {Number} value time in seconds + */ +Timer.prototype.get = Timer.prototype.getTime = function () +{ + if (this.overwriteTime >= 0) return this.overwriteTime - this._delay; + return this._currentTime - this._delay; +}; + +/** + * toggle between play/pause state + * @function + * @memberof Timer + * @instance + */ +Timer.prototype.togglePlay = function () +{ + if (this._paused) this.play(); + else this.pause(); +}; + +/** + * set current time + * @function + * @memberof Timer + * @instance + * @param {Number} t + */ +Timer.prototype.setTime = function (t) +{ + if (isNaN(t) || t < 0) t = 0; + this._timeStart = this._internalNow(); + this._timeOffset = t; + this._currentTime = t; + this.emitEvent("timeChange"); +}; + +Timer.prototype.setOffset = function (val) +{ + if (this._currentTime + val < 0) + { + this._timeStart = this._internalNow(); + this._timeOffset = 0; + this._currentTime = 0; + } + else + { + this._timeOffset += val; + this._currentTime = this._lastTime + this._timeOffset; + } + this.emitEvent("timeChange"); +}; + +/** + * (re)starts the timer + * @function + * @memberof Timer + * @instance + */ +Timer.prototype.play = function () +{ + this._timeStart = this._internalNow(); + this._paused = false; + this.emitEvent("playPause"); +}; + +/** + * pauses the timer + * @function + * @memberof Timer + * @instance + */ +Timer.prototype.pause = function () +{ + this._timeOffset = this._currentTime; + this._paused = true; + this.emitEvent("playPause"); +}; + + + +;// CONCATENATED MODULE: ./src/core/core_profiler.js + + +class Profiler +{ + constructor(patch) + { + this.startFrame = patch.getFrameNum(); + this.items = {}; + this.currentId = null; + this.currentStart = 0; + this._patch = patch; + } + + getItems() + { + return this.items; + } + + clear() + { + if (this.paused) return; + this.items = {}; + } + + togglePause() + { + this.paused = !this.paused; + if (!this.paused) + { + this.items = {}; + this.currentStart = performance.now(); + } + } + + add(type, object) + { + if (this.paused) return; + + if (this.currentId !== null) + { + if (!object || object.id != this.currentId) + { + if (this.items[this.currentId]) + { + this.items[this.currentId].timeUsed += performance.now() - this.currentStart; + + if (!this.items[this.currentId].peakTime || now() - this.items[this.currentId].peakTime > 5000) + { + this.items[this.currentId].peak = 0; + this.items[this.currentId].peakTime = now(); + } + this.items[this.currentId].peak = Math.max(this.items[this.currentId].peak, performance.now() - this.currentStart); + } + } + } + + if (object !== null) + { + if (!this.items[object.id]) + { + this.items[object.id] = { + "numTriggers": 0, + "timeUsed": 0, + }; + } + + if (this.items[object.id].lastFrame != this._patch.getFrameNum()) this.items[object.id].numTriggers = 0; + + this.items[object.id].lastFrame = this._patch.getFrameNum(); + this.items[object.id].numTriggers++; + this.items[object.id].opid = object.op.id; + this.items[object.id].title = object.op.name + "." + object.name; + this.items[object.id].subPatch = object.op.uiAttribs.subPatch; + + this.currentId = object.id; + this.currentStart = performance.now(); + } + else + { + this.currentId = null; + } + } + + print() + { + console.log("--------"); + for (const i in this.items) + { + console.log(this.items[i].title + ": " + this.items[i].numTriggers + " / " + this.items[i].timeUsed); + } + } +} + + + +;// CONCATENATED MODULE: ./src/core/cgl/constants.js +const SHADER = { + // default attributes + "SHADERVAR_VERTEX_POSITION": "vPosition", + "SHADERVAR_VERTEX_NUMBER": "attrVertIndex", + "SHADERVAR_VERTEX_NORMAL": "attrVertNormal", + "SHADERVAR_VERTEX_TEXCOORD": "attrTexCoord", + "SHADERVAR_INSTANCE_MMATRIX": "instMat", + "SHADERVAR_VERTEX_COLOR": "attrVertColor", + + "SHADERVAR_INSTANCE_INDEX": "instanceIndex", + + // default uniforms + "SHADERVAR_UNI_PROJMAT": "projMatrix", + "SHADERVAR_UNI_VIEWMAT": "viewMatrix", + "SHADERVAR_UNI_MODELMAT": "modelMatrix", + "SHADERVAR_UNI_NORMALMAT": "normalMatrix", + "SHADERVAR_UNI_INVVIEWMAT": "inverseViewMatrix", + "SHADERVAR_UNI_INVPROJMAT": "invProjMatrix", + "SHADERVAR_UNI_MATERIALID": "materialId", + "SHADERVAR_UNI_OBJECTID": "objectId", + + "SHADERVAR_UNI_VIEWPOS": "camPos", +}; + + +const BLEND_MODES = { + "BLEND_NONE": 0, + "BLEND_NORMAL": 1, + "BLEND_ADD": 2, + "BLEND_SUB": 3, + "BLEND_MUL": 4, +}; + + + + + +const RAD2DEG = 180.0 / Math.PI; +const DEG2RAD = Math.PI / 180.0; + +const constants_CONSTANTS = { + "MATH": { + "DEG2RAD": DEG2RAD, + "RAD2DEG": RAD2DEG, + }, + "SHADER": SHADER, + "BLEND_MODES": BLEND_MODES, +}; + + + + +;// CONCATENATED MODULE: ./src/core/cg/cg_uniform.js + + + +class CgUniform +{ + constructor(__shader, __type, __name, _value, _port2, _port3, _port4, _structUniformName, _structName, _propertyName) + { + this._log = new Logger("cg_uniform"); + this._type = __type; + this._name = __name; + this._shader = __shader; + this._value = 0.00001; + this._oldValue = null; + this._port = null; + this._structName = _structName; + this._structUniformName = _structUniformName; + this._propertyName = _propertyName; + + this._shader._addUniform(this); + this.needsUpdate = true; + this.shaderType = null; + this.comment = null; + + if (__type == "f") + { + this.set = this.setValue = this.setValueF.bind(this); + this.updateValue = this.updateValueF.bind(this); + } + else if (__type == "f[]") + { + this.set = this.setValue = this.setValueArrayF.bind(this); + this.updateValue = this.updateValueArrayF.bind(this); + } + else if (__type == "2f[]") + { + this.set = this.setValue = this.setValueArray2F.bind(this); + this.updateValue = this.updateValueArray2F.bind(this); + } + else if (__type == "3f[]") + { + this.set = this.setValue = this.setValueArray3F.bind(this); + this.updateValue = this.updateValueArray3F.bind(this); + } + else if (__type == "4f[]") + { + this.set = this.setValue = this.setValueArray4F.bind(this); + this.updateValue = this.updateValueArray4F.bind(this); + } + else if (__type == "i") + { + this.set = this.setValue = this.setValueI.bind(this); + this.updateValue = this.updateValueI.bind(this); + } + else if (__type == "2i") + { + this.set = this.setValue = this.setValue2I.bind(this); + this.updateValue = this.updateValue2I.bind(this); + } + else if (__type == "3i") + { + this.set = this.setValue = this.setValue3I.bind(this); + this.updateValue = this.updateValue3I.bind(this); + } + else if (__type == "4i") + { + this.set = this.setValue = this.setValue4I.bind(this); + this.updateValue = this.updateValue4I.bind(this); + } + else if (__type == "b") + { + this.set = this.setValue = this.setValueBool.bind(this); + this.updateValue = this.updateValueBool.bind(this); + } + else if (__type == "4f") + { + this.set = this.setValue = this.setValue4F.bind(this); + this.updateValue = this.updateValue4F.bind(this); + } + else if (__type == "3f") + { + this.set = this.setValue = this.setValue3F.bind(this); + this.updateValue = this.updateValue3F.bind(this); + } + else if (__type == "2f") + { + this.set = this.setValue = this.setValue2F.bind(this); + this.updateValue = this.updateValue2F.bind(this); + } + else if (__type == "t") + { + this.set = this.setValue = this.setValueT.bind(this); + this.updateValue = this.updateValueT.bind(this); + } + else if (__type == "tc") + { + this.set = this.setValue = this.setValueT.bind(this); + this.updateValue = this.updateValueT.bind(this); + } + else if (__type == "t[]") + { + this.set = this.setValue = this.setValueArrayT.bind(this); + this.updateValue = this.updateValueArrayT.bind(this); + } + else if (__type == "m4" || __type == "m4[]") + { + this.set = this.setValue = this.setValueM4.bind(this); + this.updateValue = this.updateValueM4.bind(this); + } + else throw new Error("Unknown uniform type"); + + if (typeof _value == "object" && _value instanceof Port) + { + this._port = _value; + this._value = this._port.get(); + + + if (_port2 && _port3 && _port4) + { + if (!(_port2 instanceof Port) || !(_port3 instanceof Port) || !(_port4 instanceof Port)) + { + this._log.error("[cgl_uniform] mixed port/value parameter for vec4 ", this._name); + } + + this._value = [0, 0, 0, 0]; + this._port2 = _port2; + this._port3 = _port3; + this._port4 = _port4; + + this._port.on("change", this.updateFromPort4f.bind(this)); + this._port2.on("change", this.updateFromPort4f.bind(this)); + this._port3.on("change", this.updateFromPort4f.bind(this)); + this._port4.on("change", this.updateFromPort4f.bind(this)); + + // this._port.onChange = this._port2.onChange = this._port3.onChange = this._port4.onChange = this.updateFromPort4f.bind(this); + this.updateFromPort4f(); + } + else if (_port2 && _port3) + { + if (!(_port2 instanceof Port) || !(_port3 instanceof Port)) + { + this._log.error("[cgl_uniform] mixed port/value parameter for vec4 ", this._name); + } + + this._value = [0, 0, 0]; + this._port2 = _port2; + this._port3 = _port3; + // this._port.onChange = this._port2.onChange = this._port3.onChange = this.updateFromPort3f.bind(this); + this._port.on("change", this.updateFromPort3f.bind(this)); + this._port2.on("change", this.updateFromPort3f.bind(this)); + this._port3.on("change", this.updateFromPort3f.bind(this)); + + this.updateFromPort3f(); + } + else if (_port2) + { + if (!(_port2 instanceof Port)) + { + this._log.error("[cgl_uniform] mixed port/value parameter for vec4 ", this._name); + } + + this._value = [0, 0]; + this._port2 = _port2; + // this._port.onChange = this._port2.onChange = this.updateFromPort2f.bind(this); + this._port.on("change", this.updateFromPort2f.bind(this)); + this._port2.on("change", this.updateFromPort2f.bind(this)); + + this.updateFromPort2f(); + } + else + { + // this._port.on = this.updateFromPort.bind(this); + this._port.on("change", this.updateFromPort.bind(this)); + } + } + else this._value = _value; + + this.setValue(this._value); + this.needsUpdate = true; + } + + + getType() + { + return this._type; + } + + getName() + { + return this._name; + } + + getValue() + { + return this._value; + } + + getShaderType() + { + return this.shaderType; + } + + isStructMember() + { + return !!this._structName; + } + + + updateFromPort4f() + { + this._value[0] = this._port.get(); + this._value[1] = this._port2.get(); + this._value[2] = this._port3.get(); + this._value[3] = this._port4.get(); + this.setValue(this._value); + } + + updateFromPort3f() + { + this._value[0] = this._port.get(); + this._value[1] = this._port2.get(); + this._value[2] = this._port3.get(); + this.setValue(this._value); + } + + updateFromPort2f() + { + this._value[0] = this._port.get(); + this._value[1] = this._port2.get(); + this.setValue(this._value); + } + + updateFromPort() + { + this.setValue(this._port.get()); + } +} + +/* harmony default export */ const cg_uniform = (CgUniform); + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_shader_uniform.js + + + + +/** + * Shader uniforms + * + * types: + *
    + * f    - float
    + * 2f   - vec2
    + * 3f   - vec3
    + * 4f   - vec4
    + * i    - integer
    + * t    - texture
    + * m4   - mat4, 4x4 float matrix
    + * f[]  - array of floats
    + * 2f[] - array of float vec2
    + * 3f[] - array of float vec3
    + * 4f[] - array of float vec4
    + * 
    + * + * @external CGL + * @namespace Uniform + * @class + * @param {Shader} shader + * @param {String} [type=f] + * @param {String} name + * @param {Number|Port} value can be a Number,Matrix or Port + * @example + * // bind float uniform called myfloat and initialize with value 1.0 + * const unir=new CGL.Uniform(shader,'f','myfloat',1.0); + * unir.setValue(1.0); + * + * // bind float uniform called myfloat and automatically set it to input port value + * const myPort=op.inFloat("input"); + * const pv=new CGL.Uniform(shader,'f','myfloat',myPort); + * + */ + + +// export const Uniform(__shader, __type, __name, _value, _port2, _port3, _port4, _structUniformName, _structName, _propertyName) + +class Uniform extends cg_uniform +{ + constructor(__shader, __type, __name, _value, _port2, _port3, _port4, _structUniformName, _structName, _propertyName) + { + super(__shader, __type, __name, _value, _port2, _port3, _port4, _structUniformName, _structName, _propertyName); + this._loc = -1; + this._cgl = __shader._cgl; + } + + get name() + { + return this._name; + } + + copy(newShader) + { + const uni = new Uniform(newShader, this._type, this._name, this._value, this._port2, this._port3, this._port4, this._structUniformName, this._structName, this._propertyName); + uni.shaderType = this.shaderType; + return uni; + } + + /** + * returns type as glsl type string. e.g. 'f' returns 'float' + * @function getGlslTypeString + * @memberof Uniform + * @instance + * @return {string} type as string + */ + getGlslTypeString() + { + return Uniform.glslTypeString(this._type); + } + + _isValidLoc() + { + return this._loc != -1;// && this._loc != null; + } + + resetLoc() + { + this._loc = -1; + this.needsUpdate = true; + } + + bindTextures() {} + + getLoc() + { + return this._loc; + } + + updateFromPort4f() + { + this._value[0] = this._port.get(); + this._value[1] = this._port2.get(); + this._value[2] = this._port3.get(); + this._value[3] = this._port4.get(); + this.setValue(this._value); + } + + updateFromPort3f() + { + this._value[0] = this._port.get(); + this._value[1] = this._port2.get(); + this._value[2] = this._port3.get(); + this.setValue(this._value); + } + + updateFromPort2f() + { + this._value[0] = this._port.get(); + this._value[1] = this._port2.get(); + this.setValue(this._value); + } + + updateFromPort() + { + this.setValue(this._port.get()); + } + + updateValueF() + { + if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + else this.needsUpdate = false; + + this._shader.getCgl().gl.uniform1f(this._loc, this._value); + this._cgl.profileData.profileUniformCount++; + } + + setValueF(v) + { + if (v != this._value) + { + this.needsUpdate = true; + this._value = v; + } + } + + updateValueI() + { + if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + else this.needsUpdate = false; + + this._shader.getCgl().gl.uniform1i(this._loc, this._value); + this._cgl.profileData.profileUniformCount++; + } + + updateValue2I() + { + if (!this._value) return; + + if (!this._isValidLoc()) + { + this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + this._cgl.profileData.profileShaderGetUniform++; + this._cgl.profileData.profileShaderGetUniformName = this._name; + } + + this._shader.getCgl().gl.uniform2i(this._loc, this._value[0], this._value[1]); + + this.needsUpdate = false; + this._cgl.profileData.profileUniformCount++; + } + + updateValue3I() + { + if (!this._value) return; + if (!this._isValidLoc()) + { + this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + this._cgl.profileData.profileShaderGetUniform++; + this._cgl.profileData.profileShaderGetUniformName = this._name; + } + + this._shader.getCgl().gl.uniform3i(this._loc, this._value[0], this._value[1], this._value[2]); + this.needsUpdate = false; + this._cgl.profileData.profileUniformCount++; + } + + updateValue4I() + { + if (!this._isValidLoc()) + { + this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + this._cgl.profileData.profileShaderGetUniform++; + this._cgl.profileData.profileShaderGetUniformName = this._name; + } + this._shader.getCgl().gl.uniform4i(this._loc, this._value[0], this._value[1], this._value[2], this._value[3]); + this._cgl.profileData.profileUniformCount++; + } + + setValueI(v) + { + if (v != this._value) + { + this.needsUpdate = true; + this._value = v; + } + } + + setValue2I(v) + { + if (!v) return; + if (!this._oldValue) + { + this._oldValue = [v[0] - 1, 1]; + this.needsUpdate = true; + } + else if (v[0] != this._oldValue[0] || v[1] != this._oldValue[1]) + { + this._oldValue[0] = v[0]; + this._oldValue[1] = v[1]; + this.needsUpdate = true; + } + + this._value = v; + } + + setValue3I(v) + { + if (!v) return; + if (!this._oldValue) + { + this._oldValue = [v[0] - 1, 1, 2]; + this.needsUpdate = true; + } + else if (v[0] != this._oldValue[0] || v[1] != this._oldValue[1] || v[2] != this._oldValue[2]) + { + this._oldValue[0] = v[0]; + this._oldValue[1] = v[1]; + this._oldValue[2] = v[2]; + this.needsUpdate = true; + } + + this._value = v; + } + + setValue4I(v) + { + this.needsUpdate = true; + this._value = v || vec4.create(); + } + + updateValueBool() + { + if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + else this.needsUpdate = false; + this._shader.getCgl().gl.uniform1i(this._loc, this._value ? 1 : 0); + + this._cgl.profileData.profileUniformCount++; + } + + setValueBool(v) + { + if (v != this._value) + { + this.needsUpdate = true; + this._value = v; + } + } + + setValueArray4F(v) + { + this.needsUpdate = true; + this._value = v; + } + + updateValueArray4F() + { + if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + else this.needsUpdate = false; + + if (!this._value) return; + this._shader.getCgl().gl.uniform4fv(this._loc, this._value); + this._cgl.profileData.profileUniformCount++; + } + + setValueArray3F(v) + { + this.needsUpdate = true; + this._value = v; + } + + updateValueArray3F() + { + if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + else this.needsUpdate = false; + + if (!this._value) return; + this._shader.getCgl().gl.uniform3fv(this._loc, this._value); + this._cgl.profileData.profileUniformCount++; + } + + setValueArray2F(v) + { + this.needsUpdate = true; + this._value = v; + } + + updateValueArray2F() + { + if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + else this.needsUpdate = false; + + if (!this._value) return; + this._shader.getCgl().gl.uniform2fv(this._loc, this._value); + this._cgl.profileData.profileUniformCount++; + } + + setValueArrayF(v) + { + this.needsUpdate = true; + this._value = v; + } + + updateValueArrayF() + { + if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + else this.needsUpdate = false; + + if (!this._value) return; + this._shader.getCgl().gl.uniform1fv(this._loc, this._value); + this._cgl.profileData.profileUniformCount++; + } + + setValueArrayT(v) + { + this.needsUpdate = true; + this._value = v; + } + + + updateValue3F() + { + if (!this._value) return; + if (!this._isValidLoc()) + { + this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + this._cgl.profileData.profileShaderGetUniform++; + this._cgl.profileData.profileShaderGetUniformName = this._name; + } + + this._shader.getCgl().gl.uniform3f(this._loc, this._value[0], this._value[1], this._value[2]); + this.needsUpdate = false; + this._cgl.profileData.profileUniformCount++; + } + + setValue3F(v) + { + if (!v) return; + if (!this._oldValue) + { + this._oldValue = [v[0] - 1, 1, 2]; + this.needsUpdate = true; + } + else if (v[0] != this._oldValue[0] || v[1] != this._oldValue[1] || v[2] != this._oldValue[2]) + { + this._oldValue[0] = v[0]; + this._oldValue[1] = v[1]; + this._oldValue[2] = v[2]; + this.needsUpdate = true; + } + + this._value = v; + } + + updateValue2F() + { + if (!this._value) return; + + if (!this._isValidLoc()) + { + this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + this._cgl.profileData.profileShaderGetUniform++; + this._cgl.profileData.profileShaderGetUniformName = this._name; + } + + this._shader.getCgl().gl.uniform2f(this._loc, this._value[0], this._value[1]); + this.needsUpdate = false; + this._cgl.profileData.profileUniformCount++; + } + + setValue2F(v) + { + if (!v) return; + if (!this._oldValue) + { + this._oldValue = [v[0] - 1, 1]; + this.needsUpdate = true; + } + else if (v[0] != this._oldValue[0] || v[1] != this._oldValue[1]) + { + this._oldValue[0] = v[0]; + this._oldValue[1] = v[1]; + this.needsUpdate = true; + } + this._value = v; + } + + updateValue4F() + { + if (!this._isValidLoc()) + { + this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + this._cgl.profileData.profileShaderGetUniform++; + this._cgl.profileData.profileShaderGetUniformName = this._name; + } + + if (!this._value) + { + this._log.warn("no value for uniform", this._name, this); + this._value = [0, 0, 0, 0]; + } + + this.needsUpdate = false; + this._shader.getCgl().gl.uniform4f(this._loc, this._value[0], this._value[1], this._value[2], this._value[3]); + this._cgl.profileData.profileUniformCount++; + } + + setValue4F(v) + { + if (typeof this.value == "number") this.value = vec4.create(); // this should not be needed, but somehow it crashes with some shadermods + + if (!v) return; + if (!this._oldValue) + { + this._oldValue = [v[0] - 1, 1, 2, 3]; + this.needsUpdate = true; + } + else if (v[0] != this._oldValue[0] || v[1] != this._oldValue[1] || v[2] != this._oldValue[2] || v[3] != this._oldValue[3]) + { + this._oldValue[0] = v[0]; + this._oldValue[1] = v[1]; + this._oldValue[2] = v[2]; + this.needsUpdate = true; + } + + this._value = v; + } + + updateValueM4() + { + if (!this._isValidLoc()) + { + this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + this._cgl.profileData.profileShaderGetUniform++; + this._cgl.profileData.profileShaderGetUniformName = this._name; + } + if (!this._value || this._value.length % 16 != 0) return console.log("this.name", this._name, this._value); + + this._shader.getCgl().gl.uniformMatrix4fv(this._loc, false, this._value); + this._cgl.profileData.profileUniformCount++; + } + + setValueM4(v) + { + this.needsUpdate = true; + this._value = v || mat4.create(); + } + + updateValueArrayT() + { + if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + else this.needsUpdate = false; + + if (!this._value) return; + this._shader.getCgl().gl.uniform1iv(this._loc, this._value); + this._cgl.profileData.profileUniformCount++; + } + + updateValueT() + { + if (!this._isValidLoc()) + { + this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name); + this._cgl.profileData.profileShaderGetUniform++; + this._cgl.profileData.profileShaderGetUniformName = this._name; + } + + this._cgl.profileData.profileUniformCount++; + this._shader.getCgl().gl.uniform1i(this._loc, this._value); + this.needsUpdate = false; + } + + setValueT(v) + { + this.needsUpdate = true; + this._value = v; + } +} + + +Uniform.glslTypeString = (t) => +{ + if (t == "f") return "float"; + if (t == "b") return "bool"; + if (t == "i") return "int"; + if (t == "2i") return "ivec2"; + if (t == "2f") return "vec2"; + if (t == "3f") return "vec3"; + if (t == "4f") return "vec4"; + if (t == "m4") return "mat4"; + + if (t == "t") return "sampler2D"; + if (t == "tc") return "samplerCube"; + + if (t == "3f[]") return null; // ignore this for now... + if (t == "m4[]") return null; // ignore this for now... + if (t == "f[]") return null; // ignore this for now... + + console.warn("[CGL UNIFORM] unknown glsl type string ", t); +}; + + +/** + * @function setValue + * @memberof Uniform + * @instance + * @param {Number|Array|Matrix|Texture} value + */ + + + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_texture.js + + + + + +const DEFAULT_TEXTURE_SIZE = 8; + +/** + * A Texture + * @external CGL + * @namespace Texture + * @constructor + * @param {Context} cgl + * @param {Object} [options] + * @hideconstructor + * @class + * @example + * // generate a 256x256 pixel texture of random colors + * const size=256; + * const data = new Uint8Array(size*size*4); + * + * for(var x=0;x this._cgl.maxTexSize || h > this._cgl.maxTexSize) this._log.error("texture size too big! " + w + "x" + h + " / max: " + this._cgl.maxTexSize); + + w = Math.min(w, this._cgl.maxTexSize); + h = Math.min(h, this._cgl.maxTexSize); + + w = Math.floor(w); + h = Math.floor(h); + if (this.width == w && this.height == h) return; + + w = this._cgl.checkTextureSize(w); + h = this._cgl.checkTextureSize(h); + + this.width = w; + this.height = h; + this.deleted = false; + + this.setFormat(Texture.setUpGlPixelFormat(this._cgl, this.pixelFormat)); + + this.shortInfoString = this.getInfoOneLine();// w + "x" + h + ""; + + this._cgl.gl.bindTexture(this.texTarget, this.tex); + this._cgl.profileData.profileTextureResize++; + + const uarr = null; + + this._cgl.gl.texImage2D(this.texTarget, 0, this._glInternalFormat, w, h, 0, this._glDataFormat, this._glDataType, uarr); + + this._setFilter(); + + this.updateMipMap(); + + this._cgl.gl.bindTexture(this.texTarget, null); +}; + + +/** + * @function initFromData + * @memberof Texture + * @instance + * @description create texturem from rgb data + * @param {Array} data rgb color array [r,g,b,a,r,g,b,a,...] + * @param {Number} width + * @param {Number} height + * @param {Number} filter + * @param {Number} wrap + */ +Texture.prototype.initFromData = function (data, w, h, filter, wrap) +{ + this.filter = filter; + this.wrap = wrap; + if (filter == undefined) this.filter = Texture.FILTER_LINEAR; + if (wrap == undefined) this.wrap = Texture.WRAP_CLAMP_TO_EDGE; + this.width = w; + this.height = h; + this._fromData = true; + this.deleted = false; + + if (this.height > this._cgl.maxTexSize || this.width > this._cgl.maxTexSize) + { + const t = CGL.Texture.getTempTexture(this._cgl); + this.width = t.width; + this.height = t.height; + this.tex = t.tex; + this._log.error("[cgl_texture] texture size to big!!!", this.width, this.height, this._cgl.maxTexSize); + return; + } + + if (this.flip) this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_FLIP_Y_WEBGL, this.flip); + + this._cgl.gl.bindTexture(this.texTarget, this.tex); + + this.setFormat(Texture.setUpGlPixelFormat(this._cgl, this.pixelFormat)); + + this._cgl.gl.texImage2D(this.texTarget, 0, this._glInternalFormat, w, h, 0, this._glDataFormat, this._glDataType, data); + + this._setFilter(); + this.updateMipMap(); + + if (this.flip) this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_FLIP_Y_WEBGL, false); + this._cgl.gl.bindTexture(this.texTarget, null); +}; + +Texture.prototype.updateMipMap = function () +{ + if ((this._cgl.glVersion == 2 || this.isPowerOfTwo()) && this.filter == Texture.FILTER_MIPMAP) + { + this._cgl.gl.generateMipmap(this.texTarget); + this._cgl.profileData.profileGenMipMap++; + } +}; + +/** + * set texture data from an image/canvas object + * @function initTexture + * @memberof Texture + * @instance + * @param {Object} image + * @param {Number} filter + */ +Texture.prototype.initTexture = function (img, filter) +{ + this._cgl.printError("before initTexture"); + this._cgl.checkFrameStarted("texture inittexture"); + this._fromData = false; + + this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.unpackAlpha); + if (img.width || img.videoWidth) this.width = img.videoWidth || img.width; + if (img.height || img.videoHeight) this.height = img.videoHeight || img.height; + + if (filter !== undefined) this.filter = filter; // todo: can we remove this filter param? + + if (img.height > this._cgl.maxTexSize || img.width > this._cgl.maxTexSize) + { + const t = CGL.Texture.getTempTexture(this._cgl); + this.width = t.width; + this.height = t.height; + this.tex = t.tex; + this._log.error("[cgl_texture] texture size to big!!!", img.width, img.height, this._cgl.maxTexSize); + return; + } + + + // console.log("loaded texture", img.width, img.height); + + this._cgl.gl.bindTexture(this.texTarget, this.tex); + + this.deleted = false; + this.flipped = !this.flip; + if (this.flipped) this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_FLIP_Y_WEBGL, this.flipped); + + + this.setFormat(Texture.setUpGlPixelFormat(this._cgl, this.pixelFormat)); + + this._cgl.gl.texImage2D(this.texTarget, 0, this._glInternalFormat, this._glDataFormat, this._glDataType, img); + // this._cgl.gl.texImage2D(this.texTarget, 0, this._cgl.gl.RGBA, this._cgl.gl.RGBA, this._cgl.gl.UNSIGNED_BYTE, img); + + // if (this._cgl.printError("[cgl_texture] init " + this.name)); + + this._setFilter(); + this.updateMipMap(); + + // if (this._cgl.printError("[cgl_texture] init2")); + + this._cgl.gl.bindTexture(this.texTarget, null); + this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); + if (this.flipped) this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_FLIP_Y_WEBGL, false); + + this.getInfoOneLine(); + this._cgl.printError("initTexture"); +}; + +/** + * delete texture. use this when texture is no longer needed + * @function delete + * @memberof Texture + * @instance + */ +Texture.prototype.dispose = +Texture.prototype.delete = function () +{ + if (this.loading) + { + // cant delete texture when still loading + // setTimeout(this.delete.bind(this), 50); + return; + } + + this.deleted = true; + this.width = 0; + this.height = 0; + this._cgl.profileData.profileTextureDelete++; + this._cgl.gl.deleteTexture(this.tex); + this.image = null; + + this.tex = null; +}; + +/** + * @function isPowerOfTwo + * @memberof Texture + * @instance + * @description return true if texture width and height are both power of two + * @return {Boolean} + */ +Texture.prototype.isPowerOfTwo = function () +{ + return Texture.isPowerOfTwo(this.width) && Texture.isPowerOfTwo(this.height); +}; + +Texture.prototype.printInfo = function () +{ + console.log(this.getInfo()); +}; + +Texture.prototype.getInfoReadable = function () +{ + const info = this.getInfo(); + let html = ""; + + info.name = info.name.substr(0, info.name.indexOf("?rnd=")); + + for (const i in info) + { + html += "* " + i + ": **" + info[i] + "**\n"; + } + + return html; +}; + +Texture.prototype.getInfoOneLine = function () +{ + let txt = "" + this.width + "x" + this.height; + txt += " "; + // if (this.textureType === CGL.Texture.TYPE_FLOAT) txt += " 32bit"; else txt += " 8bit"; + // if (this.textureType === CGL.Texture.TYPE_FLOAT) txt += " 32bit"; else txt += " 8bit"; + txt += this.pixelFormat; + + if (this.filter === CGL.Texture.FILTER_NEAREST) txt += " nearest"; + if (this.filter === CGL.Texture.FILTER_LINEAR) txt += " linear"; + if (this.filter === CGL.Texture.FILTER_MIPMAP) txt += " mipmap"; + + if (this.wrap === CGL.Texture.WRAP_CLAMP_TO_EDGE) txt += " clamp"; + if (this.wrap === CGL.Texture.WRAP_REPEAT) txt += " repeat"; + if (this.wrap === CGL.Texture.WRAP_MIRRORED_REPEAT) txt += " repeatmir"; + + this.shortInfoString = txt; + + return txt; +}; + +Texture.prototype.getInfoOneLineShort = function () +{ + let txt = "" + this.width + "x" + this.height; + // if (this.textureType === CGL.Texture.TYPE_FLOAT) txt += " 32bit"; else txt += " 8bit"; + txt += " "; + txt += this.pixelFormat; + + this.shortInfoString = txt; + + return txt; +}; + + +Texture.prototype.getInfo = function () +{ + return Texture.getTexInfo(this); +}; + + +Texture.prototype._setFilter = function () +{ + this._cgl.printError("before _setFilter"); + + if (!this._fromData) + { + this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.unpackAlpha); + } + + if (this.shadowMap) + { + this._cgl.gl.texParameteri(this._cgl.gl.TEXTURE_2D, this._cgl.gl.TEXTURE_COMPARE_MODE, this._cgl.gl.COMPARE_REF_TO_TEXTURE); + this._cgl.gl.texParameteri(this._cgl.gl.TEXTURE_2D, this._cgl.gl.TEXTURE_COMPARE_FUNC, this._cgl.gl.LEQUAL); + } + + if (this.textureType == Texture.TYPE_FLOAT && this.filter == Texture.FILTER_MIPMAP) + { + this.filter = Texture.FILTER_LINEAR; + this._log.stack("texture: HDR and mipmap filtering at the same time is not possible"); + } + + if (this._cgl.glVersion == 1 && !this.isPowerOfTwo()) + { + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MAG_FILTER, this._cgl.gl.NEAREST); + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MIN_FILTER, this._cgl.gl.NEAREST); + + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_S, this._cgl.gl.CLAMP_TO_EDGE); + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_T, this._cgl.gl.CLAMP_TO_EDGE); + + this.filter = Texture.FILTER_NEAREST; + this.wrap = Texture.WRAP_CLAMP_TO_EDGE; + } + else + { + if (this.wrap == Texture.WRAP_CLAMP_TO_EDGE) + { + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_S, this._cgl.gl.CLAMP_TO_EDGE); + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_T, this._cgl.gl.CLAMP_TO_EDGE); + } + else if (this.wrap == Texture.WRAP_REPEAT) + { + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_S, this._cgl.gl.REPEAT); + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_T, this._cgl.gl.REPEAT); + } + else if (this.wrap == Texture.WRAP_MIRRORED_REPEAT) + { + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_S, this._cgl.gl.MIRRORED_REPEAT); + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_T, this._cgl.gl.MIRRORED_REPEAT); + } + + if (this.filter == Texture.FILTER_NEAREST) + { + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MAG_FILTER, this._cgl.gl.NEAREST); + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MIN_FILTER, this._cgl.gl.NEAREST); + } + else if (this.filter == Texture.FILTER_LINEAR) + { + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MIN_FILTER, this._cgl.gl.LINEAR); + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MAG_FILTER, this._cgl.gl.LINEAR); + } + else if (this.filter == Texture.FILTER_MIPMAP) + { + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MAG_FILTER, this._cgl.gl.LINEAR); + this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MIN_FILTER, this._cgl.gl.LINEAR_MIPMAP_LINEAR); + } + else + { + this._log.log("unknown texture filter!", this.filter); + throw new Error("unknown texture filter!" + this.filter); + } + + if (this.anisotropic) + { + const ext = this._cgl.enableExtension("EXT_texture_filter_anisotropic"); + + + + if (this._cgl.maxAnisotropic) + { + const aniso = Math.min(this._cgl.maxAnisotropic, this.anisotropic); + this._cgl.gl.texParameterf(this._cgl.gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, aniso); + } + } + } + this.getInfoOneLine(); + this._cgl.printError("_setFilter"); +}; + + +/** + * @function load + * @static + * @memberof Texture + * @description load an image from an url + * @param {Context} cgl + * @param {String} url + * @param {Function} onFinished + * @param {Object} options + * @return {Texture} + */ +Texture.load = function (cgl, url, finishedCallback, settings) +{ + if (!url) return finishedCallback({ "error": true }); + let loadingId = null; + if (!cgl.patch.loading.existByName(url)) loadingId = cgl.patch.loading.start("texture", url); + + const texture = new Texture(cgl); + texture.name = url; + + // texture.pixelFormat = Texture.PFORMATSTR_; + + if (cgl.patch.isEditorMode()) gui.jobs().start({ "id": "loadtexture" + loadingId, "title": "loading texture " + CABLES.basename(url) }); + + texture.image = new Image(); + texture.image.crossOrigin = "anonymous"; + texture.loading = true; + + if (settings && settings.hasOwnProperty("filter")) texture.filter = settings.filter; + if (settings && settings.hasOwnProperty("flip")) texture.flip = settings.flip; + if (settings && settings.hasOwnProperty("wrap")) texture.wrap = settings.wrap; + if (settings && settings.hasOwnProperty("anisotropic")) texture.anisotropic = settings.anisotropic; + if (settings && settings.hasOwnProperty("unpackAlpha")) texture.unpackAlpha = settings.unpackAlpha; + if (settings && settings.hasOwnProperty("pixelFormat")) texture.pixelFormat = settings.pixelFormat; + + texture.image.onabort = texture.image.onerror = (e) => + { + console.warn("[cgl.texture.load] error loading texture", url, e); + texture.loading = false; + if (loadingId) cgl.patch.loading.finished(loadingId); + const error = { "error": true }; + if (finishedCallback) finishedCallback(error, texture); + if (cgl.patch.isEditorMode()) gui.jobs().finish("loadtexture" + loadingId); + }; + + texture.image.onload = function (e) + { + cgl.addNextFrameOnceCallback(() => + { + texture.initTexture(texture.image); + if (loadingId) cgl.patch.loading.finished(loadingId); + texture.loading = false; + if (cgl.patch.isEditorMode()) gui.jobs().finish("loadtexture" + loadingId); + + if (finishedCallback) finishedCallback(null, texture); + }); + }; + texture.image.src = url; + + return texture; +}; + +/** + * @static + * @function getTempTexture + * @memberof Texture + * @description returns the default temporary texture (grey diagonal stipes) + * @param {Context} cgl + * @return {Texture} + */ +Texture.getTempTexture = function (cgl) +{ + if (!cgl) console.error("[getTempTexture] no cgl!"); + if (!cgl.tempTexture) cgl.tempTexture = Texture.getTemporaryTexture(cgl, 256, Texture.FILTER_LINEAR, Texture.REPEAT); + return cgl.tempTexture; +}; + +/** + * @static + * @function getErrorTexture + * @memberof Texture + * @description returns the default temporary texture (grey diagonal stipes) + * @param {Context} cgl + * @return {Texture} + */ +Texture.getErrorTexture = function (cgl) +{ + if (!cgl) console.error("[getTempTexture] no cgl!"); + if (!cgl.errorTexture) cgl.errorTexture = Texture.getTemporaryTexture(cgl, 256, Texture.FILTER_LINEAR, Texture.REPEAT, 1, 0.2, 0.2); + return cgl.errorTexture; +}; + + +/** + * @function getEmptyTexture + * @memberof Texture + * @instance + * @description returns a reference to a small empty (transparent) texture + * @return {Texture} + */ +Texture.getEmptyTexture = function (cgl, fp) +{ + if (fp) return Texture.getEmptyTextureFloat(cgl); + if (!cgl) console.error("[getEmptyTexture] no cgl!"); + if (cgl.tempTextureEmpty) return cgl.tempTextureEmpty; + + cgl.tempTextureEmpty = new Texture(cgl, { "name": "emptyTexture" }); + const data = new Uint8Array(8 * 8 * 4).fill(0); + for (let i = 0; i < 8 * 8 * 4; i += 4) data[i + 3] = 0; + + cgl.tempTextureEmpty.initFromData(data, 8, 8, Texture.FILTER_NEAREST, Texture.WRAP_REPEAT); + + return cgl.tempTextureEmpty; +}; + +/** + * @function getEmptyTextureFloat + * @memberof Texture + * @instance + * @description returns a reference to a small empty (transparent) 32bit texture + * @return {Texture} + */ +Texture.getEmptyTextureFloat = function (cgl) +{ + if (!cgl) console.error("[getEmptyTextureFloat] no cgl!"); + if (cgl.tempTextureEmptyFloat) return cgl.tempTextureEmptyFloat; + + cgl.tempTextureEmptyFloat = new Texture(cgl, { "name": "emptyTexture", "isFloatingPointTexture": true }); + const data = new Float32Array(8 * 8 * 4).fill(1); + for (let i = 0; i < 8 * 8 * 4; i += 4) data[i + 3] = 0; + + cgl.tempTextureEmptyFloat.initFromData(data, 8, 8, Texture.FILTER_NEAREST, Texture.WRAP_REPEAT); + + return cgl.tempTextureEmptyFloat; +}; + + +/** + * @function getRandomTexture + * @memberof Texture + * @static + * @description returns a reference to a random texture + * @return {Texture} + */ +Texture.getRandomTexture = function (cgl) +{ + if (!cgl) console.error("[getRandomTexture] no cgl!"); + if (cgl.randomTexture) return cgl.randomTexture; + + const size = 256; + const data = new Uint8Array(size * size * 4); + + for (let x = 0; x < size * size; x++) + { + data[x * 4 + 0] = Math.random() * 255; + data[x * 4 + 1] = Math.random() * 255; + data[x * 4 + 2] = Math.random() * 255; + data[x * 4 + 3] = 255; + } + + cgl.randomTexture = new Texture(cgl); + cgl.randomTexture.initFromData(data, size, size, Texture.FILTER_NEAREST, Texture.WRAP_REPEAT); + + return cgl.randomTexture; +}; + +/** + * @function getRandomFloatTexture + * @memberof Texture + * @static + * @description returns a reference to a texture containing random numbers between -1 and 1 + * @return {Texture} + */ +Texture.getRandomFloatTexture = function (cgl) +{ + if (!cgl) console.error("[getRandomTexture] no cgl!"); + if (cgl.getRandomFloatTexture) return cgl.getRandomFloatTexture; + + const size = 256; + const data = new Float32Array(size * size * 4); + + for (let x = 0; x < size * size; x++) + { + data[x * 4 + 0] = (Math.random() - 0.5) * 2.0; + data[x * 4 + 1] = (Math.random() - 0.5) * 2.0; + data[x * 4 + 2] = (Math.random() - 0.5) * 2.0; + data[x * 4 + 3] = 1; + } + + cgl.getRandomFloatTexture = new Texture(cgl, { "isFloatingPointTexture": true }); + cgl.getRandomFloatTexture.initFromData(data, size, size, Texture.FILTER_NEAREST, Texture.WRAP_REPEAT); + + return cgl.getRandomFloatTexture; +}; + +/** + * @function getBlackTexture + * @memberof Texture + * @static + * @description returns a reference to a black texture + * @return {Texture} + */ +Texture.getBlackTexture = function (cgl) +{ + if (!cgl) this._log.error("[getBlackTexture] no cgl!"); + if (cgl.blackTexture) return cgl.blackTexture; + + const size = 8; + const data = new Uint8Array(size * size * 4); + + for (let x = 0; x < size * size; x++) + { + data[x * 4 + 0] = data[x * 4 + 1] = data[x * 4 + 2] = 0; + data[x * 4 + 3] = 255; + } + + cgl.blackTexture = new Texture(cgl); + cgl.blackTexture.initFromData(data, size, size, Texture.FILTER_NEAREST, Texture.WRAP_REPEAT); + + return cgl.blackTexture; +}; + + +/** + * @function getEmptyCubemapTexture + * @memberof Texture + * @static + * @description returns an empty cubemap texture with rgba = [0, 0, 0, 0] + * @return {Texture} + */ +Texture.getEmptyCubemapTexture = function (cgl) +{ + const faces = [ + cgl.gl.TEXTURE_CUBE_MAP_POSITIVE_X, + cgl.gl.TEXTURE_CUBE_MAP_NEGATIVE_X, + cgl.gl.TEXTURE_CUBE_MAP_POSITIVE_Y, + cgl.gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, + cgl.gl.TEXTURE_CUBE_MAP_POSITIVE_Z, + cgl.gl.TEXTURE_CUBE_MAP_NEGATIVE_Z + ]; + + const tex = cgl.gl.createTexture(); + const target = cgl.gl.TEXTURE_CUBE_MAP; + const filter = Texture.FILTER_NEAREST; + const wrap = Texture.WRAP_CLAMP_TO_EDGE; + const width = 8; + const height = 8; + + cgl.profileData.profileTextureNew++; + + + cgl.gl.bindTexture(target, tex); + cgl.profileData.profileTextureResize++; + + for (let i = 0; i < 6; i += 1) + { + const data = new Uint8Array(8 * 8 * 4); + + cgl.gl.texImage2D(faces[i], 0, cgl.gl.RGBA, 8, 8, 0, cgl.gl.RGBA, cgl.gl.UNSIGNED_BYTE, data); + cgl.gl.texParameteri(target, cgl.gl.TEXTURE_MAG_FILTER, cgl.gl.NEAREST); + cgl.gl.texParameteri(target, cgl.gl.TEXTURE_MIN_FILTER, cgl.gl.NEAREST); + + cgl.gl.texParameteri(target, cgl.gl.TEXTURE_WRAP_S, cgl.gl.CLAMP_TO_EDGE); + cgl.gl.texParameteri(target, cgl.gl.TEXTURE_WRAP_T, cgl.gl.CLAMP_TO_EDGE); + } + + + cgl.gl.bindTexture(target, null); + + return { + "id": CABLES.uuid(), + "tex": tex, + "cubemap": tex, + "width": width, + "height": height, + "filter": filter, + "wrap": wrap, + "unpackAlpha": true, + "flip": true, + "_fromData": true, + "name": "emptyCubemapTexture", + "anisotropic": 0, + }; +}; + +/** + * @static + * @function getTempGradientTexture + * @memberof Texture + * @description returns a gradient texture from black to white + * @param {Context} cgl + * @return {Texture} + */ +Texture.getTempGradientTexture = function (cgl) +{ + if (!cgl) console.error("[getTempGradientTexture] no cgl!"); + + if (cgl.tempTextureGradient) return cgl.tempTextureGradient; + const temptex = new Texture(cgl); + const size = 256; + const data = new Uint8Array(size * size * 4); // .fill(0); + + for (let y = 0; y < size; y++) + { + for (let x = 0; x < size; x++) + { + data[(x + y * size) * 4 + 0] = data[(x + y * size) * 4 + 1] = data[(x + y * size) * 4 + 2] = 255 - y; + data[(x + y * size) * 4 + 3] = 255; + } + } + + temptex.initFromData(data, size, size, Texture.FILTER_NEAREST, Texture.WRAP_REPEAT); + cgl.tempTextureGradient = temptex; + return temptex; +}; + +Texture.getTemporaryTexture = function (cgl, size, filter, wrap, r, g, b) +{ + if (r === undefined)r = 1; + if (g === undefined)g = 1; + if (b === undefined)b = 1; + const temptex = new Texture(cgl); + const arr = []; + for (let y = 0; y < size; y++) + { + for (let x = 0; x < size; x++) + { + if ((x + y) % 64 < 32) + { + arr.push((200 + (y / size) * 25 + (x / size) * 25) * r); + arr.push((200 + (y / size) * 25 + (x / size) * 25) * g); + arr.push((200 + (y / size) * 25 + (x / size) * 25) * b); + } + else + { + arr.push((40 + (y / size) * 25 + (x / size) * 25) * r); + arr.push((40 + (y / size) * 25 + (x / size) * 25) * g); + arr.push((40 + (y / size) * 25 + (x / size) * 25) * b); + } + arr.push(255); + } + } + + const data = new Uint8Array(arr); + temptex.initFromData(data, size, size, filter, wrap); + + return temptex; +}; + +/** + * @static + * @function createFromImage + * @memberof Texture + * @description create texturem from image data (e.g. image or canvas) + * @param {Context} cgl + * @param {Object} image + * @param {Object} options + */ +Texture.createFromImage = function (cgl, img, options) +{ + options = options || {}; + const texture = new Texture(cgl, options); + texture.flip = false; + texture.image = img; + texture.width = img.videoWidth || img.width || 8; + texture.height = img.videoHeight || img.height || 8; + if (options.hasOwnProperty("wrap"))texture.wrap = options.wrap; + + console.log("createFromImage", options); + texture.initTexture(img, options.filter); + + return texture; +}; + +// deprecated! +Texture.fromImage = function (cgl, img, filter, wrap) +{ + console.error("deprecated texture from image..."); + + const texture = new Texture(cgl); + texture.flip = false; + if (filter) texture.filter = filter; + if (wrap) texture.wrap = wrap; + texture.image = img; + texture.initTexture(img); + return texture; +}; + +/** + * @static + * @function isPowerOfTwo + * @memberof Texture + * @description returns true if x is power of two + * @param {Number} x + * @return {Boolean} + */ +Texture.isPowerOfTwo = function (x) +{ + return x == 1 || x == 2 || x == 4 || x == 8 || x == 16 || x == 32 || x == 64 || x == 128 || x == 256 || x == 512 || x == 1024 || x == 2048 || x == 4096 || x == 8192 || x == 16384; +}; + +Texture.getTexInfo = function (tex) +{ + const obj = {}; + + obj.name = tex.name; + obj["power of two"] = tex.isPowerOfTwo(); + obj.size = tex.width + " x " + tex.height; + + let targetString = tex.texTarget; + if (tex.texTarget == tex._cgl.gl.TEXTURE_2D) targetString = "TEXTURE_2D"; + obj.target = targetString; + + obj.unpackAlpha = tex.unpackAlpha; + + if (tex.cubemap)obj.cubemap = true; + + if (tex.textureType == Texture.TYPE_FLOAT) obj.textureType = "TYPE_FLOAT"; + if (tex.textureType == Texture.TYPE_HALF_FLOAT) obj.textureType = "TYPE_HALF_FLOAT"; + else if (tex.textureType == Texture.TYPE_DEPTH) obj.textureType = "TYPE_DEPTH"; + else if (tex.textureType == Texture.TYPE_DEFAULT) obj.textureType = "TYPE_DEFAULT"; + else obj.textureType = "UNKNOWN " + this.textureType; + + if (tex.wrap == Texture.WRAP_CLAMP_TO_EDGE) obj.wrap = "CLAMP_TO_EDGE"; + else if (tex.wrap == Texture.WRAP_REPEAT) obj.wrap = "WRAP_REPEAT"; + else if (tex.wrap == Texture.WRAP_MIRRORED_REPEAT) obj.wrap = "WRAP_MIRRORED_REPEAT"; + else obj.wrap = "UNKNOWN"; + + if (tex.filter == Texture.FILTER_NEAREST) obj.filter = "FILTER_NEAREST"; + else if (tex.filter == Texture.FILTER_LINEAR) obj.filter = "FILTER_LINEAR"; + else if (tex.filter == Texture.FILTER_MIPMAP) obj.filter = "FILTER_MIPMAP"; + else obj.filter = "UNKNOWN"; + + obj.pixelFormat = tex.pixelFormat || "unknown"; + + return obj; +}; + + +Texture.FILTER_NEAREST = 0; +Texture.FILTER_LINEAR = 1; +Texture.FILTER_MIPMAP = 2; + +Texture.WRAP_REPEAT = 0; +Texture.WRAP_MIRRORED_REPEAT = 1; +Texture.WRAP_CLAMP_TO_EDGE = 2; + +Texture.TYPE_DEFAULT = 0; +Texture.TYPE_DEPTH = 1; +Texture.TYPE_FLOAT = 2; + + +Texture.PFORMATSTR_RGB565 = "RGB 5/6/5bit ubyte"; + +Texture.PFORMATSTR_R8UB = "R 8bit ubyte"; +Texture.PFORMATSTR_RG8UB = "RG 8bit ubyte"; +Texture.PFORMATSTR_RGB8UB = "RGB 8bit ubyte"; +Texture.PFORMATSTR_RGBA8UB = "RGBA 8bit ubyte"; + +Texture.PFORMATSTR_SRGBA8 = "SRGBA 8bit ubyte"; + +Texture.PFORMATSTR_R11FG11FB10F = "RGB 11/11/10bit float"; + +Texture.PFORMATSTR_R16F = "R 16bit float"; +Texture.PFORMATSTR_RG16F = "RG 16bit float"; +Texture.PFORMATSTR_RGB16F = "RGB 16bit float"; +Texture.PFORMATSTR_RGBA16F = "RGBA 16bit float"; + + +Texture.PFORMATSTR_R32F = "R 32bit float"; +Texture.PFORMATSTR_RG32F = "RG 32bit float"; +Texture.PFORMATSTR_RGB32F = "RGB 32bit float"; +Texture.PFORMATSTR_RGBA32F = "RGBA 32bit float"; + +Texture.PFORMATSTR_DEPTH = "DEPTH"; + + +Texture.PIXELFORMATS = [ + + Texture.PFORMATSTR_RGB565, + + Texture.PFORMATSTR_R8UB, + Texture.PFORMATSTR_RG8UB, + Texture.PFORMATSTR_RGB8UB, + Texture.PFORMATSTR_RGBA8UB, + + Texture.PFORMATSTR_SRGBA8, + + Texture.PFORMATSTR_R11FG11FB10F, + Texture.PFORMATSTR_R16F, + Texture.PFORMATSTR_RG16F, + Texture.PFORMATSTR_RGBA16F, + + Texture.PFORMATSTR_R32F, + Texture.PFORMATSTR_RGBA32F + +]; + +Texture.isPixelFormatFloat = + (pxlfrmt) => + { + return (pxlfrmt || "").contains("float"); + }; + +Texture.isPixelFormatHalfFloat = + (pxlfrmt) => + { + return (pxlfrmt || "").contains("float") && (pxlfrmt || "").contains("16bit"); + }; + + + + + + +;// CONCATENATED MODULE: ./src/core/cg/cg_boundingbox.js + + +/** + * bounding box + * @class + * @external CGL + * @namespace BoundingBox + * @param {Geometry} geometry or bounding box + */ +class BoundingBox +{ + constructor(geom) + { + this._init(); + this._first = true; + this._wireMesh = null; + + if (geom) this.apply(geom); + } + + _init() + { + this._max = [-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE]; + this._min = [Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE]; + this._center = [0, 0, 0]; + this._size = [0, 0, 0]; + this._maxAxis = 0.0; + this._first = true; + } + + /** + * get biggest number of maxX,maxY,maxZ + * @type {Number} + */ + get maxAxis() { return this._maxAxis || 1; } + + /** + * size of bounding box + * @type {vec3} + */ + get size() { return this._size; } + + /** + * center of bounding box + * @type {vec3} + */ + get center() { return this._center; } + + /** + * center x + * @type {Number} + */ + get x() { return this._center[0]; } + + /** + * center y + * @type {Number} + */ + get y() { return this._center[1]; } + + /** + * center z + * @type {Number} + */ + get z() { return this._center[2]; } + + + /** + * minimum x + * @type {Number} + */ + get minX() { return this._min[0]; } + + /** + * minimum y + * @type {Number} + */ + get minY() { return this._min[1]; } + + /** + * minimum z + * @type {Number} + */ + get minZ() { return this._min[2]; } + + /** + * maximum x + * @type {Number} + */ + get maxX() { return this._max[0]; } + + /** + * maximum y + * @type {Number} + */ + get maxY() { return this._max[1]; } + + /** + * maximum z + * @type {Number} + */ + get maxZ() { return this._max[2]; } + + + apply(geom, mat) + { + if (!geom) + { + // console.warn("[boundingbox] no geom/vertices", geom); + return; + } + + if (geom instanceof BoundingBox) + { + const bb = geom; + + this.applyPos(bb.maxX, bb.maxY, bb.maxZ); + this.applyPos(bb.minX, bb.minY, bb.minZ); + } + else + { + for (let i = 0; i < geom.vertices.length; i += 3) + // if (geom.vertices[i] == geom.vertices[i] || geom.vertices[i] != null) + // { + // if(mat) + // { + this.applyPos(geom.vertices[i], geom.vertices[i + 1], geom.vertices[i + 2]); + // } + // else + // { + // this.applyPos(geom.vertices[i + 0],geom.vertices[i + 1],geom.vertices[i + 2]); + // } + // } + } + this.calcCenterSize(); + } + + /** + * returns a copy of the bounding box + * @function copy + * @memberof BoundingBox + * @instance + */ + copy() + { + return new BoundingBox(this); + } + + get changed() + { + return !(this._max[0] == -Number.MAX_VALUE && this._max[1] == -Number.MAX_VALUE && this._max[2] == -Number.MAX_VALUE); + } + + applyPos(x, y, z) + { + if (x == Number.MAX_VALUE || x == -Number.MAX_VALUE || + y == Number.MAX_VALUE || y == -Number.MAX_VALUE || + z == Number.MAX_VALUE || z == -Number.MAX_VALUE) return; + + if (!CABLES.UTILS.isNumeric(x) || !CABLES.UTILS.isNumeric(y) || !CABLES.UTILS.isNumeric(z)) return; + + if (this._first) + { + this._max[0] = x; + this._max[1] = y; + this._max[2] = z; + + this._min[0] = x; + this._min[1] = y; + this._min[2] = z; + this._first = false; + return; + } + + this._max[0] = Math.max(this._max[0], x); + this._max[1] = Math.max(this._max[1], y); + this._max[2] = Math.max(this._max[2], z); + + this._min[0] = Math.min(this._min[0], x); + this._min[1] = Math.min(this._min[1], y); + this._min[2] = Math.min(this._min[2], z); + } + + calcCenterSize() + { + if (this._first) return; + // this._size[0]=Math.abs(this._min[0])+Math.abs(this._max[0]); + // this._size[1]=Math.abs(this._min[1])+Math.abs(this._max[1]); + // this._size[2]=Math.abs(this._min[2])+Math.abs(this._max[2]); + this._size[0] = this._max[0] - this._min[0]; + this._size[1] = this._max[1] - this._min[1]; + this._size[2] = this._max[2] - this._min[2]; + + this._center[0] = (this._min[0] + this._max[0]) / 2; + this._center[1] = (this._min[1] + this._max[1]) / 2; + this._center[2] = (this._min[2] + this._max[2]) / 2; + + this._maxAxis = Math.max(this._size[2], Math.max(this._size[0], this._size[1])); + } + + mulMat4(m) + { + if (this._first) + { + this._max[0] = 0; + this._max[1] = 0; + this._max[2] = 0; + + this._min[0] = 0; + this._min[1] = 0; + this._min[2] = 0; + this._first = false; + } + vec3.transformMat4(this._max, this._max, m); + vec3.transformMat4(this._min, this._min, m); + this.calcCenterSize(); + } + + render(cgl, shader, op) + { + if (!this._wireMesh) this._wireMesh = new CGL.WireCube(cgl); + + // console.log("bounding box render!"); + cgl.pushModelMatrix(); + mat4.translate(cgl.mMatrix, cgl.mMatrix, this._center); + // this._wireMesh.render(cgl, this._size[0] / 2, this._size[1] / 2, this._size[2] / 2); + + if (CABLES.UI && op) + { + CABLES.UI.OverlayMeshes.drawCube(op, this._size[0] / 2, this._size[1] / 2, this._size[2] / 2); + } + + cgl.popModelMatrix(); + } +} + +;// CONCATENATED MODULE: ./src/core/cg/cg_geom.js +// import { vec2, vec3 } from "gl-matrix"; + + + + + +/** + * a geometry contains all information about a mesh, vertices, texturecoordinates etc. etc. + * @external CGL + * @namespace Geometry + * @param {String} name + * @class + * @example + * // create a triangle with all attributes + * const geom=new Geometry("triangle"), + * + * geom.vertices = [ + * 0.0, sizeH.get(), 0.0, + * -sizeW.get(), -sizeH.get(), 0.0, + * sizeW.get(), -sizeH.get(), 0.0 ]; + * + * geom.vertexNormals = [ + * 0.0, 0.0, 1.0, + * 0.0, 0.0, 1.0, + * 0.0, 0.0, 1.0 ]; + * + * geom.tangents = [ + * 1,0,0, + * 1,0,0, + * 1,0,0 ]; + * + * geom.biTangents = [ + * 0,1,0, + * 0,1,0, + * 0,1,0 ]; + * + * geom.texCoords = [ + * 0.5, 0.0, + * 1.0, 1.0, + * 0.0, 1.0, ]; + * + * geom.verticesIndices = [ + * 0, 1, 2 ]; + * + */ +const Geometry = function (name) +{ + this.name = name || "unknown"; + this._log = new Logger("cgl_geometry"); + + this.faceVertCount = 3; + this.glPrimitive = null; + this._attributes = {}; + + this._vertices = []; + this.verticesIndices = []; + + this.isGeometry = true; + + this.morphTargets = []; + + Object.defineProperty(this, "vertices", { + get() + { + return this._vertices; + }, + set(v) + { + this.setVertices(v); + }, + }); + + Object.defineProperty(this, "texCoords", { + get() + { + const att = this.getAttribute("texCoords"); + if (!att) return []; + return att.data; + }, + set(v) + { + this.setAttribute("texCoords", v, 2); + }, + }); + + Object.defineProperty(this, "vertexNormals", { + get() + { + const att = this.getAttribute("vertexNormals"); + if (!att) return []; + return att.data; + }, + set(v) + { + this.setAttribute("vertexNormals", v, 3); + }, + }); + + Object.defineProperty(this, "tangents", { + get() + { + const att = this.getAttribute("tangents"); + if (!att) return []; + return att.data; + }, + set(v) + { + this.setAttribute("tangents", v, 3); + }, + }); + + Object.defineProperty(this, "biTangents", { + get() + { + const att = this.getAttribute("biTangents"); + if (!att) return []; + return att.data; + }, + set(v) + { + this.setAttribute("biTangents", v, 3); + }, + }); + + Object.defineProperty(this, "vertexColors", { + get() + { + const att = this.getAttribute("vertexColors"); + if (!att) return []; + return att.data; + }, + set(v) + { + this.setAttribute("vertexColors", v, 4); + }, + }); +}; + +/** + * @function clear + * @memberof Geometry + * @instance + * @description clear all buffers/set them to length 0 + */ +Geometry.prototype.clear = function () +{ + this._vertices = new Float32Array([]); + this.verticesIndices = []; + this.texCoords = new Float32Array([]); + this.vertexNormals = new Float32Array([]); + this.tangents = []; + this.biTangents = []; + this._attributes = {}; +}; + + + +/** + * @function getAttributes + @memberof Geometry + * @instance + * @return {Array} returns array of attribute objects + */ +Geometry.prototype.getAttributes = function () +{ + return this._attributes; +}; + +/** + * @function getAttribute + * @memberof Geometry + * @instance + * @param {String} name + * @return {Object} + */ +Geometry.prototype.getAttribute = function (name) +{ + for (const i in this._attributes) + { + if (this._attributes[i].name == name) return this._attributes[i]; + } + return null; +}; + +/** + * @function setAttribute + * @description create an attribute + * @memberof Geometry + * @instance + * @param {String} name + * @param {Array} data + * @param {Number} itemsize + */ +Geometry.prototype.setAttribute = function (name, arr, itemSize) +{ + let attrType = ""; + if (!itemSize || itemSize > 4) + { + console.log("itemsize wrong?", itemSize, name); + this._log.stack("itemsize"); + + itemSize = 3; + } + + if (itemSize == 1) attrType = "float"; + else if (itemSize == 2) attrType = "vec2"; + else if (itemSize == 3) attrType = "vec3"; + else if (itemSize == 4) attrType = "vec4"; + + + const attr = { + "name": name, + "data": arr, + "itemSize": itemSize, + "type": attrType, + }; + + this._attributes[name] = attr; +}; + +Geometry.prototype.copyAttribute = function (name, newgeom) +{ + const attr = this.getAttribute(name); + newgeom.setAttribute(name, new Float32Array(attr.data), attr.itemSize); +}; + + +/** + * @function setVertices + * @memberof Geometry + * @instance + * @description set vertices + * @param {Array|Float32Array} data [x,y,z,x,y,z,...] + */ +Geometry.prototype.setVertices = function (arr) +{ + if (arr instanceof Float32Array) this._vertices = arr; + else this._vertices = new Float32Array(arr); +}; + +/** + * @function setTexCoords + * @memberof Geometry + * @instance + * @description set texcoords + * @param {Array|Float32Array} data [u,v,u,v,...] + */ +Geometry.prototype.setTexCoords = function (arr) +{ + if (arr instanceof Float32Array) this.texCoords = arr; + else this.texCoords = new Float32Array(arr); +}; + +// Geometry.prototype.testIndices = function () +// { +// var foundError = false; +// for (var i = 0; i < this.verticesIndices.length; i++) +// { +// if (this.verticesIndices[i * 3 + 0] >= this._vertices.length / 3 || this.verticesIndices[i * 3 + 1] >= this._vertices.length / 3 || this.verticesIndices[i * 3 + 2] >= this._vertices.length / 3) +// { +// foundError = true; +// console.log("index error!"); +// } +// } +// }; + +// deprecated +Geometry.prototype.calcNormals = function (smooth) +{ + const options = { "smooth": smooth }; + + + this.calculateNormals(options); +}; + +/** + * @function flipNormals + * @memberof Geometry + * @description flip normals + */ +Geometry.prototype.flipNormals = function (x, y, z) +{ + let vec = vec3.create(); + + if (x == undefined)x = 1; + if (y == undefined)y = 1; + if (z == undefined)z = 1; + + + for (let i = 0; i < this.vertexNormals.length; i += 3) + { + vec3.set(vec, + this.vertexNormals[i + 0], + this.vertexNormals[i + 1], + this.vertexNormals[i + 2]); + + vec[0] *= -x; + vec[1] *= -y; + vec[2] *= -z; + + vec3.normalize(vec, vec); + + this.vertexNormals[i + 0] = vec[0]; + this.vertexNormals[i + 1] = vec[1]; + this.vertexNormals[i + 2] = vec[2]; + } +}; + +Geometry.prototype.getNumTriangles = function () +{ + if (this.verticesIndices && this.verticesIndices.length) return this.verticesIndices.length / 3; + return this.vertices.length / 3; +}; + + +/** + * @function flipVertDir + * @memberof Geometry + * @description flip order of vertices in geom faces + */ +Geometry.prototype.flipVertDir = function () +{ + const newInd = []; + newInd.length = this.verticesIndices.length; + for (let i = 0; i < this.verticesIndices.length; i += 3) + { + newInd[i] = this.verticesIndices[i + 2]; + newInd[i + 1] = this.verticesIndices[i + 1]; + newInd[i + 2] = this.verticesIndices[i]; + } + this.verticesIndices = newInd; +}; + + +Geometry.prototype.setPointVertices = function (verts) +{ + if (verts.length % 3 !== 0) + { + this._log.error("SetPointVertices: Array must be multiple of three."); + return; + } + + if (!(verts instanceof Float32Array)) this.vertices = new Float32Array(verts); + else this.vertices = verts; + + if (!(this.texCoords instanceof Float32Array)) this.texCoords = new Float32Array((verts.length / 3) * 2); + + // this.texCoords.length=verts.length/3*2; + this.verticesIndices.length = verts.length / 3; + // this.verticesIndices=[]; + + for (let i = 0; i < verts.length / 3; i++) + { + this.verticesIndices[i] = i; + this.texCoords[i * 2] = 0; + this.texCoords[i * 2 + 1] = 0; + } +}; + +/** + * merge a different geometry into the this geometry + * @function merge + * @param {Geometry} geom + * @memberof Geometry + * @instance + */ +Geometry.prototype.merge = function (geom) +{ + if (!geom) return; + + if (this.isIndexed() != geom.isIndexed()) + { + if (this.isIndexed()) + { + this.unIndex(false, true); + } + if (geom.isIndexed()) + { + const g = geom.copy(); + g.unIndex(false, true); + geom = g; + } + } + + const oldIndizesLength = this.verticesIndices.length; + const vertLength = this._vertices.length / 3; + + this.verticesIndices.length += geom.verticesIndices.length; + for (let i = 0; i < geom.verticesIndices.length; i++) + this.verticesIndices[oldIndizesLength + i] = geom.verticesIndices[i] + vertLength; + + this.vertices = UTILS.float32Concat(this._vertices, geom.vertices); + this.texCoords = UTILS.float32Concat(this.texCoords, geom.texCoords); + this.vertexNormals = UTILS.float32Concat(this.vertexNormals, geom.vertexNormals); + this.tangents = UTILS.float32Concat(this.tangents, geom.tangents); + this.biTangents = UTILS.float32Concat(this.biTangents, geom.biTangents); +}; + +/** + * create a copy of the geometry + * @function copy + * @memberof Geometry + * @instance + */ +Geometry.prototype.copy = function () +{ + const geom = new Geometry(this.name + " copy"); + geom.faceVertCount = this.faceVertCount; + geom.glPrimitive = this.glPrimitive; + + geom.setVertices(this._vertices.slice(0)); + + if (this.verticesIndices) + { + geom.verticesIndices.length = this.verticesIndices.length; + for (let i = 0; i < this.verticesIndices.length; i++) geom.verticesIndices[i] = this.verticesIndices[i]; + } + + for (let i in this._attributes) this.copyAttribute(i, geom); + + geom.morphTargets.length = this.morphTargets.length; + for (let i = 0; i < this.morphTargets.length; i++) geom.morphTargets[i] = this.morphTargets[i]; + + return geom; +}; + +/** + * Calculaten normals + * @function calculateNormals + * @memberof Geometry + * @instance + */ +Geometry.prototype.calculateNormals = function (options) +{ + // todo: should check angle of normals to get edges https://community.khronos.org/t/calculating-accurate-vertex-normals/28152 + options = options || {}; + if (options.smooth === false) this.unIndex(); + + const u = vec3.create(); + const v = vec3.create(); + const n = vec3.create(); + + function calcNormal(triangle) + { + vec3.subtract(u, triangle[0], triangle[1]); + vec3.subtract(v, triangle[0], triangle[2]); + vec3.cross(n, u, v); + vec3.normalize(n, n); + + if (options && options.forceZUp) + { + if (n[2] < 0) + { + n[0] *= -1; + n[1] *= -1; + n[2] *= -1; + } + } + return n; + } + + this.getVertexVec = function (which) + { + const vec = [0, 0, 0]; + vec[0] = this.vertices[which * 3 + 0]; + vec[1] = this.vertices[which * 3 + 1]; + vec[2] = this.vertices[which * 3 + 2]; + return vec; + }; + + if (!(this.vertexNormals instanceof Float32Array) || this.vertexNormals.length != this.vertices.length) this.vertexNormals = new Float32Array(this.vertices.length); + + for (let i = 0; i < this.vertices.length; i++) + { + this.vertexNormals[i] = 0; + } + + if (!this.isIndexed()) + { + const norms = []; + for (let i = 0; i < this.vertices.length; i += 9) + { + const triangle = [[this.vertices[i + 0], this.vertices[i + 1], this.vertices[i + 2]], [this.vertices[i + 3], this.vertices[i + 4], this.vertices[i + 5]], [this.vertices[i + 6], this.vertices[i + 7], this.vertices[i + 8]]]; + const nn = calcNormal(triangle); + norms.push(nn[0], nn[1], nn[2], nn[0], nn[1], nn[2], nn[0], nn[1], nn[2]); + } + this.vertexNormals = norms; + } + else + { + const faceNormals = []; + + faceNormals.length = Math.floor(this.verticesIndices.length / 3); + + for (let i = 0; i < this.verticesIndices.length; i += 3) + { + const triangle = [this.getVertexVec(this.verticesIndices[i + 0]), this.getVertexVec(this.verticesIndices[i + 1]), this.getVertexVec(this.verticesIndices[i + 2])]; + + faceNormals[i / 3] = calcNormal(triangle); + + this.vertexNormals[this.verticesIndices[i + 0] * 3 + 0] += faceNormals[i / 3][0]; + this.vertexNormals[this.verticesIndices[i + 0] * 3 + 1] += faceNormals[i / 3][1]; + this.vertexNormals[this.verticesIndices[i + 0] * 3 + 2] += faceNormals[i / 3][2]; + + this.vertexNormals[this.verticesIndices[i + 1] * 3 + 0] += faceNormals[i / 3][0]; + this.vertexNormals[this.verticesIndices[i + 1] * 3 + 1] += faceNormals[i / 3][1]; + this.vertexNormals[this.verticesIndices[i + 1] * 3 + 2] += faceNormals[i / 3][2]; + + this.vertexNormals[this.verticesIndices[i + 2] * 3 + 0] += faceNormals[i / 3][0]; + this.vertexNormals[this.verticesIndices[i + 2] * 3 + 1] += faceNormals[i / 3][1]; + this.vertexNormals[this.verticesIndices[i + 2] * 3 + 2] += faceNormals[i / 3][2]; + } + + + for (let i = 0; i < this.verticesIndices.length; i += 3) // faces + { + for (let k = 0; k < 3; k++) // triangles + { + const vv = [this.vertexNormals[this.verticesIndices[i + k] * 3 + 0], this.vertexNormals[this.verticesIndices[i + k] * 3 + 1], this.vertexNormals[this.verticesIndices[i + k] * 3 + 2]]; + vec3.normalize(vv, vv); + this.vertexNormals[this.verticesIndices[i + k] * 3 + 0] = vv[0]; + this.vertexNormals[this.verticesIndices[i + k] * 3 + 1] = vv[1]; + this.vertexNormals[this.verticesIndices[i + k] * 3 + 2] = vv[2]; + } + } + } +}; + +/** + * Calculates tangents & bitangents with the help of uv-coordinates. Adapted from + * Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”. + * Terathon Software 3D Graphics Library. + * https://fenix.tecnico.ulisboa.pt/downloadFile/845043405449073/Tangent%20Space%20Calculation.pdf + * + * @function calcTangentsBitangents + * @memberof Geometry + * @instance + */ +Geometry.prototype.calcTangentsBitangents = function () +{ + if (!this.vertices.length) + { + // this._log.error("Cannot calculate tangents/bitangents without vertices."); + return; + } + if (!this.vertexNormals.length) + { + // this._log.error("Cannot calculate tangents/bitangents without normals."); + return; + } + if (!this.texCoords.length) + { + // console.warn("No texcoords. Replacing with default values [0, 0]."); + const texCoordLength = (this.vertices.length / 3) * 2; + this.texCoords = new Float32Array(texCoordLength); + for (let i = 0; i < texCoordLength; i += 1) this.texCoords[i] = 0; + } + if (!this.verticesIndices || !this.verticesIndices.length) + { + // this._log.error("Cannot calculate tangents/bitangents without vertex indices."); + return; + } + // this code assumes that we have three indices per triangle + if (this.verticesIndices.length % 3 !== 0) + { + this._log.error("Vertex indices mismatch!"); + return; + } + + const triangleCount = this.verticesIndices.length / 3; + const vertexCount = this.vertices.length / 3; + + this.tangents = new Float32Array(this.vertexNormals.length); + this.biTangents = new Float32Array(this.vertexNormals.length); + + // temporary buffers + const tempVertices = []; + tempVertices.length = vertexCount * 2; + const v1 = vec3.create(); + const v2 = vec3.create(); + const v3 = vec3.create(); + + const w1 = vec2.create(); + const w2 = vec2.create(); + const w3 = vec2.create(); + + const sdir = vec3.create(); + const tdir = vec3.create(); + + // for details on calculation, see article referenced above + for (let tri = 0; tri < triangleCount; tri += 1) + { + // indices of the three vertices for a triangle + const i1 = this.verticesIndices[tri * 3]; + const i2 = this.verticesIndices[tri * 3 + 1]; + const i3 = this.verticesIndices[tri * 3 + 2]; + + // vertex position as vec3 + vec3.set(v1, this.vertices[i1 * 3], this.vertices[i1 * 3 + 1], this.vertices[i1 * 3 + 2]); + vec3.set(v2, this.vertices[i2 * 3], this.vertices[i2 * 3 + 1], this.vertices[i2 * 3 + 2]); + vec3.set(v3, this.vertices[i3 * 3], this.vertices[i3 * 3 + 1], this.vertices[i3 * 3 + 2]); + + // texture coordinate as vec2 + vec2.set(w1, this.texCoords[i1 * 2], this.texCoords[i1 * 2 + 1]); + vec2.set(w2, this.texCoords[i2 * 2], this.texCoords[i2 * 2 + 1]); + vec2.set(w3, this.texCoords[i3 * 2], this.texCoords[i3 * 2 + 1]); + + const x1 = v2[0] - v1[0]; + const x2 = v3[0] - v1[0]; + const y1 = v2[1] - v1[1]; + const y2 = v3[1] - v1[1]; + const z1 = v2[2] - v1[2]; + const z2 = v3[2] - v1[2]; + + const s1 = w2[0] - w1[0]; + const s2 = w3[0] - w1[0]; + const t1 = w2[1] - w1[1]; + const t2 = w3[1] - w1[1]; + + const r = 1.0 / (s1 * t2 - s2 * t1); + + vec3.set(sdir, (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); + vec3.set(tdir, (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); + + tempVertices[i1] = sdir; + tempVertices[i2] = sdir; + tempVertices[i3] = sdir; + + tempVertices[i1 + vertexCount] = tdir; + tempVertices[i2 + vertexCount] = tdir; + tempVertices[i3 + vertexCount] = tdir; + } + + const normal = vec3.create(); + const tempVert = vec3.create(); + const tan = vec3.create(); + const bitan = vec3.create(); + const temp1 = vec3.create(); + const temp2 = vec3.create(); + const crossPd = vec3.create(); + const normalized = vec3.create(); + + for (let vert = 0; vert < vertexCount; vert += 1) + { + // NOTE: some meshes don't have index 0 - n in their indexbuffer, if this is the case, skip calculation of this vertex + if (!tempVertices[vert]) continue; + + vec3.set(normal, this.vertexNormals[vert * 3], this.vertexNormals[vert * 3 + 1], this.vertexNormals[vert * 3 + 2]); + vec3.set(tempVert, tempVertices[vert][0], tempVertices[vert][1], tempVertices[vert][2]); + + // Gram-Schmidt orthagonalize + const _dp = vec3.dot(normal, tempVert); + vec3.scale(temp1, normal, _dp); + vec3.subtract(temp2, tempVert, temp1); + + vec3.normalize(normalized, temp2); + vec3.cross(crossPd, normal, tempVert); + + // const intermDot = vec3.dot(crossPd, tempVertices[vert + vertexCount]); + const w = 1.0;// intermDot < 0.0 ? -1.0 : 1.0; + + vec3.scale(tan, normalized, 1 / w); + vec3.cross(bitan, normal, tan); + + this.tangents[vert * 3 + 0] = tan[0]; + this.tangents[vert * 3 + 1] = tan[1]; + this.tangents[vert * 3 + 2] = tan[2]; + this.biTangents[vert * 3 + 0] = bitan[0]; + this.biTangents[vert * 3 + 1] = bitan[1]; + this.biTangents[vert * 3 + 2] = bitan[2]; + } +}; + +Geometry.prototype.isIndexed = function () +{ + if (this._vertices.length == 0) return true; + return this.verticesIndices.length != 0; +}; + +/** + * @function unIndex + * @memberof Geometry + * @instance + * @param {Boolean} + * @description remove all vertex indizes, vertices array will contain 3*XYZ for every triangle + */ +Geometry.prototype.unIndex = function (reIndex, dontCalcNormals) +{ + const newVerts = []; + const newIndizes = []; + let count = 0; + + for (let j in this._attributes) + { + const attr = this._attributes[j]; + let na = []; + + for (let i = 0; i < this.verticesIndices.length; i += 3) + { + for (let s = 0; s < 3; s++) + { + if (attr.itemSize == 3) + na.push( + attr.data[this.verticesIndices[i + s] * 3 + 0], + attr.data[this.verticesIndices[i + s] * 3 + 1], + attr.data[this.verticesIndices[i + s] * 3 + 2]); + else if (attr.itemSize == 4) + na.push( + attr.data[this.verticesIndices[i + s] * 4 + 0], + attr.data[this.verticesIndices[i + s] * 4 + 1], + attr.data[this.verticesIndices[i + s] * 4 + 2], + attr.data[this.verticesIndices[i + s] * 4 + 3]); + else if (attr.itemSize == 2) + na.push( + attr.data[this.verticesIndices[i + s] * 2 + 0], + attr.data[this.verticesIndices[i + s] * 2 + 1]); + else if (attr.itemSize == 1) + na.push( + attr.data[this.verticesIndices[i + s]]); + else console.log("unknown attr", attr); + } + } + this.setAttribute(attr.name, na, attr.itemSize); + } + + for (let i = 0; i < this.verticesIndices.length; i += 3) + { + newVerts.push( + this.vertices[this.verticesIndices[i + 0] * 3 + 0], + this.vertices[this.verticesIndices[i + 0] * 3 + 1], + this.vertices[this.verticesIndices[i + 0] * 3 + 2]); + + newIndizes.push(count); + count++; + + newVerts.push( + this.vertices[this.verticesIndices[i + 1] * 3 + 0], + this.vertices[this.verticesIndices[i + 1] * 3 + 1], + this.vertices[this.verticesIndices[i + 1] * 3 + 2]); + + newIndizes.push(count); + count++; + + newVerts.push( + this.vertices[this.verticesIndices[i + 2] * 3 + 0], + this.vertices[this.verticesIndices[i + 2] * 3 + 1], + this.vertices[this.verticesIndices[i + 2] * 3 + 2]); + + newIndizes.push(count); + count++; + } + + this.vertices = newVerts; + + this.verticesIndices = []; + if (reIndex) this.verticesIndices = newIndizes; + + if (!dontCalcNormals) this.calculateNormals(); +}; + +Geometry.prototype.calcBarycentric = function () +{ + let barycentrics = []; + barycentrics.length = this.vertices.length; + for (let i = 0; i < this.vertices.length; i++) barycentrics[i] = 0; + + let count = 0; + for (let i = 0; i < this.vertices.length; i += 3) + { + barycentrics[i + count] = 1; + count++; + if (count == 3) count = 0; + } + + this.setAttribute("attrBarycentric", barycentrics, 3); +}; + +Geometry.prototype.getBounds = function () +{ + return new BoundingBox(this); +}; + +Geometry.prototype.center = function (x, y, z) +{ + if (x === undefined) + { + x = true; + y = true; + z = true; + } + + let i = 0; + const bounds = this.getBounds(); + const offset = [bounds.minX + (bounds.maxX - bounds.minX) / 2, bounds.minY + (bounds.maxY - bounds.minY) / 2, bounds.minZ + (bounds.maxZ - bounds.minZ) / 2]; + + for (i = 0; i < this.vertices.length; i += 3) + { + if (this.vertices[i + 0] == this.vertices[i + 0]) + { + if (x) this.vertices[i + 0] -= offset[0]; + if (y) this.vertices[i + 1] -= offset[1]; + if (z) this.vertices[i + 2] -= offset[2]; + } + } + + return offset; +}; + +Geometry.prototype.mapTexCoords2d = function () +{ + const bounds = this.getBounds(); + const num = this.vertices.length / 3; + + this.texCoords = new Float32Array(num * 2); + + for (let i = 0; i < num; i++) + { + const vertX = this.vertices[i * 3 + 0]; + const vertY = this.vertices[i * 3 + 1]; + this.texCoords[i * 2 + 0] = vertX / (bounds.maxX - bounds.minX) + 0.5; + this.texCoords[i * 2 + 1] = 1.0 - vertY / (bounds.maxY - bounds.minY) + 0.5; + } +}; + + +Geometry.prototype.getInfoOneLine = function () +{ + let txt = ""; + if (this.faceVertCount == 3 && this.verticesIndices)txt += this.verticesIndices.length / 3; + else txt += 0; + + txt += " tris "; + + if (this.vertices)txt += this.vertices.length / 3; + else txt += 0; + + txt += " verts"; + + return txt; +}; + +Geometry.prototype.getInfo = function () +{ + const info = {}; + + if (this.faceVertCount == 3 && this.verticesIndices)info.numFaces = this.verticesIndices.length / 3; + else info.numFaces = 0; + + if (this.verticesIndices && this.verticesIndices.length)info.indices = this.verticesIndices.length; + + if (this.vertices)info.numVerts = this.vertices.length / 3; + else info.numVerts = 0; + + if (this.vertexNormals) info.numNormals = this.vertexNormals.length / 3; + else info.numNormals = 0; + + if (this.texCoords) info.numTexCoords = this.texCoords.length / 2; + else info.numTexCoords = 0; + + if (this.tangents) info.numTangents = this.tangents.length / 3; + else info.numTangents = 0; + + if (this.biTangents) info.numBiTangents = this.biTangents.length / 3; + else info.numBiTangents = 0; + + if (this.biTangents) info.numBiTangents = this.biTangents.length / 3; + else info.numBiTangents = 0; + + if (this.vertexColors) info.numVertexColors = this.vertexColors.length / 4; + else info.numVertexColors = 0; + + if (this.getAttributes()) info.numAttribs = Object.keys(this.getAttributes()).length; + else info.numAttribs = 0; + + info.isIndexed = this.isIndexed(); + + return info; +}; + +// ----------------- + +// TODO : move this into "old" circle op +Geometry.buildFromFaces = function (arr, name, optimize) +{ + const vertices = []; + const verticesIndices = []; + + for (let i = 0; i < arr.length; i += 3) + { + const a = arr[i + 0]; + const b = arr[i + 1]; + const c = arr[i + 2]; + const face = [-1, -1, -1]; + + if (optimize) + for (let iv = 0; iv < vertices.length; iv += 3) + { + if (vertices[iv + 0] == a[0] && vertices[iv + 1] == a[1] && vertices[iv + 2] == a[2]) face[0] = iv / 3; + if (vertices[iv + 0] == b[0] && vertices[iv + 1] == b[1] && vertices[iv + 2] == b[2]) face[1] = iv / 3; + if (vertices[iv + 0] == c[0] && vertices[iv + 1] == c[1] && vertices[iv + 2] == c[2]) face[2] = iv / 3; + } + + if (face[0] == -1) + { + vertices.push(a[0], a[1], a[2]); + face[0] = (vertices.length - 1) / 3; + } + + if (face[1] == -1) + { + vertices.push(b[0], b[1], b[2]); + face[1] = (vertices.length - 1) / 3; + } + + if (face[2] == -1) + { + vertices.push(c[0], c[1], c[2]); + face[2] = (vertices.length - 1) / 3; + } + + verticesIndices.push(parseInt(face[0], 10)); + verticesIndices.push(parseInt(face[1], 10)); + verticesIndices.push(parseInt(face[2], 10)); + } + + const geom = new Geometry(name); + geom.name = name; + geom.vertices = vertices; + geom.verticesIndices = verticesIndices; + + return geom; +}; + +// TODO: not needed anymore ?! move to deprecated ops? +Geometry.json2geom = function (jsonMesh) +{ + const geom = new Geometry("jsonMeshGeom"); + geom.verticesIndices = []; + + geom.vertices = jsonMesh.vertices || []; + geom.vertexNormals = jsonMesh.normals || []; + geom.vertexColors = jsonMesh.colors || []; + geom.tangents = jsonMesh.tangents || []; + geom.biTangents = jsonMesh.bitangents || []; + if (jsonMesh.texturecoords) geom.setTexCoords(jsonMesh.texturecoords[0]); + + if (jsonMesh.vertices_b64)geom.vertices = new Float32Array(b64decTypedArray(jsonMesh.vertices_b64)); + if (jsonMesh.normals_b64) geom.vertexNormals = new Float32Array(b64decTypedArray(jsonMesh.normals_b64)); + if (jsonMesh.tangents_b64) geom.tangents = new Float32Array(b64decTypedArray(jsonMesh.tangents_b64)); + if (jsonMesh.bitangents_b64) geom.biTangents = new Float32Array(b64decTypedArray(jsonMesh.bitangents_b64)); + if (jsonMesh.texturecoords_b64) geom.setTexCoords(new Float32Array(b64decTypedArray(jsonMesh.texturecoords_b64[0]))); + + if (jsonMesh.faces_b64) + { + geom.verticesIndices = new Uint32Array(b64decTypedArray(jsonMesh.faces_b64)); + } + else + { + geom.verticesIndices.length = jsonMesh.faces.length * 3; + for (let i = 0; i < jsonMesh.faces.length; i++) + { + geom.verticesIndices[i * 3] = jsonMesh.faces[i][0]; + geom.verticesIndices[i * 3 + 1] = jsonMesh.faces[i][1]; + geom.verticesIndices[i * 3 + 2] = jsonMesh.faces[i][2]; + } + } + + return geom; +}; + + + + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_mesh_feedback.js +// view-source:http://toji.github.io/webgl2-particles-2/ + +function extendMeshWithFeedback(Mesh) +{ + Mesh.prototype.hasFeedbacks = function () + { + return this._feedBacks.length > 0; + }; + + Mesh.prototype.removeFeedbacks = function (shader) + { + if (!this._feedbacks) return; + this._feedbacks.length = 0; + this._feedBacksChanged = true; + }; + + Mesh.prototype.setAttributeFeedback = function () {}; + + Mesh.prototype.setFeedback = function (attrib, nameOut, initialArr) + { + let fb = { nameOut, }; + let found = false; + this.unBindFeedbacks(); + + for (let i = 0; i < this._feedBacks.length; i++) + { + if (this._feedBacks[i].nameOut == nameOut) + { + fb = this._feedBacks[i]; + + found = true; + } + } + + if (!found) this._feedBacksChanged = true; + + fb.initialArr = initialArr; + fb.attrib = attrib; + + // console.log("setfeedback"); + + if (fb.outBuffer) this._cgl.gl.deleteBuffer(fb.outBuffer); + // if(fb.attrib.buffer)this._cgl.gl.deleteBuffer(fb.attrib.buffer); + fb.outBuffer = this._cgl.gl.createBuffer(); + this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, fb.outBuffer); + this._cgl.gl.bufferData(this._cgl.gl.ARRAY_BUFFER, fb.initialArr, this._cgl.gl.STATIC_DRAW); + + this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, fb.attrib.buffer); + this._cgl.gl.bufferData(this._cgl.gl.ARRAY_BUFFER, fb.initialArr, this._cgl.gl.STATIC_DRAW); + + if (!found) this._feedBacks.push(fb); + + // console.log('initialArr',initialArr.length/3); + // console.log('vertices',fb.attrib.numItems); + // console.log('vertices',this._bufVertexAttrib.numItems); + + return fb; + }; + + Mesh.prototype.bindFeedback = function (attrib) + { + if (!this._feedBacks || this._feedBacks.length === 0) return; + if (this._transformFeedBackLoc == -1) this._transformFeedBackLoc = this._cgl.gl.createTransformFeedback(); + + this._cgl.gl.bindTransformFeedback(this._cgl.gl.TRANSFORM_FEEDBACK, this._transformFeedBackLoc); + + let found = false; + + for (let i = 0; i < this._feedBacks.length; i++) + { + const fb = this._feedBacks[i]; + + if (fb.attrib == attrib) + { + found = true; + // this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, fb.attrib.buffer); + // + // this._cgl.gl.vertexAttribPointer( + // fb.attrib.loc, + // fb.attrib.itemSize, + // fb.attrib.type, + // false, + // fb.attrib.itemSize*4, 0); + + this._cgl.gl.bindBufferBase(this._cgl.gl.TRANSFORM_FEEDBACK_BUFFER, i, fb.outBuffer); + } + } + + if (!found) + { + // console.log("ARTTRIB NOT FOUND",attrib.name); + } + }; + + Mesh.prototype.drawFeedbacks = function (shader, prim) + { + let i = 0; + + if (this._feedBacksChanged) + { + const names = []; + this._cgl.gl.bindTransformFeedback(this._cgl.gl.TRANSFORM_FEEDBACK, this._transformFeedBackLoc); + + for (i = 0; i < this._feedBacks.length; i++) names.push(this._feedBacks[i].nameOut); + shader.setFeedbackNames(names); + + console.log("feedbacknames", names); + + shader.compile(); + this._feedBacksChanged = false; + this._cgl.gl.bindTransformFeedback(this._cgl.gl.TRANSFORM_FEEDBACK, null); + console.log("changed finished"); + return; + } + + // + // for( i=0;i= array.length - 1) + { + this._log.log(this._cgl.canvas.id + " " + attr.name + " buffersubdata out of bounds ?", array.length, end, start, attr); + } + + if (this._cgl.glVersion == 1) this._cgl.gl.bufferSubData(this._cgl.gl.ARRAY_BUFFER, 0, array); // probably slow/ maybe create and array with only changed size ?? + else this._cgl.gl.bufferSubData(this._cgl.gl.ARRAY_BUFFER, start * 4, array, start, (end - start)); +}; + +Mesh.prototype._resizeAttr = function (array, attr) +{ + if (attr.buffer) + this._cgl.gl.deleteBuffer(attr.buffer); + + attr.buffer = this._cgl.gl.createBuffer(); + this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, attr.buffer); + this._bufferArray(array, attr); + attr.numItems = array.length / attr.itemSize;// numItems; +}; + + +Mesh.prototype._bufferArray = function (array, attr) +{ + let floatArray = attr.floatArray || null; + if (!array) return; + + + if (this._cgl.debugOneFrame) + { + console.log("_bufferArray", array.length, attr.name); // eslint-disable-line + } + + if (!(array instanceof Float32Array)) + { + if (attr && floatArray && floatArray.length == array.length) + { + floatArray.set(array); + // floatArray = floatArray; + } + else + { + floatArray = new Float32Array(array); + + if (this._cgl.debugOneFrame) + { + console.log("_bufferArray create new float32array", array.length, attr.name); // eslint-disable-line + } + + if (array.length > 10000) + { + this._cgl.profileData.profileNonTypedAttrib++; + this._cgl.profileData.profileNonTypedAttribNames = "(" + this._name + ":" + attr.name + ")"; + } + } + } + else floatArray = array; + + attr.arrayLength = floatArray.length; + attr.floatArray = null;// floatArray; + + this._cgl.gl.bufferData(this._cgl.gl.ARRAY_BUFFER, floatArray, this._cgl.gl.DYNAMIC_DRAW); +}; + +/** + * @function setAttribute + * @description update attribute + * @memberof Mesh + * @instance + * @param {String} attribute name + * @param {Array} data + * @param {Number} itemSize + * @param {Object} options + */ +Mesh.prototype.addAttribute = Mesh.prototype.updateAttribute = Mesh.prototype.setAttribute = function (name, array, itemSize, options) +{ + if (!array) + { + this._log.error("mesh addAttribute - no array given! " + name); + throw new Error(); + } + let cb = null; + let instanced = false; + let i = 0; + const numItems = array.length / itemSize; + + this._cgl.profileData.profileMeshAttributes += numItems || 0; + + if (typeof options == "function") + { + cb = options; + } + + if (typeof options == "object") + { + if (options.cb) cb = options.cb; + if (options.instanced) instanced = options.instanced; + } + + if (name == constants_CONSTANTS.SHADER.SHADERVAR_INSTANCE_MMATRIX) instanced = true; + + + for (i = 0; i < this._attributes.length; i++) + { + const attr = this._attributes[i]; + if (attr.name == name) + { + if (attr.numItems === numItems) + { + } + else + { + // this._log.log("wrong buffer size", this._geom.name, attr.name, attr.numItems, numItems); + this._resizeAttr(array, attr); + } + + this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, attr.buffer); + this._bufferArray(array, attr); + + return attr; + } + } + + // create new buffer... + + const buffer = this._cgl.gl.createBuffer(); + + this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, buffer); + // this._cgl.gl.bufferData(this._cgl.gl.ARRAY_BUFFER, floatArray, this._cgl.gl.DYNAMIC_DRAW); + + let type = this._cgl.gl.FLOAT; + if (options && options.type) type = options.type; + const attr = { + "buffer": buffer, + "name": name, + "cb": cb, + "itemSize": itemSize, + "numItems": numItems, + "startItem": 0, + "instanced": instanced, + "type": type + }; + + this._bufferArray(array, attr); + + if (name == constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_POSITION) this._bufVertexAttrib = attr; + this._attributes.push(attr); + this._attribLocs = {}; + + return attr; +}; + +Mesh.prototype.getAttributes = function () +{ + return this._attributes; +}; + +/** + * @function updateTexCoords + * @description update texture coordinates only from a geometry + * @memberof Mesh + * @instance + * @param {Geometry} geometry + */ +Mesh.prototype.updateTexCoords = function (geom) +{ + if (geom.texCoords && geom.texCoords.length > 0) + { + this.setAttribute(constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_TEXCOORD, geom.texCoords, 2); + } + else + { + const tcBuff = new Float32Array(Math.round((geom.vertices.length / 3) * 2)); + this.setAttribute(constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_TEXCOORD, tcBuff, 2); + } +}; + + +/** + * @function updateNormals + * @description update normals only from a geometry + * @memberof Mesh + * @instance + * @param {Geometry} geometry + */ +Mesh.prototype.updateNormals = function (geom) +{ + if (geom.vertexNormals && geom.vertexNormals.length > 0) + { + this.setAttribute(constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_NORMAL, geom.vertexNormals, 3); + } + else + { + const tcBuff = new Float32Array(Math.round((geom.vertices.length))); + this.setAttribute(constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_NORMAL, tcBuff, 3); + } +}; + + +Mesh.prototype._setVertexNumbers = function (arr) +{ + if (!this._verticesNumbers || this._verticesNumbers.length != this._numVerts || arr) + { + if (arr) this._verticesNumbers = arr; + else + { + this._verticesNumbers = new Float32Array(this._numVerts); + for (let i = 0; i < this._numVerts; i++) this._verticesNumbers[i] = i; + } + + this.setAttribute(constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_NUMBER, this._verticesNumbers, 1, (attr, geom, shader) => + { + if (!shader.uniformNumVertices) shader.uniformNumVertices = new Uniform(shader, "f", "numVertices", this._numVerts); + shader.uniformNumVertices.setValue(this._numVerts); + + // console.log("this._numVerts", this._numVerts, attr, shader.uniformNumVertices); + }); + } +}; + +/** + * @function setVertexIndices + * @description update vertex indices / faces + * @memberof Mesh + * @instance + * @param {array} vertIndices + */ +Mesh.prototype.setVertexIndices = function (vertIndices) +{ + if (!this._bufVerticesIndizes) + { + this._log.warn("no bufVerticesIndizes: " + this._name); + return; + } + if (vertIndices.length > 0) + { + if (vertIndices instanceof Float32Array) this._log.warn("vertIndices float32Array: " + this._name); + + for (let i = 0; i < vertIndices.length; i++) + { + if (vertIndices[i] >= this._numVerts) + { + this._log.warn("invalid index in " + this._name, i, vertIndices[i]); + return; + } + } + + this._cgl.gl.bindBuffer(this._cgl.gl.ELEMENT_ARRAY_BUFFER, this._bufVerticesIndizes); + + // todo cache this ? + // if(!this.vertIndicesTyped || this.vertIndicesTyped.length!=this._geom.verticesIndices.length) + + if (vertIndices.length > 65535) + { + this.vertIndicesTyped = new Uint32Array(vertIndices); + this._indexType = this._cgl.gl.UNSIGNED_INT; + } + else + if (vertIndices instanceof Uint32Array) + { + this.vertIndicesTyped = vertIndices; + this._indexType = this._cgl.gl.UNSIGNED_INT; + } + else + if (!(vertIndices instanceof Uint16Array)) + { + this.vertIndicesTyped = new Uint16Array(vertIndices); + this._indexType = this._cgl.gl.UNSIGNED_SHORT; + } + else this.vertIndicesTyped = vertIndices; + + this._cgl.gl.bufferData(this._cgl.gl.ELEMENT_ARRAY_BUFFER, this.vertIndicesTyped, this._cgl.gl.DYNAMIC_DRAW); + this._bufVerticesIndizes.itemSize = 1; + this._bufVerticesIndizes.numItems = vertIndices.length; + } + else this._bufVerticesIndizes.numItems = 0; +}; + +/** + * @function setGeom + * @memberof Mesh + * @instance + * @description set geometry for mesh + * @param {Geometry} geometry + */ +Mesh.prototype.setGeom = function (geom, removeRef) +{ + this._geom = geom; + if (geom.glPrimitive != null) this._glPrimitive = geom.glPrimitive; + if (this._geom && this._geom.name) this._name = "mesh " + this._geom.name; + + MESH.lastMesh = null; + this._cgl.profileData.profileMeshSetGeom++; + + this._disposeAttributes(); + + this.updateVertices(this._geom); + this.setVertexIndices(this._geom.verticesIndices); + + if (this.addVertexNumbers) this._setVertexNumbers(); + + const geomAttribs = this._geom.getAttributes(); + + const attribAssoc = { + "texCoords": constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_TEXCOORD, + "vertexNormals": constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_NORMAL, + "vertexColors": constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_COLOR, + "tangents": "attrTangent", + "biTangents": "attrBiTangent", + }; + + for (const index in geomAttribs) + if (geomAttribs[index].data && geomAttribs[index].data.length) + this.setAttribute(attribAssoc[index] || index, geomAttribs[index].data, geomAttribs[index].itemSize); + + + if (removeRef) + { + this._geom = null; + } +}; + +Mesh.prototype._preBind = function (shader) +{ + for (let i = 0; i < this._attributes.length; i++) + if (this._attributes[i].cb) + this._attributes[i].cb(this._attributes[i], this._geom, shader); +}; + +Mesh.prototype._checkAttrLengths = function () +{ + if (this.memFreed) return; + // check length + for (let i = 0; i < this._attributes.length; i++) + { + if (this._attributes[i].arrayLength / this._attributes[i].itemSize < this._attributes[0].arrayLength / this._attributes[0].itemSize) + { + let name = "unknown"; + if (this._geom)name = this._geom.name; + // this._log.warn( + // name + ": " + this._attributes[i].name + + // " wrong attr length. is:", this._attributes[i].arrayLength / this._attributes[i].itemSize, + // " should be:", this._attributes[0].arrayLength / this._attributes[0].itemSize, + // ); + } + } +}; + +Mesh.prototype._bind = function (shader) +{ + if (!shader.isValid()) return; + + let attrLocs = []; + if (this._attribLocs[shader.id]) attrLocs = this._attribLocs[shader.id]; + else this._attribLocs[shader.id] = attrLocs; + + this._lastShader = shader; + if (shader.lastCompile > this._lastAttrUpdate || attrLocs.length != this._attributes.length) + { + this._lastAttrUpdate = shader.lastCompile; + for (let i = 0; i < this._attributes.length; i++) attrLocs[i] = -1; + } + + for (let i = 0; i < this._attributes.length; i++) + { + const attribute = this._attributes[i]; + if (attrLocs[i] == -1) + { + if (attribute._attrLocationLastShaderTime != shader.lastCompile) + { + attribute._attrLocationLastShaderTime = shader.lastCompile; + attrLocs[i] = this._cgl.glGetAttribLocation(shader.getProgram(), attribute.name); + // this._log.log('attribloc',attribute.name,attrLocs[i]); + this._cgl.profileData.profileAttrLoc++; + } + } + + if (attrLocs[i] != -1) + { + this._cgl.gl.enableVertexAttribArray(attrLocs[i]); + this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, attribute.buffer); + + if (attribute.instanced) + { + // todo: easier way to fill mat4 attribs... + if (attribute.itemSize <= 4) + { + if (!attribute.itemSize || attribute.itemSize == 0) this._log.warn("instanced attrib itemsize error", this._geom.name, attribute); + + this._cgl.gl.vertexAttribPointer(attrLocs[i], attribute.itemSize, attribute.type, false, attribute.itemSize * 4, 0); + this._cgl.gl.vertexAttribDivisor(attrLocs[i], 1); + } + else if (attribute.itemSize == 16) + { + const stride = 16 * 4; + + this._cgl.gl.vertexAttribPointer(attrLocs[i], 4, attribute.type, false, stride, 0); + this._cgl.gl.enableVertexAttribArray(attrLocs[i] + 1); + this._cgl.gl.vertexAttribPointer(attrLocs[i] + 1, 4, attribute.type, false, stride, 4 * 4 * 1); + this._cgl.gl.enableVertexAttribArray(attrLocs[i] + 2); + this._cgl.gl.vertexAttribPointer(attrLocs[i] + 2, 4, attribute.type, false, stride, 4 * 4 * 2); + this._cgl.gl.enableVertexAttribArray(attrLocs[i] + 3); + this._cgl.gl.vertexAttribPointer(attrLocs[i] + 3, 4, attribute.type, false, stride, 4 * 4 * 3); + + this._cgl.gl.vertexAttribDivisor(attrLocs[i], 1); + this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 1, 1); + this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 2, 1); + this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 3, 1); + } + else + { + this._log.warn("unknown instance attrib size", attribute.name); + } + } + else + { + if (!attribute.itemSize || attribute.itemSize == 0) this._log.warn("attrib itemsize error", this._name, attribute); + this._cgl.gl.vertexAttribPointer(attrLocs[i], attribute.itemSize, attribute.type, false, attribute.itemSize * 4, 0); + + if (attribute.pointer) + { + for (let ip = 0; ip < attribute.pointer.length; ip++) + { + const pointer = attribute.pointer[ip]; + + if (pointer.loc == -1) + pointer.loc = this._cgl.glGetAttribLocation(shader.getProgram(), pointer.name); + + this._cgl.profileData.profileAttrLoc++; + + this._cgl.gl.enableVertexAttribArray(pointer.loc); + this._cgl.gl.vertexAttribPointer(pointer.loc, attribute.itemSize, attribute.type, false, pointer.stride, pointer.offset); + } + } + this.bindFeedback(attribute); + } + } + } + + if (this._bufVerticesIndizes && this._bufVerticesIndizes.numItems !== 0) this._cgl.gl.bindBuffer(this._cgl.gl.ELEMENT_ARRAY_BUFFER, this._bufVerticesIndizes); +}; + +Mesh.prototype.unBind = function () +{ + const shader = this._lastShader; + this._lastShader = null; + if (!shader) return; + + let attrLocs = []; + if (this._attribLocs[shader.id]) attrLocs = this._attribLocs[shader.id]; + else this._attribLocs[shader.id] = attrLocs; + + MESH.lastMesh = null; + + for (let i = 0; i < this._attributes.length; i++) + { + if (this._attributes[i].instanced) + { + // todo: easier way to fill mat4 attribs... + if (this._attributes[i].itemSize <= 4) + { + if (attrLocs[i] != -1) this._cgl.gl.vertexAttribDivisor(attrLocs[i], 0); + if (attrLocs[i] >= 0) this._cgl.gl.disableVertexAttribArray(attrLocs[i]); + } + else + { + this._cgl.gl.vertexAttribDivisor(attrLocs[i], 0); + this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 1, 0); + this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 2, 0); + this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 3, 0); + this._cgl.gl.disableVertexAttribArray(attrLocs[i] + 1); + this._cgl.gl.disableVertexAttribArray(attrLocs[i] + 2); + this._cgl.gl.disableVertexAttribArray(attrLocs[i] + 3); + } + } + + if (attrLocs[i] != -1) this._cgl.gl.disableVertexAttribArray(attrLocs[i]); + } +}; + +Mesh.prototype.meshChanged = function () +{ + return this._cgl.lastMesh && this._cgl.lastMesh != this; +}; + +Mesh.prototype.printDebug = function (shader) +{ + console.log("--attributes"); + for (let i = 0; i < this._attributes.length; i++) + { + console.log("attribute " + i + " " + this._attributes[i].name); + } +}; + +Mesh.prototype.setNumVertices = function (num) +{ + this._bufVertexAttrib.numItems = num; +}; + +Mesh.prototype.getNumVertices = function () +{ + return this._bufVertexAttrib.numItems; +}; + + +/** + * @function render + * @memberof Mesh + * @instance + * @description draw mesh to screen + * @param {Shader} shader + */ +Mesh.prototype.render = function (shader) +{ + // TODO: enable/disablevertex only if the mesh has changed... think drawing 10000x the same mesh + + if (!shader || !shader.isValid() || this._cgl.aborted) return; + + this._checkAttrLengths(); + + if (this._geom) + { + if (this._preWireframeGeom && !shader.wireframe && !this._geom.isIndexed()) + { + this.setGeom(this._preWireframeGeom); + this._preWireframeGeom = null; + // console.log("remove prewireframe geom"); + } + + if (shader.wireframe) + { + let changed = false; + + if (this._geom.isIndexed()) + { + if (!this._preWireframeGeom) + { + this._preWireframeGeom = this._geom; + this._geom = this._geom.copy(); + } + + this._geom.unIndex(); + changed = true; + } + + if (!this._geom.getAttribute("attrBarycentric")) + { + if (!this._preWireframeGeom) + { + this._preWireframeGeom = this._geom; + this._geom = this._geom.copy(); + } + changed = true; + + this._geom.calcBarycentric(); + } + if (changed) this.setGeom(this._geom); + } + // if (shader.wireframe) + // console.log(shader.wireframe, this._geom.isIndexed()); + } + + let needsBind = false; + if (MESH.lastMesh != this) + { + if (MESH.lastMesh) MESH.lastMesh.unBind(); + needsBind = true; + } + + + // var needsBind=false; + // { + // needsBind=true; + // } + if (needsBind) this._preBind(shader); + + if (!shader.bind()) return; + + // if(needsBind) + this._bind(shader); + if (this.addVertexNumbers) this._setVertexNumbers(); + + MESH.lastMesh = this; + + let prim = this._cgl.gl.TRIANGLES; + if (this._glPrimitive !== undefined) prim = this._glPrimitive; + if (shader.glPrimitive !== null) prim = shader.glPrimitive; + + let elementDiv = 1; + let doQuery = this._cgl.profileData.doProfileGlQuery; + let queryStarted = false; + if (doQuery) + { + let id = this._name + " - " + shader.getName() + " #" + shader.id; + if (this._numInstances) id += " instanced " + this._numInstances + "x"; + + let queryProfilerData = this._cgl.profileData.glQueryData[id]; + + if (!queryProfilerData) queryProfilerData = { "id": id, "num": 0 }; + + if (shader.opId)queryProfilerData.shaderOp = shader.opId; + if (this.opId)queryProfilerData.meshOp = this.opId; + + this._cgl.profileData.glQueryData[id] = queryProfilerData; + + if (!this._queryExt && this._queryExt !== false) this._queryExt = this._cgl.enableExtension("EXT_disjoint_timer_query_webgl2") || false; + if (this._queryExt) + { + if (queryProfilerData._drawQuery) + { + const available = this._cgl.gl.getQueryParameter(queryProfilerData._drawQuery, this._cgl.gl.QUERY_RESULT_AVAILABLE); + if (available) + { + const elapsedNanos = this._cgl.gl.getQueryParameter(queryProfilerData._drawQuery, this._cgl.gl.QUERY_RESULT); + const currentTimeGPU = elapsedNanos / 1000000; + + queryProfilerData._times = queryProfilerData._times || 0; + queryProfilerData._times += currentTimeGPU; + queryProfilerData._numcount++; + queryProfilerData.when = performance.now(); + queryProfilerData._drawQuery = null; + queryProfilerData.queryStarted = false; + } + } + + if (!queryProfilerData.queryStarted) + { + queryProfilerData._drawQuery = this._cgl.gl.createQuery(); + this._cgl.gl.beginQuery(this._queryExt.TIME_ELAPSED_EXT, queryProfilerData._drawQuery); + queryStarted = queryProfilerData.queryStarted = true; + } + } + } + + + if (this.hasFeedbacks()) + { + this.drawFeedbacks(shader, prim); + } + else if (!this._bufVerticesIndizes || this._bufVerticesIndizes.numItems === 0) + { + // for (let i = 0; i < this._attributes.length; i++) + // { + // if (this._attributes[i].arrayLength / this._attributes[i].itemSize != this._bufVertexAttrib.floatArray.length / 3) + // { + // this._log.warn("attrib buffer length wrong! ", this._attributes[i].name, this._attributes[i].arrayLength / this._attributes[i].itemSize, this._bufVertexAttrib.floatArray.length / 3, this._attributes[i].itemSize); + // // this._log.log(this); + // // debugger; + // return; + // } + // } + + + if (prim == this._cgl.gl.TRIANGLES)elementDiv = 3; + if (this._numInstances === 0) this._cgl.gl.drawArrays(prim, this._bufVertexAttrib.startItem, this._bufVertexAttrib.numItems - this._bufVertexAttrib.startItem); + else this._cgl.gl.drawArraysInstanced(prim, this._bufVertexAttrib.startItem, this._bufVertexAttrib.numItems, this._numInstances); + } + else + { + if (prim == this._cgl.gl.TRIANGLES)elementDiv = 3; + if (this._numInstances === 0) + { + // console.log("la", this._bufVerticesIndizes.numItems); + + this._cgl.gl.drawElements(prim, this._bufVerticesIndizes.numItems, this._indexType, 0); + } + else + { + this._cgl.gl.drawElementsInstanced(prim, this._bufVerticesIndizes.numItems, this._indexType, 0, this._numInstances); + } + } + + if (this._cgl.debugOneFrame && this._cgl.gl.getError() != this._cgl.gl.NO_ERROR) + { + this._log.error("mesh draw gl error"); + this._log.error("mesh", this); + this._log.error("shader", shader); + + const attribNames = []; + for (let i = 0; i < this._cgl.gl.getProgramParameter(shader.getProgram(), this._cgl.gl.ACTIVE_ATTRIBUTES); i++) + { + const name = this._cgl.gl.getActiveAttrib(shader.getProgram(), i).name; + this._log.error("attrib ", name); + } + } + + this._cgl.profileData.profileMeshNumElements += (this._bufVertexAttrib.numItems / elementDiv) * (this._numInstances || 1); + this._cgl.profileData.profileMeshDraw++; + + if (doQuery && queryStarted) + { + this._cgl.gl.endQuery(this._queryExt.TIME_ELAPSED_EXT); + } + + this._cgl.printError("mesh render " + this._name); + + this.unBind(); +}; + +Mesh.prototype.setNumInstances = function (n) +{ + n = Math.max(0, n); + if (this._numInstances != n) + { + this._numInstances = n; + const indexArr = new Float32Array(n); + for (let i = 0; i < n; i++) indexArr[i] = i; + this.setAttribute(constants_CONSTANTS.SHADER.SHADERVAR_INSTANCE_INDEX, indexArr, 1, { "instanced": true }); + } +}; + +Mesh.prototype._disposeAttributes = function () +{ + if (!this._attributes) return; + + for (let i = 0; i < this._attributes.length; i++) + { + if (this._attributes[i].buffer) + { + this._cgl.gl.deleteBuffer(this._attributes[i].buffer); + this._attributes[i].buffer = null; + } + } + this._attributes.length = 0; +}; + +Mesh.prototype.dispose = function () +{ + if (this._bufVertexAttrib && this._bufVertexAttrib.buffer) this._cgl.gl.deleteBuffer(this._bufVertexAttrib.buffer); + if (this._bufVerticesIndizes) this._cgl.gl.deleteBuffer(this._bufVerticesIndizes); + this._bufVerticesIndizes = null; + + this._disposeAttributes(); +}; + +extendMeshWithFeedback(Mesh); + + + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_simplerect.js + + + + +const MESHES = {}; + +MESHES.getSimpleRect = function (cgl, name) +{ + const geom = new Geometry(name); + + geom.vertices = [1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0, -1.0, -1.0, 0.0]; + geom.texCoords = [1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0]; + geom.verticesIndices = [0, 1, 2, 2, 1, 3]; + geom.vertexNormals = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]; + + return new Mesh(cgl, geom); +}; + + +MESHES.getSimpleCube = function (cgl, name) +{ + const geom = new Geometry(name); + geom.vertices = [-1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1]; + geom.setTexCoords([0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0,]); + geom.verticesIndices = [0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23]; + geom.vertexNormals = new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0]); + geom.tangents = new Float32Array([0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]); + geom.biTangents = new Float32Array([-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1]); + + return new Mesh(cgl, geom); +}; + + + + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_textureeffect.js + + + + +const TextureEffect = function (cgl, options) +{ + this._cgl = cgl; + this._log = new Logger("cgl_TextureEffect"); + + if (!cgl.TextureEffectMesh) this.createMesh(); + + this._textureSource = null; + this._options = options; + this.name = options.name || "unknown"; + + // TODO: do we still need the options ? + // var opts=options || + // { + // isFloatingPointTexture:false, + // filter:CGL.Texture.FILTER_LINEAR + // }; + // if(options && options.fp)opts.isFloatingPointTexture=true; + + this.imgCompVer = 0; + this.aspectRatio = 1; + this._textureTarget = null; // new CGL.Texture(this._cgl,opts); + this._frameBuf = this._cgl.gl.createFramebuffer(); + this._frameBuf2 = this._cgl.gl.createFramebuffer(); + this._renderbuffer = this._cgl.gl.createRenderbuffer(); + this._renderbuffer2 = this._cgl.gl.createRenderbuffer(); + this.switched = false; + this.depth = false; +}; + +TextureEffect.prototype.dispose = function () +{ + if (this._renderbuffer) this._cgl.gl.deleteRenderbuffer(this._renderbuffer); + if (this._frameBuf) this._cgl.gl.deleteFramebuffer(this._frameBuf); + if (this._renderbuffer2) this._cgl.gl.deleteRenderbuffer(this._renderbuffer2); + if (this._frameBuf2) this._cgl.gl.deleteFramebuffer(this._frameBuf2); +}; + +TextureEffect.prototype.getWidth = function () +{ + return this._textureSource.width; +}; + +TextureEffect.prototype.getHeight = function () +{ + return this._textureSource.height; +}; + +TextureEffect.prototype.setSourceTexture = function (tex) +{ + if (tex === null) + { + this._textureSource = new Texture(this._cgl); + this._textureSource.setSize(16, 16); + } + else + { + this._textureSource = tex; + } + + if (!this._textureSource.compareSettings(this._textureTarget)) + { + if (this._textureTarget) this._textureTarget.delete(); + + this._textureTarget = this._textureSource.clone(); + + this._cgl.profileData.profileEffectBuffercreate++; + + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuf); + + this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, this._renderbuffer); + + // if(tex.textureType==CGL.Texture.TYPE_FLOAT) this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,this._cgl.gl.RGBA32F, this._textureSource.width,this._textureSource.height); + // else this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,this._cgl.gl.RGBA8, this._textureSource.width,this._textureSource.height); + + if (this.depth) this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, this._cgl.gl.DEPTH_COMPONENT16, this._textureSource.width, this._textureSource.height); + this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._textureTarget.tex, 0); + if (this.depth) this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.RENDERBUFFER, this._renderbuffer); + + // this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._textureTarget.tex, 0); + + this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, null); + this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, null); + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null); + + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuf2); + + this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, this._renderbuffer2); + + // if(tex.textureType==CGL.Texture.TYPE_FLOAT) this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,this._cgl.gl.RGBA32F, this._textureSource.width,this._textureSource.height); + // else this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,this._cgl.gl.RGBA8, this._textureSource.width,this._textureSource.height); + + if (this.depth) this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, this._cgl.gl.DEPTH_COMPONENT16, this._textureSource.width, this._textureSource.height); + this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._textureSource.tex, 0); + + if (this.depth) this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.RENDERBUFFER, this._renderbuffer2); + + // this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._textureSource.tex, 0); + + this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, null); + this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, null); + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null); + } + + this.aspectRatio = this._textureSource.width / this._textureSource.height; +}; +TextureEffect.prototype.continueEffect = function () +{ + this._cgl.pushDepthTest(false); + this._cgl.pushModelMatrix(); + this._cgl.pushPMatrix(); + // todo why two pushs? + + + + this._cgl.pushViewPort(0, 0, this.getCurrentTargetTexture().width, this.getCurrentTargetTexture().height); + + + + mat4.perspective(this._cgl.pMatrix, 45, this.getCurrentTargetTexture().width / this.getCurrentTargetTexture().height, 0.1, 1100.0); // todo: why? + + this._cgl.pushPMatrix(); + mat4.identity(this._cgl.pMatrix); + + this._cgl.pushViewMatrix(); + mat4.identity(this._cgl.vMatrix); + + this._cgl.pushModelMatrix(); + mat4.identity(this._cgl.mMatrix); +}; + + +TextureEffect.prototype.startEffect = function (bgTex) +{ + if (!this._textureTarget) + { + this._log.warn("effect has no target"); + return; + } + + this.switched = false; + + this.continueEffect(); + + if (bgTex) + { + this._bgTex = bgTex; + } + this._countEffects = 0; +}; + +TextureEffect.prototype.endEffect = function () +{ + this._cgl.popDepthTest(); + this._cgl.popModelMatrix(); + + this._cgl.popPMatrix(); + this._cgl.popModelMatrix(); + this._cgl.popViewMatrix(); + + this._cgl.popPMatrix(); + this._cgl.popViewPort(); +}; + +TextureEffect.prototype.bind = function () +{ + if (this._textureSource === null) + { + this._log.warn("no base texture set!"); + return; + } + + if (!this.switched) + { + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuf); + this._cgl.pushGlFrameBuffer(this._frameBuf); + } + else + { + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuf2); + this._cgl.pushGlFrameBuffer(this._frameBuf2); + } +}; + +TextureEffect.prototype.finish = function () +{ + if (this._textureSource === null) + { + this._log.warn("no base texture set!"); + return; + } + + this._cgl.TextureEffectMesh.render(this._cgl.getShader()); + + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.popGlFrameBuffer()); + + this._cgl.profileData.profileTextureEffect++; + + if (this._textureTarget.filter == Texture.FILTER_MIPMAP) + { + if (!this.switched) + { + this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, this._textureTarget.tex); + this._textureTarget.updateMipMap(); + } + else + { + this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, this._textureSource.tex); + this._textureSource.updateMipMap(); + } + + this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, null); + } + + this.switched = !this.switched; + this._countEffects++; +}; + +TextureEffect.prototype.getCurrentTargetTexture = function () +{ + if (this.switched) return this._textureSource; + return this._textureTarget; +}; + +TextureEffect.prototype.getCurrentSourceTexture = function () +{ + if (this._countEffects == 0 && this._bgTex) return this._bgTex; + + if (this.switched) return this._textureTarget; + return this._textureSource; +}; + +TextureEffect.prototype.delete = function () +{ + if (this._textureTarget) this._textureTarget.delete(); + if (this._textureSource) this._textureSource.delete(); + this._cgl.gl.deleteRenderbuffer(this._renderbuffer); + this._cgl.gl.deleteFramebuffer(this._frameBuf); +}; + +TextureEffect.prototype.createMesh = function () +{ + this._cgl.TextureEffectMesh = MESHES.getSimpleRect(this._cgl, "texEffectRect"); +}; + +// --------------------------------------------------------------------------------- + +TextureEffect.checkOpNotInTextureEffect = function (op) +{ + if (!op.patch.cgl) return true; + if (op.uiAttribs.error && !op.patch.cgl.currentTextureEffect) + { + op.setUiError("textureeffect", null); + return true; + } + if (!op.patch.cgl.currentTextureEffect) return true; + + if (op.patch.cgl.currentTextureEffect && !op.uiAttribs.error) + { + op.setUiError("textureeffect", "This op can not be a child of a ImageCompose/texture effect! imagecompose should only have textureeffect childs.", 0); + return false; + } + + if (op.patch.cgl.currentTextureEffect) return false; + return true; +}; + +TextureEffect.checkOpInEffect = function (op, minver) +{ + minver = minver || 0; + + if (op.patch.cgl.currentTextureEffect) + { + if (op.uiAttribs.uierrors && op.patch.cgl.currentTextureEffect.imgCompVer >= minver) + { + op.setUiError("texeffect", null); + return true; + } + + if (minver && op.patch.cgl.currentTextureEffect.imgCompVer < minver) + { + op.setUiError("texeffect", "This op must be a child of an ImageCompose op with version >=" + minver + " Downgrade to previous version", 1); + } + } + + if (op.patch.cgl.currentTextureEffect) return true; + + if (!op.patch.cgl.currentTextureEffect && (!op.uiAttribs.uierrors || op.uiAttribs.uierrors.length == 0)) + { + op.setUiError("texeffect", "This op must be a child of an ImageCompose op! More infos here. ", 1); + return false; + } + + if (!op.patch.cgl.currentTextureEffect) return false; + return true; +}; + +TextureEffect.getBlendCode = function (ver) +{ + let src = "".endl() + + "vec3 _blend(vec3 base,vec3 blend)".endl() + + "{".endl() + + " vec3 colNew=blend;".endl() + + " #ifdef BM_MULTIPLY".endl() + + " colNew=base*blend;".endl() + + " #endif".endl() + + " #ifdef BM_MULTIPLY_INV".endl() + + " colNew=base* vec3(1.0)-blend;".endl() + + " #endif".endl() + + " #ifdef BM_AVERAGE".endl() + + " colNew=((base + blend) / 2.0);".endl() + + " #endif".endl() + + " #ifdef BM_ADD".endl() + + " colNew=min(base + blend, vec3(1.0));".endl() + + " #endif".endl() + + " #ifdef BM_SUBTRACT_ONE".endl() + + " colNew=max(base + blend - vec3(1.0), vec3(0.0));".endl() + + " #endif".endl() + + + " #ifdef BM_SUBTRACT".endl() + + " colNew=base - blend;".endl() + + " #endif".endl() + + + " #ifdef BM_DIFFERENCE".endl() + + " colNew=abs(base - blend);".endl() + + " #endif".endl() + + " #ifdef BM_NEGATION".endl() + + " colNew=(vec3(1.0) - abs(vec3(1.0) - base - blend));".endl() + + " #endif".endl() + + " #ifdef BM_EXCLUSION".endl() + + " colNew=(base + blend - 2.0 * base * blend);".endl() + + " #endif".endl() + + " #ifdef BM_LIGHTEN".endl() + + " colNew=max(blend, base);".endl() + + " #endif".endl() + + " #ifdef BM_DARKEN".endl() + + " colNew=min(blend, base);".endl() + + " #endif".endl() + + " #ifdef BM_OVERLAY".endl() + + " #define BlendOverlayf(base, blend) (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)))" + // .endl()+' #define BlendOverlay(base, blend) Blend(base, blend, BlendOverlayf)' + // .endl()+' colNew=Blend(base, blend, BlendOverlayf);' + .endl() + + " colNew=vec3(BlendOverlayf(base.r, blend.r),BlendOverlayf(base.g, blend.g),BlendOverlayf(base.b, blend.b));".endl() + + " #endif".endl() + + " #ifdef BM_SCREEN".endl() + + " #define BlendScreenf(base, blend) (1.0 - ((1.0 - base) * (1.0 - blend)))" + // .endl()+' #define BlendScreen(base, blend) Blend(base, blend, BlendScreenf)' + // .endl()+' colNew=Blend(base, blend, BlendScreenf);' + .endl() + + " colNew=vec3(BlendScreenf(base.r, blend.r),BlendScreenf(base.g, blend.g),BlendScreenf(base.b, blend.b));".endl() + + " #endif".endl() + + " #ifdef BM_SOFTLIGHT".endl() + + " #define BlendSoftLightf(base, blend) ((blend < 0.5) ? (2.0 * base * blend + base * base * (1.0 - 2.0 * blend)) : (sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend)))" + // .endl()+' #define BlendSoftLight(base, blend) Blend(base, blend, BlendSoftLightf)' + // .endl()+' colNew=Blend(base, blend, BlendSoftLightf);' + .endl() + + " colNew=vec3(BlendSoftLightf(base.r, blend.r),BlendSoftLightf(base.g, blend.g),BlendSoftLightf(base.b, blend.b));".endl() + + " #endif".endl() + + " #ifdef BM_HARDLIGHT".endl() + + " #define BlendOverlayf(base, blend) (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)))" + // .endl()+' #define BlendOverlay(base, blend) Blend(base, blend, BlendOverlayf)' + // .endl()+' colNew=Blend(blend, base, BlendOverlayf);' + .endl() + + " colNew=vec3(BlendOverlayf(base.r, blend.r),BlendOverlayf(base.g, blend.g),BlendOverlayf(base.b, blend.b));".endl() + + " #endif".endl() + + " #ifdef BM_COLORDODGE".endl() + + " #define BlendColorDodgef(base, blend) ((blend == 1.0) ? blend : min(base / (1.0 - blend), 1.0))" + // .endl()+' colNew=Blend(base, blend, BlendColorDodgef);' + .endl() + + " colNew=vec3(BlendColorDodgef(base.r, blend.r),BlendColorDodgef(base.g, blend.g),BlendColorDodgef(base.b, blend.b));".endl() + + " #endif".endl() + + " #ifdef BM_COLORBURN".endl() + + " #define BlendColorBurnf(base, blend) ((blend == 0.0) ? blend : max((1.0 - ((1.0 - base) / blend)), 0.0))" + // .endl()+' colNew=Blend(base, blend, BlendColorBurnf);' + .endl() + + " colNew=vec3(BlendColorBurnf(base.r, blend.r),BlendColorBurnf(base.g, blend.g),BlendColorBurnf(base.b, blend.b));".endl() + + " #endif".endl() + + + + + + + + + + + + " return colNew;".endl() + + "}".endl(); + + if (!ver) + src += "vec4 cgl_blend(vec4 oldColor,vec4 newColor,float amount)".endl() + + "{".endl() + + "vec4 col=vec4( _blend(oldColor.rgb,newColor.rgb) ,1.0);".endl() + + "col=vec4( mix( col.rgb, oldColor.rgb ,1.0-oldColor.a*amount),1.0);".endl() + + "return col;".endl() + + "}".endl(); + + if (ver >= 3) + src += "vec4 cgl_blendPixel(vec4 base,vec4 col,float amount)".endl() + + "{".endl() + + + "#ifdef BM_MATH_ADD".endl() + + " return vec4(base.rgb+col.rgb*amount,1.0);".endl() + + "#endif".endl() + + + "#ifdef BM_MATH_SUB".endl() + + " return vec4(base.rgb-col.rgb*amount,1.0);".endl() + + "#endif".endl() + + + "#ifdef BM_MATH_MUL".endl() + + " return vec4(base.rgb*col.rgb*amount,1.0);".endl() + + "#endif".endl() + + + "#ifdef BM_MATH_DIV".endl() + + " return vec4(base.rgb/col.rgb*amount,1.0);".endl() + + "#endif".endl() + + + + "#ifndef BM_MATH".endl() + + "vec3 colNew=_blend(base.rgb,col.rgb);".endl() + + + "float newA=clamp(base.a+(col.a*amount),0.,1.);".endl() + + + "#ifdef BM_ALPHAMASKED".endl() + + "newA=base.a;".endl() + + "#endif".endl() + + + "return vec4(".endl() + + "mix(colNew,base.rgb,1.0-(amount*col.a)),".endl() + + "newA);".endl() + + + "#endif".endl() + + "}".endl(); + + return src; +}; + +TextureEffect.onChangeBlendSelect = function (shader, blendName, maskAlpha = false) +{ + blendName = String(blendName); + shader.toggleDefine("BM_NORMAL", blendName == "normal"); + shader.toggleDefine("BM_MULTIPLY", blendName == "multiply"); + shader.toggleDefine("BM_MULTIPLY_INV", blendName == "multiply invert"); + shader.toggleDefine("BM_AVERAGE", blendName == "average"); + shader.toggleDefine("BM_ADD", blendName == "add"); + shader.toggleDefine("BM_SUBTRACT_ONE", blendName == "subtract one"); + shader.toggleDefine("BM_SUBTRACT", blendName == "subtract"); + shader.toggleDefine("BM_DIFFERENCE", blendName == "difference"); + shader.toggleDefine("BM_NEGATION", blendName == "negation"); + shader.toggleDefine("BM_EXCLUSION", blendName == "exclusion"); + shader.toggleDefine("BM_LIGHTEN", blendName == "lighten"); + shader.toggleDefine("BM_DARKEN", blendName == "darken"); + shader.toggleDefine("BM_OVERLAY", blendName == "overlay"); + shader.toggleDefine("BM_SCREEN", blendName == "screen"); + shader.toggleDefine("BM_SOFTLIGHT", blendName == "softlight"); + shader.toggleDefine("BM_HARDLIGHT", blendName == "hardlight"); + shader.toggleDefine("BM_COLORDODGE", blendName == "color dodge"); + shader.toggleDefine("BM_COLORBURN", blendName == "color burn"); + + shader.toggleDefine("BM_MATH_ADD", blendName == "Math Add"); + shader.toggleDefine("BM_MATH_SUB", blendName == "Math Subtract"); + shader.toggleDefine("BM_MATH_MUL", blendName == "Math Multiply"); + shader.toggleDefine("BM_MATH_DIV", blendName == "Math Divide"); + + shader.toggleDefine("BM_MATH", blendName.indexOf("Math ") == 0); + + + shader.toggleDefine("BM_ALPHAMASKED", maskAlpha); +}; + +TextureEffect.AddBlendSelect = function (op, name, defaultMode) +{ + const p = op.inValueSelect(name || "Blend Mode", [ + "normal", "lighten", "darken", "multiply", "multiply invert", "average", "add", "subtract", "difference", "negation", "exclusion", "overlay", "screen", "color dodge", "color burn", "softlight", "hardlight", "subtract one", + "Math Add", + "Math Subtract", + "Math Multiply", + "Math Divide", + + ], defaultMode || "normal"); + return p; +}; + +TextureEffect.AddBlendAlphaMask = function (op, name, defaultMode) +{ + const p = op.inSwitch(name || "Alpha Mask", ["Off", "On"], defaultMode || "Off"); + return p; +}; + +TextureEffect.setupBlending = function (op, shader, blendPort, amountPort, alphaMaskPort) +{ + const onChange = () => + { + let maskAlpha = false; + if (alphaMaskPort) maskAlpha = alphaMaskPort.get() == "On"; + TextureEffect.onChangeBlendSelect(shader, blendPort.get(), maskAlpha); + + let str = blendPort.get(); + if (str == "normal") str = null; + else if (str == "multiply") str = "mul"; + else if (str == "multiply invert") str = "mulinv"; + else if (str == "lighten") str = "light"; + else if (str == "darken") str = "darken"; + else if (str == "average") str = "avg"; + else if (str == "subtract one") str = "sub one"; + else if (str == "subtract") str = "sub"; + else if (str == "difference") str = "diff"; + else if (str == "negation") str = "neg"; + else if (str == "exclusion") str = "exc"; + else if (str == "overlay") str = "ovl"; + else if (str == "color dodge") str = "dodge"; + else if (str == "color burn") str = "burn"; + else if (str == "softlight") str = "soft"; + else if (str == "hardlight") str = "hard"; + else if (str == "Math Add") str = "+"; + else if (str == "Math Subtract") str = "-"; + else if (str == "Math Multiply") str = "*"; + else if (str == "Math Divide") str = "/"; + + op.setUiAttrib({ "extendTitle": str }); + }; + op.setPortGroup("Blending", [blendPort, amountPort, alphaMaskPort]); + + let maskAlpha = false; + + blendPort.onChange = onChange; + if (alphaMaskPort) + { + alphaMaskPort.onChange = onChange; + maskAlpha = alphaMaskPort.get() == "On"; + } + + TextureEffect.onChangeBlendSelect(shader, blendPort.get(), maskAlpha); +}; + + + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_shader_lib.js + + + + +const ShaderLibMods = { + "CGL.BLENDMODES": function () + { + this.name = "blendmodes"; + this.srcHeadFrag = TextureEffect.getBlendCode(); + }, + "CGL.BLENDMODES3": function () + { + this.name = "blendmodes3"; + this.srcHeadFrag = TextureEffect.getBlendCode(3); + }, + + "CGL.LUMINANCE": function () + { + this.name = "luminance"; + this.srcHeadFrag = "".endl() + + "float cgl_luminance(vec3 c)".endl() + + "{".endl() + + " return dot(vec3(0.2126,0.7152,0.0722),c);".endl() + + "}".endl(); + }, + + + // quite good random numbers, but somehow don't work in ANGLE + "CGL.RANDOM_OLD": function () + { + this.name = "randomNumber"; + this.srcHeadFrag = "".endl() + + "float cgl_random(vec2 co)".endl() + + "{".endl() + + " return fract(sin(dot(co.xy ,vec2(12.9898,4.1414))) * 432758.5453);".endl() + + "}".endl() + + "vec3 cgl_random3(vec2 co)".endl() + + "{".endl() + + " return vec3( cgl_random(co),cgl_random(co+0.5711),cgl_random(co+1.5711));".endl() + + "}"; + }, + + + // low quality generative ranodm numbers + "CGL.RANDOM_LOW": function () + { + this.name = "randomNumber"; + this.srcHeadFrag = "".endl() + + "float cgl_random(vec2 co)".endl() + + "{".endl() + + " return fract(sin(dot(co.xy ,vec2(12.9898,4.1414))) * 358.5453);".endl() + + "}".endl() + + "vec3 cgl_random3(vec2 co)".endl() + + "{".endl() + + " return vec3( cgl_random(co),cgl_random(co+0.5711),cgl_random(co+1.5711));".endl() + + "}"; + }, + + // texture based random numbers + "CGL.RANDOM_TEX": function () + { + this.name = "randomNumbertex"; + this.srcHeadFrag = "".endl() + + "UNI sampler2D CGLRNDTEX;".endl() + + "float cgl_random(vec2 co)".endl() + + "{".endl() + + " return texture(CGLRNDTEX,co*5711.0).r;".endl() + + "}".endl() + + "vec3 cgl_random3(vec2 co)".endl() + + "{".endl() + + " return texture(CGLRNDTEX,co*5711.0).rgb;".endl() + + "}"; + + this.initUniforms = function (shader) + { + return [new Uniform(shader, "t", "CGLRNDTEX", 7)]; + }; + + this.onBind = function (cgl, shader) + { + Texture.getRandomTexture(cgl); + cgl.setTexture(7, Texture.getRandomTexture(cgl).tex); + }; + }, +}; + + + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_utils.js +/** @namespace CGL */ + +/** + * multiply to get radians from degree, e.g. `360 * CGL.DEG2RAD` + * @const {Number} + * @memberof CGL + * @static + */ +const cgl_utils_DEG2RAD = Math.PI / 180.0; + +/** + * to get degrees from radians, e.g. `3.14 * CGL.RAD2DEG` + * @const {number} + * @memberof CGL + */ +const cgl_utils_RAD2DEG = 180.0 / Math.PI; + +const onLoadingAssetsFinished = null; // deprecated / remove later + +/** + * get normalized mouse wheel delta (including browser specific adjustment) + * @function getWheelDelta + * @static + * @memberof CGL + * @param {MouseEvent} event + * @return {Number} normalized delta + */ +const isWindows = window.navigator.userAgent.contains("Windows"); +const getWheelDelta_ = function (event) +{ + let normalized; + if (event.wheelDelta) + { + // chrome + normalized = (event.wheelDelta % 120) - 0 == -0 ? event.wheelDelta / 120 : event.wheelDelta / 30; + normalized *= -1.5; + if (isWindows) normalized *= 2; + } + else + { + // firefox + let d = event.deltaY; + if (event.shiftKey) d = event.deltaX; + const rawAmmount = d || event.detail; + normalized = -(rawAmmount % 3 ? rawAmmount * 10 : rawAmmount / 3); + normalized *= -3; + } + + if (normalized > 20) normalized = 20; + if (normalized < -20) normalized = -20; + + return normalized; +}; + +const getWheelSpeed = getWheelDelta_; +const getWheelDelta = getWheelDelta_; + +// from https://github.com/lodash/lodash/blob/master/escape.js + +const htmlEscapes = { + "&": "&", + "<": "<", + ">": ">", + "\"": """, + "'": "'", +}; + +/** Used to match HTML entities and HTML characters. */ +const reUnescapedHtml = /[&<>"']/g; +const reHasUnescapedHtml = RegExp(reUnescapedHtml.source); + +/* eslint-disable */ +const escapeHTML = function(string) +{ + return string && reHasUnescapedHtml.test(string) ? + string.replace(reUnescapedHtml, function(chr) { return htmlEscapes[chr]; }) + : string || ""; +} +/* eslint-enable */ + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_shader_default_glsl.vert +/* harmony default export */ const cgl_shader_default_glsl = ("{{MODULES_HEAD}}\nIN vec3 vPosition; //!@\nIN vec2 attrTexCoord;\nIN vec3 attrVertNormal;\nIN vec3 attrTangent,attrBiTangent;\n\nIN float attrVertIndex;\n\nOUT vec2 texCoord;\nOUT vec3 norm;\nUNI mat4 projMatrix;\nUNI mat4 viewMatrix;\nUNI mat4 modelMatrix;\n\nvoid main()\n{\n texCoord=attrTexCoord;\n norm=attrVertNormal;\n vec4 pos=vec4(vPosition, 1.0);\n vec3 tangent=attrTangent;\n vec3 bitangent=attrBiTangent;\n mat4 mMatrix=modelMatrix;\n gl_PointSize=10.0;\n\n {{MODULE_VERTEX_POSITION}}\n\n mat4 modelViewMatrix=viewMatrix*mMatrix;\n {{MODULE_VERTEX_MOVELVIEW}}\n\n gl_Position = projMatrix * modelViewMatrix * pos;\n}\n"); +;// CONCATENATED MODULE: ./src/core/cgl/cgl_shader.js + + + + + +// import { CGL } from "./index.js"; + + + +// --------------------------------------------------------------------------- + + +/* + +proposal default shader variable names: + +attrVertex - currently: vPosition +attrVertexIndex - currently: attrVertIndex +attrTexCoord +attrInstMat - currently: instMat +attrVertColor +attrTangent +attrBiTangent + +uProjMatrix - currently: projMatrix +uModelMatrix - currently: modelMatrix +uNormalMatrix - currently: normalMatrix +uCamPosition - currently: camPos + +*/ + + +// --------------------------------------------------------------------------- + +let materialIdCounter = 0; + +/** + * @class + * @external CGL + * @namespace Shader + * @hideconstructor + * @example + * var shader=new CGL.Shader(cgl,'MinimalMaterial'); + * shader.setSource(attachments.shader_vert,attachments.shader_frag); + */ +const Shader = function (_cgl, _name, _op) +{ + if (!_cgl) throw new Error("shader constructed without cgl " + _name); + + this._log = new Logger("cgl_shader"); + this._cgl = _cgl; + + if (!_name) this._log.stack("no shader name given"); + this._name = _name || "unknown"; + + if (_op) this.opId = _op.id; + this.glslVersion = 0; + if (_cgl.glVersion > 1) this.glslVersion = 300; + + this._materialId = ++materialIdCounter; + + this.id = simpleId(); + this._isValid = true; + this._program = null; + this._uniforms = []; + this._drawBuffers = [true]; + this._defines = []; + this._needsRecompile = true; + this._compileReason = "initial"; + + this.ignoreMissingUniforms = false; + this._projMatrixUniform = null; + this._mvMatrixUniform = null; + this._mMatrixUniform = null; + this._vMatrixUniform = null; + this._camPosUniform = null; + this._normalMatrixUniform = null; + this._inverseViewMatrixUniform = null; + + this._attrVertexPos = -1; + this.precision = _cgl.patch.config.glslPrecision || "highp"; + + this._pMatrixState = -1; + this._vMatrixState = -1; + + this._countMissingUniforms = 0; + this._modGroupCount = 0; // not needed anymore... + this._feedBackNames = []; + this._attributes = []; + + this.glPrimitive = null; + this.offScreenPass = false; + this._extensions = []; + this.srcVert = this.getDefaultVertexShader(); + this.srcFrag = this.getDefaultFragmentShader(); + this.lastCompile = 0; + + this._moduleNames = []; + this._modules = []; + this._moduleNumId = 0; + + this._libs = []; + this._structNames = []; + this._structUniformNames = []; + this._textureStackUni = []; + this._textureStackTex = []; + this._textureStackType = []; + this._textureStackTexCgl = []; + + this._tempNormalMatrix = mat4.create(); + this._tempCamPosMatrix = mat4.create(); + this._tempInverseViewMatrix = mat4.create(); + this._tempInverseProjMatrix = mat4.create(); + + this.setModules(["MODULE_VERTEX_POSITION", "MODULE_COLOR", "MODULE_BEGIN_FRAG", "MODULE_VERTEX_MOVELVIEW"]); +}; + +Shader.prototype.isValid = function () +{ + return this._isValid; +}; + +Shader.prototype.getCgl = function () +{ + return this._cgl; +}; + +Shader.prototype.getName = function () +{ + return this._name; +}; + +/** + * enable an extension for the shader + * @function enableExtension + * @memberof Shader + * @instance + * @param name extension name + */ +Shader.prototype.enableExtension = function (name) +{ + this.setWhyCompile("enable extension " + name); + this._needsRecompile = true; + this._extensions.push(name); +}; + +Shader.prototype.getAttrVertexPos = function () +{ + return this._attrVertexPos; +}; + +Shader.prototype.hasTextureUniforms = function () +{ + for (let i = 0; i < this._uniforms.length; i++) + if (this._uniforms[i].getType() == "t") return true; + return false; +}; + +Shader.prototype.setWhyCompile = function (why) +{ + this._compileReason = why; +}; + +/** + * copy all uniform values from another shader + * @function copyUniforms + * @memberof Shader + * @instance + * @param shader uniform values will be copied from this shader + */ +Shader.prototype.copyUniformValues = function (origShader) +{ + // console.log(origShader._uniforms); + for (let i = 0; i < origShader._uniforms.length; i++) + { + if (!this._uniforms[i]) + { + this._log.log("unknown uniform?!"); + continue; + } + + // this._log.log(origShader._uniforms[i].getName()); + // this.getUniform(origShader._uniforms[i].) + // this._uniforms[i].set(origShader._uniforms[i].getValue()); + + + // if (origShader._uniforms[i].getName().contains("pathPoints")) + // console.log("copyUniformValues", origShader._uniforms[i].getName(), origShader._uniforms[i].getValue()); + + this.getUniform(origShader._uniforms[i].getName()).set(origShader._uniforms[i].getValue()); + } + + this.popTextures(); + for (let i = 0; i < origShader._textureStackUni.length; i++) + { + this._textureStackUni[i] = origShader._textureStackUni[i]; + this._textureStackTex[i] = origShader._textureStackTex[i]; + this._textureStackType[i] = origShader._textureStackType[i]; + this._textureStackTexCgl[i] = origShader._textureStackTexCgl[i]; + } + + // this._textureStackUni = []; + // this._textureStackTex = []; + // this._textureStackType = []; + // this._textureStackTexCgl = []; +}; + +/** + * copy current shader + * @function copy + * @memberof Shader + * @instance + * @returns newShader + */ +Shader.prototype.copy = function () +{ + const shader = new Shader(this._cgl, this._name + " copy"); + shader.setSource(this.srcVert, this.srcFrag); + + shader._modules = JSON.parse(JSON.stringify(this._modules)); + shader._defines = JSON.parse(JSON.stringify(this._defines)); + + shader._modGroupCount = this._modGroupCount; + shader._moduleNames = this._moduleNames; + shader.glPrimitive = this.glPrimitive; + shader.offScreenPass = this.offScreenPass; + shader._extensions = this._extensions; + shader.wireframe = this.wireframe; + shader._attributes = this._attributes; + + for (let i = 0; i < this._uniforms.length; i++) + { + const u = this._uniforms[i].copy(shader); + u.resetLoc(); + } + + this.setWhyCompile("copy"); + shader._needsRecompile = true; + return shader; +}; + + +/** + * set shader source code + * @function setSource + * @memberof Shader + * @instance + * @param {String} srcVert + * @param {String} srcFrag + */ +Shader.prototype.setSource = function (srcVert, srcFrag) +{ + this.srcVert = srcVert; + this.srcFrag = srcFrag; + this.setWhyCompile("Source changed"); + this._needsRecompile = true; + this._isValid = true; +}; + +Shader.prototype._addLibs = function (src) +{ + for (const id in ShaderLibMods) + { + if (src.contains(id)) + { + const lib = new ShaderLibMods[id](); + src = src.replace("{{" + id + "}}", lib.srcHeadFrag); + this._libs.push(lib); + if (lib.initUniforms)lib.initUniforms(this); + } + } + + return src; +}; + +Shader.prototype.createStructUniforms = function () +{ + // * create structs + let structStrFrag = ""; + let structStrVert = ""; // TODO: not used yet + + this._structNames = []; + // * reset the arrays holding the value each recompile so we don't skip structs + // * key value mapping so the same struct can be added twice (two times the same modifier) + this._injectedStringsFrag = {}; + this._injectedStringsVert = {}; + + this._structUniformNamesIndicesFrag = []; + this._structUniformNamesIndicesVert = []; + + for (let i = 0; i < this._uniforms.length; i++) + { + // * only add uniforms to struct that are a member of a struct + if (this._uniforms[i].isStructMember()) + { + const injectionString = "{{INJECTION_POINT_STRUCT_" + this._uniforms[i]._structName + "}}"; + + // * check if struct is not already part of shader + if (!this._structNames.includes(this._uniforms[i]._structName)) + { + // * create struct definition with placeholder string to inject + const structDefinition = "struct " + + this._uniforms[i]._structName + " {".endl() + + injectionString + + "};".endl().endl(); + + if (this._uniforms[i].getShaderType() === "both" || this._uniforms[i].getShaderType() === "frag") + structStrFrag = structStrFrag.concat(structDefinition); + + if (this._uniforms[i].getShaderType() === "both" || this._uniforms[i].getShaderType() === "vert") + structStrVert = structStrVert.concat(structDefinition); + + this._structNames.push(this._uniforms[i]._structName); + this._injectedStringsFrag[this._uniforms[i]._structName] = []; + this._injectedStringsVert[this._uniforms[i]._structName] = []; + } + + // * create member & comment + let comment = ""; + if (this._uniforms[i].comment) comment = " // " + this._uniforms[i].comment; + + let stringToInsert = ""; + if (this._uniforms[i].getGlslTypeString() == undefined)stringToInsert += "//"; + stringToInsert += " " + this._uniforms[i].getGlslTypeString() + + " " + this._uniforms[i]._propertyName + ";" + + comment; + + if (this._uniforms[i].getShaderType() === "both") + { + // * inject member before {injectionString} + if ( + !this._injectedStringsFrag[this._uniforms[i]._structName].contains(stringToInsert) + && !this._injectedStringsVert[this._uniforms[i]._structName].contains(stringToInsert)) + { + const insertionIndexFrag = structStrFrag.lastIndexOf(injectionString); + const insertionIndexVert = structStrVert.lastIndexOf(injectionString); + + structStrFrag = + structStrFrag.slice(0, insertionIndexFrag) + + stringToInsert + structStrFrag.slice(insertionIndexFrag - 1); + + structStrVert = + structStrVert.slice(0, insertionIndexVert) + + stringToInsert + structStrVert.slice(insertionIndexVert - 1); + + this._injectedStringsFrag[this._uniforms[i]._structName].push(stringToInsert); + this._injectedStringsVert[this._uniforms[i]._structName].push(stringToInsert); + } + + if (!this._structUniformNamesIndicesFrag.includes(i)) this._structUniformNamesIndicesFrag.push(i); + if (!this._structUniformNamesIndicesVert.includes(i)) this._structUniformNamesIndicesVert.push(i); + } + else if (this._uniforms[i].getShaderType() === "frag") + { + // * inject member before {injectionString} + if (!this._injectedStringsFrag[this._uniforms[i]._structName].includes(stringToInsert)) // + { + const insertionIndexFrag = structStrFrag.lastIndexOf(injectionString); + + structStrFrag = + structStrFrag.slice(0, insertionIndexFrag) + + stringToInsert + structStrFrag.slice(insertionIndexFrag - 1); + + this._injectedStringsFrag[this._uniforms[i]._structName].push(stringToInsert); + } + + if (!this._structUniformNamesIndicesFrag.includes(i)) this._structUniformNamesIndicesFrag.push(i); + } + else if (this._uniforms[i].getShaderType() === "vert") + { + // * inject member before {injectionString} + if (!this._injectedStringsVert[this._uniforms[i]._structName].includes(stringToInsert)) + { + const insertionIndexVert = structStrVert.lastIndexOf(injectionString); + + structStrVert = + structStrVert.slice(0, insertionIndexVert) + + stringToInsert + structStrVert.slice(insertionIndexVert - 1); + + this._injectedStringsVert[this._uniforms[i]._structName].push(stringToInsert); + } + + if (!this._structUniformNamesIndicesVert.includes(i)) this._structUniformNamesIndicesVert.push(i); + } + } + } + + // * dedupe injected uni declarations + this._uniDeclarationsFrag = []; + this._uniDeclarationsVert = []; + + // * remove struct injection points and add uniform in fragment + for (let i = 0; i < this._structUniformNamesIndicesFrag.length; i += 1) + { + const index = this._structUniformNamesIndicesFrag[i]; + const uniDeclarationString = "UNI " + this._uniforms[index]._structName + " " + this._uniforms[index]._structUniformName + ";".endl(); + + if (!this._uniDeclarationsFrag.includes(uniDeclarationString)) + { + const injectionString = "{{INJECTION_POINT_STRUCT_" + this._uniforms[index]._structName + "}}"; + + structStrFrag = structStrFrag.replace(injectionString, ""); + structStrFrag += uniDeclarationString; + + this._uniDeclarationsFrag.push(uniDeclarationString); + } + } + + // * remove struct injection points and add uniform in vertex + for (let i = 0; i < this._structUniformNamesIndicesVert.length; i += 1) + { + const index = this._structUniformNamesIndicesVert[i]; + const uniDeclarationString = "UNI " + this._uniforms[index]._structName + " " + this._uniforms[index]._structUniformName + ";".endl(); + + if (!this._uniDeclarationsVert.includes(uniDeclarationString)) + { + const injectionString = "{{INJECTION_POINT_STRUCT_" + this._uniforms[index]._structName + "}}"; + + structStrVert = structStrVert.replace(injectionString, ""); + structStrVert += uniDeclarationString; + this._uniDeclarationsVert.push(uniDeclarationString); + } + } + + return [structStrVert, structStrFrag]; +}; + +Shader.prototype._getAttrSrc = function (attr, firstLevel) +{ + const r = {}; + if (attr.name && attr.type) + { + r.srcHeadVert = ""; + if (!firstLevel) r.srcHeadVert += "#ifndef ATTRIB_" + attr.name.endl(); + r.srcHeadVert += "#define ATTRIB_" + attr.name.endl(); + r.srcHeadVert += "IN " + attr.type + " " + attr.name + ";".endl(); + if (!firstLevel) r.srcHeadVert += "#endif".endl(); + + if (attr.nameFrag) + { + r.srcHeadVert += ""; + if (!firstLevel) r.srcHeadVert += "#ifndef ATTRIB_" + attr.nameFrag.endl(); + r.srcHeadVert += "#define ATTRIB_" + attr.nameFrag.endl(); + r.srcHeadVert += "OUT " + attr.type + " " + attr.nameFrag + ";".endl(); + if (!firstLevel) r.srcHeadVert += "#endif".endl(); + + r.srcVert = "".endl() + attr.nameFrag + "=" + attr.name + ";"; + + r.srcHeadFrag = ""; + if (!firstLevel) r.srcHeadFrag += "#ifndef ATTRIB_" + attr.nameFrag.endl(); + r.srcHeadFrag += "#define ATTRIB_" + attr.nameFrag.endl(); + r.srcHeadFrag += "IN " + attr.type + " " + attr.nameFrag + ";".endl(); + if (!firstLevel) r.srcHeadFrag += "#endif".endl(); + } + } + return r; +}; + +Shader.prototype.compile = function () +{ + if (this._cgl.aborted) return; + const startTime = performance.now(); + + + + this._cgl.profileData.profileShaderCompiles++; + this._cgl.profileData.profileShaderCompileName = this._name + " [" + this._compileReason + "]"; + + let extensionString = ""; + if (this._extensions) + for (let i = 0; i < this._extensions.length; i++) + extensionString += "#extension " + this._extensions[i] + " : enable".endl(); + + let definesStr = ""; + if (this._defines.length) definesStr = "\n// cgl generated".endl(); + for (let i = 0; i < this._defines.length; i++) + definesStr += "#define " + this._defines[i][0] + " " + this._defines[i][1] + "".endl(); + + const structStrings = this.createStructUniforms(); + this._cgl.profileData.addHeavyEvent("shader compile", this._name + " [" + this._compileReason + "]"); + this._compileReason = ""; + + + + if (this._uniforms) + { + // * we create an array of the uniform names to check our indices & an array to save them + const uniNames = this._uniforms.map((uni) => { return uni._name; }); + const indicesToRemove = []; + + // * we go through our uniforms and check if the same name is contained somewhere further in the array + // * if so, we add the current index to be removed later + for (let i = 0; i < this._uniforms.length; i++) + { + const uni = this._uniforms[i]; + const nextIndex = uniNames.indexOf(uni._name, i + 1); + if (nextIndex > -1) indicesToRemove.push(i); + } + + // * after that, we go through the uniforms backwards (so we keep the order) and remove the indices + // * also, we reset the locations of all the other valid uniforms + for (let j = this._uniforms.length - 1; j >= 0; j -= 1) + { + if (indicesToRemove.includes(j)) this._uniforms.splice(j, 1); + else this._uniforms[j].resetLoc(); + } + } + + this._cgl.printError("uniform resets"); + + if (this.hasTextureUniforms()) definesStr += "#define HAS_TEXTURES".endl(); + + let vs = ""; + let fs = ""; + + if (!this.srcFrag) + { + this._log.error("[cgl shader] has no fragment source!", this); + this.srcVert = this.getDefaultVertexShader(); + this.srcFrag = this.getDefaultFragmentShader(); + // return; + } + + if (this.glslVersion == 300) + { + vs = "#version 300 es" + .endl() + "// " + .endl() + "// vertex shader " + this._name + .endl() + "// " + .endl() + "precision " + this.precision + " float;" + .endl() + "precision " + this.precision + " sampler2D;" + .endl() + "" + .endl() + "#define WEBGL2" + .endl() + "#define texture2D texture" + .endl() + "#define UNI uniform" + .endl() + "#define IN in" + .endl() + "#define OUT out" + .endl(); + + fs = "#version 300 es" + .endl() + "// " + .endl() + "// fragment shader " + this._name + .endl() + "// " + .endl() + "precision " + this.precision + " float;" + .endl() + "precision " + this.precision + " sampler2D;" + .endl() + "" + .endl() + "#define WEBGL2" + .endl() + "#define texture2D texture" + .endl() + "#define IN in" + .endl() + "#define OUT out" + .endl() + "#define UNI uniform" + .endl() + "{{DRAWBUFFER}}" + + .endl(); + } + else + { + fs = "" + .endl() + "// " + .endl() + "// fragment shader " + this._name + .endl() + "// " + .endl() + "#define WEBGL1" + .endl() + "#define texture texture2D" + .endl() + "#define outColor gl_FragColor" + .endl() + "#define IN varying" + .endl() + "#define UNI uniform" + .endl(); + + vs = "" + .endl() + "// " + .endl() + "// vertex shader " + this._name + .endl() + "// " + .endl() + "#define WEBGL1" + .endl() + "#define texture texture2D" + .endl() + "#define OUT varying" + .endl() + "#define IN attribute" + .endl() + "#define UNI uniform" + .endl(); + } + + let uniformsStrVert = "\n// cgl generated".endl(); + let uniformsStrFrag = "\n// cgl generated".endl(); + + + fs += "\n// active mods: --------------- "; + vs += "\n// active mods: --------------- "; + + let foundModsFrag = false; + let foundModsVert = false; + for (let i = 0; i < this._moduleNames.length; i++) + { + for (let j = 0; j < this._modules.length; j++) + { + if (this._modules[j].name == this._moduleNames[i]) + { + if (this._modules[j].srcBodyFrag || this._modules[j].srcHeadFrag) + { + foundModsFrag = true; + fs += "\n// " + i + "." + j + ". " + this._modules[j].title + " (" + this._modules[j].name + ")"; + } + if (this._modules[j].srcBodyVert || this._modules[j].srcHeadVert) + { + vs += "\n// " + i + "." + j + ". " + this._modules[j].title + " (" + this._modules[j].name + ")"; + foundModsVert = true; + } + } + } + } + if (!foundModsVert)fs += "\n// no mods used..."; + if (!foundModsFrag)fs += "\n// no mods used..."; + fs += "\n"; + vs += "\n"; + + for (let i = 0; i < this._uniforms.length; i++) + { + if (this._uniforms[i].shaderType && !this._uniforms[i].isStructMember()) + { + let uniStr = ""; + if (!this._uniforms[i].getGlslTypeString())uniStr += "// "; + uniStr += "UNI " + this._uniforms[i].getGlslTypeString() + " " + this._uniforms[i].getName(); + let comment = ""; + if (this._uniforms[i].comment) comment = " // " + this._uniforms[i].comment; + + if (this._uniforms[i].shaderType == "vert" || this._uniforms[i].shaderType == "both") + if (!this.srcVert.contains(uniStr) && !this.srcVert.contains("uniform " + this._uniforms[i].getGlslTypeString() + " " + this._uniforms[i].getName())) + uniformsStrVert += uniStr + ";" + comment.endl(); + + if (this._uniforms[i].shaderType == "frag" || this._uniforms[i].shaderType == "both") + if (!this.srcFrag.contains(uniStr) && !this.srcFrag.contains("uniform " + this._uniforms[i].getGlslTypeString() + " " + this._uniforms[i].getName())) + uniformsStrFrag += uniStr + ";" + comment.endl(); + } + } + + + let countUniFrag = 0; + let countUniVert = 0; + for (let i = 0; i < this._uniforms.length; i++) + { + if (this._uniforms[i].shaderType && !this._uniforms[i].isStructMember()) + { + if (this._uniforms[i].shaderType == "vert" || this._uniforms[i].shaderType == "both") countUniVert++; + if (this._uniforms[i].shaderType == "frag" || this._uniforms[i].shaderType == "both") countUniFrag++; + } + } + if (countUniFrag >= this._cgl.maxUniformsFrag) this._log.warn("[cgl_shader] num uniforms frag: " + countUniFrag + " / " + this._cgl.maxUniformsFrag); + if (countUniVert >= this._cgl.maxUniformsVert) this._log.warn("[cgl_shader] num uniforms vert: " + countUniVert + " / " + this._cgl.maxUniformsVert); + + + if (!fs.contains("precision")) fs = "precision " + this.precision + " float;".endl() + fs; + if (!vs.contains("precision")) vs = "precision " + this.precision + " float;".endl() + vs; + if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) + { + fs += "#define MOBILE".endl(); + vs += "#define MOBILE".endl(); + } + vs = extensionString + vs + definesStr + structStrings[0] + uniformsStrVert + "\n// -- \n" + this.srcVert; + fs = extensionString + fs + definesStr + structStrings[1] + uniformsStrFrag + "\n// -- \n" + this.srcFrag; + + + let srcHeadVert = ""; + let srcHeadFrag = ""; + + this._modules.sort(function (a, b) + { + return a.group - b.group; + }); + + this._modules.sort(function (a, b) + { + return a.priority || 0 - b.priority || 0; + }); + + + let addedAttribs = false; + + for (let i = 0; i < this._moduleNames.length; i++) + { + let srcVert = ""; + let srcFrag = ""; + + if (!addedAttribs) + { + addedAttribs = true; + + for (let k = 0; k < this._attributes.length; k++) + { + const r = this._getAttrSrc(this._attributes[k], true); + if (r.srcHeadVert)srcHeadVert += r.srcHeadVert; + if (r.srcVert)srcVert += r.srcVert; + if (r.srcHeadFrag)srcHeadFrag += r.srcHeadFrag; + } + } + + for (let j = 0; j < this._modules.length; j++) + { + const mod = this._modules[j]; + if (mod.name == this._moduleNames[i]) + { + srcHeadVert += "\n//---- MOD: group:" + mod.group + ": idx:" + j + " - prfx:" + mod.prefix + " - " + mod.title + " ------\n"; + srcHeadFrag += "\n//---- MOD: group:" + mod.group + ": idx:" + j + " - prfx:" + mod.prefix + " - " + mod.title + " ------\n"; + + srcVert += "\n\n//---- MOD: " + mod.title + " / " + mod.priority + " ------\n"; + srcFrag += "\n\n//---- MOD: " + mod.title + " / " + mod.priority + " ------\n"; + + if (mod.attributes) + for (let k = 0; k < mod.attributes.length; k++) + { + const r = this._getAttrSrc(mod.attributes[k], false); + if (r.srcHeadVert)srcHeadVert += r.srcHeadVert; + if (r.srcVert)srcVert += r.srcVert; + if (r.srcHeadFrag)srcHeadFrag += r.srcHeadFrag; + } + + srcHeadVert += mod.srcHeadVert || ""; + srcHeadFrag += mod.srcHeadFrag || ""; + srcVert += mod.srcBodyVert || ""; + srcFrag += mod.srcBodyFrag || ""; + + srcHeadVert += "\n//---- end mod ------\n"; + srcHeadFrag += "\n//---- end mod ------\n"; + + srcVert += "\n//---- end mod ------\n"; + srcFrag += "\n//---- end mod ------\n"; + + srcVert = srcVert.replace(/{{mod}}/g, mod.prefix); + srcFrag = srcFrag.replace(/{{mod}}/g, mod.prefix); + srcHeadVert = srcHeadVert.replace(/{{mod}}/g, mod.prefix); + srcHeadFrag = srcHeadFrag.replace(/{{mod}}/g, mod.prefix); + + srcVert = srcVert.replace(/MOD_/g, mod.prefix); + srcFrag = srcFrag.replace(/MOD_/g, mod.prefix); + srcHeadVert = srcHeadVert.replace(/MOD_/g, mod.prefix); + srcHeadFrag = srcHeadFrag.replace(/MOD_/g, mod.prefix); + } + } + + + vs = vs.replace("{{" + this._moduleNames[i] + "}}", srcVert); + fs = fs.replace("{{" + this._moduleNames[i] + "}}", srcFrag); + } + vs = vs.replace("{{MODULES_HEAD}}", srcHeadVert); + fs = fs.replace("{{MODULES_HEAD}}", srcHeadFrag); + + + vs = this._addLibs(vs); + fs = this._addLibs(fs); + + + // SETUP draw buffers / multi texture render targets + + let drawBufferStr = ""; + for (let i = 0; i < 16; i++) + if (fs.contains("outColor" + i)) this._drawBuffers[i] = true; + + if (this._drawBuffers.length == 1) + { + drawBufferStr = "out vec4 outColor;".endl(); + drawBufferStr += "#define gl_FragColor outColor".endl(); + } + else + { + drawBufferStr += "#define MULTI_COLORTARGETS".endl(); + drawBufferStr += "vec4 outColor;".endl(); + + let count = 0; + for (let i = 0; i < this._drawBuffers.length; i++) + { + if (count == 0) drawBufferStr += "#define gl_FragColor outColor" + i + "".endl(); + drawBufferStr += "layout(location = " + i + ") out vec4 outColor" + i + ";".endl(); + count++; + } + } + + fs = fs.replace("{{DRAWBUFFER}}", drawBufferStr); + // ////// + + + if (!this._program) + { + this._program = this._createProgram(vs, fs); + } + else + { + // this.vshader=createShader(vs, gl.VERTEX_SHADER, this.vshader ); + // this.fshader=createShader(fs, gl.FRAGMENT_SHADER, this.fshader ); + // linkProgram(program); + this._program = this._createProgram(vs, fs); + + this._projMatrixUniform = null; + + for (let i = 0; i < this._uniforms.length; i++) this._uniforms[i].resetLoc(); + } + + this.finalShaderFrag = fs; + this.finalShaderVert = vs; + + + MESH.lastMesh = null; + MESH.lastShader = null; + + this._countMissingUniforms = 0; + this._needsRecompile = false; + this.lastCompile = now(); + + // this._cgl.printError("shader compile"); + + this._cgl.profileData.shaderCompileTime += performance.now() - startTime; +}; + +Shader.hasChanged = function () +{ + return this._needsRecompile; +}; + + +Shader.prototype.bind = function () +{ + if (!this._isValid || this._cgl.aborted) return; + + MESH.lastShader = this; + + if (!this._program || this._needsRecompile) this.compile(); + if (!this._isValid) return; + + if (!this._projMatrixUniform && !this.ignoreMissingUniforms) + { + this._countMissingUniforms++; + // if (this._countMissingUniforms == 10)console.log("stopping getlocation of missing uniforms...", this._name); + if (this._countMissingUniforms < 10) + { + this._projMatrixUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_PROJMAT); + this._attrVertexPos = this._cgl.glGetAttribLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_POSITION); + this._mvMatrixUniform = this._cgl.gl.getUniformLocation(this._program, "mvMatrix"); + this._vMatrixUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_VIEWMAT); + this._mMatrixUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_MODELMAT); + this._camPosUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_VIEWPOS); + this._normalMatrixUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_NORMALMAT); + this._inverseViewMatrixUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_INVVIEWMAT); + this._inverseProjMatrixUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_INVPROJMAT); + this._materialIdUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_MATERIALID); + this._objectIdUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_OBJECTID); + + for (let i = 0; i < this._uniforms.length; i++) this._uniforms[i].needsUpdate = true; + } + } + + + if (this._cgl.currentProgram != this._program) + { + this._cgl.profileData.profileShaderBinds++; + this._cgl.gl.useProgram(this._program); + this._cgl.currentProgram = this._program; + } + + for (let i = 0; i < this._uniforms.length; i++) + if (this._uniforms[i].needsUpdate) this._uniforms[i].updateValue(); + + if (this._pMatrixState != this._cgl.getProjectionMatrixStateCount()) + { + this._pMatrixState = this._cgl.getProjectionMatrixStateCount(); + this._cgl.gl.uniformMatrix4fv(this._projMatrixUniform, false, this._cgl.pMatrix); + this._cgl.profileData.profileMVPMatrixCount++; + } + + if (this._objectIdUniform) + this._cgl.gl.uniform1f(this._objectIdUniform, ++this._cgl.frameStore.objectIdCounter); + + if (this._materialIdUniform) + this._cgl.gl.uniform1f(this._materialIdUniform, this._materialId); + + if (this._vMatrixUniform) + { + if (this._vMatrixState != this._cgl.getViewMatrixStateCount()) + { + this._cgl.gl.uniformMatrix4fv(this._vMatrixUniform, false, this._cgl.vMatrix); + this._cgl.profileData.profileMVPMatrixCount++; + this._vMatrixState = this._cgl.getViewMatrixStateCount(); + + if (this._inverseViewMatrixUniform) + { + mat4.invert(this._tempInverseViewMatrix, this._cgl.vMatrix); + this._cgl.gl.uniformMatrix4fv(this._inverseViewMatrixUniform, false, this._tempInverseViewMatrix); + this._cgl.profileData.profileMVPMatrixCount++; + } + if (this._inverseProjMatrixUniform) + { + mat4.invert(this._tempInverseProjMatrix, this._cgl.pMatrix); + this._cgl.gl.uniformMatrix4fv(this._inverseProjMatrixUniform, false, this._tempInverseProjMatrix); + this._cgl.profileData.profileMVPMatrixCount++; + } + } + this._cgl.gl.uniformMatrix4fv(this._mMatrixUniform, false, this._cgl.mMatrix); + this._cgl.profileData.profileMVPMatrixCount++; + + if (this._camPosUniform) + { + mat4.invert(this._tempCamPosMatrix, this._cgl.vMatrix); + this._cgl.gl.uniform3f(this._camPosUniform, this._tempCamPosMatrix[12], this._tempCamPosMatrix[13], this._tempCamPosMatrix[14]); + this._cgl.profileData.profileMVPMatrixCount++; + } + } + else + { + // mvmatrix deprecated.... + const tempmv = mat4.create(); + + mat4.mul(tempmv, this._cgl.vMatrix, this._cgl.mMatrix); + this._cgl.gl.uniformMatrix4fv(this._mvMatrixUniform, false, tempmv); + this._cgl.profileData.profileMVPMatrixCount++; + } + + if (this._normalMatrixUniform) + { + // mat4.mul(this._tempNormalMatrix, this._cgl.vMatrix, this._cgl.mMatrix); + mat4.invert(this._tempNormalMatrix, this._cgl.mMatrix); + mat4.transpose(this._tempNormalMatrix, this._tempNormalMatrix); + + this._cgl.gl.uniformMatrix4fv(this._normalMatrixUniform, false, this._tempNormalMatrix); + this._cgl.profileData.profileMVPMatrixCount++; + } + + for (let i = 0; i < this._libs.length; i++) + { + if (this._libs[i].onBind) this._libs[i].onBind.bind(this._libs[i])(this._cgl, this); + } + + this._bindTextures(); + + return this._isValid; +}; + +Shader.prototype.unBind = function () +{ +}; + +/** + * easily enable/disable a define without a value + * @function toggleDefine + * @memberof Shader + * @instance + * @param {name} name + * @param {any} value or port + */ +Shader.prototype.toggleDefine = function (name, enabled) +{ + if (enabled && typeof (enabled) == "object" && enabled.addEventListener) // port + { + if (enabled.changeListener)enabled.removeEventListener(enabled.changeListener); + + enabled.onToggleDefine = (v) => + { + this.toggleDefine(name, v); + }; + + enabled.changeListener = enabled.on("change", enabled.onToggleDefine); + enabled = enabled.get(); + } + + if (enabled) this.define(name); + else this.removeDefine(name); +}; + +/** + * add a define to a shader, e.g. #define DO_THIS_THAT 1 + * @function define + * @memberof Shader + * @instance + * @param {String} name + * @param {Any} value (can be empty) + */ +Shader.prototype.define = function (name, value) +{ + if (value === null || value === undefined) value = ""; + + if (typeof (value) == "object") // port + { + value.removeEventListener("change", value.onDefineChange); + value.onDefineChange = (v) => + { + this.define(name, v); + }; + value.on("change", value.onDefineChange); + + value = value.get(); + } + + + for (let i = 0; i < this._defines.length; i++) + { + if (this._defines[i][0] == name && this._defines[i][1] == value) return; + if (this._defines[i][0] == name) + { + this._defines[i][1] = value; + this.setWhyCompile("define " + name + " " + value); + + this._needsRecompile = true; + return; + } + } + this.setWhyCompile("define " + name + " " + value); + this._needsRecompile = true; + this._defines.push([name, value]); +}; + +Shader.prototype.getDefines = function () +{ + return this._defines; +}; + +Shader.prototype.getDefine = function (name) +{ + for (let i = 0; i < this._defines.length; i++) + if (this._defines[i][0] == name) return this._defines[i][1]; + return null; +}; + +/** + * return true if shader has define + * @function hasDefine + * @memberof Shader + * @instance + * @param {String} name + * @return {Boolean} + */ +Shader.prototype.hasDefine = function (name) +{ + for (let i = 0; i < this._defines.length; i++) + if (this._defines[i][0] == name) return true; +}; + +/** + * remove a define from a shader + * @param {name} name + * @function removeDefine + * @memberof Shader + * @instance + */ +Shader.prototype.removeDefine = function (name) +{ + for (let i = 0; i < this._defines.length; i++) + { + if (this._defines[i][0] == name) + { + this._defines.splice(i, 1); + this._needsRecompile = true; + + this.setWhyCompile("define removed:" + name); + + return; + } + } +}; + +/** + * remove a module from shader + * @function removeModule + * @memberof Shader + * @instance + * @param {shaderModule} module the module to be removed + */ +Shader.prototype.removeModule = function (mod) +{ + for (let i = 0; i < this._modules.length; i++) + { + if (mod && mod.id) + { + if (this._modules[i].id == mod.id || !this._modules[i]) + { + let found = true; + while (found) + { + found = false; + for (let j = 0; j < this._uniforms.length; j++) + { + if (this._uniforms[j].getName().startsWith(mod.prefix)) + { + this._uniforms.splice(j, 1); + found = true; + continue; + } + } + } + + this._needsRecompile = true; + this.setWhyCompile("remove module " + mod.title); + this._modules.splice(i, 1); + break; + } + } + } +}; + + +Shader.prototype.getNumModules = function () +{ + return this._modules.length; +}; + + +Shader.prototype.getCurrentModules = function () { return this._modules; }; + + +/** + * add a module + * @function addModule + * @memberof Shader + * @instance + * @param {shaderModule} module the module to be added + * @param {shaderModule} [sibling] sibling module, new module will share the same group + */ +Shader.prototype.addModule = function (mod, sibling) +{ + if (this.hasModule(mod.id)) return; + if (!mod.id) mod.id = CABLES.simpleId(); + if (!mod.numId) mod.numId = this._moduleNumId; + if (!mod.num)mod.num = this._modules.length; + if (sibling && !sibling.group) sibling.group = simpleId(); + + if (!mod.group) + if (sibling) mod.group = sibling.group; + else mod.group = simpleId(); + + mod.prefix = "mod" + mod.group + "_"; + this._modules.push(mod); + + this._needsRecompile = true; + this.setWhyCompile("add module " + mod.title); + this._moduleNumId++; + + return mod; +}; + +Shader.prototype.hasModule = function (modId) +{ + for (let i = 0; i < this._modules.length; i++) + { + if (this._modules[i].id == modId) return true; + } + return false; +}; + +Shader.prototype.setModules = function (names) +{ + this._moduleNames = names; +}; + +Shader.prototype.dispose = function () +{ + this._cgl.gl.deleteProgram(this._program); +}; + +Shader.prototype.needsRecompile = function () +{ + return this._needsRecompile; +}; + +Shader.prototype.setDrawBuffers = function (arr) +{ + console.log("useless drawbuffers...?!"); + // if (this._drawBuffers.length !== arr.length) + // { + // this._drawBuffers = arr; + // this._needsRecompile = true; + // this.setWhyCompile("setDrawBuffers"); + // return; + // } + // for (let i = 0; i < arr.length; i++) + // { + // if (arr[i] !== this._drawBuffers[i]) + // { + // this._drawBuffers = arr; + // this._needsRecompile = true; + // this.setWhyCompile("setDrawBuffers"); + // return; + // } + // } +}; + +Shader.prototype.getUniforms = function () +{ + return this._uniforms; +}; + +Shader.prototype.getUniform = function (name) +{ + for (let i = 0; i < this._uniforms.length; i++) + if (this._uniforms[i].getName() == name) + return this._uniforms[i]; + return null; +}; + +Shader.prototype.removeAllUniforms = function () +{ + this._uniforms = []; + // for (let i = 0; i < this._uniforms.length; i++) + // this.removeUniform(this._uniforms[i].name); +}; + +Shader.prototype.removeUniform = function (name) +{ + for (let i = 0; i < this._uniforms.length; i++) + { + if (this._uniforms[i].getName() == name) + { + this._uniforms.splice(i, 1); + } + } + this._needsRecompile = true; + this.setWhyCompile("remove uniform " + name); +}; + + +Shader.prototype._addUniform = function (uni) +{ + this._uniforms.push(uni); + this.setWhyCompile("add uniform " + name); + this._needsRecompile = true; +}; + +/** + * add a uniform to the fragment shader + * @param {String} type ['f','t', etc] + * @param {String} name + * @param {any} value or port + * @memberof Shader + * @instance + * @function addUniformFrag + * @returns {CGL.Uniform} + */ +Shader.prototype.addUniformFrag = function (type, name, valueOrPort, p2, p3, p4) +{ + const uni = new CGL.Uniform(this, type, name, valueOrPort, p2, p3, p4); + uni.shaderType = "frag"; + return uni; +}; + +/** + * add a uniform to the vertex shader + * @param {String} type ['f','t', etc] + * @param {String} name + * @param {any} value or port + * @memberof Shader + * @instance + * @function addUniformVert + * @returns {CGL.Uniform} + */ +Shader.prototype.addUniformVert = function (type, name, valueOrPort, p2, p3, p4) +{ + const uni = new CGL.Uniform(this, type, name, valueOrPort, p2, p3, p4); + uni.shaderType = "vert"; + return uni; +}; +/** + * add a uniform to both shaders + * @param {String} type ['f','t', etc] + * @param {String} name + * @param {any} value or port + * @memberof Shader + * @instance + * @function addUniformBoth + * @returns {CGL.Uniform} + */ +Shader.prototype.addUniformBoth = function (type, name, valueOrPort, p2, p3, p4) +{ + const uni = new CGL.Uniform(this, type, name, valueOrPort, p2, p3, p4); + uni.shaderType = "both"; + return uni; +}; + +/** + * add a struct & its uniforms to the fragment shader + * @param {String} structName name of the struct, i.e.: LightStruct + * @param {String} uniformName name of the struct uniform in the shader, i.e.: lightUni + * @param {Array} members array of objects containing the struct members. see example for structure + + * @memberof Shader + * @instance + * @function addUniformStructFrag + * @returns {Object} + * @example + * const shader = new CGL.Shader(cgl, 'MinimalMaterial'); + * shader.setSource(attachments.shader_vert, attachments.shader_frag); + * shader.addUniformStructFrag("Light", "uniformLight", [ + * { "type": "3f", "name": "position", "v1": null }, + * { "type": "4f", "name": "color", "v1": inR, v2: inG, v3: inB, v4: inAlpha } + * ]); + */ +Shader.prototype.addUniformStructFrag = function (structName, uniformName, members) +{ + const uniforms = {}; + + if (!members) return uniforms; + + for (let i = 0; i < members.length; i += 1) + { + const member = members[i]; + if (!this.hasUniform(uniformName + "." + member.name)) + { + const uni = new CGL.Uniform(this, member.type, uniformName + "." + member.name, member.v1, member.v2, member.v3, member.v4, uniformName, structName, member.name); + uni.shaderType = "frag"; + uniforms[uniformName + "." + member.name] = uni; + } + } + + return uniforms; +}; + +/** + * add a struct & its uniforms to the vertex shader + * @param {String} structName name of the struct, i.e.: LightStruct + * @param {String} uniformName name of the struct uniform in the shader, i.e.: lightUni + * @param {Array} members array of objects containing the struct members. see example for structure + + * @memberof Shader + * @instance + * @function addUniformStructVert + * @returns {CGL.Uniform} + * @example + * const shader = new CGL.Shader(cgl, 'MinimalMaterial'); + * shader.setSource(attachments.shader_vert, attachments.shader_frag); + * shader.addUniformStructVert("Light", "uniformLight", [ + * { "type": "3f", "name": "position", "v1": null }, + * { "type": "4f", "name": "color", "v1": inR, v2: inG, v3: inB, v4: inAlpha } + * ]); + */ +Shader.prototype.addUniformStructVert = function (structName, uniformName, members) +{ + const uniforms = {}; + + if (!members) return uniforms; + + for (let i = 0; i < members.length; i += 1) + { + const member = members[i]; + if (!this.hasUniform(uniformName + "." + member.name)) + { + const uni = new CGL.Uniform(this, member.type, uniformName + "." + member.name, member.v1, member.v2, member.v3, member.v4, uniformName, structName, member.name); + uni.shaderType = "vert"; + uniforms[uniformName + "." + member.name] = uni; + } + } + + return uniforms; +}; + +/** + * add a struct & its uniforms to the both shaders. PLEASE NOTE: it is not possible to add the same struct to both shaders when it contains ANY integer members. + * @param {String} structName name of the struct, i.e.: LightStruct + * @param {String} uniformName name of the struct uniform in the shader, i.e.: lightUni + * @param {Array} members array of objects containing the struct members. see example for structure + + * @memberof Shader + * @instance + * @function addUniformStructBoth + * @returns {Object} + * @example + * const shader = new CGL.Shader(cgl, 'MinimalMaterial'); + * shader.setSource(attachments.shader_vert, attachments.shader_frag); + * shader.addUniformStructBoth("Light", "uniformLight", [ + * { "type": "3f", "name": "position", "v1": null }, + * { "type": "4f", "name": "color", "v1": inR, v2: inG, v3: inB, v4: inAlpha } + * ]); + */ +Shader.prototype.addUniformStructBoth = function (structName, uniformName, members) +{ + const uniforms = {}; + + if (!members) return uniforms; + + for (let i = 0; i < members.length; i += 1) + { + const member = members[i]; + if ((member.type === "2i" || member.type === "i" || member.type === "3i")) + this._log.error("Adding an integer struct member to both shaders can potentially error. Please use different structs for each shader. Error occured in struct:", structName, " with member:", member.name, " of type:", member.type, "."); + if (!this.hasUniform(uniformName + "." + member.name)) + { + const uni = new CGL.Uniform(this, member.type, uniformName + "." + member.name, member.v1, member.v2, member.v3, member.v4, uniformName, structName, member.name); + uni.shaderType = "both"; + uniforms[uniformName + "." + member.name] = uni; + } + } + + return uniforms; +}; + +Shader.prototype.hasUniform = function (name) +{ + for (let i = 0; i < this._uniforms.length; i++) + { + if (this._uniforms[i].getName() == name) return true; + } + return false; +}; + +Shader.prototype._createProgram = function (vstr, fstr) +{ + this._cgl.printError("before _createprogram"); + + const program = this._cgl.gl.createProgram(); + + this.vshader = Shader.createShader(this._cgl, vstr, this._cgl.gl.VERTEX_SHADER, this); + this.fshader = Shader.createShader(this._cgl, fstr, this._cgl.gl.FRAGMENT_SHADER, this); + + + if (this.vshader && this.fshader) + { + this._cgl.gl.attachShader(program, this.vshader); + this._cgl.gl.attachShader(program, this.fshader); + + this._linkProgram(program, vstr, fstr); + } + else + { + this._isValid = false; + this._cgl.printError("shader _createProgram"); + console.log("could not link shaderprogram"); + return null; + } + + this._cgl.printError("shader _createProgram"); + return program; +}; + +Shader.prototype.hasErrors = function () +{ + return this._hasErrors; +}; + +Shader.prototype._linkProgram = function (program, vstr, fstr) +{ + this._cgl.printError("before _linkprogram"); + + if (this._feedBackNames.length > 0) + { + this._cgl.gl.transformFeedbackVaryings(program, this._feedBackNames, this._cgl.gl.SEPARATE_ATTRIBS); + // INTERLEAVED_ATTRIBS + // SEPARATE_ATTRIBS + } + + this._cgl.gl.linkProgram(program); + this._cgl.printError("gl.linkprogram"); + this._isValid = true; + + this._hasErrors = false; + + if (this._cgl.patch.config.glValidateShader !== false) + { + this._cgl.gl.validateProgram(program); + + if (!this._cgl.gl.getProgramParameter(program, this._cgl.gl.VALIDATE_STATUS)) + { + // validation failed + console.log("shaderprogram validation failed..."); + console.log(this._name + " programinfo: ", this._cgl.gl.getProgramInfoLog(program)); + } + + if (!this._cgl.gl.getProgramParameter(program, this._cgl.gl.LINK_STATUS)) + { + this._hasErrors = true; + this._log.warn(this._cgl.gl.getShaderInfoLog(this.fshader) || "empty shader infolog"); + this._log.warn(this._cgl.gl.getShaderInfoLog(this.vshader) || "empty shader infolog"); + this._log.error(this._name + " shader linking fail..."); + + console.log(this._name + " programinfo: ", this._cgl.gl.getProgramInfoLog(program)); + + console.log("--------------------------------------"); + console.log(this); + console.log("--------------------------------------"); + this._isValid = false; + + this._name = "errorshader"; + this.setSource(Shader.getDefaultVertexShader(), Shader.getErrorFragmentShader()); + this._cgl.printError("shader link err"); + } + } +}; + +Shader.prototype.getProgram = function () +{ + return this._program; +}; + +Shader.prototype.setFeedbackNames = function (names) +{ + this.setWhyCompile("setFeedbackNames"); + this._needsRecompile = true; + this._feedBackNames = names; +}; + +Shader.prototype.getDefaultVertexShader = Shader.getDefaultVertexShader = function () +{ + return cgl_shader_default_glsl; +}; + +Shader.prototype.getDefaultFragmentShader = Shader.getDefaultFragmentShader = function (r, g, b) +{ + if (r == undefined) + { + r = 0.5; + g = 0.5; + b = 0.5; + } + return "" + .endl() + "IN vec2 texCoord;" + .endl() + "{{MODULES_HEAD}}" + .endl() + "void main()" + .endl() + "{" + .endl() + " vec4 col=vec4(" + r + "," + g + "," + b + ",1.0);" + .endl() + " {{MODULE_COLOR}}" + .endl() + " outColor = col;" + .endl() + "}"; +}; + +/** + * adds attribute definition to shader header without colliding with other shader modules... + * when attrFrag is defined, vertex shader will output this attribute to the fragment shader + * @function + * @memberof Shader + * @instance + * @param {Object} attribObject {type:x,name:x,[nameFrag:x]} + * @return {Object} + */ +Shader.prototype.addAttribute = function (attr) +{ + for (let i = 0; i < this._attributes.length; i++) + { + if (this._attributes[i].name == attr.name && this._attributes[i].nameFrag == attr.nameFrag) return; + } + this._attributes.push(attr); + this._needsRecompile = true; + this.setWhyCompile("addAttribute"); +}; + +Shader.prototype.bindTextures = +Shader.prototype._bindTextures = function () +{ + if (this._textureStackTex.length > this._cgl.maxTextureUnits) + { + this._log.warn("[shader._bindTextures] too many textures bound", this._textureStackTex.length + "/" + this._cgl.maxTextureUnits); + } + + // for (let i = this._textureStackTex.length + 1; i < this._cgl.maxTextureUnits; i++) this._cgl.setTexture(i, null); + + for (let i = 0; i < this._textureStackTex.length; i++) + { + // console.log(this._textureStackTex.length, i); + if (!this._textureStackTex[i] && !this._textureStackTexCgl[i]) + { + this._log.warn("no texture for pushtexture", this._name); + } + else + { + let t = this._textureStackTex[i]; + if (this._textureStackTexCgl[i]) + { + t = this._textureStackTexCgl[i].tex || CGL.Texture.getEmptyTexture(this._cgl).tex; + } + + let bindOk = true; + + if (!this._textureStackUni[i]) + { + // throw(new Error('no uniform given to texturestack')); + this._log.warn("no uniform for pushtexture", this._name); + bindOk = this._cgl.setTexture(i, t, this._textureStackType[i]); + } + else + { + this._textureStackUni[i].setValue(i); + bindOk = this._cgl.setTexture(i, t, this._textureStackType[i]); + + // console.log(bindOk, i, t, this._textureStackType[i]); + } + if (!bindOk) console.warn("tex bind failed", this.getName(), this._textureStackUni[i]); + } + } +}; + +Shader.prototype.setUniformTexture = function (uni, tex) +{ + tex = tex || CGL.Texture.getTempTexture(this._cgl); + for (let i = 0; i < this._textureStackUni.length; i++) + if (this._textureStackUni[i] == uni) + { + const old = this._textureStackTex[i] || this._textureStackTexCgl[i]; + if (tex.hasOwnProperty("tex")) + { + this._textureStackTexCgl[i] = tex; + this._textureStackTex[i] = null; + } + else + { + this._textureStackTexCgl[i] = null; + this._textureStackTex[i] = tex; + } + + // this._textureStackTex[i] = tex; + // this._cgl.setTexture(i, tex, this._textureStackType[i]); + return old; + } + return null; +}; + +/** + * push a texture on the stack. those textures will be bound when binding the shader. texture slots are automatically set + * @param {uniform} texture uniform + * @param {texture} texture + * @param {type} texture type, can be ignored when TEXTURE_2D + * @function pushTexture + * @memberof Shader + * @instance + */ +Shader.prototype.pushTexture = function (uniform, t, type) +{ + if (!uniform) + { + console.log("no uniform given to texturestack", uniform); + return; + } + if (!t) + { + return; + } + if (!t.hasOwnProperty("tex") && !(t instanceof WebGLTexture)) + { + this._log.warn(new Error("invalid texture").stack); + + this._log.warn("[cgl_shader] invalid texture...", t); + return; + } + + this._textureStackUni.push(uniform); + + if (t.hasOwnProperty("tex")) + { + this._textureStackTexCgl.push(t); + this._textureStackTex.push(null); + } + else + { + this._textureStackTexCgl.push(null); + this._textureStackTex.push(t); + } + + this._textureStackType.push(type); +}; + +/** + * pop last texture + * @function popTexture + * @memberof Shader + * @instance + */ +Shader.prototype.popTexture = function () +{ + this._textureStackUni.pop(); + this._textureStackTex.pop(); + this._textureStackTexCgl.pop(); + this._textureStackType.pop(); +}; + +/** + * pop all textures + * @function popTextures + * @memberof Shader + * @instance + */ +Shader.prototype.popTextures = function () +{ + this._textureStackTex.length = + this._textureStackTexCgl.length = + this._textureStackType.length = + this._textureStackUni.length = 0; +}; + +Shader.prototype.getMaterialId = function () +{ + return this._materialId; +}; + +Shader.prototype.getInfo = function () +{ + const info = {}; + info.name = this._name; + // info.modules = JSON.parse(JSON.stringify(this._modules)); + // info.defines = JSON.parse(JSON.stringify(this._defines)); + info.defines = this.getDefines(); + info.hasErrors = this.hasErrors(); + + return info; +}; + +// -------------------------- + +Shader.getErrorFragmentShader = function () +{ + return "" + .endl() + "void main()" + .endl() + "{" + .endl() + " float g=mod((gl_FragCoord.y+gl_FragCoord.x),50.0)/50.0;" + .endl() + " g= step(0.1,g);" + .endl() + " outColor = vec4( g+0.5, 0.0, 0.0, 1.0);" + .endl() + "}"; +}; + +Shader.createShader = function (cgl, str, type, cglShader) +{ + if (cgl.aborted) return; + + // cgl.printError("[Shader.createShader] ", cglShader._name); + + function getBadLines(infoLog) + { + const basLines = []; + const lines = infoLog.split("\n"); + for (const i in lines) + { + const divide = lines[i].split(":"); + if (parseInt(divide[2], 10)) basLines.push(parseInt(divide[2], 10)); + } + return basLines; + } + + + const shader = cgl.gl.createShader(type); + cgl.gl.shaderSource(shader, str); + cgl.gl.compileShader(shader); + + if (!cgl.gl.getShaderParameter(shader, cgl.gl.COMPILE_STATUS)) + { + let infoLog = cgl.gl.getShaderInfoLog(shader); + if (!infoLog) + { + console.warn("empty shader info log", this._name); + return; + } + + console.log("compile status: "); + + const badLines = getBadLines(infoLog); + let htmlWarning = "
    ";
    +        const lines = str.match(/^.*((\r\n|\n|\r)|$)/gm);
    +
    +        if (!cgl.aborted && infoLog)
    +        {
    +            if (type == cgl.gl.VERTEX_SHADER) console.log("VERTEX_SHADER");
    +            if (type == cgl.gl.FRAGMENT_SHADER) console.log("FRAGMENT_SHADER");
    +
    +            for (const i in lines)
    +            {
    +                const j = parseInt(i, 10) + 1;
    +                const line = j + ": " + lines[i];
    +                console.log(line);
    +
    +                let isBadLine = false;
    +                for (const bj in badLines)
    +                    if (badLines[bj] == j) isBadLine = true;
    +
    +                if (isBadLine)
    +                {
    +                    htmlWarning += "
    "; + // htmlWarning += ""; + htmlWarning += "
    ";
    +                }
    +                htmlWarning += escapeHTML(line);
    +
    +                if (isBadLine)
    +                {
    +                    htmlWarning += "
    "; + htmlWarning += "
    ";
    +                }
    +            }
    +        }
    +
    +        console.warn(infoLog);
    +
    +        infoLog = infoLog.replace(/\n/g, "
    "); + if (cgl.patch.isEditorMode())console.log("Shader error ", cglShader._name, infoLog, this); + + htmlWarning = infoLog + "
    " + htmlWarning + "

    "; + htmlWarning += "
    "; + + cgl.patch.emitEvent("criticalError", { "title": "Shader error " + cglShader._name, "text": htmlWarning, "exception": { "message": infoLog } }); + + // this._name = "errorshader"; + cglShader.setSource(Shader.getDefaultVertexShader(), Shader.getErrorFragmentShader()); + } + else + { + // console.log(name+' shader compiled...'); + } + // cgl.printError("shader create2"); + return shader; +}; + + + + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_profiledata.js +class ProfileData +{ + constructor(cgl) + { + this._cgl = cgl; + this._lastTime = 0; + this.pause = false; + this.profileUniformCount = 0; + this.profileShaderBinds = 0; + this.profileUniformCount = 0; + this.profileShaderCompiles = 0; + this.profileVideosPlaying = 0; + this.profileMVPMatrixCount = 0; + this.profileEffectBuffercreate = 0; + this.profileShaderGetUniform = 0; + this.profileFrameBuffercreate = 0; + this.profileMeshSetGeom = 0; + this.profileTextureNew = 0; + this.profileGenMipMap = 0; + this.profileOnAnimFrameOps = 0; + + this.profileFencedPixelRead = 0; + this.profileMainloopMs = 0; + this.profileMeshDraw = 0; + this.profileTextureEffect = 0; + this.profileTexPreviews = 0; + this.shaderCompileTime = 0; + this.profileMeshNumElements = 0; + this.profileMeshAttributes = 0; + this.profileSingleMeshAttribute = []; + this.heavyEvents = []; + + this.doProfileGlQuery = false; + this.glQueryData = {}; + } + + clear() + { + this.profileSingleMeshAttribute = {}; + this.profileMeshAttributes = 0; + this.profileUniformCount = 0; + this.profileShaderGetUniform = 0; + this.profileShaderCompiles = 0; + this.profileShaderBinds = 0; + this.profileTextureResize = 0; + this.profileFrameBuffercreate = 0; + this.profileEffectBuffercreate = 0; + this.profileTextureDelete = 0; + this.profileMeshSetGeom = 0; + this.profileVideosPlaying = 0; + this.profileMVPMatrixCount = 0; + this.profileNonTypedAttrib = 0; + this.profileNonTypedAttribNames = ""; + this.profileTextureNew = 0; + this.profileGenMipMap = 0; + this.profileFramebuffer = 0; + this.profileMeshDraw = 0; + this.profileTextureEffect = 0; + this.profileTexPreviews = 0; + this.profileMeshNumElements = 0; + this.profileFencedPixelRead = 0; + } + + clearGlQuery() + { + for (let i in this.glQueryData) + { + if (!this.glQueryData[i].lastClear || performance.now() - this.glQueryData[i].lastClear > 1000) + { + this.glQueryData[i].time = this.glQueryData[i]._times / this.glQueryData[i]._numcount; + this.glQueryData[i].num = this.glQueryData[i]._numcount; + + this.glQueryData[i]._times = 0; + this.glQueryData[i]._numcount = 0; + this.glQueryData[i].lastClear = performance.now(); + } + } + } + + addHeavyEvent(event, name, info) + { + const e = { "event": event, "name": name, "info": info, "date": performance.now() }; + this.heavyEvents.push(e); + this._cgl.emitEvent("heavyEvent", e); + } +} + + + + +;// CONCATENATED MODULE: ../shared/client/src/helper.js +class Helper +{ + constructor() + { + this._simpleIdCounter = 0; + } + + uuid() + { + let d = new Date().getTime(); + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => + { + const r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c === "x" ? r : (r & 0x3) | 0x8).toString(16); + }); + } + + isNumeric(n) + { + return !isNaN(parseFloat(n)) && isFinite(n); + } + + /** + * generate a simple ID + * @function simpleId + * @memberof Utils + * @return {Number} new id + * @static + */ + simpleId() + { + this._simpleIdCounter++; + return this._simpleIdCounter; + } +} +/* harmony default export */ const helper = (new Helper()); + +;// CONCATENATED MODULE: ../shared/client/src/eventtarget.js + + + +class Events +{ + constructor() + { + this._log = new Logger("eventtarget"); + this._eventCallbacks = {}; + this._logName = ""; + this._logEvents = false; + this._listeners = {}; + + this.on = this.addEventListener; + this.off = this.removeEventListener; + } + + addEventListener(which, cb, idPrefix) + { + const event = + { + "id": (idPrefix || "") + helper.simpleId(), + "name": which, + "cb": cb, + }; + if (!this._eventCallbacks[which]) this._eventCallbacks[which] = [event]; + else this._eventCallbacks[which].push(event); + + this._listeners[event.id] = event; + + return event.id; + } + + hasEventListener(which, cb) + { + if (which && !cb) + { + // check by id + return !!this._listeners[which]; + } + else + { + this._log.warn("old eventtarget function haseventlistener!"); + if (which && cb) + { + if (this._eventCallbacks[which]) + { + const idx = this._eventCallbacks[which].indexOf(cb); + return idx !== -1; + } + } + } + } + + hasListenerForEventName(eventName) + { + return this._eventCallbacks[eventName] && this._eventCallbacks[eventName].length > 0; + } + + removeEventListener(which, cb) + { + if (which === null || which === undefined) return; + + if (!cb) // new style, remove by id, not by name/callback + { + const event = this._listeners[which]; + if (!event) + { + this._log.log("could not find event..."); + return; + } + + let found = true; + while (found) + { + found = false; + let index = -1; + for (let i = 0; i < this._eventCallbacks[event.name].length; i++) + { + if (this._eventCallbacks[event.name][i].id.indexOf(which) === 0) // this._eventCallbacks[event.name][i].id == which || + { + found = true; + index = i; + } + } + + if (index !== -1) + { + this._eventCallbacks[event.name].splice(index, 1); + delete this._listeners[which]; + } + } + + return; + } + + this._log.info("[eventtaget] ", "old function signature: removeEventListener! use listener id"); + this._log.log((new Error()).stack); + + let index = null; + for (let i = 0; i < this._eventCallbacks[which].length; i++) + if (this._eventCallbacks[which][i].cb === cb) + index = i; + + if (index !== null) + { + delete this._eventCallbacks[index]; + } + else this._log.warn("removeEventListener not found " + which); + } + + logEvents(enabled, name) + { + this._logEvents = enabled; + this._logName = name; + } + + emitEvent(which, param1, param2, param3, param4, param5, param6) + { + if (this._logEvents) this._log.log("[event] ", this._logName, which, this._eventCallbacks); + + if (this._eventCallbacks[which]) + { + for (let i = 0; i < this._eventCallbacks[which].length; i++) + { + if (this._eventCallbacks[which][i]) + { + this._eventCallbacks[which][i].cb(param1, param2, param3, param4, param5, param6); + } + } + } + else + { + if (this._logEvents) this._log.log("[event] has no event callback", which, this._eventCallbacks); + } + } +} + + +;// CONCATENATED MODULE: ./src/core/cg/cg_canvas.js +class CgCanvas +{ + constructor(options) + { + if (!options) + { + console.error("CgCanvas no options"); + } + else + { + this._canvasEle = options.canvasEle; + } + + if (!options.cg)console.error("CgCanvas options has no cg"); + if (!options.canvasEle)console.error("CgCanvas options has no canvasEle"); + + this._cg = options.cg; + this.pixelDensity = 1; + this.canvasWidth = this.canvasEle.clientWidth; + this.canvasHeight = this.canvasEle.clientHeight; + + this._oldWidthRp = -1; + this._oldHeightRp = -1; + + this.setSize(this.canvasWidth, this.canvasHeight); + } + + get canvasEle() { return this._canvasEle; } + + + setSize(w, h, ignorestyle) + { + if (this._oldWidthRp != w * this.pixelDensity || this._oldHeightRp != h * this.pixelDensity) + { + this._oldWidthRp = this.canvasEle.width = w * this.pixelDensity; + this._oldHeightRp = this.canvasEle.height = h * this.pixelDensity; + + if (!ignorestyle) + { + this.canvasEle.style.width = w + "px"; + this.canvasEle.style.height = h + "px"; + } + + this.updateSize(); + + this._cg.emitEvent("resize"); + } + } + + updateSize() + { + this.canvasEle.width = this.canvasWidth = this.canvasEle.clientWidth * this.pixelDensity; + this.canvasEle.height = this.canvasHeight = this.canvasEle.clientHeight * this.pixelDensity; + } + + dispose() + { + this._canvasEle.remove(); + this._canvasEle = null; + } +} + + + +;// CONCATENATED MODULE: ./src/core/cg/cg_matrixstack.js + +const MatrixStack = function () +{ + this._arr = [mat4.create()]; + this._index = 0; + this.stateCounter = 0; +}; + +MatrixStack.prototype.push = function (m) +{ + this._index++; + this.stateCounter++; + + if (this._index == this._arr.length) + { + const copy = mat4.create(); + this._arr.push(copy); + } + + mat4.copy(this._arr[this._index], m || this._arr[this._index - 1]); + + return this._arr[this._index]; +}; + +MatrixStack.prototype.pop = function () +{ + this.stateCounter++; + + this._index--; + if (this._index < 0) this._index = 0; + + return this._arr[this._index]; +}; + +MatrixStack.prototype.length = function () +{ + return this._index; +}; + + + +;// CONCATENATED MODULE: ./src/core/cg/cg_state.js + + + + + +// const CGState () +class CGState extends Events +{ + constructor(_patch) + { + super(); + // this.canvas = null; + + this.fpsCounter = new CABLES.CG.FpsCounter(); + this._identView = vec3.create(); + this._ident = vec3.create(); + vec3.set(this._identView, 0, 0, -2); + vec3.set(this._ident, 0, 0, 0); + + this.patch = _patch; + + + + this.DEPTH_COMPARE_FUNC_NEVER = 0; + this.DEPTH_COMPARE_FUNC_LESS = 1; + this.DEPTH_COMPARE_FUNC_EQUAL = 2; + this.DEPTH_COMPARE_FUNC_LESSEQUAL = 3; + this.DEPTH_COMPARE_FUNC_GREATER = 4; + this.DEPTH_COMPARE_FUNC_NOTEQUAL = 5; + this.DEPTH_COMPARE_FUNC_GREATEREQUAL = 6; + this.DEPTH_COMPARE_FUNC_ALWAYS = 7; + + + /** + * Current projection matrix + * @memberof Context + * @instance + * @type {mat4} + */ + this.pMatrix = mat4.create(); + + /** + * Current model matrix + * @memberof Context + * @instance + * @type {mat4} + */ + this.mMatrix = mat4.create(); + + /** + * Current view matrix + * @memberof Context + * @instance + * @type {mat4} + */ + this.vMatrix = mat4.create(); + this._textureslots = []; + + this._pMatrixStack = new MatrixStack(); + this._mMatrixStack = new MatrixStack(); + this._vMatrixStack = new MatrixStack(); + + this.canvasScale = 1; + + mat4.identity(this.mMatrix); + mat4.identity(this.vMatrix); + + + window.matchMedia("screen and (min-resolution: 2dppx)") + .addEventListener("change", (e) => + { + this.emitEvent("resize"); + }); + } + + get canvasWidth() + { + return this.cgCanvas.canvasWidth; + } + + get canvasHeight() + { + return this.cgCanvas.canvasHeight; + } + + set pixelDensity(p) + { + if (this.cgCanvas.pixelDensity != p) + { + this.cgCanvas.pixelDensity = p; + this.cgCanvas.updateSize(); + this.emitEvent("resize"); + } + } + + get pixelDensity() + { + return this.cgCanvas.pixelDensity; + } + + + getGApiName() + { + return ["WebGL", "WebGPU"][this.gApi]; + } + + get canvas() + { + return this.cgCanvas.canvasEle; + } + + setCanvas(canvEle) + { + if (this.cgCanvas && canvEle == this.cgCanvas.canvasEle) return; + if (typeof canvEle === "string") canvEle = document.getElementById(canvEle); + + this.cgCanvas = new CgCanvas({ "canvasEle": canvEle, "cg": this }); + + if (this._setCanvas) this._setCanvas(canvEle); + + this.updateSize(); + } + + updateSize() + { + this.cgCanvas.updateSize(); + } + + setSize(w, h, ignorestyle) + { + this.cgCanvas.setSize(w, h, ignorestyle); + } + + _resizeToWindowSize() + { + this.setSize(window.innerWidth, window.innerHeight); + this.updateSize(); + } + + _resizeToParentSize() + { + const p = this.canvas.parentElement; + if (!p) + { + this._log.error("cables: can not resize to container element"); + return; + } + this.setSize(p.clientWidth, p.clientHeight); + + this.updateSize(); + } + + setAutoResize(parent) + { + window.removeEventListener("resize", this._resizeToWindowSize.bind(this)); + window.removeEventListener("resize", this._resizeToParentSize.bind(this)); + + if (parent == "window") + { + window.addEventListener("resize", this._resizeToWindowSize.bind(this)); + window.addEventListener("orientationchange", this._resizeToWindowSize.bind(this)); + this._resizeToWindowSize(); + } + if (parent == "parent") + { + window.addEventListener("resize", this._resizeToParentSize.bind(this)); + this._resizeToParentSize(); + } + } + + + /** + * push a matrix to the projection matrix stack + * @function pushPMatrix + * @memberof Context + * @instance + * @param {mat4} projectionmatrix + */ + pushPMatrix() + { + this.pMatrix = this._pMatrixStack.push(this.pMatrix); + } + + /** + * pop projection matrix stack + * @function popPMatrix + * @memberof Context + * @instance + * @returns {mat4} current projectionmatrix + */ + popPMatrix() + { + this.pMatrix = this._pMatrixStack.pop(); + return this.pMatrix; + } + + getProjectionMatrixStateCount() + { + return this._pMatrixStack.stateCounter; + } + + /** + * push a matrix to the model matrix stack + * @function pushModelMatrix + * @memberof Context + * @instance + * @param {mat4} modelmatrix + * @example + * // see source code of translate op: + * cgl.pushModelMatrix(); + * mat4.translate(cgl.mMatrix,cgl.mMatrix, vec); + * trigger.trigger(); + * cgl.popModelMatrix(); + */ + pushModelMatrix() + { + this.mMatrix = this._mMatrixStack.push(this.mMatrix); + } + + /** + * pop model matrix stack + * @function popModelMatrix + * @memberof Context + * @instance + * @returns {mat4} current modelmatrix + */ + popModelMatrix() + { + // todo: DEPRECATE + // if (this._mMatrixStack.length === 0) throw "Invalid modelview popMatrix!"; + this.mMatrix = this._mMatrixStack.pop(); + return this.mMatrix; + } + + /** + * get model matrix + * @function modelMatrix + * @memberof Context + * @instance + * @returns {mat4} current modelmatrix + */ + modelMatrix() + { + return this.mMatrix; + } + + + /** + * push a matrix to the view matrix stack + * @function pushviewMatrix + * @memberof Context + * @instance + * @param {mat4} viewmatrix + */ + pushViewMatrix() + { + this.vMatrix = this._vMatrixStack.push(this.vMatrix); + } + + /** + * pop view matrix stack + * @function popViewMatrix + * @memberof Context + * @instance + * @returns {mat4} current viewmatrix + * @function + */ + popViewMatrix() + { + this.vMatrix = this._vMatrixStack.pop(); + } + + getViewMatrixStateCount() + { + return this._vMatrixStack.stateCounter; + } + + _startMatrixStacks(identTranslate, identTranslateView) + { + identTranslate = identTranslate || this._ident; + identTranslateView = identTranslateView || this._identView; + + mat4.perspective(this.pMatrix, 45, this.canvasWidth / this.canvasHeight, 0.1, 1000.0); + + mat4.identity(this.mMatrix); + mat4.identity(this.vMatrix); + mat4.translate(this.mMatrix, this.mMatrix, identTranslate); + mat4.translate(this.vMatrix, this.vMatrix, identTranslateView); + + this.pushPMatrix(); + this.pushModelMatrix(); + this.pushViewMatrix(); + } + + _endMatrixStacks() + { + this.popViewMatrix(); + this.popModelMatrix(); + this.popPMatrix(); + } + + dispose() + { + this.aborted = true; + if (this.cgCanvas) this.cgCanvas.dispose(); + if (this._dispose) this._dispose(); + } +} + + + + + +;// CONCATENATED MODULE: ./src/core/cg/sg_fpscounter.js + + +class FpsCounter extends Events +{ + constructor() + { + super(); + this._timeStartFrame = 0; + this._timeStartSecond = 0; + this._fpsCounter = 0; + this._msCounter = 0; + this._frameCount = 0; + + this.stats = { "ms": 0, "fps": 0 }; + } + + get frameCount() + { + return this._frameCount; + } + + startFrame() + { + this._timeStartFrame = CABLES.now(); + } + + endFrame() + { + this._frameCount++; + this._fpsCounter++; + + const timeFrame = CABLES.now() - this._timeStartFrame; + this._msCounter += timeFrame; + + if (CABLES.now() - this._timeStartSecond > 1000) + { + this.endSecond(); + } + } + + endSecond() + { + this.stats.fps = this._fpsCounter; + this.stats.ms = Math.round(this._msCounter / this._fpsCounter * 100) / 100; + + this.emitEvent("performance", this.stats); + + // reset + this._fpsCounter = 0; + this._msCounter = 0; + this._timeStartSecond = CABLES.now(); + } +} + +;// CONCATENATED MODULE: ./src/core/cg/cg_constants.js + + + + + +const CG = { + + "GAPI_WEBGL": 0, + "GAPI_WEBGPU": 1, + + "DEPTH_COMPARE_NEVER": 0, + "DEPTH_COMPARE_LESS": 1, + "DEPTH_COMPARE_EQUAL": 2, + "DEPTH_COMPARE_LESSEQUAL": 3, + "DEPTH_COMPARE_GREATER": 4, + "DEPTH_COMPARE_NOTEQUAL": 5, + "DEPTH_COMPARE_GREATEREQUAL": 6, + "DEPTH_COMPARE_ALWAYS": 7, + + "CULL_NONE": 0, + "CULL_BACK": 1, + "CULL_FRONT": 2, + "CULL_BOTH": 3, + + + "Geometry": Geometry, + "BoundingBox": BoundingBox, + "FpsCounter": FpsCounter, + + "CgCanvas": CgCanvas +}; + + + + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_state.js + + + + + + + + +/** + * cables gl context/state manager + * @external CGL + * @namespace Context + * @class + * @hideconstructor + */ +// const Context(_patch) +class Context extends CGState +{ + constructor(_patch) + { + super(_patch); + // EventTarget.apply(this); + // CGState.apply(this); + + this.gApi = CG.GAPI_WEBGL; + this.aborted = false; + + this.pushMvMatrix = this.pushModelMatrix; // deprecated and wrong... still used?? + this.popMvMatrix = this.popmMatrix = this.popModelMatrix;// deprecated and wrong... still used?? + + this.profileData = new ProfileData(this); + this._log = new Logger("cgl_context"); + this._viewPort = [0, 0, 0, 0]; + this.glVersion = 0; + this.glUseHalfFloatTex = false; + this.clearCanvasTransparent = true; + this.clearCanvasDepth = true; + this.debugOneFrame = false; + this.checkGlErrors = false; // true is slow // false should be default... + this.maxTextureUnits = 0; + this.maxVaryingVectors = 0; + this.currentProgram = null; + this._hadStackError = false; + this.glSlowRenderer = false; + this._isSafariCrap = false; + + this.temporaryTexture = null; + this.frameStore = {}; + this._onetimeCallbacks = []; + this.gl = null; + + this._cursor = "auto"; + this._currentCursor = ""; + + this._viewPortStack = []; + this._glFrameBufferStack = []; + this._frameBufferStack = []; + this._shaderStack = []; + this._stackDepthTest = []; + this.mainloopOp = null; + + this._simpleShader = new Shader(this, "simpleshader"); + this._simpleShader.setModules(["MODULE_VERTEX_POSITION", "MODULE_COLOR", "MODULE_BEGIN_FRAG", "MODULE_VERTEX_MOVELVIEW"]); + this._simpleShader.setSource(Shader.getDefaultVertexShader(), Shader.getDefaultFragmentShader()); + + this._currentShader = this._simpleShader; + + + this._oldCanvasWidth = -1; + this._oldCanvasHeight = -1; + this._enabledExtensions = {}; + } + + // set pixelDensity(p) + // { + // this._pixelDensity = p; + // } + + // get pixelDensity() + // { + // return this._pixelDensity; + // } + + + + get viewPort() + { + if (this._viewPortStack.length > 3) + { + const l = this._viewPortStack.length; + + return [ + this._viewPortStack[l - 4], + this._viewPortStack[l - 3], + this._viewPortStack[l - 2], + this._viewPortStack[l - 1] + ]; + } + else + { + // workaround pre viewport stack times / or+and initial value... + + return this._viewPort; + } + } + + + + get mvMatrix() // deprecate + { + return this.mMatrix; + } + + set mvMatrix(m) // deprecate + { + this.mMatrix = m; + } + + + exitError(msgId, msg) + { + console.log(msgId, msg); + this.patch.exitError(msgId, msg); + this.aborted = true; + } + + + _setCanvas(canv) + { + if (!canv) + { + this._log.stack("_setCanvas undef"); + } + + if (!this.patch.config.canvas) this.patch.config.canvas = {}; + if (!this.patch.config.canvas.hasOwnProperty("preserveDrawingBuffer")) this.patch.config.canvas.preserveDrawingBuffer = false; + if (!this.patch.config.canvas.hasOwnProperty("premultipliedAlpha")) this.patch.config.canvas.premultipliedAlpha = false; + if (!this.patch.config.canvas.hasOwnProperty("alpha")) this.patch.config.canvas.alpha = false; + + this.patch.config.canvas.stencil = true; + + if (this.patch.config.hasOwnProperty("clearCanvasColor")) this.clearCanvasTransparent = this.patch.config.clearCanvasColor; + if (this.patch.config.hasOwnProperty("clearCanvasDepth")) this.clearCanvasDepth = this.patch.config.clearCanvasDepth; + + // safari stuff.......... + if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent) && (navigator.userAgent.match(/iPhone/i))) + { + this._isSafariCrap = true; + this.glUseHalfFloatTex = true; + } + + if (!this.patch.config.canvas.forceWebGl1) this.gl = canv.getContext("webgl2", this.patch.config.canvas); + + + if (!this.gl || this.gl.isContextLost()) + { + this.aborted = true; + this.exitError("NO_WEBGL", "sorry, could not initialize WebGL. Please check if your Browser supports WebGL or try to restart your browser."); + return; + } + + if (this.gl.getParameter(this.gl.VERSION) != "WebGL 1.0") + { + this.glVersion = 2; + } + else + { + this.gl = canv.getContext("webgl", this.patch.config.canvas) || canv.getContext("experimental-webgl", this.patch.config.canvas); + this.glVersion = 1; + + // safari + // if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent) && (navigator.userAgent.match(/iPhone/i))) + // { + // this.glUseHalfFloatTex = true; + // } + + // ios + if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) + { + if (!this.patch.config.canvas.hasOwnProperty("powerPreference")) this.patch.config.canvas.powerPreference = "high-performance"; + } + + this.enableExtension("OES_standard_derivatives"); + // this.enableExtension("GL_OES_standard_derivatives"); + const instancingExt = this.enableExtension("ANGLE_instanced_arrays") || this.gl; + if (instancingExt.vertexAttribDivisorANGLE) + { + this.gl.vertexAttribDivisor = instancingExt.vertexAttribDivisorANGLE.bind(instancingExt); + this.gl.drawElementsInstanced = instancingExt.drawElementsInstancedANGLE.bind(instancingExt); + } + } + + const dbgRenderInfo = this.enableExtension("WEBGL_debug_renderer_info"); + if (dbgRenderInfo) + { + this.glRenderer = this.gl.getParameter(dbgRenderInfo.UNMASKED_RENDERER_WEBGL); + if (this.glRenderer === "Google SwiftShader") this.glSlowRenderer = true; + } + + this.canvas.addEventListener("webglcontextlost", (event) => + { + if (this.aborted) return console.log("[cgl_state] aborted context lost... can be ignored..."); + this._log.error("canvas lost...", event); + this.emitEvent("webglcontextlost"); + this.aborted = true; + }); + + + this.maxAnisotropic = 0; + if (this.enableExtension("EXT_texture_filter_anisotropic")) + this.maxAnisotropic = this.gl.getParameter(this.enableExtension("EXT_texture_filter_anisotropic").MAX_TEXTURE_MAX_ANISOTROPY_EXT); + + + this.maxVaryingVectors = this.gl.getParameter(this.gl.MAX_VARYING_VECTORS); + this.maxTextureUnits = this.gl.getParameter(this.gl.MAX_TEXTURE_IMAGE_UNITS); + this.maxTexSize = this.gl.getParameter(this.gl.MAX_TEXTURE_SIZE); + this.maxUniformsFrag = this.gl.getParameter(this.gl.MAX_FRAGMENT_UNIFORM_VECTORS); + this.maxUniformsVert = this.gl.getParameter(this.gl.MAX_VERTEX_UNIFORM_VECTORS); + this.maxSamples = 0; + if (this.gl.MAX_SAMPLES) this.maxSamples = this.gl.getParameter(this.gl.MAX_SAMPLES); + + if (this.glVersion == 1) + { + this.enableExtension("OES_standard_derivatives"); + const instancingExt = this.enableExtension("ANGLE_instanced_arrays") || this.gl; + + if (instancingExt.vertexAttribDivisorANGLE) + { + this.gl.vertexAttribDivisor = instancingExt.vertexAttribDivisorANGLE.bind(instancingExt); + this.gl.drawElementsInstanced = instancingExt.drawElementsInstancedANGLE.bind(instancingExt); + } + } + + this.DEPTH_FUNCS = [ + this.gl.NEVER, + this.gl.ALWAYS, + this.gl.LESS, + this.gl.LEQUAL, + this.gl.GREATER, + this.gl.GEQUAL, + this.gl.EQUAL, + this.gl.NOTEQUAL + ]; + this.CULL_MODES = [ + null, + this.gl.BACK, + this.gl.FRONT, + this.gl.FRONT_AND_BACK + ]; + } + + getInfo() + { + return { + "glVersion": this.glVersion, + "glRenderer": this.glRenderer, + "glUseHalfFloatTex": this.glUseHalfFloatTex, + "maxVaryingVectors": this.maxVaryingVectors, + "maxTextureUnits": this.maxTextureUnits, + "maxTexSize": this.maxTexSize, + "maxUniformsFrag": this.maxUniformsFrag, + "maxUniformsVert": this.maxUniformsVert, + "maxSamples": this.maxSamples + }; + } + + + + + + /** + * @function popViewPort + * @memberof Context + * @instance + * @description pop viewPort stack + */ + + + popViewPort() + { + this._viewPortStack.pop(); + this._viewPortStack.pop(); + this._viewPortStack.pop(); + this._viewPortStack.pop(); + + if (this._viewPortStack.length == 0) + { + this.setViewPort(0, 0, this.canvasWidth, this.canvasHeight); + // this.gl.viewport(this._viewPort[0], this._viewPort[1], this._viewPort[2], this._viewPort[3]); + // this.setViewPort(this._viewPort[0], this._viewPort[1], this._viewPort[2], this._viewPort[3]); + } + else + { + // this.viewPort = [this._viewPortStack[this._viewPort.length - 4], this._viewPortStack[this._viewPort.length - 3], this._viewPortStack[this._viewPort.length - 2], this._viewPortStack[this._viewPort.length - 1]]; + // this.gl.viewport(this._viewPortStack[this._viewPort.length - 4], this._viewPortStack[this._viewPort.length - 3], this._viewPortStack[this._viewPort.length - 2], this._viewPortStack[this._viewPort.length - 1]); + this.setViewPort(this._viewPortStack[this._viewPort.length - 4], this._viewPortStack[this._viewPort.length - 3], this._viewPortStack[this._viewPort.length - 2], this._viewPortStack[this._viewPort.length - 1]); + } + } + + /** + * @function pushViewPort + * @memberof Context + * @instance + * @description push a new viewport onto stack + * @param {Number} x + * @param {Number} y + * @param {Number} w + * @param {Number} h + */ + + pushViewPort(x, y, w, h) + { + this._viewPortStack.push(x, y, w, h); + this.setViewPort(x, y, w, h); + } + + + // old + getViewPort() + { + return this._viewPort; + } + + // old + resetViewPort() + { + this.gl.viewport(this._viewPort[0], this._viewPort[1], this._viewPort[2], this._viewPort[3]); + } + + // old + setViewPort(x, y, w, h) + { + this._viewPort[0] = Math.round(x); + this._viewPort[1] = Math.round(y); + this._viewPort[2] = Math.round(w); + this._viewPort[3] = Math.round(h); + this.gl.viewport(this._viewPort[0], this._viewPort[1], this._viewPort[2], this._viewPort[3]); + } + + + screenShot(cb, doScreenshotClearAlpha, mimeType, quality) + { + if (doScreenshotClearAlpha) + { + this.gl.clearColor(1, 1, 1, 1); + this.gl.colorMask(false, false, false, true); + this.gl.clear(this.gl.COLOR_BUFFER_BIT); + this.gl.colorMask(true, true, true, true); + } + + if (this.canvas && this.canvas.toBlob) + { + this.canvas.toBlob((blob) => + { + if (cb) cb(blob); + else this._log.log("no screenshot callback..."); + }, mimeType, quality); + } + } + + endFrame() + { + if (this.patch.isEditorMode()) CABLES.GL_MARKER.drawMarkerLayer(this); + + this.setPreviousShader(); + + if (this._vMatrixStack.length() > 0) this.logStackError("view matrix stack length !=0 at end of rendering..."); + if (this._mMatrixStack.length() > 0) this.logStackError("mvmatrix stack length !=0 at end of rendering..."); + if (this._pMatrixStack.length() > 0) this.logStackError("pmatrix stack length !=0 at end of rendering..."); + if (this._glFrameBufferStack.length > 0) this.logStackError("glFrameBuffer stack length !=0 at end of rendering..."); + if (this._stackDepthTest.length > 0) this.logStackError("depthtest stack length !=0 at end of rendering..."); + if (this._stackDepthWrite.length > 0) this.logStackError("depthwrite stack length !=0 at end of rendering..."); + if (this._stackDepthFunc.length > 0) this.logStackError("depthfunc stack length !=0 at end of rendering..."); + if (this._stackBlend.length > 0) this.logStackError("blend stack length !=0 at end of rendering..."); + if (this._stackBlendMode.length > 0) this.logStackError("blendMode stack length !=0 at end of rendering..."); + if (this._shaderStack.length > 0) this.logStackError("this._shaderStack length !=0 at end of rendering..."); + if (this._stackCullFace.length > 0) this.logStackError("this._stackCullFace length !=0 at end of rendering..."); + if (this._stackCullFaceFacing.length > 0) this.logStackError("this._stackCullFaceFacing length !=0 at end of rendering..."); + if (this._viewPortStack.length > 0) this.logStackError("viewport stack length !=0 at end of rendering..."); + + this._frameStarted = false; + + if (this._oldCanvasWidth != this.canvasWidth || this._oldCanvasHeight != this.canvasHeight) + { + this._oldCanvasWidth = this.canvasWidth; + this._oldCanvasHeight = this.canvasHeight; + this.emitEvent("resize"); + } + + if (this._cursor != this._currentCursor) + { + this._currentCursor = this.canvas.style.cursor = this._cursor; + } + + this.emitEvent("endframe"); + + this.fpsCounter.endFrame(); + } + + logStackError(str) + { + if (!this._hadStackError) + { + this._hadStackError = true; + this._log.warn("[" + this.canvas.id + "]: ", str); + } + } + + // shader stack + getShader() + { + if (this._currentShader) if (!this.frameStore || ((this.frameStore.renderOffscreen === true) == this._currentShader.offScreenPass) === true) return this._currentShader; + + for (let i = this._shaderStack.length - 1; i >= 0; i--) if (this._shaderStack[i]) if (this.frameStore.renderOffscreen == this._shaderStack[i].offScreenPass) return this._shaderStack[i]; + } + + getDefaultShader() + { + return this._simpleShader; + } + + /** + * push a shader to the shader stack + * @function pushShader + * @memberof Context + * @instance + * @param {Object} shader + * @function + */ + + pushShader(shader) + { + if (this.frameStore.forceShaderMods) + { + for (let i = 0; i < this.frameStore.forceShaderMods.length; i++) + { + // if (!currentShader.forcedMod && currentShader != this.frameStore.forceShaderMods[i]) + // { + // currentShader.forcedMod = this.frameStore.forceShaderMods[i]; + shader = this.frameStore.forceShaderMods[i].bind(shader, false); + // } + // return currentShader; + // if (this.frameStore.forceShaderMods[i].currentShader() && shader != this.frameStore.forceShaderMods[i].currentShader().shader) + } + } + + this._shaderStack.push(shader); + this._currentShader = shader; + } + + + /** + * pop current used shader from shader stack + * @function popShader + * @memberof Context + * @instance + * @function + */ + setPreviousShader() + { + if (this.frameStore.forceShaderMods) + { + for (let i = 0; i < this.frameStore.forceShaderMods.length; i++) + { + // const a = + this.frameStore.forceShaderMods[i].unbind(false); + // if (a) return; + // this.popShader(); + } + } + + if (this._shaderStack.length === 0) throw new Error("Invalid shader stack pop!"); + this._shaderStack.pop(); + this._currentShader = this._shaderStack[this._shaderStack.length - 1]; + } + + /** + * push a framebuffer to the framebuffer stack + * @function pushGlFrameBuffer + * @memberof Context + * @instance + * @param {Object} framebuffer + * @function + */ + pushGlFrameBuffer(fb) + { + this._glFrameBufferStack.push(fb); + } + + /** + * pop framebuffer stack + * @function popGlFrameBuffer + * @memberof Context + * @instance + * @returns {Object} current framebuffer or null + */ + popGlFrameBuffer() + { + if (this._glFrameBufferStack.length == 0) return null; + this._glFrameBufferStack.pop(); + return this._glFrameBufferStack[this._glFrameBufferStack.length - 1]; + } + + /** + * get current framebuffer + * @function getCurrentFrameBuffer + * @memberof Context + * @instance + * @returns {Object} current framebuffer or null + */ + getCurrentGlFrameBuffer() + { + if (this._glFrameBufferStack.length === 0) return null; + return this._glFrameBufferStack[this._glFrameBufferStack.length - 1]; + } + + /** + * push a framebuffer to the framebuffer stack + * @function pushGlFrameBuffer + * @memberof Context + * @instance + * @param {Framebuffer} framebuffer + */ + pushFrameBuffer(fb) + { + this._frameBufferStack.push(fb); + } + + /** + * pop framebuffer stack + * @function popFrameBuffer + * @memberof Context + * @instance + * @returns {Framebuffer} current framebuffer or null + */ + popFrameBuffer() + { + if (this._frameBufferStack.length == 0) return null; + this._frameBufferStack.pop(); + return this._frameBufferStack[this._frameBufferStack.length - 1]; + } + + /** + * get current framebuffer + * @function getCurrentFrameBuffer + * @memberof Context + * @instance + * @returns {Framebuffer} current framebuffer or null + */ + getCurrentFrameBuffer() + { + if (this._frameBufferStack.length === 0) return null; + return this._frameBufferStack[this._frameBufferStack.length - 1]; + } + + + renderStart(cgl, identTranslate, identTranslateView) + { + this.fpsCounter.startFrame(); + this.pushDepthTest(true); + this.pushDepthWrite(true); + this.pushDepthFunc(cgl.gl.LEQUAL); + this.pushCullFaceFacing(cgl.gl.BACK); + this.pushCullFace(false); + + // if (this.clearCanvasTransparent) + // { + // cgl.gl.clearColor(0, 0, 0, 0); + // cgl.gl.clear(cgl.gl.COLOR_BUFFER_BIT); + // } + // if (this.clearCanvasDepth) cgl.gl.clear(cgl.gl.DEPTH_BUFFER_BIT); + + cgl.setViewPort(0, 0, cgl.canvasWidth, cgl.canvasHeight); + + this._startMatrixStacks(identTranslate, identTranslateView); + + cgl.pushBlendMode(constants_CONSTANTS.BLEND_MODES.BLEND_NORMAL, false); + + for (let i = 0; i < this._textureslots.length; i++) this._textureslots[i] = null; + + this.pushShader(this._simpleShader); + + this._frameStarted = true; + + if (this._onetimeCallbacks.length > 0) + { + for (let i = 0; i < this._onetimeCallbacks.length; i++) this._onetimeCallbacks[i](); + this._onetimeCallbacks.length = 0; + } + + for (let i = 0; i < this._textureslots.length; i++) + { + this.gl.activeTexture(this.gl.TEXTURE0 + i); + this.gl.bindTexture(this.gl.TEXTURE_2D, null); + this._textureslots[i] = null; + } + + this.emitEvent("beginFrame"); + } + + renderEnd(cgl) + { + this._endMatrixStacks(); + + this.popDepthTest(); + this.popDepthWrite(); + this.popDepthFunc(); + this.popCullFaceFacing(); + this.popCullFace(); + this.popBlend(); + this.popBlendMode(); + + cgl.endFrame(); + + this.emitEvent("endFrame"); + } + + getTexture(slot) + { + return this._textureslots[slot]; + } + + hasFrameStarted() + { + return this._frameStarted; + } + + /** + * log warning to console if the rendering of one frame has not been started / handy to check for async problems + * @function checkFrameStarted + * @memberof Context + * @instance + */ + checkFrameStarted(string) + { + if (!this._frameStarted) + { + this._log.warn("frame not started " + string); + this.patch.printTriggerStack(); + } + } + + + setTexture(slot, t, type) + { + this.checkFrameStarted("cgl setTexture"); + + if (t === null) t = CGL.Texture.getEmptyTexture(this).tex; + + // if (!this.gl.isTexture(t)) + // { + // console.log("not a texture!!!!"); return false; + // t = CGL.Texture.getEmptyTexture(this).tex; + // } + + // if (!this.gl.isTexture(t)) + // { + // t = CGL.Texture.getErrorTexture(this).tex; + // // this._log.stack("not a texture!!!!"); + // // return false; + // } + + + if (this._textureslots[slot] != t) + { + this.gl.activeTexture(this.gl.TEXTURE0 + slot); + this.gl.bindTexture(type || this.gl.TEXTURE_2D, t); + this._textureslots[slot] = t; + } + + + return true; + } + + fullScreen() + { + if (this.canvas.requestFullscreen) this.canvas.requestFullscreen(); + else if (this.canvas.mozRequestFullScreen) this.canvas.mozRequestFullScreen(); + else if (this.canvas.webkitRequestFullscreen) this.canvas.webkitRequestFullscreen(); + else if (this.canvas.msRequestFullscreen) this.canvas.msRequestFullscreen(); + } + + + printError(str) + { + if (!this.checkGlErrors) return; + let found = false; + let error = this.gl.getError(); + + if (error != this.gl.NO_ERROR) + { + let errStr = ""; + if (error == this.gl.OUT_OF_MEMORY) errStr = "OUT_OF_MEMORY"; + if (error == this.gl.INVALID_ENUM) errStr = "INVALID_ENUM"; + if (error == this.gl.INVALID_OPERATION) errStr = "INVALID_OPERATION"; + if (error == this.gl.INVALID_FRAMEBUFFER_OPERATION) errStr = "INVALID_FRAMEBUFFER_OPERATION"; + if (error == this.gl.INVALID_VALUE) errStr = "INVALID_VALUE"; + if (error == this.gl.CONTEXT_LOST_WEBGL) + { + this.aborted = true; + errStr = "CONTEXT_LOST_WEBGL"; + } + if (error == this.gl.NO_ERROR) errStr = "NO_ERROR"; + + found = true; + + + this._log.warn("gl error [" + this.canvas.id + "]: ", str, error, errStr); + + if (this.canvas.id.contains("glGuiCanvas")) + if (!this._loggedGlError) + { + this.patch.printTriggerStack(); + this._log.stack("glerror"); + this._loggedGlError = true; + } + } + error = this.gl.getError(); + + return found; + } + + saveScreenshot(filename, cb, pw, ph, noclearalpha) + { + this.patch.renderOneFrame(); + + let w = this.canvas.clientWidth * this.pixelDensity; + let h = this.canvas.clientHeight * this.pixelDensity; + + if (pw) + { + this.canvas.width = pw; + w = pw; + } + if (ph) + { + this.canvas.height = ph; + h = ph; + } + + function padLeft(nr, n, str) + { + return Array(n - String(nr).length + 1).join(str || "0") + nr; + } + + const d = new Date(); + + const dateStr = "".concat(String(d.getFullYear()) + String(d.getMonth() + 1) + String(d.getDate()), "_").concat(padLeft(d.getHours(), 2)).concat(padLeft(d.getMinutes(), 2)).concat(padLeft(d.getSeconds(), 2)); + + if (!filename) filename = "cables_" + dateStr + ".png"; + else filename += ".png"; + + this.patch.cgl.screenShot(function (blob) + { + this.canvas.width = w; + this.canvas.height = h; + + if (blob) + { + const anchor = document.createElement("a"); + + anchor.download = filename; + anchor.href = URL.createObjectURL(blob); + + setTimeout(function () + { + anchor.click(); + if (cb) cb(blob); + }, 100); + } + else + { + this._log.log("screenshot: no blob"); + } + }.bind(this), noclearalpha); + } + + _dispose() + { + this._simpleShader.dispose(); + this.gl = null; + } +} + + +Context.prototype.popShader = Context.prototype.setPreviousShader; +Context.prototype.setShader = Context.prototype.pushShader; + +/** + * execute the callback next frame, once + * @function addNextFrameOnceCallback + * @memberof Context + * @instance + * @param {function} callback + */ +Context.prototype.addNextFrameOnceCallback = function (cb) +{ + if (cb) this._onetimeCallbacks.push(cb); +}; + +// state depthtest + +/** + * push depth testing enabled state + * @function pushDepthTest + * @param {Boolean} enabled + * @memberof Context + * @instance + */ +Context.prototype._stackDepthTest = []; +Context.prototype.pushDepthTest = function (b) +{ + this._stackDepthTest.push(b); + if (!b) this.gl.disable(this.gl.DEPTH_TEST); + else this.gl.enable(this.gl.DEPTH_TEST); +}; +/** + * current state of depth testing + * @function stateCullFace + * @returns {Boolean} enabled + * @memberof Context + * @instance + */ +Context.prototype.stateDepthTest = function () +{ + return this._stackDepthTest[this._stackDepthTest.length - 1]; +}; + +/** + * pop depth testing state + * @function popCullFace + * @memberof Context + * @instance + */ +Context.prototype.popDepthTest = function () +{ + this._stackDepthTest.pop(); + + if (!this._stackDepthTest[this._stackDepthTest.length - 1]) this.gl.disable(this.gl.DEPTH_TEST); + else this.gl.enable(this.gl.DEPTH_TEST); +}; + +// -------------------------------------- +// state depthwrite + +/** + * push depth write enabled state + * @function pushDepthTest + * @param {Boolean} enabled + * @memberof Context + * @instance + */ +Context.prototype._stackDepthWrite = []; +Context.prototype.pushDepthWrite = function (b) +{ + b = b || false; + this._stackDepthWrite.push(b); + this.gl.depthMask(b); +}; + +/** + * current state of depth writing + * @function stateCullFace + * @returns {Boolean} enabled + * @memberof Context + * @instance + */ +Context.prototype.stateDepthWrite = function () +{ + return this._stackDepthWrite[this._stackDepthWrite.length - 1]; +}; + +/** + * pop depth writing state + * @function popCullFace + * @memberof Context + * @instance + */ +Context.prototype.popDepthWrite = function () +{ + this._stackDepthWrite.pop(); + this.gl.depthMask(this._stackDepthWrite[this._stackDepthWrite.length - 1] || false); +}; + + +// -------------------------------------- +// state CullFace + +/** + * push face culling face enabled state + * @function pushCullFaceFacing + * @param {Boolean} enabled + * @memberof Context + * @instance + */ +Context.prototype._stackCullFace = []; +Context.prototype.pushCullFace = function (b) +{ + this._stackCullFace.push(b); + + if (b) this.gl.enable(this.gl.CULL_FACE); + else this.gl.disable(this.gl.CULL_FACE); +}; + +/** + * current state of face culling + * @function stateCullFace + * @returns {Boolean} enabled + * @memberof Context + * @instance + */ +Context.prototype.stateCullFace = function () +{ + return this._stackCullFace[this._stackCullFace.length - 1]; +}; + +/** + * pop face culling enabled state + * @function popCullFace + * @memberof Context + * @instance + */ +Context.prototype.popCullFace = function () +{ + this._stackCullFace.pop(); + + if (this._stackCullFace[this._stackCullFace.length - 1]) this.gl.enable(this.gl.CULL_FACE); + else this.gl.disable(this.gl.CULL_FACE); +}; + + +// -------------------------------------- +// state CullFace Facing + + +/** + * push face culling face side + * @function pushCullFaceFacing + * @param {Number} cgl.gl.FRONT_AND_BACK, cgl.gl.BACK or cgl.gl.FRONT + * @memberof Context + * @instance + */ +Context.prototype._stackCullFaceFacing = []; +Context.prototype.pushCullFaceFacing = function (b) +{ + this._stackCullFaceFacing.push(b); + this.gl.cullFace(this._stackCullFaceFacing[this._stackCullFaceFacing.length - 1]); +}; + +/** + * current state of face culling side + * @function stateCullFaceFacing + * @returns {Boolean} enabled + * @memberof Context + * @instance + */ +Context.prototype.stateCullFaceFacing = function () +{ + return this._stackCullFaceFacing[this._stackCullFaceFacing.length - 1]; +}; + +/** + * pop face culling face side + * @function popCullFaceFacing + * @memberof Context + * @instance + */ +Context.prototype.popCullFaceFacing = function () +{ + this._stackCullFaceFacing.pop(); + if (this._stackCullFaceFacing.length > 0) this.gl.cullFace(this._stackCullFaceFacing[this._stackCullFaceFacing.length - 1]); +}; + + +// -------------------------------------- +// state depthfunc + +Context.prototype._stackDepthFunc = []; + +/** + * enable / disable depth testing + * like `gl.depthFunc(boolean);` + * @function pushDepthFunc + * @memberof Context + * @instance + * @param {Boolean} depthtesting + */ +Context.prototype.pushDepthFunc = function (f) +{ + this._stackDepthFunc.push(f); + this.gl.depthFunc(f); +}; + +/** + * current state of blend + * @function stateDepthFunc + * @memberof Context + * @instance + * @returns {Boolean} depth testing enabled/disabled + */ +Context.prototype.stateDepthFunc = function () +{ + if (this._stackDepthFunc.length > 0) return this._stackDepthFunc[this._stackDepthFunc.length - 1]; + return false; +}; + +/** + * pop depth testing and set the previous state + * @function popDepthFunc + * @memberof Context + * @instance + */ +Context.prototype.popDepthFunc = function () +{ + this._stackDepthFunc.pop(); + if (this._stackDepthFunc.length > 0) this.gl.depthFunc(this._stackDepthFunc[this._stackDepthFunc.length - 1]); +}; + +// -------------------------------------- +// state blending + +Context.prototype._stackBlend = []; + +/** + * enable / disable blend + * like gl.enable(gl.BLEND); / gl.disable(gl.BLEND); + * @function pushBlend + * @memberof Context + * @instance + * @param {Boolean} blending + */ +Context.prototype.pushBlend = function (b) +{ + this._stackBlend.push(b); + if (!b) this.gl.disable(this.gl.BLEND); + else this.gl.enable(this.gl.BLEND); +}; + +/** + * pop blend state and set the previous state + * @function popBlend + * @memberof Context + * @instance + */ +Context.prototype.popBlend = function () +{ + this._stackBlend.pop(); + + if (!this._stackBlend[this._stackBlend.length - 1]) this.gl.disable(this.gl.BLEND); + else this.gl.enable(this.gl.BLEND); +}; + +/** + * current state of blend + * @function stateBlend + * @returns {boolean} blending enabled/disabled + * @memberof Context + * @instance + */ +Context.prototype.stateBlend = function () +{ + return this._stackBlend[this._stackBlend.length - 1]; +}; + +const BLENDS = { + "BLEND_NONE": 0, + "BLEND_NORMAL": 1, + "BLEND_ADD": 2, + "BLEND_SUB": 3, + "BLEND_MUL": 4, +}; + +Context.prototype._stackBlendMode = []; +Context.prototype._stackBlendModePremul = []; + +/** + * push and switch to predefined blendmode (CONSTANTS.BLEND_MODES.BLEND_NONE,CONSTANTS.BLEND_MODES.BLEND_NORMAL,CONSTANTS.BLEND_MODES.BLEND_ADD,CONSTANTS.BLEND_MODES.BLEND_SUB,CONSTANTS.BLEND_MODES.BLEND_MUL) + * @function pushBlendMode + * @memberof Context + * @instance + * @param {Number} blendmode + * @param {Boolean} premultiplied mode + */ +Context.prototype.pushBlendMode = function (blendMode, premul) +{ + this._stackBlendMode.push(blendMode); + this._stackBlendModePremul.push(premul); + + const n = this._stackBlendMode.length - 1; + + this.pushBlend(this._stackBlendMode[n] !== constants_CONSTANTS.BLEND_MODES.BLEND_NONE); + this._setBlendMode(this._stackBlendMode[n], this._stackBlendModePremul[n]); +}; + +/** + * pop predefined blendmode / switch back to previous blendmode + * @function popBlendMode + * @memberof Context + * @instance + */ +Context.prototype.popBlendMode = function () +{ + this._stackBlendMode.pop(); + this._stackBlendModePremul.pop(); + + const n = this._stackBlendMode.length - 1; + + this.popBlend(this._stackBlendMode[n] !== constants_CONSTANTS.BLEND_MODES.BLEND_NONE); + + if (n >= 0) this._setBlendMode(this._stackBlendMode[n], this._stackBlendModePremul[n]); +}; + + +// -------------------------------------- +// state stencil + +Context.prototype._stackStencil = []; + +/** + * enable / disable stencil testing + +* @function pushStencil + * @memberof Context + * @instance + * @param {Boolean} enable + */ +Context.prototype.pushStencil = function (b) +{ + this._stackStencil.push(b); + if (!b) this.gl.disable(this.gl.STENCIL_TEST); + else this.gl.enable(this.gl.STENCIL_TEST); +}; + +/** + * pop stencil test state and set the previous state + * @function popStencil + * @memberof Context + * @instance + */ +Context.prototype.popStencil = function () +{ + this._stackStencil.pop(); + + if (!this._stackStencil[this._stackStencil.length - 1]) this.gl.disable(this.gl.STENCIL_TEST); + else this.gl.enable(this.gl.STENCIL_TEST); +}; + +// -------------------------------------- + + +Context.prototype.glGetAttribLocation = function (prog, name) +{ + const l = this.gl.getAttribLocation(prog, name); + // if (l == -1) + // { + // this._log.warn("get attr loc -1 ", name); + // } + return l; +}; + + +/** + * should an op now draw helpermeshes + * @function shouldDrawHelpers + * @memberof Context + * @instance + */ +Context.prototype.shouldDrawHelpers = function (op) +{ + if (this.frameStore.shadowPass) return false; + if (!op.patch.isEditorMode()) return false; + + // const fb = this.getCurrentFrameBuffer(); + // if (fb && fb.getWidth) + // { + // const fbshould = this.canvasWidth / this.canvasHeight == fb.getWidth() / fb.getHeight(); + // if (!fbshould) return false; + // } + + return gui.shouldDrawOverlay;// || (CABLES.UI.renderHelperCurrent && op.isCurrentUiOp()); +}; + +Context.prototype._setBlendMode = function (blendMode, premul) +{ + const gl = this.gl; + + if (blendMode == constants_CONSTANTS.BLEND_MODES.BLEND_NONE) + { + // this.gl.disable(this.gl.BLEND); + } + else if (blendMode == constants_CONSTANTS.BLEND_MODES.BLEND_ADD) + { + if (premul) + { + gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD); + gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE); + } + else + { + gl.blendEquation(gl.FUNC_ADD); + gl.blendFunc(gl.SRC_ALPHA, gl.ONE); + } + } + else if (blendMode == constants_CONSTANTS.BLEND_MODES.BLEND_SUB) + { + if (premul) + { + gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD); + gl.blendFuncSeparate(gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA); + } + else + { + gl.blendEquation(gl.FUNC_ADD); + gl.blendFunc(gl.ZERO, gl.ONE_MINUS_SRC_COLOR); + } + } + else if (blendMode == constants_CONSTANTS.BLEND_MODES.BLEND_MUL) + { + if (premul) + { + gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD); + gl.blendFuncSeparate(gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA); + } + else + { + gl.blendEquation(gl.FUNC_ADD); + gl.blendFunc(gl.ZERO, gl.SRC_COLOR); + } + } + else if (blendMode == constants_CONSTANTS.BLEND_MODES.BLEND_NORMAL) + { + if (premul) + { + gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD); + gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + } + else + { + gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD); + gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + } + } + else + { + this._log.log("setblendmode: unknown blendmode"); + } +}; + +Context.prototype.createMesh = function (geom, options) +{ + if (CABLES.UTILS.isNumeric(options))options = { "glPrimitive": options }; // old constructor fallback... + return new CGL.Mesh(this, geom, options); +}; + + +/** + * set cursor + * @function setCursor + * @memberof Context + * @instance + * @param {String} css cursor string + */ +Context.prototype.setCursor = function (str) +{ + this._cursor = str; +}; + +/** + * enable a webgl extension + * @function enableExtension + * @memberof Context + * @instance + * @param {String} extension name + * @returns {Object} extension object or null + */ +Context.prototype.enableExtension = function (name) +{ + if (!this.gl) return null; + // const start = performance.now(); + + if (this._enabledExtensions.hasOwnProperty(name)) + { + return this._enabledExtensions[name]; + } + + const o = this.gl.getExtension(name); + this._enabledExtensions[name] = o; + + if (!o) + this._log.warn("[cgl_state] extension not available " + name); + else + this._log.log("enabled extension", name); + + return o; +}; + +Context.prototype.checkTextureSize = function (x) +{ + x = x || 1; + x = Math.floor(x); + x = Math.min(x, this.maxTexSize); + x = Math.max(x, 1); + return x; +}; + + + + + +;// CONCATENATED MODULE: ./src/core/core_variable.js + + +/** + * @type {Object} + * @name Variable + * @param {String} name + * @param {String|Number} value + * @memberof Patch + * @constructor + */ +class PatchVariable extends Events +{ + constructor(name, val, type) + { + super(); + this._name = name; + this.type = type; + this.setValue(val); + } + + /** + * keeping this for backwards compatibility in older + * exports before using eventtarget + * + * @param cb + */ + addListener(cb) + { + this.on("change", cb, "var"); + } + + /** + * @function Variable.getValue + * @memberof Variable + * @returns {String|Number|Boolean} + */ + + getValue() + { + return this._v; + } + + /** + * @function getName + * @memberof Variable + * @instance + * @returns {String|Number|Boolean} + * @function + */ + getName() + { + return this._name; + } + + /** + * @function setValue + * @memberof Variable + * @instance + * @returns {String|Number|Boolean} + * @function + */ + setValue(v) + { + this._v = v; + this.emitEvent("change", v, this); + } +} + +/* harmony default export */ const core_variable = (PatchVariable); + +;// CONCATENATED MODULE: ./src/core/core_patch.js + + + + + + + + + + + + + +/** + * Patch class, contains all operators,values,links etc. manages loading and running of the whole patch + * + * see {@link PatchConfig} + * + * @external CABLES + * @namespace Patch + * @hideconstructor + * @param {PatchConfig} config The configuration object. + * @class + * @example + * CABLES.patch=new CABLES.Patch( + * { + * patch:pStr, + * glCanvasId:'glcanvas', + * glCanvasResizeToWindow:true, + * canvas:{powerPreference:"high-performance"}, + * prefixAssetPath:'/assets/', + * prefixJsPath:'/js/', + * onError:function(e){console.log(e);} + * glslPrecision:'highp' + * }); + */ + +const Patch = function (cfg) +{ + EventTarget.apply(this); + + this._log = new Logger("core_patch"); + this.ops = []; + this.settings = {}; + this.config = cfg || + { + "glCanvasResizeToWindow": false, + "prefixAssetPath": "", + "prefixJsPath": "", + "silent": true, + "onError": null, + "onFinishedLoading": null, + "onFirstFrameRendered": null, + "onPatchLoaded": null, + "fpsLimit": 0, + }; + this.timer = new Timer(); + this.freeTimer = new Timer(); + this.animFrameOps = []; + this.animFrameCallbacks = []; + this.gui = false; + CABLES.logSilent = this.silent = true; + this.profiler = null; + this.aborted = false; + this._crashedOps = []; + this._renderOneFrame = false; + this._animReq = null; + this._opIdCache = {}; + this._triggerStack = []; + this.storeObjNames = false; // remove after may release + + this.loading = new LoadingStatus(this); + + this._volumeListeners = []; + this._paused = false; + this._frameNum = 0; + this.instancing = new Instancing(); + this.onOneFrameRendered = null; + this.namedTriggers = {}; + + this._origData = null; + this._frameNext = 0; + this._frameInterval = 0; + this._lastFrameTime = 0; + this._frameWasdelayed = true; + this.frameStore = {}; + this.deSerialized = false; + this.reqAnimTimeStamp = 0; + + this.cgCanvas = null; + + if (!(function () { return !this; }())) console.log("not in strict mode: core patch"); + + this._isLocal = document.location.href.indexOf("file:") === 0; + + if (this.config.hasOwnProperty("silent")) this.silent = CABLES.logSilent = this.config.silent; + if (!this.config.hasOwnProperty("doRequestAnimation")) this.config.doRequestAnimation = true; + + if (!this.config.prefixAssetPath) this.config.prefixAssetPath = ""; + if (!this.config.prefixJsPath) this.config.prefixJsPath = ""; + if (!this.config.masterVolume) this.config.masterVolume = 1.0; + + this._variables = {}; + this._variableListeners = []; + this.vars = {}; + if (cfg && cfg.vars) this.vars = cfg.vars; // vars is old! + + this.cgl = new Context(this); + this.cgp = null; + + this._subpatchOpCache = {}; + + this.cgl.setCanvas(this.config.glCanvasId || this.config.glCanvas || "glcanvas"); + if (this.config.glCanvasResizeToWindow === true) this.cgl.setAutoResize("window"); + if (this.config.glCanvasResizeToParent === true) this.cgl.setAutoResize("parent"); + this.loading.setOnFinishedLoading(this.config.onFinishedLoading); + + if (this.cgl.aborted) this.aborted = true; + if (this.cgl.silent) this.silent = true; + + this.freeTimer.play(); + this.exec(); + + if (!this.aborted) + { + if (this.config.patch) + { + this.deSerialize(this.config.patch); + } + else if (this.config.patchFile) + { + ajax( + this.config.patchFile, + (err, _data) => + { + const data = JSON.parse(_data); + if (err) + { + const txt = ""; + this._log.error("err", err); + this._log.error("data", data); + this._log.error("data", data.msg); + return; + } + this.deSerialize(data); + } + ); + } + this.timer.play(); + } + + console.log("made with https://cables.gl"); // eslint-disable-line +}; + +Patch.prototype.isPlaying = function () +{ + return !this._paused; +}; + +Patch.prototype.isRenderingOneFrame = function () +{ + return this._renderOneFrame; +}; + + +Patch.prototype.renderOneFrame = function () +{ + this._paused = true; + this._renderOneFrame = true; + this.exec(); + this._renderOneFrame = false; +}; + +/** + * current number of frames per second + * @function getFPS + * @memberof Patch + * @instance + * @return {Number} fps + */ +Patch.prototype.getFPS = function () +{ + console.log("deprecated getfps"); + return 0; +}; + +/** + * returns true if patch is opened in editor/gui mode + * @function isEditorMode + * @memberof Patch + * @instance + * @return {Boolean} editor mode + */ +Patch.prototype.isEditorMode = function () +{ + return this.config.editorMode === true; +}; + +/** + * pauses patch execution + * @function pause + * @memberof Patch + * @instance + */ +Patch.prototype.pause = function () +{ + cancelAnimationFrame(this._animReq); + this.emitEvent("pause"); + this._animReq = null; + this._paused = true; + this.freeTimer.pause(); +}; + +/** + * resumes patch execution + * @function resume + * @memberof Patch + * @instance + */ +Patch.prototype.resume = function () +{ + if (this._paused) + { + cancelAnimationFrame(this._animReq); + this._paused = false; + this.freeTimer.play(); + this.emitEvent("resume"); + this.exec(); + } +}; + +/** + * set volume [0-1] + * @function setVolume + * @param {Number} volume + * @memberof Patch + * @instance + */ +Patch.prototype.setVolume = function (v) +{ + this.config.masterVolume = v; + for (let i = 0; i < this._volumeListeners.length; i++) this._volumeListeners[i].onMasterVolumeChanged(v); +}; + + +/** + * get asset path + * @function getAssetPath + * @memberof Patch + * @instance + */ +Patch.prototype.getAssetPath = function (patchId = null) +{ + if (this.isEditorMode()) + { + let id = patchId || gui.project()._id; + return "/assets/" + id + "/"; + } + else if (document.location.href.indexOf("cables.gl") > 0 || document.location.href.indexOf("cables.local") > 0) + { + const parts = document.location.pathname.split("/"); + let id = patchId || parts[parts.length - 1]; + return "/assets/" + id + "/"; + } + else if (this.config.hasOwnProperty("assetPath")) + { + return this.config.assetPath; + } + else + { + return "assets/"; + } +}; + +/** + * get js path + * @function getJsPath + * @memberof Patch + * @instance + */ +Patch.prototype.getJsPath = function () +{ + if (this.config.hasOwnProperty("jsPath")) + { + return this.config.jsPath; + } + else + { + return "js/"; + } +}; + +/** + * get url/filepath for a filename + * this uses prefixAssetpath in exported patches + * @function getFilePath + * @memberof Patch + * @instance + * @param {String} filename + * @return {String} url + */ +Patch.prototype.getFilePath = function (filename) +{ + if (!filename) return filename; + filename = String(filename); + if (filename.indexOf("https:") === 0 || filename.indexOf("http:") === 0) return filename; + if (filename.indexOf("data:") === 0) return filename; + if (filename.indexOf("file:") === 0) return filename; + + filename = filename.replace("//", "/"); + return this.config.prefixAssetPath + filename + (this.config.suffixAssetPath || ""); +}; + +Patch.prototype.clear = function () +{ + this.emitEvent("patchClearStart"); + this.cgl.TextureEffectMesh = null; + this.animFrameOps.length = 0; + this.timer = new Timer(); + while (this.ops.length > 0) this.deleteOp(this.ops[0].id); + + this._opIdCache = {}; + this.emitEvent("patchClearEnd"); +}; + +Patch.getOpClass = function (objName) +{ + const parts = objName.split("."); + let opObj = null; + + try + { + if (parts.length == 2) opObj = window[parts[0]][parts[1]]; + else if (parts.length == 3) opObj = window[parts[0]][parts[1]][parts[2]]; + else if (parts.length == 4) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]]; + else if (parts.length == 5) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]]; + else if (parts.length == 6) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]]; + else if (parts.length == 7) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]]; + else if (parts.length == 8) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]][parts[7]]; + else if (parts.length == 9) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]][parts[7]][parts[8]]; + else if (parts.length == 10) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]][parts[7]][parts[8]][parts[9]]; + return opObj; + } + catch (e) + { + return null; + } +}; + +Patch.prototype.createOp = function (identifier, id, opName = null) +{ + let op = null; + let objName = ""; + + try + { + if (!identifier) + { + console.error("createop identifier false", identifier); + console.log((new Error()).stack); + return; + } + if (identifier.indexOf("Ops.") === -1) + { + // this should be a uuid, not a namespace + // creating ops by id should be the default way from now on! + const opId = identifier; + + + + if (CABLES.OPS[opId]) + { + objName = CABLES.OPS[opId].objName; + op = new CABLES.OPS[opId].f(this, objName, id, opId); + op.opId = opId; + } + else + { + if (opName) + { + identifier = opName; + console.log("could not find op by id: " + opId); + } + else + { + throw new Error("could not find op by id: " + opId, { "cause": "opId:" + opId }); + } + } + } + + if (!op) + { + // fallback: create by objname! + objName = identifier; + const parts = identifier.split("."); + const opObj = Patch.getOpClass(objName); + + if (!opObj) + { + this.emitEvent("criticalError", { "title": "unknown op" + objName, "text": "unknown op: " + objName }); + + this._log.error("unknown op: " + objName); + throw new Error("unknown op: " + objName); + } + else + { + if (parts.length == 2) op = new window[parts[0]][parts[1]](this, objName, id); + else if (parts.length == 3) op = new window[parts[0]][parts[1]][parts[2]](this, objName, id); + else if (parts.length == 4) op = new window[parts[0]][parts[1]][parts[2]][parts[3]](this, objName, id); + else if (parts.length == 5) op = new window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]](this, objName, id); + else if (parts.length == 6) op = new window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]](this, objName, id); + else if (parts.length == 7) op = new window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]](this, objName, id); + else if (parts.length == 8) op = new window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]][parts[7]](this, objName, id); + else if (parts.length == 9) op = new window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]][parts[7]][parts[8]](this, objName, id); + else if (parts.length == 10) op = new window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]][parts[7]][parts[8]][parts[9]](this, objName, id); + else console.log("parts.length", parts.length); + } + + if (op) + { + op.opId = null; + for (const i in CABLES.OPS) + { + if (CABLES.OPS[i].objName == objName) op.opId = i; + } + } + } + } + catch (e) + { + this._crashedOps.push(objName); + + this.emitEvent("exceptionOp", e, objName, op); + + if (!this.isEditorMode()) + { + this._log.error(e); + this._log.error("[instancing error] " + objName, e); + + if (CABLES.api) CABLES.api.sendErrorReport(e); + this.exitError("INSTANCE_ERR", "Instancing Error 1" + objName, e); + throw new Error("instancing error 1" + objName); + } + } + + if (op) + { + op._objName = objName; + op.patch = this; + } + else + { + this._log.log("no op was created!?", identifier, id); + } + return op; +}; + +/** + * create a new op in patch + * @function addOp + * @memberof Patch + * @instance + * @param {String} opIdentifier, uuid or name, e.g. Ops.Math.Sum + * @param {Object} uiAttribs Attributes + * @param {String} id + * @param {boolean} fromDeserialize + * @param {String} opName, e.g. Ops.Math.Sum + * @example + * // add invisible op + * patch.addOp('Ops.Math.Sum', { showUiAttribs: false }); + */ +Patch.prototype.addOp = function (opIdentifier, uiAttribs, id, fromDeserialize, opName) +{ + const op = this.createOp(opIdentifier, id, opName); + + if (op) + { + uiAttribs = uiAttribs || {}; + if (uiAttribs.hasOwnProperty("errors")) delete uiAttribs.errors; + if (uiAttribs.hasOwnProperty("error")) delete uiAttribs.error; + uiAttribs.subPatch = uiAttribs.subPatch || 0; + + op.setUiAttribs(uiAttribs); + if (op.onCreate) op.onCreate(); + + if (op.hasOwnProperty("onAnimFrame")) this.addOnAnimFrame(op); + if (op.hasOwnProperty("onMasterVolumeChanged")) this._volumeListeners.push(op); + + if (this._opIdCache[op.id]) + { + console.log("opid with id " + op.id + " already exists in patch!"); + this.deleteOp(op.id); // strange with subpatch ops: why is this needed, somehow ops get added twice ???..... + // return; + } + + this.ops.push(op); + this._opIdCache[op.id] = op; + + if (this._subPatchCacheAdd) this._subPatchCacheAdd(uiAttribs.subPatch, op); + this.emitEvent("onOpAdd", op, fromDeserialize); + + if (op.init) op.init(); + + op.emitEvent("init", fromDeserialize); + } + else + { + this._log.error("addop: no op....."); + } + + return op; +}; + +Patch.prototype.addOnAnimFrame = function (op) +{ + for (let i = 0; i < this.animFrameOps.length; i++) if (this.animFrameOps[i] == op) { return; } + + this.animFrameOps.push(op); +}; + +Patch.prototype.removeOnAnimFrame = function (op) +{ + for (let i = 0; i < this.animFrameOps.length; i++) + { + if (this.animFrameOps[i] == op) + { + this.animFrameOps.splice(i, 1); + return; + } + } +}; + +Patch.prototype.addOnAnimFrameCallback = function (cb) +{ + this.animFrameCallbacks.push(cb); +}; + +Patch.prototype.removeOnAnimCallback = function (cb) +{ + for (let i = 0; i < this.animFrameCallbacks.length; i++) + { + if (this.animFrameCallbacks[i] == cb) + { + this.animFrameCallbacks.splice(i, 1); + return; + } + } +}; + +Patch.prototype.deleteOp = function (opid, tryRelink, reloadingOp) +{ + let found = false; + for (const i in this.ops) + { + if (this.ops[i].id == opid) + { + const op = this.ops[i]; + let reLinkP1 = null; + let reLinkP2 = null; + + if (op) + { + found = true; + if (tryRelink) + { + if (op.portsIn.length > 0 && op.portsIn[0].isLinked() && (op.portsOut.length > 0 && op.portsOut[0].isLinked())) + { + if (op.portsIn[0].getType() == op.portsOut[0].getType() && op.portsIn[0].links[0]) + { + reLinkP1 = op.portsIn[0].links[0].getOtherPort(op.portsIn[0]); + reLinkP2 = op.portsOut[0].links[0].getOtherPort(op.portsOut[0]); + } + } + } + + const opToDelete = this.ops[i]; + opToDelete.removeLinks(); + + if (this.onDelete) + { + // todo: remove + console.log("deprecated this.onDelete", this.onDelete); + this.onDelete(opToDelete); + } + + this.ops.splice(i, 1); + opToDelete.emitEvent("delete", opToDelete); + this.emitEvent("onOpDelete", opToDelete, reloadingOp); + + if (this.clearSubPatchCache) this.clearSubPatchCache(opToDelete.uiAttribs.subPatch); + + if (opToDelete.onDelete) opToDelete.onDelete(reloadingOp); + opToDelete.cleanUp(); + + if (reLinkP1 !== null && reLinkP2 !== null) + { + this.link(reLinkP1.op, reLinkP1.getName(), reLinkP2.op, reLinkP2.getName()); + } + + delete this._opIdCache[opid]; + break; + } + } + } + + if (!found) console.log("core patch deleteop: not found...", opid); +}; + +Patch.prototype.getFrameNum = function () +{ + return this._frameNum; +}; + +Patch.prototype.emitOnAnimFrameEvent = function (time, delta) +{ + time = time || this.timer.getTime(); + + for (let i = 0; i < this.animFrameCallbacks.length; ++i) + if (this.animFrameCallbacks[i]) + this.animFrameCallbacks[i](time, this._frameNum, delta); + + for (let i = 0; i < this.animFrameOps.length; ++i) + if (this.animFrameOps[i].onAnimFrame) + this.animFrameOps[i].onAnimFrame(time, this._frameNum, delta); +}; + +Patch.prototype.renderFrame = function (timestamp) +{ + this.timer.update(this.reqAnimTimeStamp); + this.freeTimer.update(this.reqAnimTimeStamp); + const time = this.timer.getTime(); + const startTime = performance.now(); + this.cgl.frameStartTime = this.timer.getTime(); + + const delta = timestamp - this.reqAnimTimeStamp || timestamp; + + this.emitOnAnimFrameEvent(null, delta); + + this.cgl.profileData.profileFrameDelta = delta; + this.reqAnimTimeStamp = timestamp; + this.cgl.profileData.profileOnAnimFrameOps = performance.now() - startTime; + + this.emitEvent("onRenderFrame", time); + + this._frameNum++; + if (this._frameNum == 1) + { + if (this.config.onFirstFrameRendered) this.config.onFirstFrameRendered(); + } +}; + +Patch.prototype.exec = function (timestamp) +{ + if (!this._renderOneFrame && (this._paused || this.aborted)) return; + this.emitEvent("reqAnimFrame"); + cancelAnimationFrame(this._animReq); + + this.config.fpsLimit = this.config.fpsLimit || 0; + if (this.config.fpsLimit) + { + this._frameInterval = 1000 / this.config.fpsLimit; + } + + const now = CABLES.now(); + const frameDelta = now - this._frameNext; + + if (this.isEditorMode()) + { + if (!this._renderOneFrame) + { + if (now - this._lastFrameTime >= 500 && this._lastFrameTime !== 0 && !this._frameWasdelayed) + { + this._lastFrameTime = 0; + setTimeout(this.exec.bind(this), 500); + this.emitEvent("renderDelayStart"); + this._frameWasdelayed = true; + return; + } + } + } + + if (this._renderOneFrame || this.config.fpsLimit === 0 || frameDelta > this._frameInterval || this._frameWasdelayed) + { + this.renderFrame(timestamp); + + if (this._frameInterval) this._frameNext = now - (frameDelta % this._frameInterval); + } + + if (this._frameWasdelayed) + { + this.emitEvent("renderDelayEnd"); + this._frameWasdelayed = false; + } + + if (this._renderOneFrame) + { + if (this.onOneFrameRendered) this.onOneFrameRendered(); // todo remove everywhere and use propper event... + this.emitEvent("renderedOneFrame"); + this._renderOneFrame = false; + } + + + if (this.config.doRequestAnimation) this._animReq = this.cgl.canvas.ownerDocument.defaultView.requestAnimationFrame(this.exec.bind(this)); +}; + +/** + * link two ops/ports + * @function link + * @memberof Patch + * @instance + * @param {Op} op1 + * @param {String} portName1 + * @param {Op} op2 + * @param {String} portName2 + */ +Patch.prototype.link = function (op1, port1Name, op2, port2Name, lowerCase, fromDeserialize) +{ + if (!op1) + { + console.warn("link: op1 is null "); + return; + } + if (!op2) + { + console.warn("link: op2 is null"); + return; + } + + const port1 = op1.getPort(port1Name, lowerCase); + const port2 = op2.getPort(port2Name, lowerCase); + + if (!port1) + { + console.warn("port1 not found! " + port1Name + "(" + op1.objName + ")"); + return; + } + + if (!port2) + { + console.warn("port2 not found! " + port2Name + " of " + op2.name + "(" + op2.objName + ")", op2); + return; + } + + if (!port1.shouldLink(port1, port2) || !port2.shouldLink(port1, port2)) + { + return false; + } + + if (Link.canLink(port1, port2)) + { + const link = new Link(this); + link.link(port1, port2); + + this.emitEvent("onLink", port1, port2, link, fromDeserialize); + return link; + } +}; + +Patch.prototype.serialize = function (options) +{ + const obj = {}; + + options = options || {}; + obj.ops = []; + obj.settings = this.settings; + for (const i in this.ops) + { + const op = this.ops[i]; + obj.ops.push(op.getSerialized()); + } + + cleanJson(obj); + + if (options.asObject) return obj; + return JSON.stringify(obj); +}; + +Patch.prototype.getOpsByRefId = function (refId) +{ + const perf = CABLES.UI.uiProfiler.start("[corepatchetend] getOpsByRefId"); + const refOps = []; + const ops = gui.corePatch().ops; + for (let i = 0; i < ops.length; i++) + if (ops[i].storage && ops[i].storage.ref == refId) refOps.push(ops[i]); + perf.finish(); + return refOps; +}; + + +Patch.prototype.getOpById = function (opid) +{ + return this._opIdCache[opid]; +}; + +Patch.prototype.getOpsByName = function (name) +{ + // TODO: is this still needed ? unclear behaviour.... + const arr = []; + for (const i in this.ops) + if (this.ops[i].name == name) arr.push(this.ops[i]); + return arr; +}; + +Patch.prototype.getOpsByObjName = function (name) +{ + const arr = []; + for (const i in this.ops) + if (this.ops[i].objName == name) arr.push(this.ops[i]); + return arr; +}; + +Patch.prototype.getOpsByOpId = function (opid) +{ + const arr = []; + for (const i in this.ops) + if (this.ops[i].opId == opid) arr.push(this.ops[i]); + return arr; +}; + +Patch.prototype.loadLib = function (which) +{ + ajaxSync( + "/ui/libs/" + which + ".js", + (err, res) => + { + const se = document.createElement("script"); + se.type = "text/javascript"; + se.text = res; + document.getElementsByTagName("head")[0].appendChild(se); + }, + "GET", + ); + // open and send a synchronous request + // xhrObj.open('GET', '/ui/libs/'+which+'.js', false); + // xhrObj.send(''); + // add the returned content to a newly created script tag +}; + + +Patch.prototype.getSubPatchOp = function (patchId, objName) +{ + for (const i in this.ops) + if (this.ops[i].uiAttribs && this.ops[i].uiAttribs.subPatch == patchId && this.ops[i].objName == objName) + return this.ops[i]; + return false; +}; + +Patch.prototype._addLink = function (opinid, opoutid, inName, outName) +{ + return this.link(this.getOpById(opinid), inName, this.getOpById(opoutid), outName, false, true); +}; + +Patch.prototype.deSerialize = function (obj, options) +{ + options = options || { "genIds": false, "createRef": false }; + if (this.aborted) return; + const newOps = []; + const loadingId = this.loading.start("core", "deserialize"); + + this.namespace = obj.namespace || ""; + this.name = obj.name || ""; + + if (typeof obj === "string") obj = JSON.parse(obj); + + this.settings = obj.settings; + + this.emitEvent("patchLoadStart"); + + if (window.logStartup)logStartup("add " + obj.ops.length + " ops... "); + + const addedOps = []; + // add ops... + for (let iop = 0; iop < obj.ops.length; iop++) + { + const start = CABLES.now(); + const opData = obj.ops[iop]; + let op = null; + + try + { + if (opData.opId) op = this.addOp(opData.opId, opData.uiAttribs, opData.id, true, opData.objName); + else op = this.addOp(opData.objName, opData.uiAttribs, opData.id, true); + } + catch (e) + { + console.log("[instancing error] op data:", opData, e); + throw new Error("could not create op by id: " + (opData.objName || opData.opId) + " (" + opData.id + ")"); + } + + if (op) + { + addedOps.push(op); + if (options.genIds) op.id = shortId(); + op.portsInData = opData.portsIn; + op._origData = JSON.parse(JSON.stringify(opData)); + op.storage = opData.storage; + // if (opData.hasOwnProperty("disabled"))op.setEnabled(!opData.disabled); + + for (const ipi in opData.portsIn) + { + const objPort = opData.portsIn[ipi]; + if (objPort && objPort.hasOwnProperty("name")) + { + // console.log("load poirt data,objPort", objPort.name, objPort); + const port = op.getPort(objPort.name); + + if (port && (port.uiAttribs.display == "bool" || port.uiAttribs.type == "bool") && !isNaN(objPort.value)) objPort.value = objPort.value == true ? 1 : 0; + if (port && objPort.value !== undefined && port.type != CONSTANTS.OP.OP_PORT_TYPE_TEXTURE) port.set(objPort.value); + + if (port) + { + port.deSerializeSettings(objPort); + } + else + { + console.log("preserve", objPort.name, objPort.value); + op.preservedPortValues = op.preservedPortValues || {}; + op.preservedPortValues[objPort.name] = objPort.value; + } + } + } + + for (const ipo in opData.portsOut) + { + const objPort = opData.portsOut[ipo]; + if (objPort && objPort.hasOwnProperty("name")) + { + const port2 = op.getPort(objPort.name); + if (port2 && port2.type != CONSTANTS.OP.OP_PORT_TYPE_TEXTURE && objPort.hasOwnProperty("value")) + port2.set(obj.ops[iop].portsOut[ipo].value); + + if (port2 && objPort.expose) port2.setUiAttribs({ "expose": true }); + } + } + newOps.push(op); + } + + const timeused = Math.round(100 * (CABLES.now() - start)) / 100; + if (!this.silent && timeused > 5) console.log("long op init ", obj.ops[iop].objName, timeused); + } + if (window.logStartup)logStartup("add ops done"); + + for (const i in this.ops) + { + if (this.ops[i].onLoadedValueSet) + { + this.ops[i].onLoadedValueSet(this.ops[i]._origData); + this.ops[i].onLoadedValueSet = null; + this.ops[i]._origData = null; + } + this.ops[i].emitEvent("loadedValueSet"); + } + + if (window.logStartup)logStartup("creating links"); + + if (options.opsCreated)options.opsCreated(addedOps); + // create links... + if (obj.ops) + { + for (let iop = 0; iop < obj.ops.length; iop++) + { + if (obj.ops[iop].portsIn) + { + for (let ipi2 = 0; ipi2 < obj.ops[iop].portsIn.length; ipi2++) + { + if (obj.ops[iop].portsIn[ipi2] && obj.ops[iop].portsIn[ipi2].links) + { + for (let ili = 0; ili < obj.ops[iop].portsIn[ipi2].links.length; ili++) + { + const l = this._addLink( + obj.ops[iop].portsIn[ipi2].links[ili].objIn, + obj.ops[iop].portsIn[ipi2].links[ili].objOut, + obj.ops[iop].portsIn[ipi2].links[ili].portIn, + obj.ops[iop].portsIn[ipi2].links[ili].portOut); + + console.log("aaaa", l); + + + // const took = performance.now - startTime; + // if (took > 100)console.log(obj().ops[iop].portsIn[ipi2].links[ili].objIn, obj.ops[iop].portsIn[ipi2].links[ili].objOut, took); + } + } + } + } + if (obj.ops[iop].portsOut) + for (let ipi2 = 0; ipi2 < obj.ops[iop].portsOut.length; ipi2++) + if (obj.ops[iop].portsOut[ipi2] && obj.ops[iop].portsOut[ipi2].links) + { + for (let ili = 0; ili < obj.ops[iop].portsOut[ipi2].links.length; ili++) + { + if (obj.ops[iop].portsOut[ipi2].links[ili]) + { + if (obj.ops[iop].portsOut[ipi2].links[ili].subOpRef) + { + // lost link + const outOp = this.getOpById(obj.ops[iop].portsOut[ipi2].links[ili].objOut); + let dstOp = null; + let theSubPatch = 0; + + for (let i = 0; i < this.ops.length; i++) + { + if ( + this.ops[i].storage && + this.ops[i].storage.ref == obj.ops[iop].portsOut[ipi2].links[ili].subOpRef && + outOp.uiAttribs.subPatch == this.ops[i].uiAttribs.subPatch + ) + { + theSubPatch = this.ops[i].patchId.get(); + break; + } + } + + for (let i = 0; i < this.ops.length; i++) + { + if ( + this.ops[i].storage && + this.ops[i].storage.ref == obj.ops[iop].portsOut[ipi2].links[ili].refOp && + this.ops[i].uiAttribs.subPatch == theSubPatch) + { + dstOp = this.ops[i]; + break; + } + } + + if (!dstOp) this._log.warn("could not find op for lost link"); + else + { + const l = this._addLink( + dstOp.id, + obj.ops[iop].portsOut[ipi2].links[ili].objOut, + + obj.ops[iop].portsOut[ipi2].links[ili].portIn, + obj.ops[iop].portsOut[ipi2].links[ili].portOut); + } + } + else + { + const l = this._addLink(obj.ops[iop].portsOut[ipi2].links[ili].objIn, obj.ops[iop].portsOut[ipi2].links[ili].objOut, obj.ops[iop].portsOut[ipi2].links[ili].portIn, obj.ops[iop].portsOut[ipi2].links[ili].portOut); + + if (!l) + { + const op1 = this.getOpById(obj.ops[iop].portsOut[ipi2].links[ili].objIn); + const op2 = this.getOpById(obj.ops[iop].portsOut[ipi2].links[ili].objOut); + + if (!op1)console.log("could not find link op1"); + if (!op2)console.log("could not find link op2"); + + const p1Name = obj.ops[iop].portsOut[ipi2].links[ili].portIn; + + if (op1 && !op1.getPort(p1Name)) + { + console.log("PRESERVE port 1 not found", p1Name); + + op1.preservedPortLinks[p1Name] = op1.preservedPortLinks[p1Name] || []; + op1.preservedPortLinks[p1Name].push(obj.ops[iop].portsOut[ipi2].links[ili]); + } + + const p2Name = obj.ops[iop].portsOut[ipi2].links[ili].portOut; + if (op2 && !op2.getPort(p2Name)) + { + console.log("PRESERVE port 2 not found", obj.ops[iop].portsOut[ipi2].links[ili].portOut); + op2.preservedPortLinks[p1Name] = op2.preservedPortLinks[p1Name] || []; + op2.preservedPortLinks[p1Name].push(obj.ops[iop].portsOut[ipi2].links[ili]); + } + } + } + } + } + } + } + } + + if (window.logStartup)logStartup("calling ops onloaded"); + + for (const i in this.ops) + { + if (this.ops[i].onLoaded) + { + // TODO: deprecate!!! + this.ops[i].onLoaded(); + this.ops[i].onLoaded = null; + } + } + + if (window.logStartup)logStartup("initializing ops..."); + for (const i in this.ops) + { + if (this.ops[i].init) + { + this.ops[i].init(); + this.ops[i].init = null; + } + } + + if (window.logStartup)logStartup("initializing vars..."); + + if (this.config.variables) + for (const varName in this.config.variables) + this.setVarValue(varName, this.config.variables[varName]); + + if (window.logStartup)logStartup("initializing var ports"); + + for (const i in this.ops) + { + this.ops[i].initVarPorts(); + delete this.ops[i].uiAttribs.pasted; + } + + setTimeout(() => { this.loading.finished(loadingId); }, 100); + + if (window.logStartup)logStartup("calling onPatchLoaded/patchLoadEnd"); + + if (this.config.onPatchLoaded) this.config.onPatchLoaded(this); + + this.deSerialized = true; + this.emitEvent("patchLoadEnd", newOps, obj, options.genIds); +}; + +Patch.prototype.profile = function (enable) +{ + this.profiler = new Profiler(this); + for (const i in this.ops) + { + this.ops[i].profile(enable); + } +}; + +// ---------------------- + +/** + * set variable value + * @function setVariable + * @memberof Patch + * @instance + * @param {String} name of variable + * @param {Number|String|Boolean} value + */ +Patch.prototype.setVariable = function (name, val) +{ + // if (this._variables.hasOwnProperty(name)) + if (this._variables[name] !== undefined) + { + this._variables[name].setValue(val); + } + else + { + console.log("variable " + name + " not found!"); + } +}; + +Patch.prototype._sortVars = function () +{ + if (!this.isEditorMode()) return; + const ordered = {}; + Object.keys(this._variables).sort( + (a, b) => + { return a.localeCompare(b, "en", { "sensitivity": "base" }); } + ).forEach((key) => + { + ordered[key] = this._variables[key]; + }); + this._variables = ordered; +}; + +/** + * has variable + * @function hasVariable + * @memberof Patch + * @instance + * @param {String} name of variable + */ +Patch.prototype.hasVar = function (name) +{ + return this._variables[name] !== undefined; + + // return this._variables.hasOwnProperty(name); +}; + +// used internally +Patch.prototype.setVarValue = function (name, val, type) +{ + if (this.hasVar(name)) + { + this._variables[name].setValue(val); + } + else + { + this._variables[name] = new core_variable(name, val, type); + this._sortVars(); + this.emitEvent("variablesChanged"); + } + return this._variables[name]; +}; +// old? +Patch.prototype.getVarValue = function (name, val) +{ + if (this._variables.hasOwnProperty(name)) return this._variables[name].getValue(); +}; + +/** + * @function getVar + * @memberof Patch + * @instance + * @param {String} name + * @return {Variable} variable + */ +Patch.prototype.getVar = function (name) +{ + if (this._variables.hasOwnProperty(name)) return this._variables[name]; +}; + + +Patch.prototype.deleteVar = function (name) +{ + for (let i = 0; i < this.ops.length; i++) + for (let j = 0; j < this.ops[i].portsIn.length; j++) + if (this.ops[i].portsIn[j].getVariableName() == name) + this.ops[i].portsIn[j].setVariable(null); + + delete this._variables[name]; + this.emitEvent("variableDeleted", name); + this.emitEvent("variablesChanged"); +}; + +/** + * @function getVars + * @memberof Patch + * @instance + * @return {Array} variables + * @function + */ +Patch.prototype.getVars = function (t) +{ + if (t === undefined) return this._variables; + + const vars = []; + if (t == CABLES.OP_PORT_TYPE_STRING) t = "string"; + if (t == CABLES.OP_PORT_TYPE_VALUE) t = "number"; + if (t == CABLES.OP_PORT_TYPE_ARRAY) t = "array"; + if (t == CABLES.OP_PORT_TYPE_OBJECT) t = "object"; + + for (const i in this._variables) + { + if (!this._variables[i].type || this._variables[i].type == t) vars.push(this._variables[i]); + } + return vars; +}; + +/** + * @function exitError + * @memberof Patch + * @instance + * @description cancel patch execution and quit showing an errormessage + * @function + */ +Patch.prototype.exitError = function (errorId, errorMessage, ex) +{ + this.aborted = true; + + if (this && this.config && this.config.onError) + { + this.config.onError(errorId, errorMessage); + } + else + { + if (!this.isEditorMode()) + { + const newDiv = document.createElement("div"); + + const rect = this.cgl.canvas.getBoundingClientRect(); + + newDiv.setAttribute("style", "position:absolute;border:5px solid red;padding:15px;background-color:black;color:white;font-family:monospace;"); + newDiv.style.top = rect.top + "px"; + newDiv.style.left = rect.left + "px"; + let str = "cables - An error occured:
    "; + str += "[" + errorId + "] - " + errorMessage; + if (ex)str += "
    Exception: " + ex.message; + newDiv.innerHTML = str; + + const pe = this.cgl.canvas.parentElement; + + while (pe.hasChildNodes()) pe.removeChild(pe.lastChild); + + document.body.appendChild(newDiv); + } + } +}; + +/** + * @function preRenderOps + * @memberof Patch + * @instance + * @description invoke pre rendering of ops + * @function + */ +Patch.prototype.preRenderOps = function () +{ + this._log.log("prerendering..."); + + for (let i = 0; i < this.ops.length; i++) + { + if (this.ops[i].preRender) + { + this.ops[i].preRender(); + this._log.log("prerender " + this.ops[i].objName); + } + } +}; + +/** + * @function dispose + * @memberof Patch + * @instance + * @description stop, dispose and cleanup patch + */ +Patch.prototype.dispose = function () +{ + this.pause(); + this.clear(); + this.cgl.dispose(); +}; + +Patch.prototype.pushTriggerStack = function (p) +{ + this._triggerStack.push(p); +}; + +Patch.prototype.popTriggerStack = function () +{ + this._triggerStack.pop(); +}; + +Patch.prototype.printTriggerStack = function () +{ + if (this._triggerStack.length == 0) + { + // console.log("stack length", this._triggerStack.length); // eslint-disable-line + return; + } + console.groupCollapsed( // eslint-disable-line + "trigger port stack " + this._triggerStack[this._triggerStack.length - 1].op.name + "." + this._triggerStack[this._triggerStack.length - 1].name, + ); + + const rows = []; + for (let i = 0; i < this._triggerStack.length; i++) + { + rows.push(i + ". " + this._triggerStack[i].op.name + " " + this._triggerStack[i].name); + } + + console.table(rows); // eslint-disable-line + console.groupEnd(); // eslint-disable-line +}; + +/** + * returns document object of the patch could be != global document object when opening canvas ina popout window + * @function getDocument + * @memberof Patch + * @instance + * @return {Object} document + */ +Patch.prototype.getDocument = function () +{ + return this.cgl.canvas.ownerDocument; +}; + +Patch.replaceOpIds = function (json, options) +{ + const opids = {}; + for (const i in json.ops) + { + opids[json.ops[i].id] = json.ops[i]; + } + + for (const j in json.ops) + { + for (const k in json.ops[j].portsOut) + { + const links = json.ops[j].portsOut[k].links; + if (links) + { + let l = links.length; + + while (l--) + { + if (links[l] && (!opids[links[l].objIn] || !opids[links[l].objOut])) + { + if (!options.doNotUnlinkLostLinks) + { + links.splice(l, 1); + } + else + { + if (options.fixLostLinks) + { + // console.log("lost link...?", links[l]); + const op = gui.corePatch().getOpById(links[l].objIn); + if (!op) console.log("op not found!"); + else + { + const outerOp = gui.patchView.getSubPatchOuterOp(op.uiAttribs.subPatch); + if (outerOp) + { + op.storage = op.storage || {}; + op.storage.ref = op.storage.ref || CABLES.shortId(); + links[l].refOp = op.storage.ref; + links[l].subOpRef = outerOp.storage.ref; + } + } + } + } + } + } + } + } + } + + + + for (const i in json.ops) + { + const op = json.ops[i]; + const oldId = op.id; + let newId = CABLES.shortId(); + + if (options.prefixHash) newId = prefixedHash(options.prefixHash + oldId); + + else if (options.prefixId) newId = options.prefixId + oldId; + else if (options.refAsId) // when saving json + { + if (op.storage && op.storage.ref) + { + newId = op.storage.ref; + delete op.storage.ref; + } + else + { + op.storage = op.storage || {}; + op.storage.ref = newId = CABLES.shortId(); + } + } + + const newID = op.id = newId; + + if (options.oldIdAsRef) // when loading json + { + op.storage = op.storage || {}; + op.storage.ref = oldId; + } + + for (const j in json.ops) + { + if (json.ops[j].portsIn) + for (const k in json.ops[j].portsIn) + { + if (json.ops[j].portsIn[k].links) + { + let l = json.ops[j].portsIn[k].links.length; + + while (l--) if (json.ops[j].portsIn[k].links[l] === null) json.ops[j].portsIn[k].links.splice(l, 1); + + for (l in json.ops[j].portsIn[k].links) + { + if (json.ops[j].portsIn[k].links[l].objIn === oldId) json.ops[j].portsIn[k].links[l].objIn = newID; + if (json.ops[j].portsIn[k].links[l].objOut === oldId) json.ops[j].portsIn[k].links[l].objOut = newID; + } + } + } + + if (json.ops[j].portsOut) + for (const k in json.ops[j].portsOut) + { + if (json.ops[j].portsOut[k].links) + { + let l = json.ops[j].portsOut[k].links.length; + + while (l--) if (json.ops[j].portsOut[k].links[l] === null) json.ops[j].portsOut[k].links.splice(l, 1); + + for (l in json.ops[j].portsOut[k].links) + { + if (json.ops[j].portsOut[k].links[l].objIn === oldId) json.ops[j].portsOut[k].links[l].objIn = newID; + if (json.ops[j].portsOut[k].links[l].objOut === oldId) json.ops[j].portsOut[k].links[l].objOut = newID; + } + } + } + } + } + + // set correct subpatch + const subpatchIds = []; + const fixedSubPatches = []; + + for (let i = 0; i < json.ops.length; i++) + { + // if (CABLES.Op.isSubPatchOpName(json.ops[i].objName)) + if (json.ops[i].storage && json.ops[i].storage.subPatchVer) + { + for (const k in json.ops[i].portsIn) + { + if (json.ops[i].portsIn[k].name === "patchId") + { + let newId = shortId(); + + if (options.prefixHash) newId = prefixedHash(options.prefixHash + json.ops[i].portsIn[k].value); + + const oldSubPatchId = json.ops[i].portsIn[k].value; + const newSubPatchId = json.ops[i].portsIn[k].value = newId; + + subpatchIds.push(newSubPatchId); + + for (let j = 0; j < json.ops.length; j++) + { + // op has no uiAttribs in export, we don't care about subpatches in export though + if (json.ops[j].uiAttribs) + { + if (json.ops[j].uiAttribs.subPatch === oldSubPatchId) + { + json.ops[j].uiAttribs.subPatch = newSubPatchId; + fixedSubPatches.push(json.ops[j].id); + } + } + } + } + } + } + } + + for (const kk in json.ops) + { + let found = false; + for (let j = 0; j < fixedSubPatches.length; j++) + { + if (json.ops[kk].id === fixedSubPatches[j]) + { + found = true; + break; + } + } + // op has no uiAttribs in export, we don't care about subpatches in export though + if (!found && json.ops[kk].uiAttribs && options.parentSubPatchId != null) + json.ops[kk].uiAttribs.subPatch = options.parentSubPatchId; + } + + return json; +}; + +/** + * remove an eventlistener + * @instance + * @function addEventListener + * @param {String} name of event + * @param {function} callback + */ + +/** + * remove an eventlistener + * @instance + * @function removeEventListener + * @param {String} name of event + * @param {function} callback + */ + +/** + * op added to patch event + * @event onOpAdd + * + * @memberof Patch + * @type {Object} + * @property {Op} op new op + */ + +/** + * op deleted from patch + * @event onOpDelete + * @memberof Patch + * @type {Object} + * @property {Op} op that will be deleted + */ + +/** + * link event - two ports will be linked + * @event onLink + * @memberof Patch + * @type {Object} + * @property {Port} port1 + * @property {Port} port2 + */ + +/** + * unlink event - a link was deleted + * @event onUnLink + * @memberof Patch + * @type {Object} + */ + +/** + * variables has been changed / a variable has been added to the patch + * @event variablesChanged + * @memberof Patch + * @type {Object} + * @property {Port} port1 + * @property {Port} port2 + */ + +/** + * configuration object for loading a patch + * @typedef {Object} PatchConfig + * @hideconstructor + * @property {String} [prefixAssetPath=''] prefix for path to assets + * @property {String} [assetPath=''] path to assets + * @property {String} [jsPath=''] path to javascript files + * @property {String} [glCanvasId='glcanvas'] dom element id of canvas element + * @property {Function} [onError=null] called when an error occurs + * @property {Function} [onFinishedLoading=null] called when patch finished loading all assets + * @property {Function} [onFirstFrameRendered=null] called when patch rendered it's first frame + * @property {Boolean} [glCanvasResizeToWindow=false] resize canvas automatically to window size + * @property {Boolean} [doRequestAnimation=true] do requestAnimationFrame set to false if you want to trigger exec() from outside (only do if you know what you are doing) + * @property {Boolean} [clearCanvasColor=true] clear canvas in transparent color every frame + * @property {Boolean} [clearCanvasDepth=true] clear depth every frame + * @property {Boolean} [glValidateShader=true] enable/disable validation of shaders * + * @property {Boolean} [silent=false] + * @property {Number} [fpsLimit=0] 0 for maximum possible frames per second + * @property {String} [glslPrecision='mediump'] default precision for glsl shader + * + */ + +/* harmony default export */ const core_patch = (Patch); + + +;// CONCATENATED MODULE: ./src/core/embedding.js + + + +const EMBED = {}; + +/** + * add patch into html element (will create canvas and set size to fill containerElement) + * @name CABLES.EMBED#addPatch + * @param {object|string} containerElement dom element or id of element + * @param {options} patch options + * @function + */ +EMBED.addPatch = function (_element, options) +{ + let el = _element; + let id = generateUUID(); + if (typeof _element == "string") + { + id = _element; + el = document.getElementById(id); + + if (!el) + { + console.error(id + " Polyshape Container Element not found!"); + return; + } + } + + const canvEl = document.createElement("canvas"); + canvEl.id = "glcanvas_" + id; + canvEl.width = el.clientWidth; + canvEl.height = el.clientHeight; + + window.addEventListener( + "resize", + function () + { + this.setAttribute("width", el.clientWidth); + this.height = el.clientHeight; + }.bind(canvEl), + ); + + el.appendChild(canvEl); + + options = options || {}; + options.glCanvasId = canvEl.id; + + if (!options.onError) + { + options.onError = function (err) + { + console.error(err); + }; + } + + CABLES.patch = new core_patch(options); + return canvEl; +}; + + + +;// CONCATENATED MODULE: ./src/core/webaudio.js +/** @namespace WEBAUDIO */ + + + +const WEBAUDIO = {}; + +WEBAUDIO.toneJsInitialized = false; + +/* + * External JSDoc definitions + */ + +/** + * Part of the Web Audio API, the AudioBuffer interface represents a short audio asset residing in memory. + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/AudioBuffer} + */ + +/** + * Part of the Web Audio API, the AudioNode interface is a generic interface for representing an audio processing module. + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/AudioNode} + */ + +/** + * The AudioContext interface represents an audio-processing graph built from audio modules linked together + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/AudioContext} + */ + +/** + * Checks if a global audio context has been created and creates + * it if necessary. This audio context can be used for native Web Audio as well as Tone.js ops. + * Associates the audio context with Tone.js if it is being used + * @param {CABLES.Op} op - The operator which needs the Audio Context + */ +WEBAUDIO.createAudioContext = function (op) +{ + window.AudioContext = window.AudioContext || window.webkitAudioContext; + if (window.AudioContext) + { + if (!window.audioContext) + { + window.audioContext = new AudioContext(); + } + // check if tone.js lib is being used + if (window.Tone && !WEBAUDIO.toneJsInitialized) + { + // set current audio context in tone.js + Tone.setContext(window.audioContext); + WEBAUDIO.toneJsInitialized = true; + } + } + else + { + op.patch.config.onError("NO_WEBAUDIO", "Web Audio is not supported in this browser."); + return; + } + return window.audioContext; +}; + +/** + * Returns the audio context. + * Before `createAudioContext` must have been called at least once. + * It most cases you should use `createAudioContext`, which just returns the audio context + * when it has been created already. + */ +WEBAUDIO.getAudioContext = function () +{ + return window.audioContext; +}; + +/** + * Creates an audio in port for the op with name `portName` + * When disconnected it will disconnect the previous connected audio node + * from the op's audio node. + * @param {CABLES.Op} op - The operator to create the audio port in + * @param {string} portName - The name of the port + * @param {AudioNode} audioNode - The audionode incoming connections should connect to + * @param {number} [inputChannelIndex=0] - If the audio node has multiple inputs, this is the index of the input channel to connect to + * @returns {CABLES.Port|undefined} - The newly created audio in port or `undefined` if there was an error + */ +WEBAUDIO.createAudioInPort = function (op, portName, audioNode, inputChannelIndex) +{ + if (!op || !portName || !audioNode) + { + const msg = "ERROR: createAudioInPort needs three parameters, op, portName and audioNode"; + op.log(msg); + throw new Error(msg); + // return; + } + if (!inputChannelIndex) + { + inputChannelIndex = 0; + } + op.webAudio = op.webAudio || {}; + op.webAudio.audioInPorts = op.webAudio.audioInPorts || []; + const port = op.inObject(portName); + port.webAudio = {}; + port.webAudio.previousAudioInNode = null; + port.webAudio.audioNode = audioNode; + + op.webAudio.audioInPorts[portName] = port; + + port.onChange = function () + { + const audioInNode = port.get(); + // when port disconnected, disconnect audio nodes + if (!audioInNode) + { + if (port.webAudio.previousAudioInNode) + { + try + { + if (port.webAudio.previousAudioInNode.disconnect) port.webAudio.previousAudioInNode.disconnect(port.webAudio.audioNode, 0, inputChannelIndex); + op.setUiError("audioCtx", null); + } + catch (e) + { + try + { + port.webAudio.previousAudioInNode.disconnect(port.webAudio.audioNode); + } + catch (er) + { + op.log( + "Disconnecting audio node with in/out port index, as well as without in/out-port-index did not work ", + e, + ); + if (e.printStackTrace) + { + e.printStackTrace(); + } + throw e; + } + } + } + } + else + { + try + { + if (audioInNode.connect) + { + audioInNode.connect(port.webAudio.audioNode, 0, inputChannelIndex); + op.setUiError("audioCtx", null); + } + else op.setUiError("audioCtx", "The passed input is not an audio context. Please make sure you connect an audio context to the input.", 2); + } + catch (e) + { + op.log("Error: Failed to connect web audio node!", e); + op.log("port.webAudio.audioNode", port.webAudio.audioNode); + op.log("audioInNode: ", audioInNode); + op.log("inputChannelIndex:", inputChannelIndex); + op.log("audioInNode.connect: ", audioInNode.connect); + throw e; + } + } + port.webAudio.previousAudioInNode = audioInNode; + }; + // TODO: Maybe add subtype to audio-node-object? + return port; +}; + +/** + * Sometimes it is necessary to replace a node of a port, if so all + * connections to this node must be disconnected and connections to the new + * node must be made. + * Can be used for both Audio ports as well as AudioParam ports + * if used with an AudioParam pass e.g. `synth.frequency` as newNode + * @param {CABLES.Port} port - The port where the audio node needs to be replaced + */ +WEBAUDIO.replaceNodeInPort = function (port, oldNode, newNode) +{ + const connectedNode = port.webAudio.previousAudioInNode; + // check if connected + if (connectedNode && connectedNode.disconnect) + { + try + { + connectedNode.disconnect(oldNode); + } + catch (e) + { + if (e.printStackTrace) + { + e.printStackTrace(); + } + throw new Error("replaceNodeInPort: Could not disconnect old audio node. " + e.name + " " + e.message); + } + port.webAudio.audioNode = newNode; + try + { + connectedNode.connect(newNode); + } + catch (e) + { + if (e.printStackTrace) + { + e.printStackTrace(); + } + throw new Error("replaceNodeInPort: Could not connect to new node. " + e.name + " " + e.message); + } + } +}; + +/** + * Creates an audio out port which takes care of (dis-)connecting on it’s own + * @param {CABLES.op} op - The op to create an audio out port for + * @param {string} portName - The name of the port to be created + * @param {AudioNode} audioNode - The audio node to link to the port + * @returns {(CABLES.Port|undefined)} - The newly created audio out port or `undefined` if there was an error + */ +WEBAUDIO.createAudioOutPort = function (op, portName, audioNode) +{ + if (!op || !portName || !audioNode) + { + const msg = "ERROR: createAudioOutPort needs three parameters, op, portName and audioNode"; + op.log(msg); + throw new Error(msg); + } + + const port = op.outObject(portName); + // TODO: Maybe add subtype to audio-node-object? + port.set(audioNode); + return port; +}; + +/** + * Creates an audio param in port for the op with name portName. + * The port accepts other audio nodes as signals as well as values (numbers) + * When the port is disconnected it will disconnect the previous connected audio node + * from the op's audio node and restore the number value set before. + * @param {CABLES.Op} op - The operator to create an audio param input port for + * @param {string} portName - The name of the port to create + * @returns {(CABLES.Port|undefined)} - The newly created port, which takes care of (dis-)connecting on its own, or `undefined` if there was an error + */ +WEBAUDIO.createAudioParamInPort = function (op, portName, audioNode, options, defaultValue) +{ + if (!op || !portName || !audioNode) + { + op.log("ERROR: createAudioParamInPort needs three parameters, op, portName and audioNode"); + if (op && op.name) op.log("opname: ", op.name); + op.log("portName", portName); + op.log("audioNode: ", audioNode); + return; + } + op.webAudio = op.webAudio || {}; + op.webAudio.audioInPorts = op.webAudio.audioInPorts || []; + // var port = op.inObject(portName); + const port = op.inDynamic( + portName, + [CONSTANTS.OP.OP_PORT_TYPE_VALUE, CONSTANTS.OP.OP_PORT_TYPE_OBJECT], + options, + defaultValue, + ); + port.webAudio = {}; + port.webAudio.previousAudioInNode = null; + port.webAudio.audioNode = audioNode; + + op.webAudio.audioInPorts[portName] = port; + + // port.onLinkChanged = function() { + // op.log("onLinkChanged"); + // if(port.isLinked()) { + // + // if(port.links[0].portOut.type === CABLES.CONSTANTS.OP.OP_PORT_TYPE_) { // value + // + // } else if(port.links[0].portOut.type === CABLES.CONSTANTS.OP.OP_PORT_TYPE_OBJECT) { // object + // + // } + // } else { // unlinked + // + // } + // }; + + port.onChange = function () + { + const audioInNode = port.get(); + const node = port.webAudio.audioNode; + const audioCtx = WEBAUDIO.getAudioContext(); + + if (audioInNode != undefined) + { + if (typeof audioInNode === "object" && audioInNode.connect) + { + try + { + audioInNode.connect(node); + } + catch (e) + { + op.log("Could not connect audio node: ", e); + if (e.printStackTrace) + { + e.printStackTrace(); + } + throw e; + } + port.webAudio.previousAudioInNode = audioInNode; + } + else + { + // tone.js audio param + if (node._param && node._param.minValue && node._param.maxValue) + { + if (audioInNode >= node._param.minValue && audioInNode <= node._param.maxValue) + { + try + { + if (node.setValueAtTime) + { + node.setValueAtTime(audioInNode, audioCtx.currentTime); + } + else + { + node.value = audioInNode; + } + } + catch (e) + { + op.log("Possible AudioParam problem with tone.js op: ", e); + if (e.printStackTrace) + { + e.printStackTrace(); + } + throw e; + } + } + else + { + op.log("Warning: The value for an audio parameter is out of range!"); + } + } // native Web Audio param + else if (node.minValue && node.maxValue) + { + if (audioInNode >= node.minValue && audioInNode <= node.maxValue) + { + try + { + if (node.setValueAtTime) + { + node.setValueAtTime(audioInNode, audioCtx.currentTime); + } + else + { + node.value = audioInNode; + } + } + catch (e) + { + op.log( + "AudioParam has minValue / maxValue defined, and value is in range, but setting the value failed! ", + e, + ); + if (e.printStackTrace) + { + e.printStackTrace(); + } + throw e; + } + } + else + { + op.log("Warning: The value for an audio parameter is out of range!"); + } + } // no min-max values, try anyway + else + { + try + { + if (node.setValueAtTime) + { + node.setValueAtTime(audioInNode, audioCtx.currentTime); + } + else + { + node.value = audioInNode; + } + } + catch (e) + { + op.log("Possible AudioParam problem (without minValue / maxValue): ", e); + if (e.printStackTrace) + { + e.printStackTrace(); + } + throw e; + } + } + + if (port.webAudio.previousAudioInNode && port.webAudio.previousAudioInNode.disconnect) + { + try + { + port.webAudio.previousAudioInNode.disconnect(node); + } + catch (e) + { + op.log("Could not disconnect previous audio node: ", e); + throw e; + } + port.webAudio.previousAudioInNode = undefined; + } + } + } + else + { + // disconnected + if (port.webAudio.previousAudioInNode) + { + } + } + }; + return port; +}; + + +/** + * Loads an audio file and updates the loading indicators when cables is run in the editor. + * @param {CABLES.Patch} patch - The cables patch, when called from inside an op this is `op.patch` + * @param {string} url - The url of the audio file to load + * @param {loadAudioFileFinishedCallback} onFinished - The callback to be called when the loading is finished, passes the AudioBuffer + * @param {loadAudioFileErrorCallback} onError - The callback when there was an error loading the file, the rror message is passed + * @see {@link https://developer.mozilla.org/de/docs/Web/API/AudioContext/decodeAudioData} + */ +WEBAUDIO.loadAudioFile = function (patch, url, onFinished, onError, loadingTask) +{ + const audioContext = WEBAUDIO.createAudioContext(); + + let loadingId = null; + if (loadingTask || loadingTask === undefined) + { + loadingId = patch.loading.start("audio", url); + if (patch.isEditorMode()) gui.jobs().start({ "id": "loadaudio" + loadingId, "title": " loading audio (" + url + ")" }); + } + const request = new XMLHttpRequest(); + if (!url) + { + return; + } + request.open("GET", url, true); + request.responseType = "arraybuffer"; + // TODO: maybe crossorigin stuff needed? + // Decode asynchronously + request.onload = function () + { + patch.loading.finished(loadingId); + if (patch.isEditorMode()) gui.jobs().finish("loadaudio" + loadingId); + audioContext.decodeAudioData(request.response, onFinished, onError); + }; + request.send(); +}; + +/** + * Checks if the passed time is a valid time to be used in any of the Tone.js ops. + * @param {(string|number)} t - The time to check + * @returns {boolean} - True if time is valid, false if not + */ +WEBAUDIO.isValidToneTime = function (t) +{ + try + { + const time = new Tone.Time(t); + } + catch (e) + { + return false; + } + return true; +}; + +/** + * Checks if the passed note is a valid note to be used with Tone.js + * @param {string} note - The note to be checked, e.g. `"C4"` + * @returns {boolean} - True if the note is a valid note, false otherwise + */ +WEBAUDIO.isValidToneNote = function (note) +{ + try + { + Tone.Frequency(note); + } + catch (e) + { + return false; + } + return true; +}; + + + +;// CONCATENATED MODULE: ./src/core/sessionvar.js +// todo: old... remove this from ops... + +const Variable = function () +{ + let value = null; + const changedCallbacks = []; + + this.onChanged = function (f) + { + changedCallbacks.push(f); + }; + + this.getValue = function () + { + return value; + }; + + this.setValue = function (v) + { + value = v; + this.emitChanged(); + }; + + this.emitChanged = function () + { + for (let i = 0; i < changedCallbacks.length; i++) + { + changedCallbacks[i](); + } + }; +}; + + + +;// CONCATENATED MODULE: ./src/core/banchprofiler.js +class Branch +{ + constructor(name) + { + this.name = name; + this.dur = 0; + this._startTime = 0; + this.childs = []; + } + + start() + { + this._startTime = performance.now(); + } + + end() + { + this.dur = performance.now() - this._startTime; + } + + push(name) + { + const b = new Branch(name); + this.childs.push(b); + b.start(); + return b; + } + + print(level) + { + level = level || 0; + + let str = ""; + for (let i = 0; i < level; i++) str += " "; + + for (let i = 0; i < this.childs.length; i++) + { + this.childs[i].print(level + 1); + } + } +} + +// ////////////////////////////////////////// + +class BranchStack +{ + constructor() + { + } + + start() + { + this.root = new Branch("Root"); + this.root.start(); + + this.current = this.root; + } + + push(name) + { + if (!this.current) this.start(); + + const prev = this.current; + this.current = this.current.push(name); + this.current.prev = prev; + this.current.start(); + return this.current; + } + + pop() + { + if (!this.current) return; + this.current.end(); + this.current = this.current.prev; + } + + finish() + { + this.current.end(); + this.root.print(); + this.current = null; + } +} + + + + +;// CONCATENATED MODULE: ./src/core/cgp/cgp_uniform.js + + +class cgp_uniform_Uniform extends cg_uniform +{ + constructor(__shader, __type, __name, _value, _port2, _port3, _port4, _structUniformName, _structName, _propertyName) + { + super(__shader, __type, __name, _value, _port2, _port3, _port4, _structUniformName, _structName, _propertyName); + this._loc = -1; + this._cgl = __shader._cgl; + } + + + updateValueF() { } + + setValueF(v) + { + this.needsUpdate = true; + this._value = v; + } + + updateValue2F() { } + + setValue2F(v) + { + this.needsUpdate = true; + this._value = v; + } + + updateValue3F() { } + + setValue3F(v) + { + this.needsUpdate = true; + this._value = v; + } + + updateValue4F() { } + + setValue4F(v) + { + this.needsUpdate = true; + this._value = v; + } + + getSizeBytes() + { + if (this._type == "f") return 1 * 4; + if (this._type == "i") return 1 * 4; + if (this._type == "2i") return 2 * 4; + if (this._type == "2f") return 2 * 4; + if (this._type == "3f") return 3 * 4; + if (this._type == "4f") return 4 * 4; + if (this._type == "m4") return 4 * 4 * 4; + + this._log.warn("unknown type getSizeBytes"); + // if (this._type == "t") return "sampler2D"; + // if (this._type == "tc") return "samplerCube"; + // if (this._type == "b") return "bool"; + + // if (t == "3f[]") return null; // ignore this for now... + // if (t == "m4[]") return null; // ignore this for now... + // if (t == "f[]") return null; // ignore this for now... + } +} + +;// CONCATENATED MODULE: ./src/core/cgp/cgp_shader.js + + + + +class cgp_shader_Shader +{ + constructor(_cgp, _name) + { + if (!_cgp) throw new Error("shader constructed without cgp " + _name); + this._log = new Logger("cgp_shader"); + this._cgp = _cgp; + this._name = _name; + this._uniforms = []; + + if (!_name) this._log.stack("no shader name given"); + this._name = _name || "unknown"; + this.id = simpleId(); + this._isValid = true; + this._compileReason = ""; + this.shaderModule = null; + this._needsRecompile = true; + + this._src = ""; + } + + get isValid() + { + return this._isValid; + } + + get uniforms() + { + return this._uniforms; + } + + getName() + { + return this._name; + } + + setWhyCompile(why) + { + this._compileReason = why; + } + + setSource(src) + { + this._src = src; + this.setWhyCompile("Source changed"); + this._needsRecompile = true; + } + + compile() + { + this._isValid = true; + console.log("compiling shader...", this._compileReason); + this._cgp.pushErrorScope(); + this.shaderModule = this._cgp.device.createShaderModule({ "code": this._src }); + this._cgp.popErrorScope("cgp_shader " + this._name, this.error.bind(this)); + this._needsRecompile = false; + } + + error(e) + { + this._isValid = false; + } + + + bind() + { + let sizes = {}; + for (let i = 0; i < this._uniforms.length; i++) + { + // console.log(this._uniforms[i]); + } + + if (this._needsRecompile) this.compile(); + } + + /** + * add a uniform to the fragment shader + * @param {String} type ['f','t', etc] + * @param {String} name + * @param {any} value or port + * @memberof Shader + * @instance + * @function addUniformFrag + * @returns {Uniform} + */ + addUniformFrag(type, name, valueOrPort, p2, p3, p4) + { + const uni = new cgp_uniform_Uniform(this, type, name, valueOrPort, p2, p3, p4); + uni.shaderType = "frag"; + return uni; + } + + /** + * add a uniform to the vertex shader + * @param {String} type ['f','t', etc] + * @param {String} name + * @param {any} value or port + * @memberof Shader + * @instance + * @function addUniformVert + * @returns {Uniform} + */ + addUniformVert(type, name, valueOrPort, p2, p3, p4) + { + const uni = new cgp_uniform_Uniform(this, type, name, valueOrPort, p2, p3, p4); + uni.shaderType = "vert"; + return uni; + } + + /** + * add a uniform to all shader programs + * @param {String} type ['f','t', etc] + * @param {String} name + * @param {any} value or port + * @memberof Shader + * @instance + * @function addUniform + * @returns {Uniform} + */ + addUniform(type, name, valueOrPort, p2, p3, p4) + { + const uni = new cgp_uniform_Uniform(this, type, name, valueOrPort, p2, p3, p4); + uni.shaderType = "both"; + return uni; + } + + + _addUniform(uni) + { + this._uniforms.push(uni); + this.setWhyCompile("add uniform " + name); + this._needsRecompile = true; + } +} + +;// CONCATENATED MODULE: ./src/core/cgp/cgl_shader_default.wgsl +/* harmony default export */ const cgl_shader_default = ("struct VSUniforms\n{\n modelMatrix: mat4x4,\n viewMatrix: mat4x4,\n projMatrix: mat4x4,\n};\n\nstruct FSUniforms\n{\n color:vec4\n};\n\n@group(0) @binding(0) var vsUniforms: VSUniforms;\n@group(0) @binding(1) var fsUniforms: FSUniforms;\n\nstruct MyVSInput\n{\n @location(0) position: vec3,\n @location(1) normal: vec3,\n @location(2) texcoord: vec2,\n};\n\nstruct MyVSOutput\n{\n @builtin(position) position: vec4,\n @location(0) normal: vec3,\n @location(1) texcoord: vec2,\n};\n\n@vertex\nfn myVSMain(v: MyVSInput) -> MyVSOutput\n{\n var vsOut: MyVSOutput;\n var pos =vec4(v.position, 1.0);\n\n var mvMatrix=vsUniforms.viewMatrix * vsUniforms.modelMatrix;\n vsOut.position = vsUniforms.projMatrix * mvMatrix * pos;\n\n vsOut.normal = v.normal;\n vsOut.texcoord = v.texcoord;\n return vsOut;\n}\n\n@fragment\nfn myFSMain(v: MyVSOutput) -> @location(0) vec4\n{\n return fsUniforms.color+vec4(.5,.5,.5,1.0);\n}\n\n"); +;// CONCATENATED MODULE: ./src/core/cgp/cgp_state.js + + + + + +// https://github.com/greggman/webgpu-utils +// https://developer.chrome.com/blog/from-webgl-to-webgpu/ +// https://gpuweb.github.io/gpuweb/explainer/ + + +/** + * cables webgpu context/state manager + * @external CGP + * @namespace Context + * @class + * @hideconstructor + */ +// const Context = function (_patch) +class WebGpuContext extends CGState +{ + constructor(_patch) + { + super(); + + this.patch = _patch; + + this.gApi = CG.GAPI_WEBGPU; + this._viewport = [0, 0, 256, 256]; + this._shaderStack = []; + this._simpleShader = null; + + this._stackCullFaceFacing = []; + this._stackDepthTest = []; + this._stackCullFace = []; + this._stackDepthFunc = []; + this._stackDepthWrite = []; + + this.DEPTH_FUNCS = [ + "never", + "always", + "less", + "less-equal", + "greater", + "greater-equal", + "equal", + "not-equal" + ]; + + this.CULL_MODES = [ + "none", + "back", + "front", + "none" // both does not exist in webgpu + ]; + } + + + /// //////////////////// + + getViewPort() + { + return [0, 0, this.canvasWidth, this.canvasHeight]; + } + + renderStart(cgp, identTranslate, identTranslateView) + { + if (!this._simpleShader) + { + this._simpleShader = new cgp_shader_Shader(this, "simple default shader"); + this._simpleShader.setSource(cgl_shader_default); + this._simpleShader.addUniformFrag("4f", "color", 1, 1, 0, 1); + } + + this.fpsCounter.startFrame(); + + this._startMatrixStacks(identTranslate, identTranslateView); + this.setViewPort(0, 0, this.canvasWidth, this.canvasHeight); + + this.pushShader(this._simpleShader); + this.pushDepthTest(true); + this.pushDepthWrite(true); + this.pushDepthFunc("less-equal"); + + this.emitEvent("beginFrame"); + } + + renderEnd() + { + this._endMatrixStacks(); + + this.popShader(); + this.popDepthFunc(); + this.popDepthWrite(); + this.popDepthTest(); + + this.emitEvent("endFrame"); + this.fpsCounter.endFrame(); + } + + + setViewPort(x, y, w, h) + { + this._viewport = [x, y, w, h]; + } + + /** + * @function getViewPort + * @memberof Context + * @instance + * @description get current gl viewport + * @returns {Array} array [x,y,w,h] + */ + getViewPort() + { + return this._viewPort; + } + + + createMesh(geom, glPrimitive) + { + return new CGP.Mesh(this, geom, glPrimitive); + } + + getShader() + { + return {}; + } + + /** + * push a shader to the shader stack + * @function pushShader + * @memberof Context + * @instance + * @param {Object} shader + * @function + */ + pushShader(shader) + { + this._shaderStack.push(shader); + // currentShader = shader; + } + + /** + * pop current used shader from shader stack + * @function popShader + * @memberof Context + * @instance + * @function + */ + popShader() + { + if (this._shaderStack.length === 0) throw new Error("Invalid shader stack pop!"); + this._shaderStack.pop(); + // currentShader = this._shaderStack[this._shaderStack.length - 1]; + } + + getShader() + { + return this._shaderStack[this._shaderStack.length - 1]; + // if (currentShader) if (!this.frameStore || ((this.frameStore.renderOffscreen === true) == currentShader.offScreenPass) === true) return currentShader; + // for (let i = this._shaderStack.length - 1; i >= 0; i--) if (this._shaderStack[i]) if (this.frameStore.renderOffscreen == this._shaderStack[i].offScreenPass) return this._shaderStack[i]; + } + + pushErrorScope() + { + this.device.pushErrorScope("validation"); + } + + popErrorScope(name, cb) + { + this.device.popErrorScope().then((error) => + { + if (error) + { + this.patch.emitEvent("criticalError", { "title": "WebGPU error \"" + name + "\"", "codeText": error.message }); + // if (this.patch.isEditorMode())console.log("WebGPU error " + this._name, error.message); + + console.warn("[cgp]", name, error.message, error, cb); + if (cb)cb(error); + } + }); + } + + /** + * push depth testing enabled state + * @function pushDepthTest + * @param {Boolean} enabled + * @memberof Context + * @instance + */ + + pushDepthTest(b) + { + this._stackDepthTest.push(b); + } + + /** + * current state of depth testing + * @function stateDepthTest + * @returns {Boolean} enabled + * @memberof Context + * @instance + */ + stateDepthTest() + { + return this._stackDepthTest[this._stackDepthTest.length - 1]; + } + + /** + * pop depth testing state + * @function popDepthTest + * @memberof Context + * @instance + */ + popDepthTest() + { + this._stackDepthTest.pop(); + } + + // -------------------------------------- + // state depthwrite + + /** + * push depth write enabled state + * @function pushDepthTest + * @param {Boolean} enabled + * @memberof Context + * @instance + */ + + pushDepthWrite(b) + { + b = b || false; + this._stackDepthWrite.push(b); + } + + /** + * current state of depth writing + * @function stateCullFace + * @returns {Boolean} enabled + * @memberof Context + * @instance + */ + stateDepthWrite() + { + return this._stackDepthWrite[this._stackDepthWrite.length - 1]; + } + + /** + * pop depth writing state + * @function popCullFace + * @memberof Context + * @instance + */ + popDepthWrite() + { + this._stackDepthWrite.pop(); + } + + + // -------------------------------------- + // state depthfunc + + + /** + * @function pushDepthFunc + * @memberof Context + * @instance + * @param {string} depth compare func + */ + pushDepthFunc(f) + { + this._stackDepthFunc.push(f); + } + + /** + * @function stateDepthFunc + * @memberof Context + * @instance + * @returns {string} + */ + stateDepthFunc() + { + if (this._stackDepthFunc.length > 0) return this._stackDepthFunc[this._stackDepthFunc.length - 1]; + return false; + } + + /** + * pop depth compare func + * @function popDepthFunc + * @memberof Context + * @instance + */ + popDepthFunc() + { + this._stackDepthFunc.pop(); + } + + + + // -------------------------------------- + // state CullFace + + /** + * push face culling face enabled state + * @function pushCullFaceFacing + * @param {Boolean} enabled + * @memberof Context + * @instance + */ + pushCullFace(b) + { + this._stackCullFace.push(b); + } + + /** + * current state of face culling + * @function stateCullFace + * @returns {Boolean} enabled + * @memberof Context + * @instance + */ + stateCullFace() + { + return this._stackCullFace[this._stackCullFace.length - 1]; + } + + /** + * pop face culling enabled state + * @function popCullFace + * @memberof Context + * @instance + */ + popCullFace() + { + this._stackCullFace.pop(); + } + + + // -------------------------------------- + // state CullFace Facing + + + /** + * push face culling face side + * @function pushCullFaceFacing + * @memberof Context + * @instance + */ + + pushCullFaceFacing(b) + { + this._stackCullFaceFacing.push(b); + } + + /** + * current state of face culling side + * @function stateCullFaceFacing + * @returns {Boolean} enabled + * @memberof Context + * @instance + */ + stateCullFaceFacing() + { + return this._stackCullFaceFacing[this._stackCullFaceFacing.length - 1]; + } + + /** + * pop face culling face side + * @function popCullFaceFacing + * @memberof Context + * @instance + */ + popCullFaceFacing() + { + this._stackCullFaceFacing.pop(); + } +} + + +;// CONCATENATED MODULE: ./src/core/cgp/cgp_uniformbuffer.js +class UniformBuffer +{ + constructor(shader, shaderType) + { + this._shaderType = shaderType; // frag, vert... + this._shader = shader; + this._cgp = shader._cgp; + + this._gpuBuffer = null; + this._values = null; + + this._sizeBytes = 0; + this.update(); + } + + update() + { + this._sizeBytes = 0; + + for (let i = 0; i < this._shader.uniforms.length; i++) + { + const uni = this._shader.uniforms[i]; + + if (this._shaderType == uni.shaderType) + this._sizeBytes += uni.getSizeBytes(); + } + + this._gpuBuffer = this._cgp.device.createBuffer( + { + "size": this._sizeBytes, + "usage": GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + + + this._values = new Float32Array(this._sizeBytes / 4); + this.updateUniformValues(); + } + + updateUniformValues() + { + let count = 0; + for (let i = 0; i < this._shader.uniforms.length; i++) + { + const uni = this._shader.uniforms[i]; + if (uni.shaderType == this._shaderType) + { + if (uni.getSizeBytes() / 4 > 1) + { + for (let j = 0; j < uni.getValue().length; j++) + { + this._values[count] = uni.getValue()[j]; + count++; + } + } + else + { + this._values[count] = uni.getValue(); + count++; + } + } + } + + + this._cgp.device.queue.writeBuffer( + this._gpuBuffer, + 0, + this._values.buffer, + this._values.byteOffset, + this._values.byteLength + ); + } +} + +;// CONCATENATED MODULE: ./src/core/cgp/cgp_pipeline.js + + + +class Pipeline +{ + constructor(_cgp, _name) + { + if (!_cgp) throw new Error("Pipeline constructed without cgp " + _name); + this._cgp = _cgp; + this._isValid = true; + + this._pipeCfg = null; + this._renderPipeline = null; + + this._fsUniformBuffer = null; + this._vsUniformBuffer = null; + + this._old = {}; + + + this.DEPTH_COMPARE_FUNCS_STRINGS = [ + "never", + "less", + "equal", + "lessequal", + "greater", + "notequal", + "greaterequal", + "always"]; + } + + get isValid() { return this._isValid; } + + setPipeline(shader, mesh) + { + if (!mesh || !shader) + { + console.log("pipeline unknown shader/mesh"); + return; + } + + let needsRebuild = + !this._renderPipeline || + !this._pipeCfg || + this._old.mesh != mesh || + this._old.shader != shader || + mesh.needsPipelineUpdate || + shader.needsPipelineUpdate; + + if (this._pipeCfg) + { + if (this._pipeCfg.depthStencil.depthWriteEnabled != this._cgp.stateDepthWrite()) + { + needsRebuild = true; + this._pipeCfg.depthStencil.depthWriteEnabled = this._cgp.stateDepthWrite(); + } + + if (this._cgp.stateDepthTest() === false) + { + if (this._pipeCfg.depthStencil.depthCompare != "never") + { + this._pipeCfg.depthStencil.depthCompare = "never"; + needsRebuild = true; + } + } + else + if (this._pipeCfg.depthStencil.depthCompare != this._cgp.stateDepthFunc()) + { + needsRebuild = true; + this._pipeCfg.depthStencil.depthCompare = this._cgp.stateDepthFunc(); + } + + + if (this._cgp.stateCullFace() === false) + { + if (this._pipeCfg.primitive.cullMode != "none") + { + needsRebuild = true; + this._pipeCfg.primitive.cullMode = "none"; + } + } + else + { + needsRebuild = true; + this._pipeCfg.primitive.cullMode = this._cgp.stateCullFaceFacing(); + } + } + + if (needsRebuild) + { + if (!this._pipeCfg || this._old.shader != shader) this._pipeCfg = this.getPiplelineObject(shader, mesh); + + this._old.shader = shader; + this._old.mesh = mesh; + + + // try + // { + this._renderPipeline = this._cgp.device.createRenderPipeline(this._pipeCfg); + // } + // catch (e) + // { + // console.error(e.message); + // } + + this._bindUniforms(shader); + } + + if (this._renderPipeline && this._isValid) + { + mat4.copy(this._matModel, this._cgp.mMatrix); + mat4.copy(this._matView, this._cgp.vMatrix); + mat4.copy(this._matProj, this._cgp.pMatrix); + + this._cgp.device.queue.writeBuffer( + this._vsUniformBuffer, + 0, + this._vsUniformValues.buffer, + this._vsUniformValues.byteOffset, + this._vsUniformValues.byteLength + ); + + this._uniBufFrag.updateUniformValues(); + + this._cgp.passEncoder.setPipeline(this._renderPipeline); + this._cgp.passEncoder.setBindGroup(0, this._bindGroup); + // this._pipeline = this._cgp.device.createRenderPipeline(this._pipeCfg); + } + } + + getPiplelineObject(shader, mesh) + { + const pipeCfg = { + "layout": "auto", + "vertex": { + "module": shader.shaderModule, + "entryPoint": "myVSMain", + "buffers": [ + // position + { + "arrayStride": 3 * 4, // 3 floats, 4 bytes each + "attributes": [ + { "shaderLocation": 0, "offset": 0, "format": "float32x3" }, + ], + }, + // normals + { + "arrayStride": 3 * 4, // 3 floats, 4 bytes each + "attributes": [ + { "shaderLocation": 1, "offset": 0, "format": "float32x3" }, + ], + }, + // texcoords + { + "arrayStride": 2 * 4, // 2 floats, 4 bytes each + "attributes": [ + { "shaderLocation": 2, "offset": 0, "format": "float32x2", }, + ], + }, + ], + }, + "fragment": { + "module": shader.shaderModule, + "entryPoint": "myFSMain", + "targets": [ + { "format": this._cgp.presentationFormat }, + ], + }, + "primitive": { + "topology": "triangle-list", + "cullMode": "back", // back/none/front + + // "point-list", + // "line-list", + // "line-strip", + // "triangle-list", + // "triangle-strip" + }, + "depthStencil": { + "depthWriteEnabled": true, + "depthCompare": "less", + "format": "depth24plus", + }, + + }; + + return pipeCfg; + } + + + _bindUniforms(shader) + { + this._cgp.pushErrorScope(); + + + const counts = { }; + + this._uniBufFrag = new UniformBuffer(shader, "frag"); + + // for (let i = 0; i < shader.uniforms.length; i++) + // { + // const uni = shader.uniforms[i]; + // const type = uni.shaderType; + // counts[type] = counts[type] || 0; + + + // counts[type] += uni.getSizeBytes(); + // } + // console.log(counts, counts.frag); + + + const vUniformBufferSize = 3 * 16 * 4; // 2 mat4s * 16 floats per mat * 4 bytes per float + // const fUniformBufferSize = counts.frag;// 2 * 3 * 4; // 1 vec3 * 3 floats per vec3 * 4 bytes per float + + this._vsUniformBuffer = this._cgp.device.createBuffer({ + "size": vUniformBufferSize, + "usage": GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + + // this._fsUniformBuffer = this._cgp.device.createBuffer({ + // "size": fUniformBufferSize, + // "usage": GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + // }); + + // this._fsUniformValues = new Float32Array(counts.frag / 4); + + this._vsUniformValues = new Float32Array(vUniformBufferSize / 4); + + this._matModel = this._vsUniformValues.subarray(0, 16); + this._matView = this._vsUniformValues.subarray(16, 32); + this._matProj = this._vsUniformValues.subarray(32, 48); + + + // this._fsUniformValues[1] = 1.0; + // this._fsUniformValues[0] = 1.0; + // const lightDirection = this._fsUniformValues.subarray(0, 3); + + // console.log("pipeline bindgrouplayout ", pipeline.getBindGroupLayout(0)); + + this._bindGroup = this._cgp.device.createBindGroup( + { + "layout": this._renderPipeline.getBindGroupLayout(0), + "entries": [ + { "binding": 0, "resource": { "buffer": this._vsUniformBuffer } }, + { "binding": 1, "resource": { "buffer": this._uniBufFrag._gpuBuffer } } + // { binding: 2, resource: sampler }, + // { binding: 3, resource: tex.createView() }, + ], + }); + + this._cgp.device.queue.writeBuffer( + this._vsUniformBuffer, + 0, + this._vsUniformValues.buffer, + this._vsUniformValues.byteOffset, + this._vsUniformValues.byteLength + ); + + this._uniBufFrag.updateUniformValues(); + this._cgp.popErrorScope("cgp_pipeline end", (e) => + { + this._isValid = false; + }); + } +} + +;// CONCATENATED MODULE: ./src/core/cgp/cgp_mesh.js + + + +class cgp_mesh_Mesh +{ + constructor(_cgp, __geom) + { + this._log = new Logger("cgl_mesh"); + this._cgp = _cgp; + this._geom = null; + this.numIndex = 0; + + this._pipe = new Pipeline(this._cgp); + + this._numNonIndexed = 0; + this._positionBuffer = null; + this._bufVerticesIndizes = null; + this._attributes = []; + + this._needsPipelineUpdate = false; + + if (__geom) this.setGeom(__geom); + } + + _createBuffer(device, data, usage) + { + const buffer = device.createBuffer({ + "size": data.byteLength, + "usage": usage, + "mappedAtCreation": true, + }); + const dst = new data.constructor(buffer.getMappedRange()); + dst.set(data); + buffer.unmap(); + return buffer; + } + + /** + * @function setGeom + * @memberof Mesh + * @instance + * @description set geometry for mesh + * @param {Geometry} geometry + */ + setGeom(geom, removeRef) + { + this._needsPipelineUpdate = true; + this._geom = geom; + this._disposeAttributes(); + + this._positionBuffer = this._createBuffer(this._cgp.device, new Float32Array(geom.vertices), GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST); + + let vi = geom.verticesIndices; + if (!geom.isIndexed()) vi = Array.from(Array(geom.vertices.length / 3).keys()); + this._numIndices = vi.length; + this._indicesBuffer = this._createBuffer(this._cgp.device, new Uint32Array(vi), GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST); + + if (geom.texCoords && geom.texCoords.length) this.setAttribute("texCoords", geom.texCoords, 2); + if (geom.vertexNormals && geom.vertexNormals.length) this.setAttribute("normals", geom.vertexNormals, 3); + } + + + _disposeAttributes() + { + this._needsPipelineUpdate = true; + for (let i = 0; i < this._attributes.length; i++) + { + this._attributes[i].buffer.destroy(); + } + this._attributes.length = 0; + } + + dispose() + { + this._disposeAttributes(); + } + + /** + * @function setAttribute + * @description update attribute + * @memberof Mesh + * @instance + * @param {String} attribute name + * @param {Array} data + * @param {Number} itemSize + * @param {Object} options + */ + setAttribute(name, array, itemSize, options) + { + if (!array) + { + this._log.error("mesh addAttribute - no array given! " + name); + throw new Error(); + } + + for (let i = 0; i < this._attributes.length; i++) + { + const attr = this._attributes[i]; + if (attr.name == name) + { + // if (attr.numItems === numItems) + // { + // } + // else + // { + // // this._log.log("wrong buffer size", this._geom.name, attr.name, attr.numItems, numItems); + // this._resizeAttr(array, attr); + // } + // normalBuffer = this._createBuffer(this._cgp.device, new Float32Array(geom.vertexNormals), GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST); + + // this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, attr.buffer); + // this._bufferArray(array, attr); + + return attr; + } + } + + const buffer = this._createBuffer(this._cgp.device, new Float32Array(array), GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST); + + const attr = { + "buffer": buffer, + "name": name, + // "cb": cb, + // "itemSize": itemSize, + // "numItems": numItems, + // "startItem": 0, + // "instanced": instanced, + // "type": type + }; + this._attributes.push(attr); + + return attr; + } + + // setPipeline() + // { + + // this._cgp.passEncoder.setPipeline(this._pipe.getPiplelineObject(this._cgp.getShader(),this)); + + + // } + + render() + { + if (!this._positionBuffer) return; + + // this.setPipeline(); + + const shader = this._cgp.getShader(); + if (shader)shader.bind(); + + if (!this._cgp.getShader() || !this._cgp.getShader().isValid) + { + // console.log("invalid"); + return; + } + + this._pipe.setPipeline(this._cgp.getShader(), this); + + if (!this._pipe.isValid) + { + // console.log("invalid"); + return; + } + + + this._cgp.passEncoder.setVertexBuffer(0, this._positionBuffer); + for (let i = 0; i < this._attributes.length; i++) + { + this._cgp.passEncoder.setVertexBuffer(i + 1, this._attributes[i].buffer); + } + + this._cgp.passEncoder.setIndexBuffer(this._indicesBuffer, "uint32"); + + if (this._numNonIndexed) + this._cgp.passEncoder.draw(this._numIndices); + else + this._cgp.passEncoder.drawIndexed(this._numIndices); + + // if (shader)shader.unbind(); + } +} + +;// CONCATENATED MODULE: ./src/core/cgp/cgp_texture.js + + +class cgp_texture_Texture +{ + constructor(_cgp, options) + { + if (!_cgp) throw new Error("no cgp"); + this._log = new Logger("cgp_texture"); + this._cgp = _cgp; + this.id = CABLES.uuid(); + + options = options || {}; + + this.name = options.name || "unknown"; + } + + /** + * set texture data from an image/canvas object + * @function initTexture + * @memberof Texture + * @instance + * @param {Object} image + * @param {Number} filter + */ + initTexture(img, filter) + { + this.width = img.width; + this.height = img.height; + + this.textureType = "rgba8unorm"; + + const textureDescriptor = { + // Unlike in WebGL, the size of our texture must be set at texture creation time. + // This means we have to wait until the image is loaded to create the texture, since we won't + // know the size until then. + "size": { "width": img.width, "height": img.height }, + "format": this.textureType, + "usage": GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST + }; + const texture = this._cgp.device.createTexture(textureDescriptor); + + this._cgp.device.queue.copyExternalImageToTexture({ "source": img }, { "texture": texture }, textureDescriptor.size); + + return texture; + } + + getInfo() + { + const tex = this; + const obj = {}; + + obj.name = tex.name; + obj.size = tex.width + " x " + tex.height; + + obj.textureType = tex.textureType; + + return obj; + } +} + + +/** + * @function load + * @static + * @memberof Texture + * @description load an image from an url + * @param {Context} cgl + * @param {String} url + * @param {Function} onFinished + * @param {Object} options + * @return {Texture} + */ +cgp_texture_Texture.load = function (cgp, url, onFinished, settings) +{ + fetch(url).then((response) => + { + response.blob().then((blob) => + { + createImageBitmap(blob).then((imgBitmap) => + { + const texture = new cgp_texture_Texture(cgp, { "name": url }); + texture.initTexture(imgBitmap); + if (onFinished)onFinished(texture); + else console.log("Texture.load no onFinished callback"); + }); + }); + }); +}; + +;// CONCATENATED MODULE: ./src/core/cgp/index.js + + + + + + +const cgp_CGP = { + "Context": WebGpuContext, + "Shader": cgp_shader_Shader, + "Mesh": cgp_mesh_Mesh, + "Pipeline": Pipeline, + "Texture": cgp_texture_Texture, +}; + +window.CGP = cgp_CGP; + + + + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_framebuffer.js + + + +// todo: convert to prototyped... + +/** + * a framebuffer + * @external CGL + * @namespace Framebuffer + * @constructor + * @param {Context} cgl + * @param {Number} width + * @param {Number} height + * @param {Object} [options] + */ +const Framebuffer = function (_cgl, _w, _h, options) +{ + const cgl = _cgl; + this._log = new Logger("Framebuffer"); + this.valid = true; + + let depthTextureExt = cgl.gl.DEPTH_TEXTURE; + if (!depthTextureExt) depthTextureExt = cgl.enableExtension("WEBGL_depth_texture"); + if (!depthTextureExt) depthTextureExt = cgl.enableExtension("WEBKIT_WEBGL_depth_texture"); + if (!depthTextureExt) depthTextureExt = cgl.enableExtension("MOZ_WEBGL_depth_texture"); + + if (!depthTextureExt) + { + cgl.exitError("NO_DEPTH_TEXTURE", "no depth texture support"); + // return; + } + + let width = _w || 512; + let height = _h || 512; + + options = options || { + "isFloatingPointTexture": false, + }; + + if (!options.hasOwnProperty("clear")) options.clear = true; + if (!options.hasOwnProperty("filter")) options.filter = Texture.FILTER_LINEAR; + + const texture = new Texture(cgl, { + "isFloatingPointTexture": options.isFloatingPointTexture, + "filter": options.filter, + "wrap": options.wrap || Texture.CLAMP_TO_EDGE + }); + + let textureDepth = null; + if (depthTextureExt) + { + textureDepth = new Texture(cgl, { + "isDepthTexture": true, + }); + } + this._options = options; + + const frameBuf = cgl.gl.createFramebuffer(); + const depthBuffer = cgl.gl.createRenderbuffer(); + + this.getWidth = function () + { + return width; + }; + this.getHeight = function () + { + return height; + }; + + /** + * get native gl framebuffer + * @function getGlFrameBuffer + * @memberof Framebuffer + * @returns {Object} framebuffer + */ + this.getGlFrameBuffer = function () + { + return frameBuf; + }; + + /** + * get depth renderbuffer + * @function getDepthRenderBuffer + * @memberof Framebuffer + * @returns {Object} renderbuffer + */ + this.getDepthRenderBuffer = function () + { + return depthBuffer; + }; + + /** + * get color texture + * @function getTextureColor + * @memberof Framebuffer + * @returns {Texture} rgba texture + */ + this.getTextureColor = function () + { + return texture; + }; + + /** + * get depth texture + * @function getTextureDepth + * @memberof Framebuffer + * @returns {Texture} depth texture + */ + this.getTextureDepth = function () + { + return textureDepth; + }; + + this.setFilter = function (f) + { + texture.filter = f; + texture.setSize(width, height); + }; + + this.setSize = function (w, h) + { + if (w < 2) w = 2; + if (h < 2) h = 2; + + width = Math.ceil(w); + height = Math.ceil(h); + + cgl.profileData.profileFrameBuffercreate++; + + cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, frameBuf); + cgl.gl.bindRenderbuffer(cgl.gl.RENDERBUFFER, depthBuffer); + + texture.setSize(width, height); + if (textureDepth) textureDepth.setSize(width, height); + + // if(depthTextureExt) cgl.gl.renderbufferStorage(cgl.gl.RENDERBUFFER, cgl.gl.DEPTH_COMPONENT16, width,height); + if (depthTextureExt) cgl.gl.renderbufferStorage(cgl.gl.RENDERBUFFER, cgl.gl.DEPTH_COMPONENT16, width, height); + + cgl.gl.framebufferTexture2D(cgl.gl.FRAMEBUFFER, cgl.gl.COLOR_ATTACHMENT0, cgl.gl.TEXTURE_2D, texture.tex, 0); + + if (depthTextureExt) + { + cgl.gl.framebufferRenderbuffer(cgl.gl.FRAMEBUFFER, cgl.gl.DEPTH_ATTACHMENT, cgl.gl.RENDERBUFFER, depthBuffer); + cgl.gl.framebufferTexture2D( + cgl.gl.FRAMEBUFFER, + cgl.gl.DEPTH_ATTACHMENT, // safari needs DEPTH_ATTACHMENT NOT DEPTH_ATTACHMENT16 + // cgl.gl.DEPTH_COMPONENT16, + cgl.gl.TEXTURE_2D, + textureDepth.tex, + 0, + ); + } + + if (!cgl.gl.isFramebuffer(frameBuf)) throw new Error("Invalid framebuffer"); + const status = cgl.gl.checkFramebufferStatus(cgl.gl.FRAMEBUFFER); + + switch (status) + { + case cgl.gl.FRAMEBUFFER_COMPLETE: + break; + case cgl.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + this._log.warn("FRAMEBUFFER_INCOMPLETE_ATTACHMENT...", width, height, texture.tex, depthBuffer); + this.valid = false; + throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); + case cgl.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + this._log.warn("FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); + this.valid = false; + throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); + case cgl.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + this._log.warn("FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); + this.valid = false; + throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); + case cgl.gl.FRAMEBUFFER_UNSUPPORTED: + this._log.warn("FRAMEBUFFER_UNSUPPORTED"); + this.valid = false; + throw new Error("Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED"); + case 0x8CDB: + this._log.warn("Incomplete: FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER from ext. Or Safari/iOS undefined behaviour."); + this.valid = false; + break; + default: + this._log.warn("incomplete framebuffer", status); + this.valid = false; + throw new Error("Incomplete framebuffer: " + status); + // throw("Incomplete framebuffer: " + status); + } + + cgl.gl.bindTexture(cgl.gl.TEXTURE_2D, null); + cgl.gl.bindRenderbuffer(cgl.gl.RENDERBUFFER, null); + cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, null); + }; + + this.renderStart = function () + { + cgl.pushModelMatrix(); + cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, frameBuf); + cgl.pushGlFrameBuffer(frameBuf); + cgl.pushFrameBuffer(this); + + cgl.pushPMatrix(); + cgl.gl.viewport(0, 0, width, height); + + if (this._options.clear) + { + cgl.gl.clearColor(0, 0, 0, 0); + cgl.gl.clear(cgl.gl.COLOR_BUFFER_BIT | cgl.gl.DEPTH_BUFFER_BIT); + } + }; + + this.renderEnd = function () + { + cgl.popPMatrix(); + cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, cgl.popGlFrameBuffer()); + cgl.popFrameBuffer(); + + cgl.popModelMatrix(); + cgl.resetViewPort(); + }; + + + this.delete = function () + { + texture.delete(); + this.valid = false; + if (textureDepth) textureDepth.delete(); + cgl.gl.deleteRenderbuffer(depthBuffer); + cgl.gl.deleteFramebuffer(frameBuf); + }; + + this.dispose = this.delete; + + this.setSize(width, height); +}; + + + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_framebuffer2.js +// * see framebuffer1 + + + + + + +const Framebuffer2 = function (cgl, w, h, options) +{ + if (cgl.glVersion == 1) return console.log("framebuffer2 used on webgl1"); + this._log = new Logger("cgl_framebuffer2"); + this.Framebuffer2DrawTargetsDefault = null; + this.Framebuffer2BlittingFramebuffer = null; + this.Framebuffer2FinalFramebuffer = null; + this._cgl = cgl; + + this._cgl.printError("before framebuffer2 constructor"); + + this._width = 0; + this._height = 0; + this.valid = true; + + this._depthRenderbuffer = null; + this._frameBuffer = null; + this._textureFrameBuffer = null; + this._colorRenderbuffers = []; + this._drawTargetArray = []; + this._disposed = false; + + if (!this.Framebuffer2BlittingFramebuffer) this.Framebuffer2BlittingFramebuffer = cgl.gl.createFramebuffer(); + if (!this.Framebuffer2FinalFramebuffer) this.Framebuffer2FinalFramebuffer = cgl.gl.createFramebuffer(); + + if (!this.Framebuffer2DrawTargetsDefault) this.Framebuffer2DrawTargetsDefault = [cgl.gl.COLOR_ATTACHMENT0]; + + this._options = options || { + "isFloatingPointTexture": false, + }; + + // this._cgl.printError("fb2 before"); + + this.name = this._options.name || "unknown"; + + this._cgl.profileData.addHeavyEvent("framebuffer create", this.name); + + if (!this._options.hasOwnProperty("numRenderBuffers")) this._options.numRenderBuffers = 1; + if (!this._options.hasOwnProperty("depth")) this._options.depth = true; + if (!this._options.hasOwnProperty("clear")) this._options.clear = true; + if (!this._options.hasOwnProperty("multisampling")) + { + this._options.multisampling = false; + this._options.multisamplingSamples = 0; + } + + if (this._options.multisamplingSamples) + { + if (this._cgl.glSlowRenderer) this._options.multisamplingSamples = 0; + if (!this._cgl.gl.MAX_SAMPLES) this._options.multisamplingSamples = 0; + else this._options.multisamplingSamples = Math.min(this._cgl.maxSamples, this._options.multisamplingSamples); + } + + if (!this._options.hasOwnProperty("filter")) this._options.filter = Texture.FILTER_LINEAR; + if (!this._options.hasOwnProperty("wrap")) this._options.wrap = Texture.WRAP_REPEAT; + + this._numRenderBuffers = this._options.numRenderBuffers; + this._colorTextures = []; + + this.clearColors = []; + for (let i = 0; i < this._numRenderBuffers; i++) this.clearColors.push([0, 0, 0, 1]); + + + if (!options.pixelFormat) + { + if (options.isFloatingPointTexture) this._options.pixelFormat = Texture.PFORMATSTR_RGBA32F; + else this._options.pixelFormat = Texture.PFORMATSTR_RGBA8UB; + } + + + for (let i = 0; i < this._numRenderBuffers; i++) + { + this._colorTextures[i] = new Texture(cgl, { + "name": "fb2 " + this.name + " " + i, + "isFloatingPointTexture": this._options.isFloatingPointTexture, + "anisotropic": this._options.anisotropic || 0, + "pixelFormat": this._options.pixelFormat, + "filter": this._options.filter, + "wrap": this._options.wrap, + }); + } + + + + let fil = Texture.FILTER_NEAREST; + if (this._options.shadowMap) fil = Texture.FILTER_LINEAR; + + const defaultTexSize = 512; + + if (this._options.depth) + { + this._textureDepth = new Texture(cgl, + { + "name": "fb2 depth " + this.name, + "isDepthTexture": true, + "filter": fil, + "shadowMap": this._options.shadowMap || false, + "width": w || defaultTexSize, + "height": h || defaultTexSize, + }); + } + + if (cgl.aborted) return; + + this.setSize(w || defaultTexSize, h || defaultTexSize); + + this._cgl.printError("framebuffer2 constructor"); +}; + +Framebuffer2.prototype.getWidth = function () +{ + return this._width; +}; +Framebuffer2.prototype.getHeight = function () +{ + return this._height; +}; + +Framebuffer2.prototype.getGlFrameBuffer = function () +{ + return this._frameBuffer; +}; + +Framebuffer2.prototype.getDepthRenderBuffer = function () +{ + return this._depthRenderbuffer; +}; + +Framebuffer2.prototype.getTextureColor = function () +{ + return this._colorTextures[0]; +}; + +Framebuffer2.prototype.getTextureColorNum = function (i) +{ + return this._colorTextures[i]; +}; + +Framebuffer2.prototype.getTextureDepth = function () +{ + return this._textureDepth; +}; + +Framebuffer2.prototype.setFilter = function (f) +{ + for (let i = 0; i < this._numRenderBuffers; i++) + { + this._colorTextures[i].filter = f; + this._colorTextures[i].setSize(this._width, this._height); + } +}; + +Framebuffer2.prototype.delete = Framebuffer2.prototype.dispose = function () +{ + this._disposed = true; + let i = 0; + for (i = 0; i < this._numRenderBuffers; i++) this._colorTextures[i].delete(); + // this._texture.delete(); + if (this._textureDepth) this._textureDepth.delete(); + for (i = 0; i < this._numRenderBuffers; i++) this._cgl.gl.deleteRenderbuffer(this._colorRenderbuffers[i]); + this._cgl.gl.deleteRenderbuffer(this._depthRenderbuffer); + this._cgl.gl.deleteFramebuffer(this._frameBuffer); + this._cgl.gl.deleteFramebuffer(this._textureFrameBuffer); +}; + +Framebuffer2.prototype.setSize = function (w, h) +{ + if (this._disposed) return this._log.warn("disposed framebuffer setsize..."); + this._cgl.profileData.addHeavyEvent("framebuffer resize", this.name); + + let i = 0; + + this._width = this._cgl.checkTextureSize(w); + this._height = this._cgl.checkTextureSize(h); + + this._cgl.profileData.profileFrameBuffercreate++; + + if (this._frameBuffer) + { + for (i = 0; i < this._numRenderBuffers; i++) this._cgl.gl.deleteRenderbuffer(this._colorRenderbuffers[i]); + // this._cgl.gl.deleteRenderbuffer(this._colorRenderbuffer); + this._cgl.gl.deleteRenderbuffer(this._depthRenderbuffer); + this._cgl.gl.deleteFramebuffer(this._frameBuffer); + this._cgl.gl.deleteFramebuffer(this._textureFrameBuffer); + } + + this._frameBuffer = this._cgl.gl.createFramebuffer(); + this._textureFrameBuffer = this._cgl.gl.createFramebuffer(); + + const depth = this._options.depth; + + for (i = 0; i < this._numRenderBuffers; i++) + { + this._colorTextures[i].setSize(this._width, this._height); + } + + + + for (i = 0; i < this._numRenderBuffers; i++) + { + const renderBuffer = this._cgl.gl.createRenderbuffer(); + + // color renderbuffer + + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuffer); + this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, renderBuffer); + + const info = Texture.setUpGlPixelFormat(this._cgl, this._options.pixelFormat); + let internFormat = info.glInternalFormat; + + // if (this._options.isFloatingPointTexture) + // { + if (CGL.Texture.isPixelFormatHalfFloat(info.pixelFormat)) + { + if (!this._cgl.enableExtension("OES_texture_float_linear")) + { + this._options.filter = Texture.FILTER_NEAREST; + this.setFilter(this._options.filter); + } + } + else if (CGL.Texture.isPixelFormatFloat(info.pixelFormat)) + { + if (!this._cgl.enableExtension("OES_texture_float_linear")) + { + console.log("no linear pixelformat,using nearest"); + this._options.filter = Texture.FILTER_NEAREST; + this.setFilter(this._options.filter); + } + } + // else if (info.pixelFormat == Texture.PFORMATSTR_RGBA32F || info.pixelFormat == Texture.PFORMATSTR_R11FG11FB10F + // else if (info.pixelFormat == Texture.PFORMATSTR_RGBA32F || info.pixelFormat == Texture.PFORMATSTR_R11FG11FB10F + // else if (info.pixelFormat == Texture.PFORMATSTR_RG16F) + // { + // const extcb = this._cgl.enableExtension("EXT_color_buffer_float"); + + // if (!this._cgl.enableExtension("OES_texture_float_linear")) + // { + // console.log("no linear pixelformat,switching to nearest"); + // this._options.filter = Texture.FILTER_NEAREST; + // this.setFilter(this._options.filter); + // } + // } + // } + + if (this._options.multisampling && this._options.multisamplingSamples) + { + this._cgl.gl.renderbufferStorageMultisample(this._cgl.gl.RENDERBUFFER, this._options.multisamplingSamples, internFormat, this._width, this._height); + } + else + { + this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, internFormat, this._width, this._height); + } + + + + this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0 + i, this._cgl.gl.RENDERBUFFER, renderBuffer); + this._colorRenderbuffers[i] = renderBuffer; + } + + // this._cgl.gl.bindFramebuffer(this._cgl.gl.DRAW_FRAMEBUFFER, this._textureFrameBuffer); + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._textureFrameBuffer); + + for (i = 0; i < this._numRenderBuffers; i++) + { + this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0 + i, this._cgl.gl.TEXTURE_2D, this._colorTextures[i].tex, 0); + } + + if (this._options.depth) + { + this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.TEXTURE_2D, this._textureDepth.tex, 0); + } + + // depth renderbuffer + + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuffer); + + + let depthType = this._cgl.gl.DEPTH_COMPONENT32F; + + if (this._cgl.glSlowRenderer) depthType = this._cgl.gl.DEPTH_COMPONENT16; + if (depth) + { + this._textureDepth.setSize(this._width, this._height); + this._depthRenderbuffer = this._cgl.gl.createRenderbuffer(); + + this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, this._depthRenderbuffer); + if (this._options.isFloatingPointTexture) + { + if (this._options.multisampling) this._cgl.gl.renderbufferStorageMultisample(this._cgl.gl.RENDERBUFFER, this._options.multisamplingSamples, depthType, this._width, this._height); + else this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, depthType, this._width, this._height); + } + else if (this._options.multisampling) + { + this._cgl.gl.renderbufferStorageMultisample(this._cgl.gl.RENDERBUFFER, this._options.multisamplingSamples, depthType, this._width, this._height); + // this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,depthType, this._width, this._height); + } + else + { + this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, depthType, this._width, this._height); + } + + this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.RENDERBUFFER, this._depthRenderbuffer); + } + + // this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null); + // this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._textureFrameBuffer); + + this._drawTargetArray.length = 0; + for (i = 0; i < this._numRenderBuffers; i++) this._drawTargetArray.push(this._cgl.gl.COLOR_ATTACHMENT0 + i); + + // this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null); + + + if (!this._cgl.gl.isFramebuffer(this._textureFrameBuffer)) this._log.warn("invalid framebuffer");// throw new Error("Invalid framebuffer"); + const status = this._cgl.gl.checkFramebufferStatus(this._cgl.gl.FRAMEBUFFER); + + if (status != this._cgl.gl.FRAMEBUFFER_COMPLETE) + { + this._log.error("framebuffer incomplete: " + this.name, this); + console.log("options", this._options); + + switch (status) + { + case this._cgl.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + this._log.warn("FRAMEBUFFER_INCOMPLETE_ATTACHMENT...", this); + throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); + case this._cgl.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + this._log.warn("FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); + throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); + case this._cgl.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + this._log.warn("FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); + throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); + case this._cgl.gl.FRAMEBUFFER_UNSUPPORTED: + this._log.warn("FRAMEBUFFER_UNSUPPORTED"); + throw new Error("Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED"); + default: + this.valid = false; + this._log.warn("incomplete framebuffer", status, this._frameBuffer); + this._cgl.printError(); + this._cgl.exitError("Framebuffer incomplete..."); + + this._frameBuffer = null; + // debugger; + throw new Error("Incomplete framebuffer: " + status); + + // throw("Incomplete framebuffer: " + status); + } + } + + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null); + this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, null); + + // this._cgl.printError("fb setsize"); +}; + +Framebuffer2.prototype.renderStart = function () +{ + if (this._disposed) return this._log.warn("disposed framebuffer renderStart..."); + this._cgl.checkFrameStarted("fb2 renderstart"); + this._cgl.pushModelMatrix(); // needed ?? + + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuffer); + this._cgl.pushGlFrameBuffer(this._frameBuffer); + this._cgl.pushFrameBuffer(this); + + this._cgl.pushPMatrix(); + this._cgl.pushViewPort(0, 0, this._width, this._height); + + this._cgl.gl.drawBuffers(this._drawTargetArray); + + if (this._options.clear) + { + this._cgl.gl.clearColor(0, 0, 0, 0); + this._cgl.gl.clear(this._cgl.gl.COLOR_BUFFER_BIT | this._cgl.gl.DEPTH_BUFFER_BIT); + } +}; + +Framebuffer2.prototype.clear = function () +{ + if (this._numRenderBuffers <= 1) + { + this._cgl.gl.bindFramebuffer(this._cgl.gl.READ_FRAMEBUFFER, this._frameBuffer); + this._cgl.gl.bindFramebuffer(this._cgl.gl.DRAW_FRAMEBUFFER, this._textureFrameBuffer); + } + else this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuffer); + + this._cgl.gl.drawBuffers(this._drawTargetArray); + + for (let i = 0; i < this._numRenderBuffers; i++) + { + this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0 + i, this._cgl.gl.TEXTURE_2D, this._colorTextures[i].tex, 0); + this._cgl.gl.clearBufferfv(this._cgl.gl.COLOR, i, this.clearColors[i]); + } + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null); +}; + +Framebuffer2.prototype.renderEnd = function () +{ + if (this._disposed) return this._log.warn("disposed framebuffer renderEnd..."); + this._cgl.popPMatrix(); + + this._cgl.profileData.profileFramebuffer++; + + + if (this._numRenderBuffers <= 1) + { + this._cgl.gl.bindFramebuffer(this._cgl.gl.READ_FRAMEBUFFER, this._frameBuffer); + this._cgl.gl.bindFramebuffer(this._cgl.gl.DRAW_FRAMEBUFFER, this._textureFrameBuffer); + + // const a = this._cgl.gl.getFramebufferAttachmentParameter(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING); + // if (a == this._cgl.gl.SRGB)console.log("SRGB", this._cgl.gl.SRGB); + // else if (a == this._cgl.gl.LINEAR)console.log("LINEAR", this._cgl.gl.LINEAR); + + + this._cgl.gl.clearBufferfv(this._cgl.gl.COLOR, 0, [0.0, 0.0, 0.0, 1.0]); + this._cgl.gl.blitFramebuffer(0, 0, this._width, this._height, 0, 0, this._width, this._height, this._cgl.gl.COLOR_BUFFER_BIT | this._cgl.gl.DEPTH_BUFFER_BIT, this._cgl.gl.NEAREST); + } + else + { + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this.Framebuffer2BlittingFramebuffer); + this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.RENDERBUFFER, this._depthRenderbuffer); + + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this.Framebuffer2FinalFramebuffer); + this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.TEXTURE_2D, this._textureDepth.tex, 0); + + // console.log("fb this._numRenderBuffers", this._numRenderBuffers); + for (let i = 0; i < this._numRenderBuffers; i++) + { + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this.Framebuffer2BlittingFramebuffer); + this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.RENDERBUFFER, this._colorRenderbuffers[i]); + + + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this.Framebuffer2FinalFramebuffer); + this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._colorTextures[i].tex, 0); + + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null); + + this._cgl.gl.bindFramebuffer(this._cgl.gl.READ_FRAMEBUFFER, this.Framebuffer2BlittingFramebuffer); + this._cgl.gl.bindFramebuffer(this._cgl.gl.DRAW_FRAMEBUFFER, this.Framebuffer2FinalFramebuffer); + + // this._cgl.gl.clearBufferfv(this._cgl.gl.COLOR, i, [0.0, 0.0, 0.0, 1.0]); + + + + let flags = this._cgl.gl.COLOR_BUFFER_BIT; + if (i == 0) flags |= this._cgl.gl.DEPTH_BUFFER_BIT; + + this._cgl.gl.blitFramebuffer(0, 0, this._width, this._height, 0, 0, this._width, this._height, flags, this._cgl.gl.NEAREST); + } + } + + this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.popGlFrameBuffer()); + this._cgl.popFrameBuffer(); + + this._cgl.popModelMatrix(); + // this._cgl.resetViewPort(); + this._cgl.popViewPort(); + + + if (this._colorTextures[0].filter == Texture.FILTER_MIPMAP) + { + for (let i = 0; i < this._numRenderBuffers; i++) + { + this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, this._colorTextures[i].tex); + this._colorTextures[i].updateMipMap(); + this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, null); + } + } +}; + + + +/// /////// + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_marker.js +const Marker = function (_cgl) // deprecated... +{ + this.draw = function (cgl, _size, depthTest) {}; +}; + +const WirePoint = function (cgl) // deprecated... +{ + this.render = function (_cgl, _size) {}; +}; + +const WireCube = function (cgl) // deprecated... +{ + this.render = function (_cgl, sizeX, sizeY, sizeZ) {}; +}; + +;// CONCATENATED MODULE: ./src/core/cgl/cgl_unicolorshader.js + + +class UniColorShader +{ + constructor(_cgl) + { + this.shader = new CGL.Shader(_cgl, "markermaterial"); + + const frag = "" + .endl() + "void main()" + .endl() + "{" + .endl() + " outColor = vec4(color.rgb,1.0);" + .endl() + "}"; + + + const vert = "" + .endl() + "IN vec3 vPosition;" + .endl() + "UNI mat4 projMatrix;" + .endl() + "UNI mat4 mvMatrix;" + + .endl() + "void main()" + .endl() + "{" + .endl() + " gl_Position = projMatrix * mvMatrix * vec4(vPosition,1.0);" + .endl() + "}"; + + this.shader.setSource(vert, frag); + this.coloruni = this.shader.addUniformFrag("4f", "color", [1, 0.777, 1, 1]); + } + + setColor(r, g, b, a) + { + this.coloruni.set(r, g, b, a); + } +} + +;// CONCATENATED MODULE: ./src/core/cgl/index.js + + + + + + + + + + + + + + + + + + + + + + +const cgl_CGL = { + "Framebuffer": Framebuffer, + "Framebuffer2": Framebuffer2, + "Geometry": Geometry, + "BoundingBox": BoundingBox, + "Marker": Marker, + "WirePoint": WirePoint, + "WireCube": WireCube, + "MatrixStack": MatrixStack, + "Mesh": Mesh, + "MESH": MESH, + "ShaderLibMods": ShaderLibMods, + "Shader": Shader, + "Uniform": Uniform, + "MESHES": MESHES, + "Context": Context, + "Texture": Texture, + "TextureEffect": TextureEffect, + "isWindows": isWindows, + "getWheelSpeed": getWheelSpeed, + "getWheelDelta": getWheelDelta, + "onLoadingAssetsFinished": onLoadingAssetsFinished, + "ProfileData": ProfileData, + "UniColorShader": UniColorShader, + ...constants_CONSTANTS.BLEND_MODES, + ...constants_CONSTANTS.SHADER, + ...constants_CONSTANTS.MATH, + ...constants_CONSTANTS.BLEND_MODES, +}; + +window.CGL = cgl_CGL; + + + + + +;// CONCATENATED MODULE: ./src/core/index.js + + + + + + + + + + + + + + + + + + + + +window.CABLES = window.CABLES || {}; + +CABLES.CGL = cgl_CGL; +CABLES.CG = CG; +CABLES.CGP = cgp_CGP; +CABLES.EMBED = EMBED; +CABLES.Link = Link; +CABLES.Port = Port; +CABLES.Op = Op; +CABLES.Profiler = Profiler; +CABLES.Patch = core_patch; +CABLES.Instancing = Instancing; +CABLES.Timer = Timer; +CABLES.WEBAUDIO = WEBAUDIO; +CABLES.Variable = Variable; +CABLES.LoadingStatus = LoadingStatus; +CABLES.now = now; +CABLES.internalNow = internalNow; +CABLES.BranchStack = BranchStack; +CABLES.Branch = Branch; + + +CABLES = Object.assign(CABLES, + base64_namespaceObject, + utils_namespaceObject, + anim_namespaceObject, + CONSTANTS.PORT, + CONSTANTS.PACO, + CONSTANTS.ANIM, + CONSTANTS.OP +); + +/* harmony default export */ const core = (CABLES); + +if (!(function () { return !this; }())) console.warn("not in strict mode: index core"); // eslint-disable-line + +CABLES = __webpack_exports__["default"]; +/******/ })() +; + + +var CABLES = CABLES || {}; CABLES.build = {"timestamp":1715927482175,"created":"2024-05-17T06:31:22.175Z","git":{"branch":"master","commit":"83d9847c52906e47691c89c7ec564876e8749a3b","date":"1715927217","message":"subpatch ops wrong"}}; +/*! +@fileoverview gl-matrix - High performance matrix and vector operations +@author Brandon Jones +@author Colin MacKenzie IV +@version 3.1.0 + +Copyright (c) 2015-2019, Brandon Jones, Colin MacKenzie IV. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t=t||self).glMatrix={})}(this,function(t){"use strict";var n=1e-6,a="undefined"!=typeof Float32Array?Float32Array:Array,r=Math.random;var u=Math.PI/180;Math.hypot||(Math.hypot=function(){for(var t=0,n=arguments.length;n--;)t+=arguments[n]*arguments[n];return Math.sqrt(t)});var e=Object.freeze({EPSILON:n,get ARRAY_TYPE(){return a},RANDOM:r,setMatrixArrayType:function(t){a=t},toRadian:function(t){return t*u},equals:function(t,a){return Math.abs(t-a)<=n*Math.max(1,Math.abs(t),Math.abs(a))}});function o(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*i+e*c,t[1]=u*i+o*c,t[2]=r*h+e*s,t[3]=u*h+o*s,t}function i(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}var c=o,h=i,s=Object.freeze({create:function(){var t=new a(4);return a!=Float32Array&&(t[1]=0,t[2]=0),t[0]=1,t[3]=1,t},clone:function(t){var n=new a(4);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t},fromValues:function(t,n,r,u){var e=new a(4);return e[0]=t,e[1]=n,e[2]=r,e[3]=u,e},set:function(t,n,a,r,u){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t},transpose:function(t,n){if(t===n){var a=n[1];t[1]=n[2],t[2]=a}else t[0]=n[0],t[1]=n[2],t[2]=n[1],t[3]=n[3];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*e-u*r;return o?(o=1/o,t[0]=e*o,t[1]=-r*o,t[2]=-u*o,t[3]=a*o,t):null},adjoint:function(t,n){var a=n[0];return t[0]=n[3],t[1]=-n[1],t[2]=-n[2],t[3]=a,t},determinant:function(t){return t[0]*t[3]-t[2]*t[1]},multiply:o,rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+e*i,t[1]=u*c+o*i,t[2]=r*-i+e*c,t[3]=u*-i+o*c,t},scale:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1];return t[0]=r*i,t[1]=u*i,t[2]=e*c,t[3]=o*c,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t},str:function(t){return"mat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3])},LDU:function(t,n,a,r){return t[2]=r[2]/r[0],a[0]=r[0],a[1]=r[1],a[3]=r[3]-t[2]*a[1],[t,n,a]},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t},subtract:i,exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=a[0],c=a[1],h=a[2],s=a[3];return Math.abs(r-i)<=n*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-c)<=n*Math.max(1,Math.abs(u),Math.abs(c))&&Math.abs(e-h)<=n*Math.max(1,Math.abs(e),Math.abs(h))&&Math.abs(o-s)<=n*Math.max(1,Math.abs(o),Math.abs(s))},multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t},mul:c,sub:h});function M(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return t[0]=r*h+e*s,t[1]=u*h+o*s,t[2]=r*M+e*f,t[3]=u*M+o*f,t[4]=r*l+e*v+i,t[5]=u*l+o*v+c,t}function f(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t}var l=M,v=f,b=Object.freeze({create:function(){var t=new a(6);return a!=Float32Array&&(t[1]=0,t[2]=0,t[4]=0,t[5]=0),t[0]=1,t[3]=1,t},clone:function(t){var n=new a(6);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t},fromValues:function(t,n,r,u,e,o){var i=new a(6);return i[0]=t,i[1]=n,i[2]=r,i[3]=u,i[4]=e,i[5]=o,i},set:function(t,n,a,r,u,e,o){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=a*e-r*u;return c?(c=1/c,t[0]=e*c,t[1]=-r*c,t[2]=-u*c,t[3]=a*c,t[4]=(u*i-e*o)*c,t[5]=(r*o-a*i)*c,t):null},determinant:function(t){return t[0]*t[3]-t[1]*t[2]},multiply:M,rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=Math.sin(a),s=Math.cos(a);return t[0]=r*s+e*h,t[1]=u*s+o*h,t[2]=r*-h+e*s,t[3]=u*-h+o*s,t[4]=i,t[5]=c,t},scale:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1];return t[0]=r*h,t[1]=u*h,t[2]=e*s,t[3]=o*s,t[4]=i,t[5]=c,t},translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=r*h+e*s+i,t[5]=u*h+o*s+c,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t[4]=0,t[5]=0,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t[4]=0,t[5]=0,t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=n[0],t[5]=n[1],t},str:function(t){return"mat2d("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],1)},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t},subtract:f,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return Math.abs(r-h)<=n*Math.max(1,Math.abs(r),Math.abs(h))&&Math.abs(u-s)<=n*Math.max(1,Math.abs(u),Math.abs(s))&&Math.abs(e-M)<=n*Math.max(1,Math.abs(e),Math.abs(M))&&Math.abs(o-f)<=n*Math.max(1,Math.abs(o),Math.abs(f))&&Math.abs(i-l)<=n*Math.max(1,Math.abs(i),Math.abs(l))&&Math.abs(c-v)<=n*Math.max(1,Math.abs(c),Math.abs(v))},mul:l,sub:v});function m(){var t=new a(9);return a!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[5]=0,t[6]=0,t[7]=0),t[0]=1,t[4]=1,t[8]=1,t}function d(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],x=a[6],p=a[7],y=a[8];return t[0]=f*r+l*o+v*h,t[1]=f*u+l*i+v*s,t[2]=f*e+l*c+v*M,t[3]=b*r+m*o+d*h,t[4]=b*u+m*i+d*s,t[5]=b*e+m*c+d*M,t[6]=x*r+p*o+y*h,t[7]=x*u+p*i+y*s,t[8]=x*e+p*c+y*M,t}function x(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t}var p=d,y=x,q=Object.freeze({create:m,fromMat4:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[4],t[4]=n[5],t[5]=n[6],t[6]=n[8],t[7]=n[9],t[8]=n[10],t},clone:function(t){var n=new a(9);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromValues:function(t,n,r,u,e,o,i,c,h){var s=new a(9);return s[0]=t,s[1]=n,s[2]=r,s[3]=u,s[4]=e,s[5]=o,s[6]=i,s[7]=c,s[8]=h,s},set:function(t,n,a,r,u,e,o,i,c,h){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t[8]=h,t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},transpose:function(t,n){if(t===n){var a=n[1],r=n[2],u=n[5];t[1]=n[3],t[2]=n[6],t[3]=a,t[5]=n[7],t[6]=r,t[7]=u}else t[0]=n[0],t[1]=n[3],t[2]=n[6],t[3]=n[1],t[4]=n[4],t[5]=n[7],t[6]=n[2],t[7]=n[5],t[8]=n[8];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=s*o-i*h,f=-s*e+i*c,l=h*e-o*c,v=a*M+r*f+u*l;return v?(v=1/v,t[0]=M*v,t[1]=(-s*r+u*h)*v,t[2]=(i*r-u*o)*v,t[3]=f*v,t[4]=(s*a-u*c)*v,t[5]=(-i*a+u*e)*v,t[6]=l*v,t[7]=(-h*a+r*c)*v,t[8]=(o*a-r*e)*v,t):null},adjoint:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8];return t[0]=o*s-i*h,t[1]=u*h-r*s,t[2]=r*i-u*o,t[3]=i*c-e*s,t[4]=a*s-u*c,t[5]=u*e-a*i,t[6]=e*h-o*c,t[7]=r*c-a*h,t[8]=a*o-r*e,t},determinant:function(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],c=t[7],h=t[8];return n*(h*e-o*c)+a*(-h*u+o*i)+r*(c*u-e*i)},multiply:d,translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=a[0],l=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=c,t[6]=f*r+l*o+h,t[7]=f*u+l*i+s,t[8]=f*e+l*c+M,t},rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=Math.sin(a),l=Math.cos(a);return t[0]=l*r+f*o,t[1]=l*u+f*i,t[2]=l*e+f*c,t[3]=l*o-f*r,t[4]=l*i-f*u,t[5]=l*c-f*e,t[6]=h,t[7]=s,t[8]=M,t},scale:function(t,n,a){var r=a[0],u=a[1];return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=u*n[3],t[4]=u*n[4],t[5]=u*n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=n[0],t[7]=n[1],t[8]=1,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=-a,t[4]=r,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=n[1],t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromMat2d:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=0,t[3]=n[2],t[4]=n[3],t[5]=0,t[6]=n[4],t[7]=n[5],t[8]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,c=u+u,h=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*c,b=e*o,m=e*i,d=e*c;return t[0]=1-M-v,t[3]=s-d,t[6]=f+m,t[1]=s+d,t[4]=1-h-v,t[7]=l-b,t[2]=f-m,t[5]=l+b,t[8]=1-h-M,t},normalFromMat4:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,p=a*c-u*o,y=a*h-e*o,q=r*c-u*i,g=r*h-e*i,A=u*h-e*c,w=s*b-M*v,R=s*m-f*v,z=s*d-l*v,P=M*m-f*b,j=M*d-l*b,I=f*d-l*m,S=x*I-p*j+y*P+q*z-g*R+A*w;return S?(S=1/S,t[0]=(i*I-c*j+h*P)*S,t[1]=(c*z-o*I-h*R)*S,t[2]=(o*j-i*z+h*w)*S,t[3]=(u*j-r*I-e*P)*S,t[4]=(a*I-u*z+e*R)*S,t[5]=(r*z-a*j-e*w)*S,t[6]=(b*A-m*g+d*q)*S,t[7]=(m*y-v*A-d*p)*S,t[8]=(v*g-b*y+d*x)*S,t):null},projection:function(t,n,a){return t[0]=2/n,t[1]=0,t[2]=0,t[3]=0,t[4]=-2/a,t[5]=0,t[6]=-1,t[7]=1,t[8]=1,t},str:function(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t},subtract:x,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=t[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],x=a[6],p=a[7],y=a[8];return Math.abs(r-f)<=n*Math.max(1,Math.abs(r),Math.abs(f))&&Math.abs(u-l)<=n*Math.max(1,Math.abs(u),Math.abs(l))&&Math.abs(e-v)<=n*Math.max(1,Math.abs(e),Math.abs(v))&&Math.abs(o-b)<=n*Math.max(1,Math.abs(o),Math.abs(b))&&Math.abs(i-m)<=n*Math.max(1,Math.abs(i),Math.abs(m))&&Math.abs(c-d)<=n*Math.max(1,Math.abs(c),Math.abs(d))&&Math.abs(h-x)<=n*Math.max(1,Math.abs(h),Math.abs(x))&&Math.abs(s-p)<=n*Math.max(1,Math.abs(s),Math.abs(p))&&Math.abs(M-y)<=n*Math.max(1,Math.abs(M),Math.abs(y))},mul:p,sub:y});function g(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function A(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],b=n[12],m=n[13],d=n[14],x=n[15],p=a[0],y=a[1],q=a[2],g=a[3];return t[0]=p*r+y*i+q*M+g*b,t[1]=p*u+y*c+q*f+g*m,t[2]=p*e+y*h+q*l+g*d,t[3]=p*o+y*s+q*v+g*x,p=a[4],y=a[5],q=a[6],g=a[7],t[4]=p*r+y*i+q*M+g*b,t[5]=p*u+y*c+q*f+g*m,t[6]=p*e+y*h+q*l+g*d,t[7]=p*o+y*s+q*v+g*x,p=a[8],y=a[9],q=a[10],g=a[11],t[8]=p*r+y*i+q*M+g*b,t[9]=p*u+y*c+q*f+g*m,t[10]=p*e+y*h+q*l+g*d,t[11]=p*o+y*s+q*v+g*x,p=a[12],y=a[13],q=a[14],g=a[15],t[12]=p*r+y*i+q*M+g*b,t[13]=p*u+y*c+q*f+g*m,t[14]=p*e+y*h+q*l+g*d,t[15]=p*o+y*s+q*v+g*x,t}function w(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=r+r,c=u+u,h=e+e,s=r*i,M=r*c,f=r*h,l=u*c,v=u*h,b=e*h,m=o*i,d=o*c,x=o*h;return t[0]=1-(l+b),t[1]=M+x,t[2]=f-d,t[3]=0,t[4]=M-x,t[5]=1-(s+b),t[6]=v+m,t[7]=0,t[8]=f+d,t[9]=v-m,t[10]=1-(s+l),t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t}function R(t,n){return t[0]=n[12],t[1]=n[13],t[2]=n[14],t}function z(t,n){var a=n[0],r=n[1],u=n[2],e=n[4],o=n[5],i=n[6],c=n[8],h=n[9],s=n[10];return t[0]=Math.hypot(a,r,u),t[1]=Math.hypot(e,o,i),t[2]=Math.hypot(c,h,s),t}function P(t,n){var r=new a(3);z(r,n);var u=1/r[0],e=1/r[1],o=1/r[2],i=n[0]*u,c=n[1]*e,h=n[2]*o,s=n[4]*u,M=n[5]*e,f=n[6]*o,l=n[8]*u,v=n[9]*e,b=n[10]*o,m=i+M+b,d=0;return m>0?(d=2*Math.sqrt(m+1),t[3]=.25*d,t[0]=(f-v)/d,t[1]=(l-h)/d,t[2]=(c-s)/d):i>M&&i>b?(d=2*Math.sqrt(1+i-M-b),t[3]=(f-v)/d,t[0]=.25*d,t[1]=(c+s)/d,t[2]=(l+h)/d):M>b?(d=2*Math.sqrt(1+M-i-b),t[3]=(l-h)/d,t[0]=(c+s)/d,t[1]=.25*d,t[2]=(f+v)/d):(d=2*Math.sqrt(1+b-i-M),t[3]=(c-s)/d,t[0]=(l+h)/d,t[1]=(f+v)/d,t[2]=.25*d),t}function j(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t[9]=n[9]-a[9],t[10]=n[10]-a[10],t[11]=n[11]-a[11],t[12]=n[12]-a[12],t[13]=n[13]-a[13],t[14]=n[14]-a[14],t[15]=n[15]-a[15],t}var I=A,S=j,E=Object.freeze({create:function(){var t=new a(16);return a!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0),t[0]=1,t[5]=1,t[10]=1,t[15]=1,t},clone:function(t){var n=new a(16);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n[9]=t[9],n[10]=t[10],n[11]=t[11],n[12]=t[12],n[13]=t[13],n[14]=t[14],n[15]=t[15],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},fromValues:function(t,n,r,u,e,o,i,c,h,s,M,f,l,v,b,m){var d=new a(16);return d[0]=t,d[1]=n,d[2]=r,d[3]=u,d[4]=e,d[5]=o,d[6]=i,d[7]=c,d[8]=h,d[9]=s,d[10]=M,d[11]=f,d[12]=l,d[13]=v,d[14]=b,d[15]=m,d},set:function(t,n,a,r,u,e,o,i,c,h,s,M,f,l,v,b,m){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t[8]=h,t[9]=s,t[10]=M,t[11]=f,t[12]=l,t[13]=v,t[14]=b,t[15]=m,t},identity:g,transpose:function(t,n){if(t===n){var a=n[1],r=n[2],u=n[3],e=n[6],o=n[7],i=n[11];t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=a,t[6]=n[9],t[7]=n[13],t[8]=r,t[9]=e,t[11]=n[14],t[12]=u,t[13]=o,t[14]=i}else t[0]=n[0],t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=n[1],t[5]=n[5],t[6]=n[9],t[7]=n[13],t[8]=n[2],t[9]=n[6],t[10]=n[10],t[11]=n[14],t[12]=n[3],t[13]=n[7],t[14]=n[11],t[15]=n[15];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,p=a*c-u*o,y=a*h-e*o,q=r*c-u*i,g=r*h-e*i,A=u*h-e*c,w=s*b-M*v,R=s*m-f*v,z=s*d-l*v,P=M*m-f*b,j=M*d-l*b,I=f*d-l*m,S=x*I-p*j+y*P+q*z-g*R+A*w;return S?(S=1/S,t[0]=(i*I-c*j+h*P)*S,t[1]=(u*j-r*I-e*P)*S,t[2]=(b*A-m*g+d*q)*S,t[3]=(f*g-M*A-l*q)*S,t[4]=(c*z-o*I-h*R)*S,t[5]=(a*I-u*z+e*R)*S,t[6]=(m*y-v*A-d*p)*S,t[7]=(s*A-f*y+l*p)*S,t[8]=(o*j-i*z+h*w)*S,t[9]=(r*z-a*j-e*w)*S,t[10]=(v*g-b*y+d*x)*S,t[11]=(M*y-s*g-l*x)*S,t[12]=(i*R-o*P-c*w)*S,t[13]=(a*P-r*R+u*w)*S,t[14]=(b*p-v*q-m*x)*S,t[15]=(s*q-M*p+f*x)*S,t):null},adjoint:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15];return t[0]=i*(f*d-l*m)-M*(c*d-h*m)+b*(c*l-h*f),t[1]=-(r*(f*d-l*m)-M*(u*d-e*m)+b*(u*l-e*f)),t[2]=r*(c*d-h*m)-i*(u*d-e*m)+b*(u*h-e*c),t[3]=-(r*(c*l-h*f)-i*(u*l-e*f)+M*(u*h-e*c)),t[4]=-(o*(f*d-l*m)-s*(c*d-h*m)+v*(c*l-h*f)),t[5]=a*(f*d-l*m)-s*(u*d-e*m)+v*(u*l-e*f),t[6]=-(a*(c*d-h*m)-o*(u*d-e*m)+v*(u*h-e*c)),t[7]=a*(c*l-h*f)-o*(u*l-e*f)+s*(u*h-e*c),t[8]=o*(M*d-l*b)-s*(i*d-h*b)+v*(i*l-h*M),t[9]=-(a*(M*d-l*b)-s*(r*d-e*b)+v*(r*l-e*M)),t[10]=a*(i*d-h*b)-o*(r*d-e*b)+v*(r*h-e*i),t[11]=-(a*(i*l-h*M)-o*(r*l-e*M)+s*(r*h-e*i)),t[12]=-(o*(M*m-f*b)-s*(i*m-c*b)+v*(i*f-c*M)),t[13]=a*(M*m-f*b)-s*(r*m-u*b)+v*(r*f-u*M),t[14]=-(a*(i*m-c*b)-o*(r*m-u*b)+v*(r*c-u*i)),t[15]=a*(i*f-c*M)-o*(r*f-u*M)+s*(r*c-u*i),t},determinant:function(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],c=t[7],h=t[8],s=t[9],M=t[10],f=t[11],l=t[12],v=t[13],b=t[14],m=t[15];return(n*o-a*e)*(M*m-f*b)-(n*i-r*e)*(s*m-f*v)+(n*c-u*e)*(s*b-M*v)+(a*i-r*o)*(h*m-f*l)-(a*c-u*o)*(h*b-M*l)+(r*c-u*i)*(h*v-s*l)},multiply:A,translate:function(t,n,a){var r,u,e,o,i,c,h,s,M,f,l,v,b=a[0],m=a[1],d=a[2];return n===t?(t[12]=n[0]*b+n[4]*m+n[8]*d+n[12],t[13]=n[1]*b+n[5]*m+n[9]*d+n[13],t[14]=n[2]*b+n[6]*m+n[10]*d+n[14],t[15]=n[3]*b+n[7]*m+n[11]*d+n[15]):(r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=c,t[6]=h,t[7]=s,t[8]=M,t[9]=f,t[10]=l,t[11]=v,t[12]=r*b+i*m+M*d+n[12],t[13]=u*b+c*m+f*d+n[13],t[14]=e*b+h*m+l*d+n[14],t[15]=o*b+s*m+v*d+n[15]),t},scale:function(t,n,a){var r=a[0],u=a[1],e=a[2];return t[0]=n[0]*r,t[1]=n[1]*r,t[2]=n[2]*r,t[3]=n[3]*r,t[4]=n[4]*u,t[5]=n[5]*u,t[6]=n[6]*u,t[7]=n[7]*u,t[8]=n[8]*e,t[9]=n[9]*e,t[10]=n[10]*e,t[11]=n[11]*e,t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},rotate:function(t,a,r,u){var e,o,i,c,h,s,M,f,l,v,b,m,d,x,p,y,q,g,A,w,R,z,P,j,I=u[0],S=u[1],E=u[2],O=Math.hypot(I,S,E);return O0?(r[0]=2*(c*i+M*u+h*o-s*e)/f,r[1]=2*(h*i+M*e+s*u-c*o)/f,r[2]=2*(s*i+M*o+c*e-h*u)/f):(r[0]=2*(c*i+M*u+h*o-s*e),r[1]=2*(h*i+M*e+s*u-c*o),r[2]=2*(s*i+M*o+c*e-h*u)),w(t,n,r),t},getTranslation:R,getScaling:z,getRotation:P,fromRotationTranslationScale:function(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3],c=u+u,h=e+e,s=o+o,M=u*c,f=u*h,l=u*s,v=e*h,b=e*s,m=o*s,d=i*c,x=i*h,p=i*s,y=r[0],q=r[1],g=r[2];return t[0]=(1-(v+m))*y,t[1]=(f+p)*y,t[2]=(l-x)*y,t[3]=0,t[4]=(f-p)*q,t[5]=(1-(M+m))*q,t[6]=(b+d)*q,t[7]=0,t[8]=(l+x)*g,t[9]=(b-d)*g,t[10]=(1-(M+v))*g,t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t},fromRotationTranslationScaleOrigin:function(t,n,a,r,u){var e=n[0],o=n[1],i=n[2],c=n[3],h=e+e,s=o+o,M=i+i,f=e*h,l=e*s,v=e*M,b=o*s,m=o*M,d=i*M,x=c*h,p=c*s,y=c*M,q=r[0],g=r[1],A=r[2],w=u[0],R=u[1],z=u[2],P=(1-(b+d))*q,j=(l+y)*q,I=(v-p)*q,S=(l-y)*g,E=(1-(f+d))*g,O=(m+x)*g,T=(v+p)*A,D=(m-x)*A,F=(1-(f+b))*A;return t[0]=P,t[1]=j,t[2]=I,t[3]=0,t[4]=S,t[5]=E,t[6]=O,t[7]=0,t[8]=T,t[9]=D,t[10]=F,t[11]=0,t[12]=a[0]+w-(P*w+S*R+T*z),t[13]=a[1]+R-(j*w+E*R+D*z),t[14]=a[2]+z-(I*w+O*R+F*z),t[15]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,c=u+u,h=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*c,b=e*o,m=e*i,d=e*c;return t[0]=1-M-v,t[1]=s+d,t[2]=f-m,t[3]=0,t[4]=s-d,t[5]=1-h-v,t[6]=l+b,t[7]=0,t[8]=f+m,t[9]=l-b,t[10]=1-h-M,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},frustum:function(t,n,a,r,u,e,o){var i=1/(a-n),c=1/(u-r),h=1/(e-o);return t[0]=2*e*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*e*c,t[6]=0,t[7]=0,t[8]=(a+n)*i,t[9]=(u+r)*c,t[10]=(o+e)*h,t[11]=-1,t[12]=0,t[13]=0,t[14]=o*e*2*h,t[15]=0,t},perspective:function(t,n,a,r,u){var e,o=1/Math.tan(n/2);return t[0]=o/a,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=o,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=-1,t[12]=0,t[13]=0,t[15]=0,null!=u&&u!==1/0?(e=1/(r-u),t[10]=(u+r)*e,t[14]=2*u*r*e):(t[10]=-1,t[14]=-2*r),t},perspectiveFromFieldOfView:function(t,n,a,r){var u=Math.tan(n.upDegrees*Math.PI/180),e=Math.tan(n.downDegrees*Math.PI/180),o=Math.tan(n.leftDegrees*Math.PI/180),i=Math.tan(n.rightDegrees*Math.PI/180),c=2/(o+i),h=2/(u+e);return t[0]=c,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=h,t[6]=0,t[7]=0,t[8]=-(o-i)*c*.5,t[9]=(u-e)*h*.5,t[10]=r/(a-r),t[11]=-1,t[12]=0,t[13]=0,t[14]=r*a/(a-r),t[15]=0,t},ortho:function(t,n,a,r,u,e,o){var i=1/(n-a),c=1/(r-u),h=1/(e-o);return t[0]=-2*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*c,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*h,t[11]=0,t[12]=(n+a)*i,t[13]=(u+r)*c,t[14]=(o+e)*h,t[15]=1,t},lookAt:function(t,a,r,u){var e,o,i,c,h,s,M,f,l,v,b=a[0],m=a[1],d=a[2],x=u[0],p=u[1],y=u[2],q=r[0],A=r[1],w=r[2];return Math.abs(b-q)0&&(s*=l=1/Math.sqrt(l),M*=l,f*=l);var v=c*f-h*M,b=h*s-i*f,m=i*M-c*s;return(l=v*v+b*b+m*m)>0&&(v*=l=1/Math.sqrt(l),b*=l,m*=l),t[0]=v,t[1]=b,t[2]=m,t[3]=0,t[4]=M*m-f*b,t[5]=f*v-s*m,t[6]=s*b-M*v,t[7]=0,t[8]=s,t[9]=M,t[10]=f,t[11]=0,t[12]=u,t[13]=e,t[14]=o,t[15]=1,t},str:function(t){return"mat4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+", "+t[9]+", "+t[10]+", "+t[11]+", "+t[12]+", "+t[13]+", "+t[14]+", "+t[15]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t[9]=n[9]+a[9],t[10]=n[10]+a[10],t[11]=n[11]+a[11],t[12]=n[12]+a[12],t[13]=n[13]+a[13],t[14]=n[14]+a[14],t[15]=n[15]+a[15],t},subtract:j,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=n[11]*a,t[12]=n[12]*a,t[13]=n[13]*a,t[14]=n[14]*a,t[15]=n[15]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t[9]=n[9]+a[9]*r,t[10]=n[10]+a[10]*r,t[11]=n[11]+a[11]*r,t[12]=n[12]+a[12]*r,t[13]=n[13]+a[13]*r,t[14]=n[14]+a[14]*r,t[15]=n[15]+a[15]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]&&t[9]===n[9]&&t[10]===n[10]&&t[11]===n[11]&&t[12]===n[12]&&t[13]===n[13]&&t[14]===n[14]&&t[15]===n[15]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=t[8],f=t[9],l=t[10],v=t[11],b=t[12],m=t[13],d=t[14],x=t[15],p=a[0],y=a[1],q=a[2],g=a[3],A=a[4],w=a[5],R=a[6],z=a[7],P=a[8],j=a[9],I=a[10],S=a[11],E=a[12],O=a[13],T=a[14],D=a[15];return Math.abs(r-p)<=n*Math.max(1,Math.abs(r),Math.abs(p))&&Math.abs(u-y)<=n*Math.max(1,Math.abs(u),Math.abs(y))&&Math.abs(e-q)<=n*Math.max(1,Math.abs(e),Math.abs(q))&&Math.abs(o-g)<=n*Math.max(1,Math.abs(o),Math.abs(g))&&Math.abs(i-A)<=n*Math.max(1,Math.abs(i),Math.abs(A))&&Math.abs(c-w)<=n*Math.max(1,Math.abs(c),Math.abs(w))&&Math.abs(h-R)<=n*Math.max(1,Math.abs(h),Math.abs(R))&&Math.abs(s-z)<=n*Math.max(1,Math.abs(s),Math.abs(z))&&Math.abs(M-P)<=n*Math.max(1,Math.abs(M),Math.abs(P))&&Math.abs(f-j)<=n*Math.max(1,Math.abs(f),Math.abs(j))&&Math.abs(l-I)<=n*Math.max(1,Math.abs(l),Math.abs(I))&&Math.abs(v-S)<=n*Math.max(1,Math.abs(v),Math.abs(S))&&Math.abs(b-E)<=n*Math.max(1,Math.abs(b),Math.abs(E))&&Math.abs(m-O)<=n*Math.max(1,Math.abs(m),Math.abs(O))&&Math.abs(d-T)<=n*Math.max(1,Math.abs(d),Math.abs(T))&&Math.abs(x-D)<=n*Math.max(1,Math.abs(x),Math.abs(D))},mul:I,sub:S});function O(){var t=new a(3);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t}function T(t){var n=t[0],a=t[1],r=t[2];return Math.hypot(n,a,r)}function D(t,n,r){var u=new a(3);return u[0]=t,u[1]=n,u[2]=r,u}function F(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t}function L(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t}function V(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t}function Q(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return Math.hypot(a,r,u)}function Y(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return a*a+r*r+u*u}function X(t){var n=t[0],a=t[1],r=t[2];return n*n+a*a+r*r}function Z(t,n){var a=n[0],r=n[1],u=n[2],e=a*a+r*r+u*u;return e>0&&(e=1/Math.sqrt(e)),t[0]=n[0]*e,t[1]=n[1]*e,t[2]=n[2]*e,t}function _(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function B(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],c=a[2];return t[0]=u*c-e*i,t[1]=e*o-r*c,t[2]=r*i-u*o,t}var N,k=F,U=L,W=V,C=Q,G=Y,H=T,J=X,K=(N=O(),function(t,n,a,r,u,e){var o,i;for(n||(n=3),a||(a=0),i=r?Math.min(r*n+a,t.length):t.length,o=a;o1?0:u<-1?Math.PI:Math.acos(u)},zero:function(t){return t[0]=0,t[1]=0,t[2]=0,t},str:function(t){return"vec3("+t[0]+", "+t[1]+", "+t[2]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=a[0],i=a[1],c=a[2];return Math.abs(r-o)<=n*Math.max(1,Math.abs(r),Math.abs(o))&&Math.abs(u-i)<=n*Math.max(1,Math.abs(u),Math.abs(i))&&Math.abs(e-c)<=n*Math.max(1,Math.abs(e),Math.abs(c))},sub:k,mul:U,div:W,dist:C,sqrDist:G,len:H,sqrLen:J,forEach:K});function tt(){var t=new a(4);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[3]=0),t}function nt(t){var n=new a(4);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n}function at(t,n,r,u){var e=new a(4);return e[0]=t,e[1]=n,e[2]=r,e[3]=u,e}function rt(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t}function ut(t,n,a,r,u){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t}function et(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t}function ot(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}function it(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t[3]=n[3]*a[3],t}function ct(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t[3]=n[3]/a[3],t}function ht(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t}function st(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2],e=n[3]-t[3];return Math.hypot(a,r,u,e)}function Mt(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2],e=n[3]-t[3];return a*a+r*r+u*u+e*e}function ft(t){var n=t[0],a=t[1],r=t[2],u=t[3];return Math.hypot(n,a,r,u)}function lt(t){var n=t[0],a=t[1],r=t[2],u=t[3];return n*n+a*a+r*r+u*u}function vt(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*a+r*r+u*u+e*e;return o>0&&(o=1/Math.sqrt(o)),t[0]=a*o,t[1]=r*o,t[2]=u*o,t[3]=e*o,t}function bt(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]+t[3]*n[3]}function mt(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t[2]=o+r*(a[2]-o),t[3]=i+r*(a[3]-i),t}function dt(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]}function xt(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=a[0],c=a[1],h=a[2],s=a[3];return Math.abs(r-i)<=n*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-c)<=n*Math.max(1,Math.abs(u),Math.abs(c))&&Math.abs(e-h)<=n*Math.max(1,Math.abs(e),Math.abs(h))&&Math.abs(o-s)<=n*Math.max(1,Math.abs(o),Math.abs(s))}var pt=ot,yt=it,qt=ct,gt=st,At=Mt,wt=ft,Rt=lt,zt=function(){var t=tt();return function(n,a,r,u,e,o){var i,c;for(a||(a=4),r||(r=0),c=u?Math.min(u*a+r,n.length):n.length,i=r;i=1);do{c=(e=2*r()-1)*e+(o=2*r()-1)*o}while(c>=1);var h=Math.sqrt((1-i)/c);return t[0]=n*a,t[1]=n*u,t[2]=n*e*h,t[3]=n*o*h,t},transformMat4:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3];return t[0]=a[0]*r+a[4]*u+a[8]*e+a[12]*o,t[1]=a[1]*r+a[5]*u+a[9]*e+a[13]*o,t[2]=a[2]*r+a[6]*u+a[10]*e+a[14]*o,t[3]=a[3]*r+a[7]*u+a[11]*e+a[15]*o,t},transformQuat:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],c=a[2],h=a[3],s=h*r+i*e-c*u,M=h*u+c*r-o*e,f=h*e+o*u-i*r,l=-o*r-i*u-c*e;return t[0]=s*h+l*-o+M*-c-f*-i,t[1]=M*h+l*-i+f*-o-s*-c,t[2]=f*h+l*-c+s*-i-M*-o,t[3]=n[3],t},zero:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=0,t},str:function(t){return"vec4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},exactEquals:dt,equals:xt,sub:pt,mul:yt,div:qt,dist:gt,sqrDist:At,len:wt,sqrLen:Rt,forEach:zt});function jt(){var t=new a(4);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t[3]=1,t}function It(t,n,a){a*=.5;var r=Math.sin(a);return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=Math.cos(a),t}function St(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*s+o*i+u*h-e*c,t[1]=u*s+o*c+e*i-r*h,t[2]=e*s+o*h+r*c-u*i,t[3]=o*s-r*i-u*c-e*h,t}function Et(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+o*i,t[1]=u*c+e*i,t[2]=e*c-u*i,t[3]=o*c-r*i,t}function Ot(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c-e*i,t[1]=u*c+o*i,t[2]=e*c+r*i,t[3]=o*c-u*i,t}function Tt(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+u*i,t[1]=u*c-r*i,t[2]=e*c+o*i,t[3]=o*c-e*i,t}function Dt(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=Math.sqrt(a*a+r*r+u*u),i=Math.exp(e),c=o>0?i*Math.sin(o)/o:0;return t[0]=a*c,t[1]=r*c,t[2]=u*c,t[3]=i*Math.cos(o),t}function Ft(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=Math.sqrt(a*a+r*r+u*u),i=o>0?Math.atan2(o,e)/o:0;return t[0]=a*i,t[1]=r*i,t[2]=u*i,t[3]=.5*Math.log(a*a+r*r+u*u+e*e),t}function Lt(t,a,r,u){var e,o,i,c,h,s=a[0],M=a[1],f=a[2],l=a[3],v=r[0],b=r[1],m=r[2],d=r[3];return(o=s*v+M*b+f*m+l*d)<0&&(o=-o,v=-v,b=-b,m=-m,d=-d),1-o>n?(e=Math.acos(o),i=Math.sin(e),c=Math.sin((1-u)*e)/i,h=Math.sin(u*e)/i):(c=1-u,h=u),t[0]=c*s+h*v,t[1]=c*M+h*b,t[2]=c*f+h*m,t[3]=c*l+h*d,t}function Vt(t,n){var a,r=n[0]+n[4]+n[8];if(r>0)a=Math.sqrt(r+1),t[3]=.5*a,a=.5/a,t[0]=(n[5]-n[7])*a,t[1]=(n[6]-n[2])*a,t[2]=(n[1]-n[3])*a;else{var u=0;n[4]>n[0]&&(u=1),n[8]>n[3*u+u]&&(u=2);var e=(u+1)%3,o=(u+2)%3;a=Math.sqrt(n[3*u+u]-n[3*e+e]-n[3*o+o]+1),t[u]=.5*a,a=.5/a,t[3]=(n[3*e+o]-n[3*o+e])*a,t[e]=(n[3*e+u]+n[3*u+e])*a,t[o]=(n[3*o+u]+n[3*u+o])*a}return t}var Qt,Yt,Xt,Zt,_t,Bt,Nt=nt,kt=at,Ut=rt,Wt=ut,Ct=et,Gt=St,Ht=ht,Jt=bt,Kt=mt,$t=ft,tn=$t,nn=lt,an=nn,rn=vt,un=dt,en=xt,on=(Qt=O(),Yt=D(1,0,0),Xt=D(0,1,0),function(t,n,a){var r=_(n,a);return r<-.999999?(B(Qt,Yt,n),H(Qt)<1e-6&&B(Qt,Xt,n),Z(Qt,Qt),It(t,Qt,Math.PI),t):r>.999999?(t[0]=0,t[1]=0,t[2]=0,t[3]=1,t):(B(Qt,n,a),t[0]=Qt[0],t[1]=Qt[1],t[2]=Qt[2],t[3]=1+r,rn(t,t))}),cn=(Zt=jt(),_t=jt(),function(t,n,a,r,u,e){return Lt(Zt,n,u,e),Lt(_t,a,r,e),Lt(t,Zt,_t,2*e*(1-e)),t}),hn=(Bt=m(),function(t,n,a,r){return Bt[0]=a[0],Bt[3]=a[1],Bt[6]=a[2],Bt[1]=r[0],Bt[4]=r[1],Bt[7]=r[2],Bt[2]=-n[0],Bt[5]=-n[1],Bt[8]=-n[2],rn(t,Vt(t,Bt))}),sn=Object.freeze({create:jt,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t},setAxisAngle:It,getAxisAngle:function(t,a){var r=2*Math.acos(a[3]),u=Math.sin(r/2);return u>n?(t[0]=a[0]/u,t[1]=a[1]/u,t[2]=a[2]/u):(t[0]=1,t[1]=0,t[2]=0),r},getAngle:function(t,n){var a=Jt(t,n);return Math.acos(2*a*a-1)},multiply:St,rotateX:Et,rotateY:Ot,rotateZ:Tt,calculateW:function(t,n){var a=n[0],r=n[1],u=n[2];return t[0]=a,t[1]=r,t[2]=u,t[3]=Math.sqrt(Math.abs(1-a*a-r*r-u*u)),t},exp:Dt,ln:Ft,pow:function(t,n,a){return Ft(t,n),Ht(t,t,a),Dt(t,t),t},slerp:Lt,random:function(t){var n=r(),a=r(),u=r(),e=Math.sqrt(1-n),o=Math.sqrt(n);return t[0]=e*Math.sin(2*Math.PI*a),t[1]=e*Math.cos(2*Math.PI*a),t[2]=o*Math.sin(2*Math.PI*u),t[3]=o*Math.cos(2*Math.PI*u),t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*a+r*r+u*u+e*e,i=o?1/o:0;return t[0]=-a*i,t[1]=-r*i,t[2]=-u*i,t[3]=e*i,t},conjugate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t},fromMat3:Vt,fromEuler:function(t,n,a,r){var u=.5*Math.PI/180;n*=u,a*=u,r*=u;var e=Math.sin(n),o=Math.cos(n),i=Math.sin(a),c=Math.cos(a),h=Math.sin(r),s=Math.cos(r);return t[0]=e*c*s-o*i*h,t[1]=o*i*s+e*c*h,t[2]=o*c*h-e*i*s,t[3]=o*c*s+e*i*h,t},str:function(t){return"quat("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},clone:Nt,fromValues:kt,copy:Ut,set:Wt,add:Ct,mul:Gt,scale:Ht,dot:Jt,lerp:Kt,length:$t,len:tn,squaredLength:nn,sqrLen:an,normalize:rn,exactEquals:un,equals:en,rotationTo:on,sqlerp:cn,setAxes:hn});function Mn(t,n,a){var r=.5*a[0],u=.5*a[1],e=.5*a[2],o=n[0],i=n[1],c=n[2],h=n[3];return t[0]=o,t[1]=i,t[2]=c,t[3]=h,t[4]=r*h+u*c-e*i,t[5]=u*h+e*o-r*c,t[6]=e*h+r*i-u*o,t[7]=-r*o-u*i-e*c,t}function fn(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t}var ln=Ut;var vn=Ut;function bn(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[4],c=a[5],h=a[6],s=a[7],M=n[4],f=n[5],l=n[6],v=n[7],b=a[0],m=a[1],d=a[2],x=a[3];return t[0]=r*x+o*b+u*d-e*m,t[1]=u*x+o*m+e*b-r*d,t[2]=e*x+o*d+r*m-u*b,t[3]=o*x-r*b-u*m-e*d,t[4]=r*s+o*i+u*h-e*c+M*x+v*b+f*d-l*m,t[5]=u*s+o*c+e*i-r*h+f*x+v*m+l*b-M*d,t[6]=e*s+o*h+r*c-u*i+l*x+v*d+M*m-f*b,t[7]=o*s-r*i-u*c-e*h+v*x-M*b-f*m-l*d,t}var mn=bn;var dn=Jt;var xn=$t,pn=xn,yn=nn,qn=yn;var gn=Object.freeze({create:function(){var t=new a(8);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[4]=0,t[5]=0,t[6]=0,t[7]=0),t[3]=1,t},clone:function(t){var n=new a(8);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n},fromValues:function(t,n,r,u,e,o,i,c){var h=new a(8);return h[0]=t,h[1]=n,h[2]=r,h[3]=u,h[4]=e,h[5]=o,h[6]=i,h[7]=c,h},fromRotationTranslationValues:function(t,n,r,u,e,o,i){var c=new a(8);c[0]=t,c[1]=n,c[2]=r,c[3]=u;var h=.5*e,s=.5*o,M=.5*i;return c[4]=h*u+s*r-M*n,c[5]=s*u+M*t-h*r,c[6]=M*u+h*n-s*t,c[7]=-h*t-s*n-M*r,c},fromRotationTranslation:Mn,fromTranslation:function(t,n){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=.5*n[0],t[5]=.5*n[1],t[6]=.5*n[2],t[7]=0,t},fromRotation:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},fromMat4:function(t,n){var r=jt();P(r,n);var u=new a(3);return R(u,n),Mn(t,r,u),t},copy:fn,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},set:function(t,n,a,r,u,e,o,i,c){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t},getReal:ln,getDual:function(t,n){return t[0]=n[4],t[1]=n[5],t[2]=n[6],t[3]=n[7],t},setReal:vn,setDual:function(t,n){return t[4]=n[0],t[5]=n[1],t[6]=n[2],t[7]=n[3],t},getTranslation:function(t,n){var a=n[4],r=n[5],u=n[6],e=n[7],o=-n[0],i=-n[1],c=-n[2],h=n[3];return t[0]=2*(a*h+e*o+r*c-u*i),t[1]=2*(r*h+e*i+u*o-a*c),t[2]=2*(u*h+e*c+a*i-r*o),t},translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=.5*a[0],c=.5*a[1],h=.5*a[2],s=n[4],M=n[5],f=n[6],l=n[7];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=o*i+u*h-e*c+s,t[5]=o*c+e*i-r*h+M,t[6]=o*h+r*c-u*i+f,t[7]=-r*i-u*c-e*h+l,t},rotateX:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Et(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateY:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Ot(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateZ:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Tt(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateByQuatAppend:function(t,n,a){var r=a[0],u=a[1],e=a[2],o=a[3],i=n[0],c=n[1],h=n[2],s=n[3];return t[0]=i*o+s*r+c*e-h*u,t[1]=c*o+s*u+h*r-i*e,t[2]=h*o+s*e+i*u-c*r,t[3]=s*o-i*r-c*u-h*e,i=n[4],c=n[5],h=n[6],s=n[7],t[4]=i*o+s*r+c*e-h*u,t[5]=c*o+s*u+h*r-i*e,t[6]=h*o+s*e+i*u-c*r,t[7]=s*o-i*r-c*u-h*e,t},rotateByQuatPrepend:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*s+o*i+u*h-e*c,t[1]=u*s+o*c+e*i-r*h,t[2]=e*s+o*h+r*c-u*i,t[3]=o*s-r*i-u*c-e*h,i=a[4],c=a[5],h=a[6],s=a[7],t[4]=r*s+o*i+u*h-e*c,t[5]=u*s+o*c+e*i-r*h,t[6]=e*s+o*h+r*c-u*i,t[7]=o*s-r*i-u*c-e*h,t},rotateAroundAxis:function(t,a,r,u){if(Math.abs(u)0){a=Math.sqrt(a);var r=n[0]/a,u=n[1]/a,e=n[2]/a,o=n[3]/a,i=n[4],c=n[5],h=n[6],s=n[7],M=r*i+u*c+e*h+o*s;t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=(i-r*M)/a,t[5]=(c-u*M)/a,t[6]=(h-e*M)/a,t[7]=(s-o*M)/a}return t},str:function(t){return"quat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=a[0],f=a[1],l=a[2],v=a[3],b=a[4],m=a[5],d=a[6],x=a[7];return Math.abs(r-M)<=n*Math.max(1,Math.abs(r),Math.abs(M))&&Math.abs(u-f)<=n*Math.max(1,Math.abs(u),Math.abs(f))&&Math.abs(e-l)<=n*Math.max(1,Math.abs(e),Math.abs(l))&&Math.abs(o-v)<=n*Math.max(1,Math.abs(o),Math.abs(v))&&Math.abs(i-b)<=n*Math.max(1,Math.abs(i),Math.abs(b))&&Math.abs(c-m)<=n*Math.max(1,Math.abs(c),Math.abs(m))&&Math.abs(h-d)<=n*Math.max(1,Math.abs(h),Math.abs(d))&&Math.abs(s-x)<=n*Math.max(1,Math.abs(s),Math.abs(x))}});function An(){var t=new a(2);return a!=Float32Array&&(t[0]=0,t[1]=0),t}function wn(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t}function Rn(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t}function zn(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t}function Pn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return Math.hypot(a,r)}function jn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return a*a+r*r}function In(t){var n=t[0],a=t[1];return Math.hypot(n,a)}function Sn(t){var n=t[0],a=t[1];return n*n+a*a}var En=In,On=wn,Tn=Rn,Dn=zn,Fn=Pn,Ln=jn,Vn=Sn,Qn=function(){var t=An();return function(n,a,r,u,e,o){var i,c;for(a||(a=2),r||(r=0),c=u?Math.min(u*a+r,n.length):n.length,i=r;i0&&(u=1/Math.sqrt(u)),t[0]=n[0]*u,t[1]=n[1]*u,t},dot:function(t,n){return t[0]*n[0]+t[1]*n[1]},cross:function(t,n,a){var r=n[0]*a[1]-n[1]*a[0];return t[0]=t[1]=0,t[2]=r,t},lerp:function(t,n,a,r){var u=n[0],e=n[1];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t},random:function(t,n){n=n||1;var a=2*r()*Math.PI;return t[0]=Math.cos(a)*n,t[1]=Math.sin(a)*n,t},transformMat2:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u,t[1]=a[1]*r+a[3]*u,t},transformMat2d:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u+a[4],t[1]=a[1]*r+a[3]*u+a[5],t},transformMat3:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[3]*u+a[6],t[1]=a[1]*r+a[4]*u+a[7],t},transformMat4:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[4]*u+a[12],t[1]=a[1]*r+a[5]*u+a[13],t},rotate:function(t,n,a,r){var u=n[0]-a[0],e=n[1]-a[1],o=Math.sin(r),i=Math.cos(r);return t[0]=u*i-e*o+a[0],t[1]=u*o+e*i+a[1],t},angle:function(t,n){var a=t[0],r=t[1],u=n[0],e=n[1],o=a*a+r*r;o>0&&(o=1/Math.sqrt(o));var i=u*u+e*e;i>0&&(i=1/Math.sqrt(i));var c=(a*u+r*e)*o*i;return c>1?0:c<-1?Math.PI:Math.acos(c)},zero:function(t){return t[0]=0,t[1]=0,t},str:function(t){return"vec2("+t[0]+", "+t[1]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]},equals:function(t,a){var r=t[0],u=t[1],e=a[0],o=a[1];return Math.abs(r-e)<=n*Math.max(1,Math.abs(r),Math.abs(e))&&Math.abs(u-o)<=n*Math.max(1,Math.abs(u),Math.abs(o))},len:En,sub:On,mul:Tn,div:Dn,dist:Fn,sqrDist:Ln,sqrLen:Vn,forEach:Qn});t.glMatrix=e,t.mat2=s,t.mat2d=b,t.mat3=q,t.mat4=E,t.quat=sn,t.quat2=gn,t.vec2=Yn,t.vec3=$,t.vec4=Pt,Object.defineProperty(t,"__esModule",{value:!0})}); + +// ["glMatrix", "mat2", "mat2d", "mat3", "mat4", "quat", "quat2", "vec2", "vec3", "vec4"] +window.glMatrix = glMatrix; +window.mat2 = glMatrix.mat2; +window.mat2d = glMatrix.mat2d; +window.mat3 = glMatrix.mat3; +window.mat4 = glMatrix.mat4; +window.quat = glMatrix.quat; +window.quat2 = glMatrix.quat2; +window.vec2 = glMatrix.vec2; +window.vec3 = glMatrix.vec3; +window.vec4 = glMatrix.vec4; + + +if(!CABLES.exportedPatches)CABLES.exportedPatches={};CABLES.exportedPatches["uvBp73"]={_id:"65bcb16a71656d76fa1ec204",ops:[{id:"zdo60lxbk",uiAttribs:{},portsIn:[{name:"FPS Limit",value:0},{name:"Reduce FPS not focussed",value:1},{name:"Reduce FPS loading",value:0},{name:"Clear",value:1},{name:"ClearAlpha",value:0},{name:"Fullscreen Button",value:0},{name:"Active",value:1},{name:"Hires Displays",value:1},{name:"Pixel Unit index",value:0},{name:"Pixel Unit",value:"Display"}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"e0268dfa-e089-4f1f-966c-c30218792023",objOut:"zdo60lxbk"}]},{name:"width",value:1532},{name:"height",value:834}],objName:"Ops.Gl.MainLoop"},{id:"141502b6-2964-42b8-b273-c6d7f5bcf303",uiAttribs:{},portsOut:[{name:"trigger 0",links:[{portIn:"Trigger",portOut:"trigger 0",objIn:"e0698285-4e6a-4339-a9ba-d9b3e441372c",objOut:"141502b6-2964-42b8-b273-c6d7f5bcf303"},{portIn:"Increment",portOut:"trigger 0",objIn:"6hojoyomj",objOut:"141502b6-2964-42b8-b273-c6d7f5bcf303"}]},{name:"trigger 5",links:[{portIn:"in0 Cursor Update",portOut:"trigger 5",objIn:"cd9136e7-4c7b-4555-bf01-18381685410b",objOut:"141502b6-2964-42b8-b273-c6d7f5bcf303"}]},{name:"trigger 8",links:[{portIn:"Trigger",portOut:"trigger 8",objIn:"ch5u1xz0l",objOut:"141502b6-2964-42b8-b273-c6d7f5bcf303"}]},{name:"trigger 9",links:[{portIn:"exe",portOut:"trigger 9",objIn:"124910bf-e88f-4da5-847e-888a7ac73020",objOut:"141502b6-2964-42b8-b273-c6d7f5bcf303"}]},{name:"trigger 15",links:[{portIn:"Trigger",portOut:"trigger 15",objIn:"afa40c7e-19f5-4546-911c-1e34c62f310b",objOut:"141502b6-2964-42b8-b273-c6d7f5bcf303"}]}],objName:"Ops.Trigger.Sequence"},{id:"4950e7c1-dcaf-47ac-9ca9-512013c4e9c9",uiAttribs:{subPatch:"66dae55a-8297-4120-81e2-d946cc6b2b60"},portsIn:[{name:"Coordinates index",value:0},{name:"Coordinates",value:"-1 to 1"},{name:"Area index",value:3},{name:"Area",value:"Canvas Area"},{name:"flip y",value:0},{name:"right click prevent default",value:1},{name:"Touch support",value:1},{name:"Passive Events",value:0},{name:"Active",value:1}],portsOut:[{name:"x",links:[{portIn:"out1 Ops.Devices.Mouse.Mouse_v3 x",portOut:"x",objIn:"7bebb5f0-9d69-43ee-98be-27a13edd98db",objOut:"4950e7c1-dcaf-47ac-9ca9-512013c4e9c9"}]},{name:"y",links:[{portIn:"out2 Ops.Devices.Mouse.Mouse_v3 y",portOut:"y",objIn:"7bebb5f0-9d69-43ee-98be-27a13edd98db",objOut:"4950e7c1-dcaf-47ac-9ca9-512013c4e9c9"}]},{name:"click",links:[{portIn:"Trigger",portOut:"click",objIn:"xz7qgpta6",objOut:"4950e7c1-dcaf-47ac-9ca9-512013c4e9c9"}]},{name:"Button is down",value:0},{name:"Mouse is hovering",links:[{portIn:"Value",portOut:"Mouse is hovering",objIn:"d155f04b-ae78-473c-994b-81138389d0f0",objOut:"4950e7c1-dcaf-47ac-9ca9-512013c4e9c9"}]},{name:"Movement X",value:0},{name:"Movement Y",value:0}],objName:"Ops.Devices.Mouse.Mouse_v3"},{id:"d155f04b-ae78-473c-994b-81138389d0f0",uiAttribs:{subPatch:"66dae55a-8297-4120-81e2-d946cc6b2b60"},portsIn:[{name:"Variable",value:"ui_mouseOver"}],objName:"Ops.Vars.VarSetNumber_v2"},{id:"dq71li66q",uiAttribs:{subPatch:"66dae55a-8297-4120-81e2-d946cc6b2b60"},portsIn:[{name:"Multiply",value:1},{name:"Limit",value:1},{name:"Min",value:0},{name:"Max",value:1},{name:"Rubberband",value:0}],portsOut:[{name:"Absolute Value",links:[{portIn:"out0 DeltaSum Absolute Value",portOut:"Absolute Value",objIn:"7bebb5f0-9d69-43ee-98be-27a13edd98db",objOut:"dq71li66q"}]}],objName:"Ops.Math.DeltaSum"},{id:"9d85ffdc-685a-42ef-bd41-b501521a114c",uiAttribs:{subPatch:"66dae55a-8297-4120-81e2-d946cc6b2b60"},portsOut:[{name:"create port",value:0}],objName:"Ops.Ui.PatchInput"},{id:"7bebb5f0-9d69-43ee-98be-27a13edd98db",uiAttribs:{subPatch:"66dae55a-8297-4120-81e2-d946cc6b2b60"},portsIn:[{name:"create port",value:0}],objName:"Ops.Ui.PatchOutput"},{id:"cd9136e7-4c7b-4555-bf01-18381685410b",uiAttribs:{},storage:{subPatchVer:1},portsIn:[{name:"create port",value:0},{name:"dataStr",value:'{"ports":[{"name":"in0 Cursor Update","type":1}],"portsOut":[{"name":"out0 DeltaSum Absolute Value","type":0},{"name":"out1 Ops.Devices.Mouse.Mouse_v3 x","type":0},{"name":"out2 Ops.Devices.Mouse.Mouse_v3 y","type":0}]}'},{name:"patchId",value:"66dae55a-8297-4120-81e2-d946cc6b2b60"}],portsOut:[{name:"create port out",value:0},{name:"out0 DeltaSum Absolute Value",links:[{portIn:"Value",portOut:"out0 DeltaSum Absolute Value",objIn:"9fsk0rgx7",objOut:"cd9136e7-4c7b-4555-bf01-18381685410b"}]}],objName:"Ops.Ui.SubPatch"},{id:"c2a85325-d75f-4f01-9b5c-83a2edd8d35d",uiAttribs:{},portsIn:[{name:"posY",value:-.2},{name:"posZ",value:0},{name:"scale",value:.25},{name:"rotX",value:0},{name:"rotY",value:180},{name:"rotZ",value:315.48}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"li365texv",objOut:"c2a85325-d75f-4f01-9b5c-83a2edd8d35d"},{portIn:"render",portOut:"trigger",objIn:"i111f5qjb",objOut:"c2a85325-d75f-4f01-9b5c-83a2edd8d35d"}]}],objName:"Ops.Gl.Matrix.Transform"},{id:"e0268dfa-e089-4f1f-966c-c30218792023",uiAttribs:{},portsIn:[{name:"r",value:0},{name:"g",value:0},{name:"b",value:0},{name:"a",value:1}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"te11ob7nw",objOut:"e0268dfa-e089-4f1f-966c-c30218792023"},{portIn:"Trigger",portOut:"trigger",objIn:"zcc6zzw4d",objOut:"e0268dfa-e089-4f1f-966c-c30218792023"}]}],objName:"Ops.Gl.ClearColor"},{id:"b65ca0b8-40c9-4d0a-9e22-aba7d89f3abf",uiAttribs:{subPatch:"66dae55a-8297-4120-81e2-d946cc6b2b60"},portsIn:[{name:"Active",value:1},{name:"Speed",value:-.01},{name:"Input Type index",value:0},{name:"Input Type",value:"All"},{name:"Area index",value:0},{name:"Area",value:"Canvas Area"}],portsOut:[{name:"Delta X",value:0},{name:"Delta Y",links:[{portIn:"Delta Value",portOut:"Delta Y",objIn:"dq71li66q",objOut:"b65ca0b8-40c9-4d0a-9e22-aba7d89f3abf"}]},{name:"Is Dragging",links:[{portIn:"Value",portOut:"Is Dragging",objIn:"ls3p3eowk",objOut:"b65ca0b8-40c9-4d0a-9e22-aba7d89f3abf"}]}],objName:"Ops.Patch.PuvBp73.MouseDrag"},{id:"b6dd9bba-0e82-4220-a27d-884c1d3887a3",uiAttribs:{},portsIn:[{name:"Attribute index",value:1},{name:"Attribute",value:"TexCoords"},{name:"Absolute",value:0},{name:"World Space",value:1}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"gfjoyon3n",objOut:"b6dd9bba-0e82-4220-a27d-884c1d3887a3"}]}],objName:"Ops.Gl.Shader.AttributeAsColorMaterial"},{id:"e0698285-4e6a-4339-a9ba-d9b3e441372c",uiAttribs:{},portsIn:[{name:"Named Trigger",value:"mainExe"}],objName:"Ops.Trigger.TriggerSend"},{id:"babe81ef-3ee9-4ed3-ba28-8b648c21dd11",uiAttribs:{},portsIn:[{name:"Title",value:"Dial Blueprint"}],objName:"Ops.Ui.Area"},{id:"a82e74aa-f66f-47c9-a07a-2f1b0376925b",uiAttribs:{},portsIn:[{name:"Title",value:"Data"}],objName:"Ops.Ui.Area"},{id:"afa40c7e-19f5-4546-911c-1e34c62f310b",uiAttribs:{},portsIn:[{name:"Named Trigger",value:"finalExe"}],objName:"Ops.Trigger.TriggerSend"},{id:"1aaf40f7-386a-40d0-80de-4857b3f558f4",uiAttribs:{},portsIn:[{name:"Variable",value:"ui_NormValue"}],portsOut:[{name:"Value",links:[{portIn:"Number",portOut:"Value",objIn:"rjsjd3otn",objOut:"1aaf40f7-386a-40d0-80de-4857b3f558f4"}]}],objName:"Ops.Vars.VarGetNumber_v2"},{id:"7dq6j5p5k",uiAttribs:{},portsIn:[{name:"Check Body Collisions",value:0}],portsOut:[{name:"Next",links:[{portIn:"Trigger",portOut:"Next",objIn:"9sm9dp98r",objOut:"7dq6j5p5k"}]},{name:"Total Bodies",value:4}],objName:"Ops.Graphics.Intersection.IntersectWorld"},{id:"9sm9dp98r",uiAttribs:{},portsIn:[{name:"Coordinate Format index",value:0},{name:"Coordinate Format",value:"-1 to 1"},{name:"Z",value:0},{name:"To X",value:0},{name:"To Y",value:0},{name:"To Z",value:0},{name:"Active",value:1},{name:"Change Cursor",value:0}],portsOut:[{name:"Next",links:[{portIn:"render",portOut:"Next",objIn:"ge3zj70cy",objOut:"9sm9dp98r"},{portIn:"render",portOut:"Next",objIn:"mbk4m8pcr",objOut:"9sm9dp98r"},{portIn:"render",portOut:"Next",objIn:"7qikt1vaf",objOut:"9sm9dp98r"},{portIn:"render",portOut:"Next",objIn:"aupoduf7d",objOut:"9sm9dp98r"}]},{name:"Has Hit",value:0},{name:"Hit Body Name",links:[{portIn:"Value",portOut:"Hit Body Name",objIn:"tg35ehmtt",objOut:"9sm9dp98r"}]},{name:"Hit X",value:0},{name:"Hit Y",value:0},{name:"Hit Z",value:0}],objName:"Ops.Graphics.Intersection.IntersectTestRaycast"},{id:"jrkdakvqd",uiAttribs:{},portsIn:[{name:"Shape index",value:0},{name:"Shape",value:"Sphere"},{name:"Name",value:"dial.1"},{name:"Radius",value:.22},{name:"Size X",value:.55},{name:"Size Y",value:.55},{name:"Size Z",value:0},{name:"Positions"},{name:"Append Index to name",value:1}],objName:"Ops.Graphics.Intersection.IntersectBody"},{id:"bs0d2bloj",uiAttribs:{},portsIn:[{name:"Named Trigger",value:"mainExe"}],portsOut:[{name:"Triggered",links:[{portIn:"Trigger",portOut:"Triggered",objIn:"7dq6j5p5k",objOut:"bs0d2bloj"}]}],objName:"Ops.Trigger.TriggerReceive"},{id:"ge3zj70cy",uiAttribs:{},portsIn:[{name:"x",value:-.88},{name:"y",value:-.19},{name:"z",value:0}],portsOut:[{name:"trigger",links:[{portIn:"Trigger",portOut:"trigger",objIn:"jrkdakvqd",objOut:"ge3zj70cy"}]}],objName:"Ops.Gl.Matrix.Translate"},{id:"5me0htliz",uiAttribs:{},portsIn:[{name:"Shape index",value:0},{name:"Shape",value:"Sphere"},{name:"Name",value:"dial.2"},{name:"Radius",value:.22},{name:"Size X",value:.55},{name:"Size Y",value:.55},{name:"Size Z",value:0},{name:"Positions"},{name:"Append Index to name",value:1}],objName:"Ops.Graphics.Intersection.IntersectBody"},{id:"mbk4m8pcr",uiAttribs:{},portsIn:[{name:"x",value:-.3},{name:"y",value:-.19},{name:"z",value:0}],portsOut:[{name:"trigger",links:[{portIn:"Trigger",portOut:"trigger",objIn:"5me0htliz",objOut:"mbk4m8pcr"}]}],objName:"Ops.Gl.Matrix.Translate"},{id:"adh054ku6",uiAttribs:{},portsIn:[{name:"Shape index",value:0},{name:"Shape",value:"Sphere"},{name:"Name",value:"dial.3"},{name:"Radius",value:.23},{name:"Size X",value:.55},{name:"Size Y",value:.55},{name:"Size Z",value:0},{name:"Positions"},{name:"Append Index to name",value:1}],objName:"Ops.Graphics.Intersection.IntersectBody"},{id:"yjtjh6kai",uiAttribs:{},portsIn:[{name:"Shape index",value:0},{name:"Shape",value:"Sphere"},{name:"Name",value:"dial.4"},{name:"Radius",value:.23},{name:"Size X",value:.55},{name:"Size Y",value:.55},{name:"Size Z",value:0},{name:"Positions"},{name:"Append Index to name",value:1}],objName:"Ops.Graphics.Intersection.IntersectBody"},{id:"sfqxroo9q",uiAttribs:{},portsIn:[{name:"Coordinates index",value:0},{name:"Coordinates",value:"-1 to 1"},{name:"Area index",value:0},{name:"Area",value:"Canvas"},{name:"flip y",value:1},{name:"right click prevent default",value:1},{name:"Touch support",value:1},{name:"Passive Events",value:0},{name:"Active",value:1}],portsOut:[{name:"x",links:[{portIn:"X",portOut:"x",objIn:"9sm9dp98r",objOut:"sfqxroo9q"}]},{name:"y",links:[{portIn:"Y",portOut:"y",objIn:"9sm9dp98r",objOut:"sfqxroo9q"}]},{name:"Button is down",links:[{portIn:"Value",portOut:"Button is down",objIn:"er6016ry9",objOut:"sfqxroo9q"}]},{name:"Mouse is hovering",value:1},{name:"Movement X",value:0},{name:"Movement Y",value:-.5}],objName:"Ops.Devices.Mouse.Mouse_v3"},{id:"124910bf-e88f-4da5-847e-888a7ac73020",uiAttribs:{},portsIn:[{name:"num x",value:4},{name:"num y",value:1},{name:"center",value:1}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"c2a85325-d75f-4f01-9b5c-83a2edd8d35d",objOut:"124910bf-e88f-4da5-847e-888a7ac73020"},{portIn:"render",portOut:"trigger",objIn:"zlpf1p0f5",objOut:"124910bf-e88f-4da5-847e-888a7ac73020"}]},{name:"x",links:[{portIn:"posX",portOut:"x",objIn:"c2a85325-d75f-4f01-9b5c-83a2edd8d35d",objOut:"124910bf-e88f-4da5-847e-888a7ac73020"},{portIn:"posX",portOut:"x",objIn:"zlpf1p0f5",objOut:"124910bf-e88f-4da5-847e-888a7ac73020"}]},{name:"y",value:0},{name:"index",links:[{portIn:"Value",portOut:"index",objIn:"euqza6b25",objOut:"124910bf-e88f-4da5-847e-888a7ac73020"}]},{name:"total iterations",value:4}],objName:"Ops.Trigger.Repeat2d"},{id:"7qikt1vaf",uiAttribs:{},portsIn:[{name:"x",value:.31},{name:"y",value:-.19},{name:"z",value:0}],portsOut:[{name:"trigger",links:[{portIn:"Trigger",portOut:"trigger",objIn:"adh054ku6",objOut:"7qikt1vaf"}]}],objName:"Ops.Gl.Matrix.Translate"},{id:"aupoduf7d",uiAttribs:{},portsIn:[{name:"x",value:.9},{name:"y",value:-.19},{name:"z",value:0}],portsOut:[{name:"trigger",links:[{portIn:"Trigger",portOut:"trigger",objIn:"yjtjh6kai",objOut:"aupoduf7d"}]}],objName:"Ops.Gl.Matrix.Translate"},{id:"32lmfrmux",uiAttribs:{},portsIn:[{name:"Title",value:"Intersect"}],objName:"Ops.Ui.Area"},{id:"tg35ehmtt",uiAttribs:{},portsIn:[{name:"Variable",value:"ui_hitBodyName"}],objName:"Ops.Vars.VarSetString_v2"},{id:"gb0lraco2",uiAttribs:{},portsIn:[{name:"Variable",value:"ui_activeDial_ID"}],portsOut:[{name:"Value",links:[{portIn:"number1",portOut:"Value",objIn:"kcwn0w2tu",objOut:"gb0lraco2"}]}],objName:"Ops.Vars.VarGetNumber_v2"},{id:"qyara3wac",uiAttribs:{},portsOut:[{name:"result",value:0}],objName:"Ops.Math.Compare.Equals"},{id:"xz7qgpta6",uiAttribs:{subPatch:"66dae55a-8297-4120-81e2-d946cc6b2b60"},portsIn:[{name:"Named Trigger",value:"mouseDown"}],objName:"Ops.Trigger.TriggerSend"},{id:"v1hlb4w7t",uiAttribs:{},portsIn:[{name:"Variable",value:"ui_activeDial_ID"}],portsOut:[{name:"Value",links:[{portIn:"number1",portOut:"Value",objIn:"k9cpiqwvn",objOut:"v1hlb4w7t"}]}],objName:"Ops.Vars.VarGetNumber_v2"},{id:"k9cpiqwvn",uiAttribs:{},portsIn:[{name:"number2",value:1}],portsOut:[{name:"result",links:[{portIn:"Index",portOut:"result",objIn:"rjsjd3otn",objOut:"k9cpiqwvn"}]}],objName:"Ops.Math.Subtract"},{id:"53603a6e-a331-41a7-9822-120aba8de4f8",uiAttribs:{},portsIn:[{name:"number2",value:270}],portsOut:[{name:"result",links:[{portIn:"rotY",portOut:"result",objIn:"li365texv",objOut:"53603a6e-a331-41a7-9822-120aba8de4f8"}]}],objName:"Ops.Math.Multiply"},{id:"931c114e-4c92-4747-896b-6697a0610953",uiAttribs:{},portsIn:[{name:"number2",value:.75}],portsOut:[{name:"result",links:[{portIn:"percent",portOut:"result",objIn:"gfjoyon3n",objOut:"931c114e-4c92-4747-896b-6697a0610953"},{portIn:"percent",portOut:"result",objIn:"8eccns7e5",objOut:"931c114e-4c92-4747-896b-6697a0610953"}]}],objName:"Ops.Math.Multiply"},{id:"9fsk0rgx7",uiAttribs:{},portsIn:[{name:"Variable",value:"ui_NormValue"}],objName:"Ops.Vars.VarSetNumber_v2"},{id:"aqjh1act1",uiAttribs:{},portsIn:[{name:"Value Invalid Index",value:0}],portsOut:[{name:"value",links:[{portIn:"number1",portOut:"value",objIn:"53603a6e-a331-41a7-9822-120aba8de4f8",objOut:"aqjh1act1"},{portIn:"number1",portOut:"value",objIn:"931c114e-4c92-4747-896b-6697a0610953",objOut:"aqjh1act1"},{portIn:"Value",portOut:"value",objIn:"j3kd0q09w",objOut:"aqjh1act1"},{portIn:"Value",portOut:"value",objIn:"1rc15x0gs",objOut:"aqjh1act1"}]},{name:"Valid Index",value:1}],objName:"Ops.Array.ArrayGetNumber"},{id:"x6efudpvd",uiAttribs:{},portsIn:[{name:"Variable",value:"ui_dialValues"}],objName:"Ops.Vars.VarSetArray_v2"},{id:"i0rjtphmz",uiAttribs:{},portsIn:[{name:"Variable",value:"ui_dialValues"}],portsOut:[{name:"Value",links:[{portIn:"array",portOut:"Value",objIn:"aqjh1act1",objOut:"i0rjtphmz"}]}],objName:"Ops.Vars.VarGetArray_v2"},{id:"hsmbgpnm6",uiAttribs:{},portsIn:[{name:"Array length",value:4},{name:"Mode select index",value:0},{name:"Mode select",value:"Number"},{name:"Default Value",value:0},{name:"Reverse",value:0}],portsOut:[{name:"Array",links:[{portIn:"Array",portOut:"Array",objIn:"rjsjd3otn",objOut:"hsmbgpnm6"}]},{name:"Array length out",value:4}],objName:"Ops.Array.Array_v3"},{id:"er6016ry9",uiAttribs:{},portsIn:[{name:"Variable",value:"ui_buttonIsDown"}],objName:"Ops.Vars.VarSetNumber_v2"},{id:"ls3p3eowk",uiAttribs:{subPatch:"66dae55a-8297-4120-81e2-d946cc6b2b60"},portsIn:[{name:"Variable",value:"ui_mouseIsDragging"}],objName:"Ops.Vars.VarSetNumber_v2"},{id:"c390aebl7",uiAttribs:{},portsIn:[{name:"Variable",value:"ui_mouseIsDragging"}],portsOut:[{name:"Value",links:[{portIn:"Pass Through",portOut:"Value",objIn:"d7vl5bf8b",objOut:"c390aebl7"}]}],objName:"Ops.Vars.VarGetNumber_v2"},{id:"kcwn0w2tu",uiAttribs:{},portsIn:[{name:"number2",value:1}],portsOut:[{name:"result",links:[{portIn:"number1",portOut:"result",objIn:"qyara3wac",objOut:"kcwn0w2tu"}]}],objName:"Ops.Math.Subtract"},{id:"pd9s43czm",uiAttribs:{},storage:{blueprintVer:2,subPatchVer:2},portsIn:[{name:"patchId",value:"bp2sub_pd9s43czm"}],objName:"Ops.Patch.PuvBp73.SubPatch2"},{id:"te11ob7nw",uiAttribs:{},portsIn:[{name:"projection mode index",value:0},{name:"projection mode",value:"prespective"},{name:"frustum near",value:.01},{name:"frustum far",value:5e3},{name:"fov",value:30},{name:"Auto Aspect Ratio",value:1},{name:"Aspect Ratio",value:1},{name:"eye X",value:0},{name:"eye Y",value:-.03},{name:"eye Z",value:.73},{name:"center X",value:0},{name:"center Y",value:0},{name:"center Z",value:0},{name:"truck",value:0},{name:"boom",value:.23},{name:"dolly",value:0},{name:"tilt",value:0},{name:"pan",value:0},{name:"roll",value:0}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"p78s2gczc",objOut:"te11ob7nw"}]},{name:"Aspect",value:1.8369304556354915}],objName:"Ops.Gl.Matrix.Camera"},{id:"p78s2gczc",uiAttribs:{},portsIn:[{name:"min distance",value:.001},{name:"max distance",value:1},{name:"min rot y",value:0},{name:"max rot y",value:0},{name:"initial radius",value:0},{name:"initial axis y",value:.5},{name:"initial axis x",value:.25},{name:"mul",value:1},{name:"Smoothness",value:.3},{name:"Speed X",value:1},{name:"Speed Y",value:1},{name:"Active",value:1},{name:"Allow Panning",value:1},{name:"Allow Zooming",value:1},{name:"Allow Rotation",value:0},{name:"restricted",value:1}],portsOut:[{name:"trigger",links:[{portIn:"exe",portOut:"trigger",objIn:"141502b6-2964-42b8-b273-c6d7f5bcf303",objOut:"p78s2gczc"},{portIn:"Trigger",portOut:"trigger",objIn:"4pu8mr0y2",objOut:"p78s2gczc"}]},{name:"radius",value:.001},{name:"Rot X",value:90},{name:"Rot Y",value:90}],objName:"Ops.Gl.Matrix.OrbitControls"},{id:"uc9r4wu0r",uiAttribs:{},portsIn:[{name:"b",value:.856},{name:"a",value:.63},{name:"colorizeTexture",value:1},{name:"Vertex Colors",value:0},{name:"Alpha Mask Source index",value:0},{name:"Alpha Mask Source",value:"Luminance"},{name:"Opacity TexCoords Transform",value:0},{name:"Discard Transparent Pixels",value:0},{name:"diffuseRepeatX",value:1},{name:"diffuseRepeatY",value:1},{name:"Tex Offset X",value:0},{name:"Tex Offset Y",value:0},{name:"Crop TexCoords",value:0},{name:"billboard",value:0}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"8eccns7e5",objOut:"uc9r4wu0r"}]}],objName:"Ops.Gl.Shader.BasicMaterial_v3"},{id:"j3kd0q09w",uiAttribs:{},portsIn:[{name:"Min",value:0},{name:"Max",value:.9},{name:"Easing index",value:4},{name:"Easing",value:"Cubic In"}],portsOut:[{name:"Result",links:[{portIn:"Value",portOut:"Result",objIn:"conrnxfgk",objOut:"j3kd0q09w"},{portIn:"r",portOut:"Result",objIn:"uc9r4wu0r",objOut:"j3kd0q09w"}]}],objName:"Ops.Math.Ease"},{id:"dugq70sv7",uiAttribs:{},portsOut:[{name:"Used Heap Size",value:80.84566116333008},{name:"Total Heap Size",value:87.53744506835938}],objName:"Ops.Devices.Browser.JsMemory"},{id:"conrnxfgk",uiAttribs:{},portsIn:[{name:"Min",value:0},{name:"Max",value:.27},{name:"Easing index",value:5},{name:"Easing",value:"Cubic Out"}],portsOut:[{name:"Result",links:[{portIn:"Offset X",portOut:"Result",objIn:"chztenqi0",objOut:"conrnxfgk"},{portIn:"g",portOut:"Result",objIn:"uc9r4wu0r",objOut:"conrnxfgk"}]}],objName:"Ops.Math.Ease"},{id:"8dsa2kb7j",uiAttribs:{},portsIn:[{name:"Draw",value:1,title:"Render mesh"},{name:"segments",value:32},{name:"stacks",value:1},{name:"length",value:.22},{name:"outer radius",value:.58},{name:"inner radius",value:.32},{name:"UV mode index",value:0},{name:"UV mode",value:"simple"},{name:"Flip Mapping",value:0},{name:"Caps",value:1},{name:"Flat Normals",value:0}],objName:"Ops.Gl.Meshes.Cylinder_v2"},{id:"chztenqi0",uiAttribs:{},portsIn:[{name:"r",value:.412},{name:"g",value:.512},{name:"b",value:.553},{name:"Opacity",value:1},{name:"AO Intensity",value:1},{name:"Normal Map Intensity",value:1},{name:"Repeat X",value:0},{name:"Repeat Y",value:1},{name:"Offset Y",value:0},{name:"Screen Space Normals",value:0},{name:"Calc normal tangents",value:0},{name:"Opacity TexCoords Transform",value:0},{name:"Discard Transparent Pixels",value:1},{name:"Alpha Mask Source index",value:0},{name:"Alpha Mask Source",value:"Luminance"}],portsOut:[{name:"Next",links:[{portIn:"render",portOut:"Next",objIn:"8dsa2kb7j",objOut:"chztenqi0"}]}],objName:"Ops.Gl.Shader.MatCapMaterial_v3"},{id:"0oya8etuv",uiAttribs:{},portsIn:[{name:"File",value:"assets/lib_matcaps_Chrome_Blue_Tint-White.png",display:"file"},{name:"Filter index",value:1},{name:"Filter",value:"linear"},{name:"Wrap index",value:0},{name:"Wrap",value:"repeat"},{name:"Anisotropic index",value:0},{name:"Anisotropic",value:"0"},{name:"Data Format index",value:3},{name:"Data Format",value:"RGBA"},{name:"Flip",value:0},{name:"Pre Multiplied Alpha",value:0},{name:"Active",value:1},{name:"Save Memory",value:1},{name:"Add Cachebuster",value:1}],portsOut:[{name:"Texture",links:[{portIn:"MatCap",portOut:"Texture",objIn:"chztenqi0",objOut:"0oya8etuv"}]},{name:"Width",value:256},{name:"Height",value:256},{name:"Aspect Ratio",value:1},{name:"Loaded",value:1},{name:"Loading",value:0}],objName:"Ops.Gl.Texture_v2"},{id:"li365texv",uiAttribs:{},portsIn:[{name:"posX",value:0},{name:"posY",value:0},{name:"posZ",value:0},{name:"scale",value:1},{name:"rotX",value:0},{name:"rotZ",value:0}],portsOut:[{name:"trigger",links:[{portIn:"Render",portOut:"trigger",objIn:"chztenqi0",objOut:"li365texv"}]}],objName:"Ops.Gl.Matrix.Transform"},{id:"bd0mu1qkj",uiAttribs:{},portsIn:[{name:"Title",value:"Main"}],objName:"Ops.Ui.Area"},{id:"fvg1zz75v",uiAttribs:{},portsIn:[{name:"Size index",value:0},{name:"Size",value:"Canvas"},{name:"texture width",value:1532},{name:"texture height",value:834},{name:"Auto Aspect",value:1},{name:"filter index",value:1},{name:"filter",value:"linear"},{name:"Wrap index",value:0},{name:"Wrap",value:"Clamp"},{name:"MSAA index",value:2},{name:"MSAA",value:"4x"},{name:"Pixel Format index",value:5},{name:"Pixel Format",value:"SRGBA 8bit ubyte"},{name:"Depth",value:1},{name:"Clear",value:1}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"tckfhevim",objOut:"fvg1zz75v"}]},{name:"texture",links:[{portIn:"Base Texture",portOut:"texture",objIn:"48vrkn65x",objOut:"fvg1zz75v"}]}],objName:"Ops.Gl.RenderToTexture_v3"},{id:"9dqwuc8l6",uiAttribs:{},portsIn:[{name:"render",title:"Trigger"},{name:"Render Mesh",value:1,title:"Render"},{name:"width",value:1},{name:"height",value:1.8},{name:"pivot x index",value:1},{name:"pivot x",value:"center"},{name:"pivot y index",value:1},{name:"pivot y",value:"center"},{name:"axis index",value:0},{name:"axis",value:"xy"},{name:"Flip TexCoord X",value:0},{name:"Flip TexCoord Y",value:1},{name:"num columns",value:1},{name:"num rows",value:1}],objName:"Ops.Gl.Meshes.Rectangle_v4"},{id:"62jtojeuu",uiAttribs:{},portsIn:[{name:"posX",value:0},{name:"posY",value:-.97},{name:"posZ",value:-2.94},{name:"scale",value:3.57},{name:"rotX",value:-84.79},{name:"rotY",value:0},{name:"rotZ",value:180.28}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"9dqwuc8l6",objOut:"62jtojeuu"}]}],objName:"Ops.Gl.Matrix.TransformView"},{id:"flor1ge09",uiAttribs:{},portsIn:[{name:"r",value:.07},{name:"g",value:.06},{name:"b",value:.51},{name:"Opacity",value:.78},{name:"AO Intensity",value:1},{name:"Normal Map Intensity",value:1},{name:"Repeat X",value:1},{name:"Repeat Y",value:1},{name:"Offset X",value:0},{name:"Offset Y",value:0},{name:"Screen Space Normals",value:0},{name:"Calc normal tangents",value:1},{name:"Opacity TexCoords Transform",value:0},{name:"Discard Transparent Pixels",value:1},{name:"Alpha Mask Source index",value:0},{name:"Alpha Mask Source",value:"Luminance"}],portsOut:[{name:"Next",links:[{portIn:"render",portOut:"Next",objIn:"wcm52u6xo",objOut:"flor1ge09"}]}],objName:"Ops.Gl.Shader.MatCapMaterial_v3"},{id:"wcm52u6xo",uiAttribs:{},portsIn:[{name:"x",value:-1.26},{name:"y",value:.46},{name:"z",value:-1.17}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"62jtojeuu",objOut:"wcm52u6xo"}]}],objName:"Ops.Gl.Matrix.ScaleXYZViewMatrix"},{id:"tckfhevim",uiAttribs:{},portsIn:[{name:"x",value:1.2},{name:"y",value:-2.97},{name:"z",value:-1}],portsOut:[{name:"trigger",links:[{portIn:"exe",portOut:"trigger",objIn:"124910bf-e88f-4da5-847e-888a7ac73020",objOut:"tckfhevim"}]}],objName:"Ops.Deprecated.Gl.Matrix.ScaleXYZ"},{id:"x8l31ycyr",uiAttribs:{},portsIn:[{name:"Num",value:64},{name:"Spacing",value:.3},{name:"Center",value:1},{name:"Axis index",value:1},{name:"Axis",value:"XZ"}],objName:"Ops.Gl.Meshes.Grid"},{id:"33hdtkr51",uiAttribs:{},portsIn:[{name:"x",value:0},{name:"y",value:.22},{name:"z",value:-.01}],portsOut:[{name:"trigger",links:[{portIn:"Render",portOut:"trigger",objIn:"flor1ge09",objOut:"33hdtkr51"}]}],objName:"Ops.Gl.Matrix.Translate"},{id:"ajz3m2b7r",uiAttribs:{},portsIn:[{name:"r",value:.4752931908661422},{name:"g",value:.36659911993317373},{name:"b",value:.9581856509868598},{name:"a",value:1},{name:"colorizeTexture",value:1},{name:"Vertex Colors",value:0},{name:"Alpha Mask Source index",value:0},{name:"Alpha Mask Source",value:"Luminance"},{name:"Opacity TexCoords Transform",value:0},{name:"Discard Transparent Pixels",value:1},{name:"diffuseRepeatX",value:1},{name:"diffuseRepeatY",value:1},{name:"Tex Offset X",value:-2.19},{name:"Tex Offset Y",value:11.92},{name:"Crop TexCoords",value:0},{name:"billboard",value:0}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"o4q65sx2h",objOut:"ajz3m2b7r"}]}],objName:"Ops.Gl.Shader.BasicMaterial_v3"},{id:"6a24jo2e0",uiAttribs:{},portsIn:[{name:"Title",value:"Setting"}],objName:"Ops.Ui.Area"},{id:"o4q65sx2h",uiAttribs:{},portsIn:[{name:"x",value:0},{name:"y",value:-.56},{name:"z",value:3.58}],portsOut:[{name:"trigger",links:[{portIn:"Render",portOut:"trigger",objIn:"x8l31ycyr",objOut:"o4q65sx2h"}]}],objName:"Ops.Gl.Matrix.Translate"},{id:"eupi4n3t8",uiAttribs:{},portsIn:[{name:"Scale index",value:0},{name:"Scale",value:"Stretch"},{name:"Flip Y",value:0},{name:"Flip X",value:0}],portsOut:[{name:"trigger",links:[{portIn:"Execute",portOut:"trigger",objIn:"ii9hyaw76",objOut:"eupi4n3t8"}]}],objName:"Ops.Gl.Meshes.FullscreenRectangle_v2"},{id:"txsuzzmpp",uiAttribs:{},portsIn:[{name:"Gradient",value:'{"keys" : [{"pos":0,"r":0,"g":0,"b":0},{"pos":1,"r":1,"g":1,"b":1}]}'},{name:"Direction index",value:1},{name:"Direction",value:"Y"},{name:"Smoothstep",value:0},{name:"Step",value:0},{name:"Flip",value:1},{name:"sRGB",value:1},{name:"Oklab",value:0},{name:"Size",value:64},{name:"filter index",value:1},{name:"filter",value:"linear"},{name:"wrap index",value:0},{name:"wrap",value:"clamp to edge"},{name:"Gradient Array",value:0}],portsOut:[{name:"Texture",links:[{portIn:"R",portOut:"Texture",objIn:"ii9hyaw76",objOut:"txsuzzmpp"}]}],objName:"Ops.Gl.GradientTexture"},{id:"ii9hyaw76",uiAttribs:{},portsIn:[{name:"Filter index",value:1},{name:"Filter",value:"linear"},{name:"Wrap index",value:1},{name:"Wrap",value:"repeat"},{name:"Pixel Format index",value:9},{name:"Pixel Format",value:"RGBA 16bit float"},{name:"Size index",value:0},{name:"Size",value:"Biggest"},{name:"R Source index",value:0},{name:"R Source",value:"R"},{name:"R Value index",value:0},{name:"R Value",value:"Source"},{name:"R Default",value:1},{name:"G Source index",value:0},{name:"G Source",value:"R"},{name:"G Value index",value:1},{name:"G Value",value:"Invert"},{name:"G Default",value:1},{name:"B Source index",value:2},{name:"B Source",value:"B"},{name:"B Value index",value:0},{name:"B Value",value:"Source"},{name:"B Default",value:1},{name:"A Source index",value:0},{name:"A Source",value:"R"},{name:"A Value index",value:0},{name:"A Value",value:"Source"},{name:"A Default",value:1}],portsOut:[{name:"Next",links:[{portIn:"Render",portOut:"Next",objIn:"bom62ei05",objOut:"ii9hyaw76"}]},{name:"Texture",links:[{portIn:"Base Texture",portOut:"Texture",objIn:"bom62ei05",objOut:"ii9hyaw76"}]}],objName:"Ops.Gl.Textures.CombineTextures"},{id:"dvpyr3uz9",uiAttribs:{},portsIn:[{name:"File",value:"assets/65bbe44771656d76fa1e7e54_voro.png",display:"file"},{name:"Filter index",value:2},{name:"Filter",value:"mipmap"},{name:"Wrap index",value:0},{name:"Wrap",value:"repeat"},{name:"Anisotropic index",value:0},{name:"Anisotropic",value:"0"},{name:"Data Format index",value:3},{name:"Data Format",value:"RGBA"},{name:"Flip",value:0},{name:"Pre Multiplied Alpha",value:0},{name:"Active",value:1},{name:"Save Memory",value:1},{name:"Add Cachebuster",value:1}],portsOut:[{name:"Texture",links:[{portIn:"G",portOut:"Texture",objIn:"ii9hyaw76",objOut:"dvpyr3uz9"}]},{name:"Width",value:1660},{name:"Height",value:840},{name:"Aspect Ratio",value:1.9761904761904763},{name:"Loaded",value:1},{name:"Loading",value:0}],objName:"Ops.Gl.Texture_v2"},{id:"48vrkn65x",uiAttribs:{},portsIn:[{name:"Size index",value:0},{name:"Size",value:"Auto"},{name:"Width",value:640},{name:"Height",value:480},{name:"Filter index",value:1},{name:"Filter",value:"linear"},{name:"Wrap index",value:1},{name:"Wrap",value:"repeat"},{name:"Anisotropic index",value:0},{name:"Anisotropic",value:"0"},{name:"Pixel Format index",value:5},{name:"Pixel Format",value:"SRGBA 8bit ubyte"},{name:"R",value:0},{name:"G",value:0},{name:"B",value:0},{name:"A",value:0}],portsOut:[{name:"Next",links:[{portIn:"render",portOut:"Next",objIn:"6fb2f0244",objOut:"48vrkn65x"}]},{name:"texture_out",links:[{portIn:"Diffuse",portOut:"texture_out",objIn:"flor1ge09",objOut:"48vrkn65x"}]},{name:"Aspect Ratio",value:1.8369304556354915},{name:"Texture Width",value:1532},{name:"Texture Height",value:834}],objName:"Ops.Gl.ImageCompose.ImageCompose_v4"},{id:"6fb2f0244",uiAttribs:{},portsIn:[{name:"Passes",value:1},{name:"Clamp",value:0},{name:"direction index",value:0},{name:"direction",value:"both"},{name:"Mask Invert",value:0}],objName:"Ops.Gl.ImageCompose.FastBlur_v2"},{id:"bom62ei05",uiAttribs:{},portsIn:[{name:"Size index",value:0},{name:"Size",value:"Auto"},{name:"Width",value:640},{name:"Height",value:480},{name:"Filter index",value:1},{name:"Filter",value:"linear"},{name:"Wrap index",value:1},{name:"Wrap",value:"repeat"},{name:"Anisotropic index",value:0},{name:"Anisotropic",value:"0"},{name:"Pixel Format index",value:4},{name:"Pixel Format",value:"RGBA 8bit ubyte"},{name:"R",value:0},{name:"G",value:0},{name:"B",value:0},{name:"A",value:0}],portsOut:[{name:"Next",links:[{portIn:"Render",portOut:"Next",objIn:"m6kwtuieo",objOut:"bom62ei05"}]},{name:"texture_out",links:[{portIn:"Texture",portOut:"texture_out",objIn:"eupi4n3t8",objOut:"bom62ei05"}]},{name:"Aspect Ratio",value:1.9761904761904763},{name:"Texture Width",value:1660},{name:"Texture Height",value:840}],objName:"Ops.Gl.ImageCompose.ImageCompose_v4"},{id:"m6kwtuieo",uiAttribs:{},portsIn:[{name:"Blend Mode index",value:0},{name:"Blend Mode",value:"normal"},{name:"Alpha Mask index",value:0},{name:"Alpha Mask",value:"Off"},{name:"Amount",value:1},{name:"Strength",value:1},{name:"Radius",value:.3},{name:"Sharp",value:.25},{name:"Aspect",value:1},{name:"r",value:0},{name:"g",value:0},{name:"b",value:0},{name:"Alpha",value:0}],objName:"Ops.Gl.ImageCompose.Vignette_v3"},{id:"kgtq6kbqp",uiAttribs:{},portsIn:[{name:"Font",value:"chivo"},{name:"Scale",value:.11},{name:"Letter Spacing",value:-.02},{name:"Line Height",value:1},{name:"Align index",value:0},{name:"Align",value:"Left"},{name:"Vertical Align index",value:2},{name:"Vertical Align",value:"Middle"},{name:"r",value:0},{name:"g",value:0},{name:"b",value:0},{name:"a",value:.91},{name:"SDF",value:1},{name:"Smoothing",value:.126},{name:"Border",value:1},{name:"Border Width",value:.222},{name:"Smoothness",value:.25},{name:"Border r",value:0},{name:"Border g",value:0},{name:"Border b",value:1},{name:"Shadow",value:0},{name:"Positions",value:0},{name:"Scalings",value:0},{name:"Rotations",value:0},{name:"Colors",value:0}],portsOut:[{name:"Num Lines",value:1},{name:"Width",value:.23304531249999996},{name:"Height",value:.06678697916666666},{name:"Start Y",value:.03477526041666667},{name:"Num Chars",value:9}],objName:"Ops.Gl.TextMeshMSDF_v2"},{id:"1rc15x0gs",uiAttribs:{},portsIn:[{name:"Variable",value:"_currentDialValueInsideRepeat2D"}],objName:"Ops.Vars.VarSetNumber_v2"},{id:"o8zk12f1r",uiAttribs:{},portsIn:[{name:"Variable",value:"_currentDialValueInsideRepeat2D"}],portsOut:[{name:"Value",links:[{portIn:"number",portOut:"Value",objIn:"2lpsqzgrb",objOut:"o8zk12f1r"}]}],objName:"Ops.Vars.VarGetNumber_v2"},{id:"2lpsqzgrb",uiAttribs:{},portsIn:[{name:"Decimal Places",value:4}],portsOut:[{name:"result",links:[{portIn:"Number",portOut:"result",objIn:"vib72zx3n",objOut:"2lpsqzgrb"}]}],objName:"Ops.Math.Round"},{id:"vib72zx3n",uiAttribs:{},portsOut:[{name:"Result",links:[{portIn:"String B",portOut:"Result",objIn:"hhpgrbf2g",objOut:"vib72zx3n"}]}],objName:"Ops.String.NumberToString_v2"},{id:"i111f5qjb",uiAttribs:{},portsIn:[{name:"x",value:0},{name:"y",value:0},{name:"z",value:0}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"uc9r4wu0r",objOut:"i111f5qjb"}]}],objName:"Ops.Gl.Matrix.Translate"},{id:"zlpf1p0f5",uiAttribs:{},portsIn:[{name:"posY",value:.09},{name:"posZ",value:.24},{name:"scale",value:1},{name:"rotX",value:0},{name:"rotY",value:0},{name:"rotZ",value:0}],portsOut:[{name:"trigger",links:[{portIn:"Render",portOut:"trigger",objIn:"kgtq6kbqp",objOut:"zlpf1p0f5"}]}],objName:"Ops.Gl.Matrix.TransformView"},{id:"prvtvnqot",uiAttribs:{},portsIn:[{name:"Font Name",value:"chivo"},{name:"Font Data",value:"assets/ChivoMono-Medium-msdf.json",display:"file"},{name:"Font Image",value:"assets/ChivoMono-Medium.png",display:"file"},{name:"Font Image 1",value:0,display:"file"},{name:"Font Image 2",value:0,display:"file"},{name:"Font Image 3",value:0,display:"file"}],portsOut:[{name:"Loaded",value:true},{name:"Total Chars",value:66},{name:"Chars",value:"jQgbdf03689CGOShikl12457ABDEFHIJKLMNPRTUVWXYZpqtyw+acemnorsuvxz*-."}],objName:"Ops.Gl.FontMSDF_v2"},{id:"f67se0kft",uiAttribs:{},portsIn:[{name:"Title",value:"Text"}],objName:"Ops.Ui.Area"},{id:"6hojoyomj",uiAttribs:{},portsIn:[{name:"Limit",value:1},{name:"Length",value:10},{name:"Mode index",value:1},{name:"Mode",value:"Stop at Max"},{name:"Default",value:0}],portsOut:[{name:"Value",links:[{portIn:"val",portOut:"Value",objIn:"1b7ls5v00",objOut:"6hojoyomj"}]}],objName:"Ops.Math.Incrementor"},{id:"m4wpz0q5c",uiAttribs:{},portsIn:[{name:"number2",value:.06}],portsOut:[{name:"result",links:[{portIn:"mul",portOut:"result",objIn:"124910bf-e88f-4da5-847e-888a7ac73020",objOut:"m4wpz0q5c"}]}],objName:"Ops.Math.Multiply"},{id:"1b7ls5v00",uiAttribs:{},portsIn:[{name:"min",value:0},{name:"max",value:9}],portsOut:[{name:"result",links:[{portIn:"number1",portOut:"result",objIn:"m4wpz0q5c",objOut:"1b7ls5v00"}]}],objName:"Ops.Math.SmootherStep"},{id:"hhpgrbf2g",uiAttribs:{},portsIn:[{name:"Format",value:"*$a $b"},{name:"String C",value:2},{name:"String D",value:3},{name:"String E",value:""},{name:"String F",value:""}],portsOut:[{name:"Result",links:[{portIn:"Text",portOut:"Result",objIn:"kgtq6kbqp",objOut:"hhpgrbf2g"}]}],objName:"Ops.String.StringCompose_v3"},{id:"euqza6b25",uiAttribs:{},portsIn:[{name:"Variable",value:"_currentIndexInsideRepeat2D"}],objName:"Ops.Vars.VarSetNumber_v2"},{id:"34zd4vl4f",uiAttribs:{},portsIn:[{name:"Variable",value:"_currentIndexInsideRepeat2D"}],portsOut:[{name:"Value",links:[{portIn:"index",portOut:"Value",objIn:"aqjh1act1",objOut:"34zd4vl4f"},{portIn:"number2",portOut:"Value",objIn:"qyara3wac",objOut:"34zd4vl4f"}]}],objName:"Ops.Vars.VarGetNumber_v2"},{id:"8eccns7e5",uiAttribs:{},portsIn:[{name:"radius",value:.97},{name:"innerRadius",value:.949},{name:"segments",value:32},{name:"steps",value:1},{name:"invertSteps",value:0},{name:"mapping index",value:1},{name:"mapping",value:"round"},{name:"Spline",value:0},{name:"Draw",value:1,title:"Render mesh"}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"b6dd9bba-0e82-4220-a27d-884c1d3887a3",objOut:"8eccns7e5"}]}],objName:"Ops.Gl.Meshes.Circle_v3"},{id:"gfjoyon3n",uiAttribs:{},portsIn:[{name:"radius",value:.86},{name:"innerRadius",value:.895},{name:"segments",value:100},{name:"steps",value:2},{name:"invertSteps",value:1},{name:"mapping index",value:0},{name:"mapping",value:"flat"},{name:"Spline",value:0},{name:"Draw",value:1,title:"Render mesh"}],objName:"Ops.Gl.Meshes.Circle_v3"},{id:"mtxdae1jj",uiAttribs:{},portsIn:[{name:"Variable",value:"_currentIndexInsideRepeat2D"}],portsOut:[{name:"Value",links:[{portIn:"index",portOut:"Value",objIn:"fxd9qy0nv",objOut:"mtxdae1jj"}]}],objName:"Ops.Vars.VarGetNumber_v2"},{id:"ejryfn62d",uiAttribs:{},portsIn:[{name:"Title",value:"*"}],objName:"Ops.Ui.Area"},{id:"yvvnsby8j",uiAttribs:{},portsIn:[{name:"text",value:"decay, size, mod, mix"},{name:"separator",value:","},{name:"Numbers",value:0},{name:"Trim",value:1},{name:"Split Lines",value:0}],portsOut:[{name:"array",links:[{portIn:"array",portOut:"array",objIn:"fxd9qy0nv",objOut:"yvvnsby8j"}]},{name:"length",value:4}],objName:"Ops.Array.StringToArray_v2"},{id:"fxd9qy0nv",uiAttribs:{},portsOut:[{name:"result",links:[{portIn:"String A",portOut:"result",objIn:"hhpgrbf2g",objOut:"fxd9qy0nv"}]}],objName:"Ops.Array.ArrayGetString"},{id:"xqowbomkj",uiAttribs:{},portsIn:[{name:"Title",value:"*"}],objName:"Ops.Ui.Area"},{id:"rdmibd961",uiAttribs:{},portsIn:[{name:"Start Row",value:0}],objName:"Ops.Ui.VizArrayTable"},{id:"okiq8ed9q",uiAttribs:{},portsIn:[{name:"Named Trigger",value:"mainExe"}],portsOut:[{name:"Triggered",links:[{portIn:"render",portOut:"Triggered",objIn:"eupi4n3t8",objOut:"okiq8ed9q"}]}],objName:"Ops.Trigger.TriggerReceive"},{id:"ch5u1xz0l",uiAttribs:{},portsIn:[{name:"Named Trigger",value:"midExe"}],objName:"Ops.Trigger.TriggerSend"},{id:"faiior48h",uiAttribs:{},portsIn:[{name:"Named Trigger",value:"midExe"}],portsOut:[{name:"Triggered",links:[{portIn:"render",portOut:"Triggered",objIn:"fvg1zz75v",objOut:"faiior48h"},{portIn:"Render",portOut:"Triggered",objIn:"48vrkn65x",objOut:"faiior48h"},{portIn:"render",portOut:"Triggered",objIn:"33hdtkr51",objOut:"faiior48h"}]}],objName:"Ops.Trigger.TriggerReceive"},{id:"smns78b6k",uiAttribs:{},portsIn:[{name:"Title",value:"*"}],objName:"Ops.Ui.Area"},{id:"c9u5wxkzu",uiAttribs:{},portsIn:[{name:"Value",value:0}],portsOut:[{name:"Next",links:[{portIn:"render",portOut:"Next",objIn:"33hdtkr51",objOut:"c9u5wxkzu"}]},{name:"Number",value:0}],objName:"Ops.Number.TriggerOnChangeNumber"},{id:"piq1e64rw",uiAttribs:{},portsIn:[{name:"Title",value:"*"}],objName:"Ops.Ui.Area"},{id:"t83msa078",uiAttribs:{},portsIn:[{name:"Title",value:"*"}],objName:"Ops.Ui.Area"},{id:"ifc049dka",uiAttribs:{},portsIn:[{name:"Id",value:""},{name:"Class",value:"nel-logo"},{name:"Style",value:""},{name:"Interactive",value:1},{name:"Visible",value:1},{name:"Convert Line Breaks",value:0},{name:"Propagate Click-Events",value:1}],portsOut:[{name:"DOM Element",links:[{portIn:"DOMElement",portOut:"DOM Element",objIn:"m4lf0ljbk",objOut:"ifc049dka"},{portIn:"Element",portOut:"DOM Element",objIn:"ql6igmez3",objOut:"ifc049dka"}]},{name:"Hover",links:[{portIn:"Use Value 1",portOut:"Hover",objIn:"acmkbycvu",objOut:"ifc049dka"}]},{name:"Clicked",links:[{portIn:"Open",portOut:"Clicked",objIn:"g5qz1ee85",objOut:"ifc049dka"}]}],objName:"Ops.Html.DivElement_v3"},{id:"p1qw1y67z",uiAttribs:{},portsIn:[{name:"value",value:'\n\x3c!-- Generator: Adobe Illustrator 24.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --\x3e\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n'},{name:"Syntax index",value:3},{name:"Syntax",value:"html"}],portsOut:[{name:"Result",links:[{portIn:"Text",portOut:"Result",objIn:"ifc049dka",objOut:"p1qw1y67z"}]}],objName:"Ops.String.StringEditor"},{id:"ehh39rz6v",uiAttribs:{},portsIn:[{name:"css code",value:".nel-logo {\n \nposition:absolute;\nz-index:100;\nleft: 100px;\nopacity: 0.9;\n}"},{name:"Active",value:1}],objName:"Ops.Html.CSS_v2"},{id:"p160hjd8r",uiAttribs:{},portsIn:[{name:"posX",value:-1.53},{name:"posY",value:-1.09},{name:"posZ",value:-1.65},{name:"scale",value:1},{name:"rotX",value:8.63},{name:"rotY",value:69.58},{name:"rotZ",value:0}],portsOut:[{name:"trigger",links:[{portIn:"trigger",portOut:"trigger",objIn:"m4lf0ljbk",objOut:"p160hjd8r"}]}],objName:"Ops.Gl.Matrix.Transform"},{id:"m4lf0ljbk",uiAttribs:{},portsIn:[{name:"origin index",value:7},{name:"origin",value:"bottom-middle"}],objName:"Ops.Html.TransformCSS3DElement"},{id:"4pu8mr0y2",uiAttribs:{},portsIn:[{name:"Named Trigger",value:"preSequenceFlow"}],objName:"Ops.Trigger.TriggerSend"},{id:"jfun4qac1",uiAttribs:{},portsIn:[{name:"Pixel Unit index",value:0},{name:"Pixel Unit",value:"Display"}],portsOut:[{name:"width",value:1532},{name:"height",value:834},{name:"Pixel Ratio",value:2},{name:"Pixel Width",links:[{portIn:"number1",portOut:"Pixel Width",objIn:"cd0k5qsyf",objOut:"jfun4qac1"}]},{name:"Pixel Height",value:1668},{name:"Aspect Ratio",value:1.8369304556354915},{name:"Landscape",value:1}],objName:"Ops.Gl.CanvasInfo_v2"},{id:"cd0k5qsyf",uiAttribs:{},portsIn:[{name:"number2",value:800}],portsOut:[{name:"result",value:3.83}],objName:"Ops.Math.Divide"},{id:"of6q9dm1m",uiAttribs:{},portsIn:[{name:"Named Trigger",value:"mainExe"}],portsOut:[{name:"Triggered",links:[{portIn:"render",portOut:"Triggered",objIn:"ajz3m2b7r",objOut:"of6q9dm1m"}]}],objName:"Ops.Trigger.TriggerReceive"},{id:"rid9x7kap",uiAttribs:{},portsIn:[{name:"Named Trigger",value:"preSequenceFlow"}],portsOut:[{name:"Triggered",links:[{portIn:"render",portOut:"Triggered",objIn:"p160hjd8r",objOut:"rid9x7kap"}]}],objName:"Ops.Trigger.TriggerReceive"},{id:"efooconni",uiAttribs:{},portsIn:[{name:"Title",value:"HTML"}],objName:"Ops.Ui.Area"},{id:"ql6igmez3",uiAttribs:{},portsIn:[{name:"Property",value:"opacity"},{name:"Value Suffix",value:""}],objName:"Ops.Html.CSSProperty_v2"},{id:"acmkbycvu",uiAttribs:{},portsIn:[{name:"Value 0",value:.7},{name:"Value 1",value:1}],portsOut:[{name:"Out Value",links:[{portIn:"Value",portOut:"Out Value",objIn:"ql6igmez3",objOut:"acmkbycvu"}]}],objName:"Ops.Boolean.BoolToNumber_v2"},{id:"g5qz1ee85",uiAttribs:{},portsIn:[{name:"URL",value:"https://neverenginelabs.com"},{name:"Target Name",value:"_blank"},{name:"Specs",value:""}],objName:"Ops.Html.HyperLink_v2"},{id:"zcc6zzw4d",uiAttribs:{},portsIn:[{name:"Named Trigger",value:"exeNoCamera"}],objName:"Ops.Trigger.TriggerSend"},{id:"catyviogw",uiAttribs:{},portsIn:[{name:"x",value:1.73},{name:"y",value:.95},{name:"z",value:0}],portsOut:[{name:"trigger",links:[{portIn:"Trigger",portOut:"trigger",objIn:"ny2jicns4",objOut:"catyviogw"}]}],objName:"Ops.Gl.Matrix.Translate"},{id:"jmw19jjzi",uiAttribs:{},portsIn:[{name:"r",value:.222},{name:"g",value:.898},{name:"b",value:1},{name:"Vertex Colors",value:0},{name:"Alpha Mask Source index",value:0},{name:"Alpha Mask Source",value:"Luminance"},{name:"Opacity TexCoords Transform",value:0},{name:"Discard Transparent Pixels",value:0},{name:"diffuseRepeatX",value:-.36},{name:"diffuseRepeatY",value:-.18},{name:"Tex Offset X",value:-24.27},{name:"Tex Offset Y",value:7.78},{name:"Crop TexCoords",value:0},{name:"billboard",value:0}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"catyviogw",objOut:"jmw19jjzi"},{portIn:"Update",portOut:"trigger",objIn:"gf07781ar",objOut:"jmw19jjzi"}]}],objName:"Ops.Gl.Shader.BasicMaterial_v3"},{id:"avhqfpehd",uiAttribs:{},portsIn:[{name:"Named Trigger",value:"exeNoCamera"}],portsOut:[{name:"Triggered",links:[{portIn:"Trigger",portOut:"Triggered",objIn:"12xx7g980",objOut:"avhqfpehd"}]}],objName:"Ops.Trigger.TriggerReceive"},{id:"0cristvpm",uiAttribs:{},portsIn:[{name:"Font File",value:"assets/forkawesome-webfont.ttf",display:"file"}],portsOut:[{name:"Opentype Font",links:[{portIn:"Opentype Font",portOut:"Opentype Font",objIn:"btqy1laa6",objOut:"0cristvpm"}]}],objName:"Ops.Extension.OpenType.OpentypeFont"},{id:"btqy1laa6",uiAttribs:{},portsIn:[{name:"Text",value:""},{name:"Letter Spacing",value:0}],portsOut:[{name:"Path String",links:[{portIn:"SVG Path",portOut:"Path String",objIn:"m3rdjk1xk",objOut:"btqy1laa6"}]}],objName:"Ops.Extension.OpenType.OpentypeToSvgPath"},{id:"m3rdjk1xk",uiAttribs:{},portsIn:[{name:"Bezier Stepsize",value:3},{name:"Rescale",value:.07}],portsOut:[{name:"Geometry",links:[{portIn:"Geometry",portOut:"Geometry",objIn:"s71v490xs",objOut:"m3rdjk1xk"}]}],objName:"Ops.Graphics.Geometry.SvgPathToGeometry_v2"},{id:"9vf5ijecy",uiAttribs:{},portsIn:[{name:"Render Mesh",value:1},{name:"Add Vertex Numbers",value:0}],objName:"Ops.Gl.RenderGeometry_v2"},{id:"12xx7g980",uiAttribs:{},portsIn:[{name:"Check Body Collisions",value:0}],portsOut:[{name:"Next",links:[{portIn:"Trigger",portOut:"Next",objIn:"zmasrvvjw",objOut:"12xx7g980"}]},{name:"Total Bodies",value:1}],objName:"Ops.Graphics.Intersection.IntersectWorld"},{id:"ny2jicns4",uiAttribs:{},portsIn:[{name:"Shape index",value:1},{name:"Shape",value:"BoxAA"},{name:"Name",value:"icon.save"},{name:"Radius",value:.09},{name:"Size X",value:.24},{name:"Size Y",value:.23},{name:"Size Z",value:.19},{name:"Positions"},{name:"Append Index to name",value:0}],portsOut:[{name:"Next",links:[{portIn:"render",portOut:"Next",objIn:"lp0zvoc9g",objOut:"ny2jicns4"}]}],objName:"Ops.Graphics.Intersection.IntersectBody"},{id:"zmasrvvjw",uiAttribs:{},portsIn:[{name:"Coordinate Format index",value:0},{name:"Coordinate Format",value:"-1 to 1"},{name:"Z",value:0},{name:"To X",value:0},{name:"To Y",value:0},{name:"To Z",value:0},{name:"Active",value:1},{name:"Change Cursor",value:1}],portsOut:[{name:"Next",links:[{portIn:"render",portOut:"Next",objIn:"jmw19jjzi",objOut:"zmasrvvjw"}]},{name:"Has Hit",value:0},{name:"Hit Body Name",value:""},{name:"Hit X",links:[{portIn:"colorizeTexture",portOut:"Hit X",objIn:"jmw19jjzi",objOut:"zmasrvvjw"}]},{name:"Hit Y",links:[{portIn:"number1",portOut:"Hit Y",objIn:"w59tgvg1u",objOut:"zmasrvvjw"}]},{name:"Hit Z",links:[{portIn:"A",portOut:"Hit Z",objIn:"yn916v8en",objOut:"zmasrvvjw"}]}],objName:"Ops.Graphics.Intersection.IntersectTestRaycast"},{id:"mts5kprh0",uiAttribs:{},portsIn:[{name:"Coordinates index",value:0},{name:"Coordinates",value:"-1 to 1"},{name:"Area index",value:0},{name:"Area",value:"Canvas"},{name:"flip y",value:1},{name:"right click prevent default",value:1},{name:"Touch support",value:1},{name:"Passive Events",value:0},{name:"Active",value:1}],portsOut:[{name:"x",links:[{portIn:"X",portOut:"x",objIn:"zmasrvvjw",objOut:"mts5kprh0"}]},{name:"y",links:[{portIn:"Y",portOut:"y",objIn:"zmasrvvjw",objOut:"mts5kprh0"}]},{name:"Button is down",value:0},{name:"Mouse is hovering",value:1},{name:"Movement X",value:0},{name:"Movement Y",value:-.5}],objName:"Ops.Devices.Mouse.Mouse_v3"},{id:"s71v490xs",uiAttribs:{},portsIn:[{name:"Smooth",value:1},{name:"Walls",value:0},{name:"Top",value:1},{name:"Bottom",value:0}],portsOut:[{name:"Result Geometry",links:[{portIn:"Geometry",portOut:"Result Geometry",objIn:"9vf5ijecy",objOut:"s71v490xs"}]}],objName:"Ops.Graphics.Geometry.GeometryExtrude"},{id:"w59tgvg1u",uiAttribs:{},portsIn:[{name:"number2",value:.05}],portsOut:[{name:"result",links:[{portIn:"Value",portOut:"result",objIn:"gf07781ar",objOut:"w59tgvg1u"}]}],objName:"Ops.Math.Multiply"},{id:"lp0zvoc9g",uiAttribs:{},portsIn:[{name:"x",value:-.05},{name:"y",value:-.05},{name:"z",value:0}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"9vf5ijecy",objOut:"lp0zvoc9g"}]}],objName:"Ops.Gl.Matrix.Translate"},{id:"lk6h207g7",uiAttribs:{},portsIn:[{name:"File",value:"assets/lib_matcaps_Chrome_Blue_Tint-White.png",display:"file"},{name:"Filter index",value:1},{name:"Filter",value:"linear"},{name:"Wrap index",value:0},{name:"Wrap",value:"repeat"},{name:"Anisotropic index",value:0},{name:"Anisotropic",value:"0"},{name:"Data Format index",value:3},{name:"Data Format",value:"RGBA"},{name:"Flip",value:1},{name:"Pre Multiplied Alpha",value:1},{name:"Active",value:1},{name:"Save Memory",value:1},{name:"Add Cachebuster",value:1}],portsOut:[{name:"Texture",links:[{portIn:"texture",portOut:"Texture",objIn:"jmw19jjzi",objOut:"lk6h207g7"}]},{name:"Width",value:256},{name:"Height",value:256},{name:"Aspect Ratio",value:1},{name:"Loaded",value:1},{name:"Loading",value:0}],objName:"Ops.Gl.Texture_v2"},{id:"gf07781ar",uiAttribs:{},portsIn:[{name:"Separate inc/dec",value:0},{name:"Inc factor",value:4,title:"Inc/Dec factor"},{name:"Dec factor",value:4}],portsOut:[{name:"Result",links:[{portIn:"Height",portOut:"Result",objIn:"s71v490xs",objOut:"gf07781ar"}]}],objName:"Ops.Anim.Smooth"},{id:"g464u24ms",uiAttribs:{},portsIn:[{name:"Title",value:"Icons"}],objName:"Ops.Ui.Area"},{id:"yn916v8en",uiAttribs:{},portsIn:[{name:"B",value:5},{name:"C",value:.5},{name:"D",value:3},{name:"Expression",value:"(a*b) + c"}],portsOut:[{name:"Result",links:[{portIn:"a",portOut:"Result",objIn:"jmw19jjzi",objOut:"yn916v8en"}]},{name:"Expression Valid",value:true}],objName:"Ops.Math.MathExpression"},{id:"zi3u8x4zd",uiAttribs:{subPatch:"66dae55a-8297-4120-81e2-d946cc6b2b60"},portsIn:[{name:"Variable",value:"ui_activeDial_ID"}],portsOut:[{name:"Value",links:[{portIn:"number1",portOut:"Value",objIn:"zhjkbd61e",objOut:"zi3u8x4zd"}]}],objName:"Ops.Vars.VarGetNumber_v2"},{id:"0txm5qrgs",uiAttribs:{subPatch:"66dae55a-8297-4120-81e2-d946cc6b2b60"},portsIn:[{name:"Variable",value:"ui_dialValues"}],portsOut:[{name:"Value",links:[{portIn:"array",portOut:"Value",objIn:"ccotjup9t",objOut:"0txm5qrgs"}]}],objName:"Ops.Vars.VarGetArray_v2"},{id:"ccotjup9t",uiAttribs:{subPatch:"66dae55a-8297-4120-81e2-d946cc6b2b60"},portsIn:[{name:"Value Invalid Index",value:0}],portsOut:[{name:"value",links:[{portIn:"Default Value",portOut:"value",objIn:"dq71li66q",objOut:"ccotjup9t"}]},{name:"Valid Index",value:1}],objName:"Ops.Array.ArrayGetNumber"},{id:"zhjkbd61e",uiAttribs:{subPatch:"66dae55a-8297-4120-81e2-d946cc6b2b60"},portsIn:[{name:"number2",value:1}],portsOut:[{name:"result",links:[{portIn:"index",portOut:"result",objIn:"ccotjup9t",objOut:"zhjkbd61e"}]}],objName:"Ops.Math.Subtract"},{id:"d7vl5bf8b",uiAttribs:{},portsIn:[{name:"When False index",value:0},{name:"When False",value:"keep last array"}],portsOut:[{name:"Array Out",links:[{portIn:"Value",portOut:"Array Out",objIn:"x6efudpvd",objOut:"d7vl5bf8b"}]}],objName:"Ops.Array.GateArray_v2"},{id:"rjsjd3otn",uiAttribs:{},portsOut:[{name:"Result",links:[{portIn:"Array",portOut:"Result",objIn:"rdmibd961",objOut:"rjsjd3otn"},{portIn:"Array in",portOut:"Result",objIn:"d7vl5bf8b",objOut:"rjsjd3otn"}]}],objName:"Ops.Patch.PuvBp73.ArraySetNumberAtIndex_v4"}],export:{time:"2024-06-29 16:32:47",service:"download",exportNumber:8}};if(!CABLES.exportedPatch){CABLES.exportedPatch=CABLES.exportedPatches["uvBp73"]}"use strict";var CABLES=CABLES||{};CABLES.OPS=CABLES.OPS||{};var Ops=Ops||{};Ops.Gl=Ops.Gl||{};Ops.Ui=Ops.Ui||{};Ops.Anim=Ops.Anim||{};Ops.Html=Ops.Html||{};Ops.Math=Ops.Math||{};Ops.Vars=Ops.Vars||{};Ops.Array=Ops.Array||{};Ops.Patch=Ops.Patch||{};Ops.Number=Ops.Number||{};Ops.String=Ops.String||{};Ops.Boolean=Ops.Boolean||{};Ops.Devices=Ops.Devices||{};Ops.Trigger=Ops.Trigger||{};Ops.Graphics=Ops.Graphics||{};Ops.Extension=Ops.Extension||{};Ops.Gl.Matrix=Ops.Gl.Matrix||{};Ops.Gl.Meshes=Ops.Gl.Meshes||{};Ops.Gl.Shader=Ops.Gl.Shader||{};Ops.Deprecated=Ops.Deprecated||{};Ops.Gl.Textures=Ops.Gl.Textures||{};Ops.Math.Compare=Ops.Math.Compare||{};Ops.Deprecated.Gl=Ops.Deprecated.Gl||{};Ops.Devices.Mouse=Ops.Devices.Mouse||{};Ops.Patch.PuvBp73=Ops.Patch.PuvBp73||{};Ops.Devices.Browser=Ops.Devices.Browser||{};Ops.Gl.ImageCompose=Ops.Gl.ImageCompose||{};Ops.Graphics.Geometry=Ops.Graphics.Geometry||{};Ops.Extension.OpenType=Ops.Extension.OpenType||{};Ops.Deprecated.Gl.Matrix=Ops.Deprecated.Gl.Matrix||{};Ops.Graphics.Intersection=Ops.Graphics.Intersection||{};Ops.Patch.PuvBp73.SubPatch2=function(){CABLES.Op.apply(this,arguments);const e=this;const n=e.attachments={inc_gen_ports_js:"op.initInnerPorts=function(addedOps)\n{\n for(let i=0;ir.get())}};Ops.Math.Compare.GreaterThan.prototype=new CABLES.Op;CABLES.OPS["b250d606-f7f8-44d3-b099-c29efff2608a"]={f:Ops.Math.Compare.GreaterThan,objName:"Ops.Math.Compare.GreaterThan"};Ops.Vars.VarSetNumber_v2=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inValueFloat("Value",0);e.varName=e.inDropDown("Variable",[],"",true);new CABLES.VarSetOpWrapper(e,"number",n,e.varName)};Ops.Vars.VarSetNumber_v2.prototype=new CABLES.Op;CABLES.OPS["b5249226-6095-4828-8a1c-080654e192fa"]={f:Ops.Vars.VarSetNumber_v2,objName:"Ops.Vars.VarSetNumber_v2"};Ops.Number.GateNumber=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inValue("Value In",0),r=e.inValueBool("Pass Through"),i=e.inSwitch("When False",["keep last number","custom"],"keep last number"),a=e.inFloat("Custom Value",0),s=e.outNumber("Value Out");n.onChange=l;r.onChange=l;n.changeAlways=s.changeAlways=true;i.onChange=o;function o(){a.setUiAttribs({greyout:i.get()!="custom"});l()}function l(){if(r.get()){s.set(n.get())}else{if(i.get()=="custom")s.set(a.get())}}};Ops.Number.GateNumber.prototype=new CABLES.Op;CABLES.OPS["594105c8-1fdb-4f3c-bbd5-29b9ad6b33e0"]={f:Ops.Number.GateNumber,objName:"Ops.Number.GateNumber"};Ops.Ui.SubPatchInput=function(){CABLES.Op.apply(this,arguments);const t=this;const e=t.attachments={};t.innerInput=true;const n=t.inTriggerButton("Goto SubPatchOp");n.setUiAttribs({hidePort:true});n.onTriggered=()=>{const e=t.patch.getSubPatchOuterOp(t.uiAttribs.subPatch);gui.patchView.centerSelectOp(e.id)}};Ops.Ui.SubPatchInput.prototype=new CABLES.Op;CABLES.OPS["c4e4e933-136e-479e-8de8-0b35b75d9217"]={f:Ops.Ui.SubPatchInput,objName:"Ops.Ui.SubPatchInput"};Ops.Ui.SubPatchOutput=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};e.innerOutput=true};Ops.Ui.SubPatchOutput.prototype=new CABLES.Op;CABLES.OPS["02d45073-7936-4830-81ad-59a162febf1f"]={f:Ops.Ui.SubPatchOutput,objName:"Ops.Ui.SubPatchOutput"};Ops.Gl.MainLoop=function(){CABLES.Op.apply(this,arguments);const r=this;const e=r.attachments={};const t=r.inValue("FPS Limit",0),n=r.outTrigger("trigger"),i=r.outNumber("width"),a=r.outNumber("height"),s=r.inValueBool("Reduce FPS not focussed",false),o=r.inValueBool("Reduce FPS loading"),l=r.inValueBool("Clear",true),u=r.inValueBool("ClearAlpha",true),c=r.inValueBool("Fullscreen Button",false),p=r.inValueBool("Active",true),h=r.inValueBool("Hires Displays",false),f=r.inSwitch("Pixel Unit",["Display","CSS"],"Display");r.onAnimFrame=T;h.onChange=function(){if(h.get())r.patch.cgl.pixelDensity=window.devicePixelRatio;else r.patch.cgl.pixelDensity=1;r.patch.cgl.updateSize();if(CABLES.UI)gui.setLayout()};p.onChange=function(){r.patch.removeOnAnimFrame(r);if(p.get()){r.setUiAttrib({extendTitle:""});r.onAnimFrame=T;r.patch.addOnAnimFrame(r);r.log("adding again!")}else{r.setUiAttrib({extendTitle:"Inactive"})}};const d=r.patch.cgl;let g=0;let m=0;let v=null;let b=false;if(!r.patch.cgl)r.uiAttr({error:"No webgl cgl context"});const y=vec3.create();vec3.set(y,0,0,0);const x=vec3.create();vec3.set(x,0,0,-2);c.onChange=C;setTimeout(C,100);let S=null;let O=true;let _=true;window.addEventListener("blur",()=>{O=false});window.addEventListener("focus",()=>{O=true});document.addEventListener("visibilitychange",()=>{_=!document.hidden});I();d.mainloopOp=this;f.onChange=()=>{i.set(0);a.set(0)};function A(){if(o.get()&&r.patch.loading.getProgress()<1)return 5;if(s.get()){if(!_)return 10;if(!O)return 30}return t.get()}function C(){function e(){if(S)S.style.display="block"}function t(){if(S)S.style.display="none"}r.patch.cgl.canvas.addEventListener("mouseleave",t);r.patch.cgl.canvas.addEventListener("mouseenter",e);if(c.get()){if(!S){S=document.createElement("div");const n=r.patch.cgl.canvas.parentElement;if(n)n.appendChild(S);S.addEventListener("mouseenter",e);S.addEventListener("click",function(e){if(CABLES.UI&&!e.shiftKey)gui.cycleFullscreen();else d.fullScreen()})}S.style.padding="10px";S.style.position="absolute";S.style.right="5px";S.style.top="5px";S.style.width="20px";S.style.height="20px";S.style.cursor="pointer";S.style["border-radius"]="40px";S.style.background="#444";S.style["z-index"]="9999";S.style.display="none";S.innerHTML=''}else{if(S){S.style.display="none";S.remove();S=null}}}r.onDelete=function(){d.gl.clearColor(0,0,0,0);d.gl.clear(d.gl.COLOR_BUFFER_BIT|d.gl.DEPTH_BUFFER_BIT)};function T(e){if(!p.get())return;if(d.aborted||d.canvas.clientWidth===0||d.canvas.clientHeight===0)return;r.patch.cg=d;if(h.get())r.patch.cgl.pixelDensity=window.devicePixelRatio;const t=performance.now();r.patch.config.fpsLimit=A();if(d.canvasWidth==-1){d.setCanvas(r.patch.config.glCanvasId);return}if(d.canvasWidth!=i.get()||d.canvasHeight!=a.get()){let e=1;if(f.get()=="CSS")e=r.patch.cgl.pixelDensity;i.set(d.canvasWidth/e);a.set(d.canvasHeight/e)}if(CABLES.now()-m>1e3){CGL.fpsReport=CGL.fpsReport||[];if(r.patch.loading.getProgress()>=1&&m!==0)CGL.fpsReport.push(g);g=0;m=CABLES.now()}CGL.MESH.lastShader=null;CGL.MESH.lastMesh=null;d.renderStart(d,y,x);if(l.get()){d.gl.clearColor(0,0,0,1);d.gl.clear(d.gl.COLOR_BUFFER_BIT|d.gl.DEPTH_BUFFER_BIT)}n.trigger();if(CGL.MESH.lastMesh)CGL.MESH.lastMesh.unBind();if(CGL.Texture.previewTexture){if(!CGL.Texture.texturePreviewer)CGL.Texture.texturePreviewer=new CGL.Texture.texturePreview(d);CGL.Texture.texturePreviewer.render(CGL.Texture.previewTexture)}d.renderEnd(d);r.patch.cg=null;if(u.get()){d.gl.clearColor(1,1,1,1);d.gl.colorMask(false,false,false,true);d.gl.clear(d.gl.COLOR_BUFFER_BIT);d.gl.colorMask(true,true,true,true)}if(!d.frameStore.phong)d.frameStore.phong={};g++;r.patch.cgl.profileData.profileMainloopMs=performance.now()-t}function I(){clearTimeout(v);v=setTimeout(()=>{if(r.patch.getOpsByObjName(r.name).length>1){r.setUiError("multimainloop","there should only be one mainloop op!");if(!b)b=r.patch.addEventListener("onOpDelete",I)}else r.setUiError("multimainloop",null,1)},500)}};Ops.Gl.MainLoop.prototype=new CABLES.Op;CABLES.OPS["b0472a1d-db16-4ba6-8787-f300fbdc77bb"]={f:Ops.Gl.MainLoop,objName:"Ops.Gl.MainLoop"};Ops.Trigger.Sequence=function(){CABLES.Op.apply(this,arguments);const a=this;const e=a.attachments={};const t=a.inTrigger("exe"),n=a.inTriggerButton("Clean up connections");a.setUiAttrib({resizable:true,resizableY:false,stretchPorts:true});const r=[],s=[],i=16;let o=null,l=[];t.onTriggered=p;n.onTriggered=h;n.setUiAttribs({hideParam:true,hidePort:true});for(let t=0;t0)l.push(s[e])}function c(){u();clearTimeout(o);o=setTimeout(()=>{let t=false;for(let e=0;e1)t=true;n.setUiAttribs({hideParam:!t});if(a.isCurrentUiOp())a.refreshParams()},60)}function p(){for(let e=0;e1)for(let e=1;e0)r++;t.push(s[n].links[e]);const i=s[n].links[e].getOtherPort(s[n]);a.patch.link(a,"trigger "+r,i.op,i.name);r++}for(let e=0;et.left&&e.clientXt.top&&e.clientY0)E(e.touches[0])}function U(e){h.set(true);if(e.touches&&e.touches.length>0)_(e.touches[0])}function R(e){h.set(false);A()}function P(){if(!b)return;b.removeEventListener("touchend",R);b.removeEventListener("touchstart",U);b.removeEventListener("touchmove",N);b.removeEventListener("click",T);b.removeEventListener("mousemove",L);b.removeEventListener("mouseleave",I);b.removeEventListener("mousedown",_);b.removeEventListener("mouseup",A);b.removeEventListener("mouseenter",O);b.removeEventListener("contextmenu",C);b=null}function M(){if(b||!o.get())P();if(!o.get())return;b=y=m.canvas;if(i.get()=="Canvas Area"){y=m.canvas.parentElement;b=document.body}if(i.get()=="Document")y=b=document.body;if(i.get()=="Parent Element")b=y=m.canvas.parentElement;let e=false;if(s.get())e={passive:true};if(r.get()){b.addEventListener("touchend",R,e);b.addEventListener("touchstart",U,e);b.addEventListener("touchmove",N,e)}b.addEventListener("mousemove",L,e);b.addEventListener("mouseleave",I,e);b.addEventListener("mousedown",_,e);b.addEventListener("mouseup",A,e);b.addEventListener("mouseenter",O,e);b.addEventListener("contextmenu",C,e);b.addEventListener("click",T,e)}};Ops.Devices.Mouse.Mouse_v3.prototype=new CABLES.Op;CABLES.OPS["6d1edbc0-088a-43d7-9156-918fb3d7f24b"]={f:Ops.Devices.Mouse.Mouse_v3,objName:"Ops.Devices.Mouse.Mouse_v3"};Ops.Math.DeltaSum=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const o=e.inValue("Delta Value"),n=e.inValue("Default Value",0),l=e.inValue("Multiply",1),r=e.inTriggerButton("Reset"),a=e.inValueBool("Limit",false),u=e.inValue("Min",0),c=e.inValue("Max",100),p=e.inValue("Rubberband",0),s=e.outNumber("Absolute Value");o.changeAlways=true;e.setPortGroup("Limit",[a,u,c,p]);let h=0;let f=CABLES.now();let d=null;a.onChange=g;n.onChange=r.onTriggered=i;c.onChange=u.onChange=v;g();function i(){let e=n.get();if(a.get()){e=Math.max(u.get(),e);e=Math.min(c.get(),e)}h=e;s.set(h)}function g(){u.setUiAttribs({greyout:!a.get()});c.setUiAttribs({greyout:!a.get()});p.setUiAttribs({greyout:!a.get()});v()}function m(){const e=u.get();const t=c.get();if(ht)h=t;s.set(h)}function v(){if(a.get()){const e=u.get();const t=c.get();const n=p.get();const r=u.get()-n;const i=c.get()+n;if(hi)h=i;if(n!==0){clearTimeout(d);d=setTimeout(m.bind(this),300)}}s.set(h)}o.onChange=function(){let e=o.get();const t=p.get();if(t!==0){const n=u.get();const r=c.get();const i=u.get()-t;const a=c.get()+t;if(hr){const s=Math.abs(a-h)/t;e*=s*s}}f=CABLES.now();h+=e*l.get();v()}};Ops.Math.DeltaSum.prototype=new CABLES.Op;CABLES.OPS["d9d4b3db-c24b-48da-b798-9e6230d861f7"]={f:Ops.Math.DeltaSum,objName:"Ops.Math.DeltaSum"};Ops.Ui.PatchInput=function(){CABLES.Op.apply(this,arguments);const i=this;const e=i.attachments={};const a=i.addOutPort(new CABLES.Port(i,"create port",CABLES.OP_PORT_TYPE_DYNAMIC));function s(){for(let e in i.patch.ops){if(i.patch.ops[e].patchId){if(i.patch.ops[e].patchId.get()==i.uiAttribs.subPatch){return i.patch.ops[e]}}}}a.onLinkChanged=()=>{const e=s();if(!a.links.length||!e||!e.addNewInPort)return;const t=a.links[0].getOtherPort(a);a.removeLinks();const n=e.addNewInPort(t);const r=gui.scene().link(t.parent,t.getName(),i,n);e.saveData()}};Ops.Ui.PatchInput.prototype=new CABLES.Op;CABLES.OPS["e3f68bc3-892a-4c78-9974-aca25c27025d"]={f:Ops.Ui.PatchInput,objName:"Ops.Ui.PatchInput"};Ops.Ui.PatchOutput=function(){CABLES.Op.apply(this,arguments);const i=this;const e=i.attachments={};const a=i.addInPort(new CABLES.Port(i,"create port",CABLES.OP_PORT_TYPE_DYNAMIC));function s(){for(let e in i.patch.ops){if(i.patch.ops[e].patchId){if(i.patch.ops[e].patchId.get()==i.uiAttribs.subPatch){return i.patch.ops[e]}}}}a.onLinkChanged=()=>{const e=s();if(!a.links.length)return;const t=a.links[0].getOtherPort(a);a.removeLinks();const n=e.addNewOutPort(t);const r=gui.scene().link(t.parent,t.getName(),i,n);e.saveData()}};Ops.Ui.PatchOutput.prototype=new CABLES.Op;CABLES.OPS["851b44cb-5667-4140-9800-5aeb7031f1d7"]={f:Ops.Ui.PatchOutput,objName:"Ops.Ui.PatchOutput"};Ops.Ui.SubPatch=function(){CABLES.Op.apply(this,arguments);const u=this;const e=u.attachments={};u.dyn=u.addInPort(new CABLES.Port(u,"create port",CABLES.OP_PORT_TYPE_DYNAMIC));u.dynOut=u.addOutPort(new CABLES.Port(u,"create port out",CABLES.OP_PORT_TYPE_DYNAMIC));const t=u.addInPort(new CABLES.Port(u,"dataStr",CABLES.OP_PORT_TYPE_VALUE,{display:"readonly"}));u.patchId=u.addInPort(new CABLES.Port(u,"patchId",CABLES.OP_PORT_TYPE_VALUE,{display:"readonly"}));t.setUiAttribs({hideParam:true});u.patchId.setUiAttribs({hidePort:true});let c={ports:[],portsOut:[]};let n=CABLES.generateUUID();u.patchId.set(n);d();f();let p=false;u.saveData=s;u.init=()=>{u.setStorage({subPatchVer:1})};u.patchId.onChange=function(){if(!u.patch.isEditorMode())return;const t=u.patch.getSubPatchOps(n);if(t.length===2){if(u.patch.isEditorMode()&&CABLES.UI.DEFAULTOPS.isInBlueprint(u))CABLES.UI.undo.pause();for(let e=0;e=0;e--){if(u.patch.ops[e]&&u.patch.ops[e].uiAttribs&&u.patch.ops[e].uiAttribs.subPatch==u.patchId.get()){u.patch.deleteOp(u.patch.ops[e].id)}}};u.rebuildListeners=()=>{u.log("rebuild listeners...");const t=f();for(let e=0;et.left&&e.clientXt.top&&e.clientY{r.varName.set(e);r.patch.namedTriggers[e]=r.patch.namedTriggers[e]||[];n()}});return}r.refreshParams()}if(!r.patch.namedTriggers[r.varName.get()]){r.patch.namedTriggers[r.varName.get()]=r.patch.namedTriggers[r.varName.get()]||[];r.patch.emitEvent("namedTriggersChanged")}r.setTitle(">"+r.varName.get());r.refreshParams();r.patch.emitEvent("opTriggerNameChanged",r,r.varName.get())}function a(){const t=r.patch.namedTriggers[r.varName.get()];r.patch.emitEvent("namedTriggerSent",r.varName.get());if(!t){r.setUiError("unknowntrigger","unknown trigger");return}else r.setUiError("unknowntrigger",null);for(let e=0;et.minX&&e.pos[0]t.minY&&e.pos[1]t.minZ&&e.pos[2]e.maxX)i-=(t.pos[0]-e.maxX)**2;if(t.pos[1]e.maxY)i-=(t.pos[1]-e.maxY)**2;if(t.pos[2]e.maxZ)i-=(t.pos[2]-e.maxZ)**2;if(i>0){return{body0:a,name0:a.name,body1:s,name1:s.name}}}else{console.warn("unknown collision pair...",a.type,s.type)}}function f(){const n=[];const r=o.frameStore.collisionWorld.bodies;for(let t=0;t0){const c=(-o-Math.sqrt(u))/(2+i);if(cb)continue;r=true;E.set(s.name);I.set(true);vec3.mul(P,k,[v,v,v]);vec3.add(P,P,t);L.set(P[0]);N.set(P[1]);U.set(P[2])}}if(!r){E.set("");I.set(false);L.set(0);N.set(0);U.set(0)}}}};Ops.Graphics.Intersection.IntersectTestRaycast.prototype=new CABLES.Op;CABLES.OPS["dd5d9b39-75c2-40b1-98a4-7a0fdafdb5cb"]={f:Ops.Graphics.Intersection.IntersectTestRaycast,objName:"Ops.Graphics.Intersection.IntersectTestRaycast"};Ops.Graphics.Intersection.IntersectBody=function(){CABLES.Op.apply(this,arguments);const a=this;const e=a.attachments={};const t=["Sphere","BoxAA","Point"],n=a.inTrigger("Trigger"),r=a.inSwitch("Shape",t,"Sphere"),s=a.inString("Name",""),o=a.inFloat("Radius",.5),l=a.inFloat("Size X",1),u=a.inFloat("Size Y",1),c=a.inFloat("Size Z",1),p=a.inArray("Positions",null,3),h=a.inBool("Append Index to name",true),f=a.outTrigger("Next");a.setPortGroup("Array",[p,h]);const d=a.patch.cgl;const i=vec3.create();const g=vec3.create();y();let m=[];let v={name:"???",type:1};n.onTriggered=C;function b(){return{name:v.name,type:v.type}}r.onChange=()=>{v.type=t.indexOf(r.get())+1;y()};function y(){o.setUiAttribs({greyout:r.get()!="Sphere"});l.setUiAttribs({greyout:r.get()!="BoxAA"});u.setUiAttribs({greyout:r.get()!="BoxAA"});c.setUiAttribs({greyout:r.get()!="BoxAA"})}function x(e){e.minX=e.pos[0]-e.size[0]/2;e.maxX=e.pos[0]+e.size[0]/2;e.minY=e.pos[1]-e.size[1]/2;e.maxY=e.pos[1]+e.size[1]/2;e.minZ=e.pos[2]-e.size[2]/2;e.maxZ=e.pos[2]+e.size[2]/2}const S=1;const O=2;const _=3;function A(e){if(!CABLES.UI)return;if(!d.shouldDrawHelpers(a))return;if(e.type===S){d.pushModelMatrix();CABLES.UI.OverlayMeshes.drawSphere(a,e.radius,true);d.popModelMatrix()}else if(e.type===O){d.pushModelMatrix();CABLES.UI.OverlayMeshes.drawCube(a,e.size[0]/2,e.size[1]/2,e.size[2]/2);d.popModelMatrix()}else if(e.type===_){d.pushModelMatrix();CABLES.UI.OverlayMeshes.drawAxisMarker(a,.05);d.popModelMatrix()}else console.warn("[intersectWorld] unknown col shape")}function C(){if(!d.frameStore||!d.frameStore.collisionWorld)return;const t=a.patch.cgl;const n=p.get();const r=o.get();if(n&&n.length>0&&n.length%3==0){m.length=n.length/3;for(let e=0;e"+r.varName.get());r.patch.namedTriggers[r.varName.get()]=r.patch.namedTriggers[r.varName.get()]||[];let e=r.patch.namedTriggers[r.varName.get()];e.push(i);n=r.varName.get();s();r.patch.emitEvent("opTriggerNameChanged",r,r.varName.get())};r.on("uiParamPanel",s);function s(){if(!r.varName.get()){r.setUiError("unknowntrigger","unknown trigger")}else r.setUiError("unknowntrigger",null)}};Ops.Trigger.TriggerReceive.prototype=new CABLES.Op;CABLES.OPS["0816c999-f2db-466b-9777-2814573574c5"]={f:Ops.Trigger.TriggerReceive,objName:"Ops.Trigger.TriggerReceive"};Ops.Gl.Matrix.Translate=function(){CABLES.Op.apply(this,arguments);const t=this;const e=t.attachments={};const n=t.inTrigger("render"),r=t.outTrigger("trigger"),i=t.inValue("x"),a=t.inValue("y"),s=t.inValue("z");const o=vec3.create();n.onTriggered=function(){const e=t.patch.cg;vec3.set(o,i.get(),a.get(),s.get());e.pushModelMatrix();mat4.translate(e.mMatrix,e.mMatrix,o);r.trigger();e.popModelMatrix()}};Ops.Gl.Matrix.Translate.prototype=new CABLES.Op;CABLES.OPS["1f89ba0e-e7eb-46d7-8c66-7814b7c528b9"]={f:Ops.Gl.Matrix.Translate,objName:"Ops.Gl.Matrix.Translate"};Ops.Trigger.Repeat2d=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inTrigger("exe"),s=e.inValueInt("num x",5),o=e.inValueInt("num y",5),l=e.inValueFloat("mul",1),u=e.inValueBool("center"),c=e.outTrigger("trigger"),p=e.outNumber("x"),h=e.outNumber("y"),f=e.outNumber("index"),d=e.outNumber("total iterations");n.onTriggered=function(){let n=0;let e=0;const r=l.get();const i=s.get();const a=o.get();if(u.get()){n=(i-1)*r/2;e=(a-1)*r/2}for(let t=0;tJ){e=L;T%=L}else T%=L;I%=Math.PI;vec3.set(g,0,0,0);vec3.set(f,0,0,0);vec3.set(h,0,1,0);x=r.get()*Math.PI*2+e;S=n.get()-.5;v=t.get();p=R(S)}function ee(){Q=e.get()*10+1}e.onChange=ee;let te=true;function N(e,t){if(te)return t;return e+(t-e)/Q}let U=0;const ne=0;B.onTriggered=function(){const e=i.patch.cg;if(!E){ce(e.canvas);pe()}e.pushViewMatrix();T=N(T,x);I=N(I,S);let t=(I+.5)*180;if(o.get()!==0&&tl.get()){t=l.get();I=U}else{U=I}const n=T*CGL.RAD2DEG;W.set(t);Y.set(n);re(p,I);vec3.add(O,p,g);vec3.add(A,f,g);_[0]=N(_[0],O[0]);_[1]=N(_[1],O[1]);_[2]=N(_[2],O[2]);C[0]=N(C[0],A[0]);C[1]=N(C[1],A[1]);C[2]=N(C[2],A[2]);const r=vec3.create();mat4.lookAt(d,_,C,h);mat4.rotate(d,d,T,h);mat4.multiply(e.vMatrix,e.vMatrix,d);X.trigger();e.popViewMatrix();te=false};function re(e,t){const n=u.get();if(vs.get()*n)v=s.get()*n;c.set(v*n);let r=0,i=0;i=360*t/2*CGL.DEG2RAD;vec3.set(e,Math.cos(i)*v*n,Math.sin(i)*v*n,0);return e}function R(e){const t=u.get();if(vs.get()*t)v=s.get()*t;c.set(v*t);let n=0,r=0;const i=vec3.create();r=360*e/2*CGL.DEG2RAD;vec3.set(i,Math.cos(r)*v*t,Math.sin(r)*v*t,0);return i}function P(e){if(!m)return;const t=e.clientX;const n=e.clientY;let r=t-b;let i=n-y;r*=G.get();i*=V.get();if(e.buttons==2&&F.get()){g[2]+=r*.01*u.get();g[1]+=i*.01*u.get()}else if(e.buttons==4&&j.get()){v+=i*.05;p=R(S)}else{if(z.get()){x+=r*.003;S+=i*.002;if(H.get()){if(S>.5)S=.5;if(S<-.5)S=-.5}}}b=t;y=n}function M(e){b=e.clientX;y=e.clientY;m=true;try{E.setPointerCapture(e.pointerId)}catch(e){}}function k(e){m=false;try{E.releasePointerCapture(e.pointerId)}catch(e){}}function ie(){const e=i.patch.cg.canvas;if(document.pointerLockElement===e||document.mozPointerLockElement===e||document.webkitPointerLockElement===e){document.addEventListener("mousemove",P,false)}}function ae(e){}t.onChange=function(){v=t.get();$()};r.onChange=function(){T=x=r.get()*Math.PI*2};n.onChange=function(){I=S=n.get()-.5;p=R(S)};const se=function(e){if(j.get()){const t=CGL.getWheelSpeed(e)*.06;v+=parseFloat(t)*1.2;p=R(S)}};const oe=function(e){if(e.touches&&e.touches.length>0)M(e.touches[0])};const le=function(e){k()};const ue=function(e){if(e.touches&&e.touches.length>0)P(e.touches[0])};D.onChange=function(){if(D.get())pe();else he()};function ce(e){he();E=e;pe()}function pe(){if(!E)return;E.addEventListener("pointermove",P);E.addEventListener("pointerdown",M);E.addEventListener("pointerup",k);E.addEventListener("pointerleave",k);E.addEventListener("pointerenter",ae);E.addEventListener("contextmenu",function(e){e.preventDefault()});E.addEventListener("wheel",se,{passive:true})}function he(){if(!E)return;E.removeEventListener("pointermove",P);E.removeEventListener("pointerdown",M);E.removeEventListener("pointerup",k);E.removeEventListener("pointerleave",k);E.removeEventListener("pointerenter",k);E.removeEventListener("wheel",se)}p=R(0);r.set(.25);t.set(.05)};Ops.Gl.Matrix.OrbitControls.prototype=new CABLES.Op;CABLES.OPS["eaf4f7ce-08a3-4d1b-b9f4-ebc0b7b1cde1"]={f:Ops.Gl.Matrix.OrbitControls,objName:"Ops.Gl.Matrix.OrbitControls"};Ops.Gl.Shader.BasicMaterial_v3=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={basicmaterial_frag:"{{MODULES_HEAD}}\n\nIN vec2 texCoord;\n\n#ifdef VERTEX_COLORS\nIN vec4 vertCol;\n#endif\n\n#ifdef HAS_TEXTURES\n IN vec2 texCoordOrig;\n #ifdef HAS_TEXTURE_DIFFUSE\n UNI sampler2D tex;\n #endif\n #ifdef HAS_TEXTURE_OPACITY\n UNI sampler2D texOpacity;\n #endif\n#endif\n\n\n\nvoid main()\n{\n {{MODULE_BEGIN_FRAG}}\n vec4 col=color;\n\n\n #ifdef HAS_TEXTURES\n vec2 uv=texCoord;\n\n #ifdef CROP_TEXCOORDS\n if(uv.x<0.0 || uv.x>1.0 || uv.y<0.0 || uv.y>1.0) discard;\n #endif\n\n #ifdef HAS_TEXTURE_DIFFUSE\n col=texture(tex,uv);\n\n #ifdef COLORIZE_TEXTURE\n col.r*=color.r;\n col.g*=color.g;\n col.b*=color.b;\n #endif\n #endif\n col.a*=color.a;\n #ifdef HAS_TEXTURE_OPACITY\n #ifdef TRANSFORMALPHATEXCOORDS\n uv=texCoordOrig;\n #endif\n #ifdef ALPHA_MASK_IR\n col.a*=1.0-texture(texOpacity,uv).r;\n #endif\n #ifdef ALPHA_MASK_IALPHA\n col.a*=1.0-texture(texOpacity,uv).a;\n #endif\n #ifdef ALPHA_MASK_ALPHA\n col.a*=texture(texOpacity,uv).a;\n #endif\n #ifdef ALPHA_MASK_LUMI\n col.a*=dot(vec3(0.2126,0.7152,0.0722), texture(texOpacity,uv).rgb);\n #endif\n #ifdef ALPHA_MASK_R\n col.a*=texture(texOpacity,uv).r;\n #endif\n #ifdef ALPHA_MASK_G\n col.a*=texture(texOpacity,uv).g;\n #endif\n #ifdef ALPHA_MASK_B\n col.a*=texture(texOpacity,uv).b;\n #endif\n // #endif\n #endif\n #endif\n\n {{MODULE_COLOR}}\n\n #ifdef DISCARDTRANS\n if(col.a<0.2) discard;\n #endif\n\n #ifdef VERTEX_COLORS\n col*=vertCol;\n #endif\n\n outColor = col;\n}\n",basicmaterial_vert:"\n{{MODULES_HEAD}}\n\nOUT vec2 texCoord;\nOUT vec2 texCoordOrig;\n\nUNI mat4 projMatrix;\nUNI mat4 modelMatrix;\nUNI mat4 viewMatrix;\n\n#ifdef HAS_TEXTURES\n UNI float diffuseRepeatX;\n UNI float diffuseRepeatY;\n UNI float texOffsetX;\n UNI float texOffsetY;\n#endif\n\n#ifdef VERTEX_COLORS\n in vec4 attrVertColor;\n out vec4 vertCol;\n\n#endif\n\n\nvoid main()\n{\n mat4 mMatrix=modelMatrix;\n mat4 modelViewMatrix;\n\n norm=attrVertNormal;\n texCoordOrig=attrTexCoord;\n texCoord=attrTexCoord;\n #ifdef HAS_TEXTURES\n texCoord.x=texCoord.x*diffuseRepeatX+texOffsetX;\n texCoord.y=(1.0-texCoord.y)*diffuseRepeatY+texOffsetY;\n #endif\n\n #ifdef VERTEX_COLORS\n vertCol=attrVertColor;\n #endif\n\n vec4 pos = vec4(vPosition, 1.0);\n\n #ifdef BILLBOARD\n vec3 position=vPosition;\n modelViewMatrix=viewMatrix*modelMatrix;\n\n gl_Position = projMatrix * modelViewMatrix * vec4((\n position.x * vec3(\n modelViewMatrix[0][0],\n modelViewMatrix[1][0],\n modelViewMatrix[2][0] ) +\n position.y * vec3(\n modelViewMatrix[0][1],\n modelViewMatrix[1][1],\n modelViewMatrix[2][1]) ), 1.0);\n #endif\n\n {{MODULE_VERTEX_POSITION}}\n\n #ifndef BILLBOARD\n modelViewMatrix=viewMatrix * mMatrix;\n\n {{MODULE_VERTEX_MOVELVIEW}}\n\n #endif\n\n // mat4 modelViewMatrix=viewMatrix*mMatrix;\n\n #ifndef BILLBOARD\n // gl_Position = projMatrix * viewMatrix * modelMatrix * pos;\n gl_Position = projMatrix * modelViewMatrix * pos;\n #endif\n}\n"};const n=e.inTrigger("render");const r=e.outTrigger("trigger");const i=e.outObject("shader",null,"shader");i.ignoreValueSerialize=true;e.toWorkPortsNeedToBeLinked(n);e.toWorkShouldNotBeChild("Ops.Gl.TextureEffects.ImageCompose",CABLES.OP_PORT_TYPE_FUNCTION);const a=e.patch.cgl;const s=new CGL.Shader(a,"basicmaterialnew",this);s.addAttribute({type:"vec3",name:"vPosition"});s.addAttribute({type:"vec2",name:"attrTexCoord"});s.addAttribute({type:"vec3",name:"attrVertNormal",nameFrag:"norm"});s.addAttribute({type:"float",name:"attrVertIndex"});s.setModules(["MODULE_VERTEX_POSITION","MODULE_COLOR","MODULE_BEGIN_FRAG","MODULE_VERTEX_MOVELVIEW"]);s.setSource(t.basicmaterial_vert,t.basicmaterial_frag);i.setRef(s);n.onTriggered=I;const o=e.inValueSlider("r",Math.random());const l=e.inValueSlider("g",Math.random());const u=e.inValueSlider("b",Math.random());const c=e.inValueSlider("a",1);o.setUiAttribs({colorPick:true});const p=s.addUniformFrag("4f","color",o,l,u,c);s.uniformColorDiffuse=p;const h=e.inTexture("texture");let f=null;h.onChange=L;const d=e.inValueBool("colorizeTexture",false);const g=e.inValueBool("Vertex Colors",false);const m=e.inTexture("textureOpacity");let v=null;const b=e.inSwitch("Alpha Mask Source",["Luminance","R","G","B","A","1-A","1-R"],"Luminance");b.setUiAttribs({greyout:true});m.onChange=E;const y=e.inValueBool("Opacity TexCoords Transform",false);const x=e.inValueBool("Discard Transparent Pixels");const S=e.inValue("diffuseRepeatX",1),O=e.inValue("diffuseRepeatY",1),_=e.inValue("Tex Offset X",0),A=e.inValue("Tex Offset Y",0),C=e.inBool("Crop TexCoords",false);s.addUniformFrag("f","diffuseRepeatX",S);s.addUniformFrag("f","diffuseRepeatY",O);s.addUniformFrag("f","texOffsetX",_);s.addUniformFrag("f","texOffsetY",A);const T=e.inValueBool("billboard",false);b.onChange=T.onChange=x.onChange=y.onChange=C.onChange=g.onChange=d.onChange=U;e.setPortGroup("Color",[o,l,u,c]);e.setPortGroup("Color Texture",[h,g,d]);e.setPortGroup("Opacity",[m,b,x,y]);e.setPortGroup("Texture Transform",[S,O,_,A,C]);E();L();e.preRender=function(){s.bind();I()};function I(){if(!s)return;a.pushShader(s);s.popTextures();if(f&&h.get())s.pushTexture(f,h.get());if(v&&m.get())s.pushTexture(v,m.get());r.trigger();a.popShader()}function E(){if(m.get()){if(v!==null)return;s.removeUniform("texOpacity");s.define("HAS_TEXTURE_OPACITY");if(!v)v=new CGL.Uniform(s,"t","texOpacity")}else{s.removeUniform("texOpacity");s.removeDefine("HAS_TEXTURE_OPACITY");v=null}U()}function L(){if(h.get()){if(!s.hasDefine("HAS_TEXTURE_DIFFUSE"))s.define("HAS_TEXTURE_DIFFUSE");if(!f)f=new CGL.Uniform(s,"t","texDiffuse")}else{s.removeUniform("texDiffuse");s.removeDefine("HAS_TEXTURE_DIFFUSE");f=null}N()}function N(){const e=h.isLinked()||m.isLinked();S.setUiAttribs({greyout:!e});O.setUiAttribs({greyout:!e});_.setUiAttribs({greyout:!e});A.setUiAttribs({greyout:!e});d.setUiAttribs({greyout:!e});b.setUiAttribs({greyout:!m.get()});y.setUiAttribs({greyout:!m.get()});let t=true;t=h.get()&&!d.get();o.setUiAttribs({greyout:t});l.setUiAttribs({greyout:t});u.setUiAttribs({greyout:t})}function U(){s.toggleDefine("VERTEX_COLORS",g.get());s.toggleDefine("CROP_TEXCOORDS",C.get());s.toggleDefine("COLORIZE_TEXTURE",d.get());s.toggleDefine("TRANSFORMALPHATEXCOORDS",y.get());s.toggleDefine("DISCARDTRANS",x.get());s.toggleDefine("BILLBOARD",T.get());s.toggleDefine("ALPHA_MASK_ALPHA",b.get()=="A");s.toggleDefine("ALPHA_MASK_IALPHA",b.get()=="1-A");s.toggleDefine("ALPHA_MASK_IR",b.get()=="1-R");s.toggleDefine("ALPHA_MASK_LUMI",b.get()=="Luminance");s.toggleDefine("ALPHA_MASK_R",b.get()=="R");s.toggleDefine("ALPHA_MASK_G",b.get()=="G");s.toggleDefine("ALPHA_MASK_B",b.get()=="B");N()}};Ops.Gl.Shader.BasicMaterial_v3.prototype=new CABLES.Op;CABLES.OPS["ec55d252-3843-41b1-b731-0482dbd9e72b"]={f:Ops.Gl.Shader.BasicMaterial_v3,objName:"Ops.Gl.Shader.BasicMaterial_v3"};Ops.Math.Ease=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inValue("Value"),r=e.inValue("Min",0),i=e.inValue("Max",1),a=e.outNumber("Result"),s=new CABLES.Anim;s.createPort(e,"Easing",l);s.setValue(0,0);s.setValue(1,1);e.onLoaded=r.onChange=i.onChange=o;function o(){s.keys[0].time=s.keys[0].value=Math.min(r.get(),i.get());s.keys[1].time=s.keys[1].value=Math.max(r.get(),i.get())}function l(){s.keys[0].setEasing(s.defaultEasing)}n.onChange=function(){const e=s.getValue(n.get());a.set(e)}};Ops.Math.Ease.prototype=new CABLES.Op;CABLES.OPS["8f6e4a08-33e6-408f-ac4a-198bd03b417b"]={f:Ops.Math.Ease,objName:"Ops.Math.Ease"};Ops.Devices.Browser.JsMemory=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inTrigger("Update"),r=e.outNumber("Used Heap Size",0),i=e.outNumber("Total Heap Size",0);if(performance.memory&&performance.memory.usedJSHeapSize)n.onTriggered=a;function a(){r.set(performance.memory.usedJSHeapSize/1024/1024);i.set(performance.memory.totalJSHeapSize/1024/1024)}};Ops.Devices.Browser.JsMemory.prototype=new CABLES.Op;CABLES.OPS["7176f9c7-1ee8-419e-b58b-178cca9265e7"]={f:Ops.Devices.Browser.JsMemory,objName:"Ops.Devices.Browser.JsMemory"};Ops.Gl.Meshes.Cylinder_v2=function(){CABLES.Op.apply(this,arguments);const _=this;const e=_.attachments={};const t=_.inTrigger("render"),n=_.inValueBool("Draw",true),A=_.inValueInt("segments",40),C=_.inValueInt("stacks",1),T=_.inValueFloat("length",1),I=_.inValueFloat("outer radius",.5),E=_.inValueFloat("inner radius",0),L=_.inValueSelect("UV mode",["simple","atlas"],"simple"),N=_.inValueBool("Flip Mapping",false),U=_.inValueBool("Caps",true),R=_.inValueBool("Flat Normals",false),r=_.outTrigger("next"),P=_.outObject("geometry"),M=new CGL.Geometry("cylinder");n.setUiAttribs({title:"Render mesh"});const k=Math.PI*2,i=_.patch.cgl;let w=true;let B=null;L.setUiAttribs({hidePort:true});_.preRender=a;function a(){const e=N.get();const t=Math.max(A.get(),3)|0,n=Math.max(E.get(),0),r=Math.max(I.get(),n),i=Math.max(C.get(),C.defaultValue)|0,a=T.get(),s=a/i,o=k/t,l=L.get();let u=[],c=[],p=[],h=[],f=[],d=[],g,m,v,b,y,x,S,O;if(l=="atlas")O=.5;else O=1;for(b=0,v=-a/2;b<=i;b++,v+=s){for(y=x=0;y<=t;y++,x+=o){u.push((g=Math.sin(x))*r,(m=Math.cos(x))*r,v);S=Math.sqrt(g*g+m*m);g/=S;m/=S;c.push(g,m,0);p.push(-m,g,0);h.push(0,0,1);if(e)f.push(y/t,1-(v/a+.5)*O);else f.push((v/a+.5)*O,y/t)}}for(y=0;y1){m.set(false);v.set(true);const r=a.get();i.setUiAttrib({extendTitle:CABLES.basename(t)});if(n)i.refreshParams();b.patch.loading.addAssetLoadingTask(()=>{i.setUiError("urlerror",null);CGL.Texture.load(b,t,function(e,t){b.checkFrameStarted("texture inittexture");if(a.get()!=r){b.patch.loading.finished(x);x=null;return}if(S)S.delete();if(e){const n=CGL.Texture.getErrorTexture(b);p.setRef(n);i.setUiError("urlerror",'could not load texture: "'+a.get()+'"',2);b.patch.loading.finished(x);x=null;return}f.set(t.width);d.set(t.height);g.set(t.width/t.height);S=t;p.setRef(S);v.set(false);m.set(true);if(c.get())S.image=null;if(x){b.patch.loading.finished(x);x=null}i.checkMainloopExists()},{anisotropic:A,wrap:_,flip:o.get(),unpackAlpha:l.get(),pixelFormat:E(),filter:O});i.checkMainloopExists()})}else{b.patch.loading.finished(x);x=null;T()}}function N(){if(t.get()=="nearest")O=CGL.Texture.FILTER_NEAREST;else if(t.get()=="linear")O=CGL.Texture.FILTER_LINEAR;else if(t.get()=="mipmap")O=CGL.Texture.FILTER_MIPMAP;else if(t.get()=="Anisotropic")O=CGL.Texture.FILTER_ANISOTROPIC;r.setUiAttribs({greyout:O!=CGL.Texture.FILTER_MIPMAP});A=parseFloat(r.get());I()}function U(){if(n.get()=="repeat")_=CGL.Texture.WRAP_REPEAT;if(n.get()=="mirrored repeat")_=CGL.Texture.WRAP_MIRRORED_REPEAT;if(n.get()=="clamp to edge")_=CGL.Texture.WRAP_CLAMP_TO_EDGE;I()}i.onFileChanged=function(e){if(a.get()&&a.get().indexOf(e)>-1){p.set(CGL.Texture.getEmptyTexture(i.patch.cgl));p.set(CGL.Texture.getTempTexture(b));L(true)}}};Ops.Gl.Texture_v2.prototype=new CABLES.Op;CABLES.OPS["790f3702-9833-464e-8e37-6f0f813f7e16"]={f:Ops.Gl.Texture_v2,objName:"Ops.Gl.Texture_v2"};Ops.Gl.RenderToTexture_v3=function(){CABLES.Op.apply(this,arguments);const i=this;const e=i.attachments={};const t=i.inTrigger("render"),n=i.inSwitch("Size",["Canvas","Manual"],"Canvas"),r=i.inValueInt("texture width",512),a=i.inValueInt("texture height",512),s=i.inBool("Auto Aspect",true),o=i.inSwitch("filter",["nearest","linear","mipmap"],"linear"),l=i.inSwitch("Wrap",["Clamp","Repeat","Mirror"],"Repeat"),u=i.inSwitch("MSAA",["none","2x","4x","8x"],"none"),c=i.outTrigger("trigger"),p=i.outTexture("texture"),h=i.outTexture("textureDepth"),f=i.inDropDown("Pixel Format",CGL.Texture.PIXELFORMATS,CGL.Texture.PFORMATSTR_RGBA8UB),d=i.inValueBool("Depth",true),g=i.inValueBool("Clear",true);const m=i.patch.cgl;let v=null;let b=true;i.setPortGroup("Size",[n,r,a,s]);f.onChange=d.onChange=g.onChange=o.onChange=l.onChange=u.onChange=x;n.onChange=y;t.onTriggered=i.preRender=S;y();function y(){r.setUiAttribs({greyout:n.get()!="Manual"});a.setUiAttribs({greyout:n.get()!="Manual"});s.setUiAttribs({greyout:n.get()!="Manual"})}function x(){b=true}function S(){CGL.TextureEffect.checkOpNotInTextureEffect(i);if(!v||b){if(v)v.delete();let n=CGL.Texture.WRAP_REPEAT;if(l.get()=="Clamp")n=CGL.Texture.WRAP_CLAMP_TO_EDGE;else if(l.get()=="Mirror")n=CGL.Texture.WRAP_MIRRORED_REPEAT;let r=CGL.Texture.FILTER_NEAREST;if(o.get()=="nearest")r=CGL.Texture.FILTER_NEAREST;else if(o.get()=="linear")r=CGL.Texture.FILTER_LINEAR;else if(o.get()=="mipmap")r=CGL.Texture.FILTER_MIPMAP;if(f.get().indexOf("loat")&&o.get()=="mipmap")i.setUiError("fpmipmap","Can't use mipmap and float texture at the same time");else i.setUiError("fpmipmap",null);if(m.glVersion>=2){let e=true;let t=4;if(u.get()=="none"){t=0;e=false}if(u.get()=="2x")t=2;if(u.get()=="4x")t=4;if(u.get()=="8x")t=8;v=new CGL.Framebuffer2(m,8,8,{name:"render2texture "+i.id,pixelFormat:f.get(),multisampling:e,multisamplingSamples:t,wrap:n,filter:r,depth:d.get(),clear:g.get()})}else{v=new CGL.Framebuffer(m,8,8,{isFloatingPointTexture:false,clear:g.get()})}if(v&&v.valid){h.set(v.getTextureDepth());b=false}else{v=null;b=true}}let e=s.get();if(n.get()=="Canvas"){e=true;r.set(i.patch.cgl.checkTextureSize(m.canvasWidth));a.set(i.patch.cgl.checkTextureSize(m.canvasHeight))}if(v.getWidth()!=i.patch.cgl.checkTextureSize(r.get())||v.getHeight()!=i.patch.cgl.checkTextureSize(a.get())){v.setSize(i.patch.cgl.checkTextureSize(r.get()),i.patch.cgl.checkTextureSize(a.get()))}v.renderStart(m);m.pushViewPort(0,0,r.get(),a.get());if(e)mat4.perspective(m.pMatrix,45,r.get()/a.get(),.1,1e3);c.trigger();v.renderEnd(m);m.popViewPort();h.setRef(v.getTextureDepth());p.setRef(v.getTextureColor())}};Ops.Gl.RenderToTexture_v3.prototype=new CABLES.Op;CABLES.OPS["41eec5c7-c480-477a-be81-04c3efac8357"]={f:Ops.Gl.RenderToTexture_v3,objName:"Ops.Gl.RenderToTexture_v3"};Ops.Gl.Meshes.Rectangle_v4=function(){CABLES.Op.apply(this,arguments);const t=this;const e=t.attachments={};const n=t.inTrigger("render"),r=t.inValueBool("Render Mesh",true),I=t.inValue("width",1),E=t.inValue("height",1),L=t.inSwitch("pivot x",["left","center","right"],"center"),N=t.inSwitch("pivot y",["top","center","bottom"],"center"),U=t.inSwitch("axis",["xy","xz"],"xy"),R=t.inBool("Flip TexCoord X",false),P=t.inBool("Flip TexCoord Y",true),M=t.inValueInt("num columns",1),k=t.inValueInt("num rows",1),i=t.outTrigger("trigger"),w=t.outObject("geometry",null,"geometry");w.ignoreValueSerialize=true;const a=t.patch.cgl;const B=new CGL.Geometry("rectangle");r.setUiAttribs({title:"Render"});n.setUiAttribs({title:"Trigger"});i.setUiAttribs({title:"Next"});t.setPortGroup("Pivot",[L,N,U]);t.setPortGroup("Size",[I,E]);t.setPortGroup("Structure",[M,k]);t.toWorkPortsNeedToBeLinked(n);t.toWorkShouldNotBeChild("Ops.Gl.TextureEffects.ImageCompose",CABLES.OP_PORT_TYPE_TRIGGER);const G=0;const V=1;let D=G;let F=null;let j=true;let z=true;const s=vec3.create();vec3.set(s,1,1,1);U.onChange=L.onChange=N.onChange=R.onChange=P.onChange=k.onChange=M.onChange=o;H();I.onChange=E.onChange=()=>{if(z)H();else j=true};function H(){if(D===G)vec3.set(s,I.get(),E.get(),1);if(D===V)vec3.set(s,I.get(),1,E.get())}w.onLinkChanged=()=>{z=!w.isLinked();H();j=true};function o(){j=true}n.onTriggered=()=>{if(j)l();const e=t.patch.cg;if(F&&r.get()){if(z){e.pushModelMatrix();mat4.scale(e.mMatrix,e.mMatrix,s)}F.render(e.getShader());if(z)e.popModelMatrix()}i.trigger()};t.onDelete=()=>{if(F)F.dispose();o()};function l(){if(U.get()=="xy")D=G;if(U.get()=="xz")D=V;H();let n=I.get();let r=E.get();if(z)n=r=1;let i=0;let a=0;if(L.get()=="center")i=0;else if(L.get()=="right")i=-n/2;else if(L.get()=="left")i=+n/2;if(N.get()=="center")a=0;else if(N.get()=="top")a=-r/2;else if(N.get()=="bottom")a=+r/2;const s=Math.max(1,Math.round(k.get()));const o=Math.max(1,Math.round(M.get()));const l=n/o;const u=r/s;const c=[];const p=new Float32Array((o+1)*(s+1)*2);const h=new Float32Array((o+1)*(s+1)*3);const f=new Float32Array((o+1)*(s+1)*3);const d=new Float32Array((o+1)*(s+1)*3);const g=new Float32Array((o+1)*(s+1)*3);let m=0;let v=0;let b=0;let y=0;let x=0;for(let t=0;t<=s;t++){for(let e=0;e<=o;e++){h[v++]=e*l-n/2+i;if(D==V)h[v++]=0;h[v++]=t*u-r/2+a;if(D==G)h[v++]=0;p[m++]=e/o;p[m++]=t/s;if(D==G){f[b++]=0;f[b++]=0;f[b++]=1;d[y++]=1;d[y++]=0;d[y++]=0;g[x++]=0;g[x++]=1;g[x++]=0}else if(D==V){f[b++]=0;f[b++]=1;f[b++]=0;g[x++]=0;g[x++]=0;g[x++]=1}}}c.length=o*s*6;let S=0;for(let t=0;tf){e=f*1/n;t=f}l.pushViewPort((f-t)/2,(d-e)/2,t,e)}if(m){if(s.get())l.setTexture(0,s.get().tex);u.render(g)}else{u.render(l.getShader())}l.gl.clear(l.gl.DEPTH_BUFFER_BIT);l.popPMatrix();l.popModelMatrix();l.popViewMatrix();if(b&&s.get())l.popViewPort();o.trigger()}function _(){u=null}function A(){if(l.viewPort[2]==f&&l.viewPort[3]==d&&u)return;let e=0,t=0;f=l.viewPort[2];d=l.viewPort[3];c.vertices=new Float32Array([e+f,t+d,0,e,t+d,0,e+f,t,0,e,t,0]);let n=null;if(i.get())n=new Float32Array([1,0,0,0,1,1,0,1]);else n=new Float32Array([1,1,0,1,1,0,0,0]);if(a.get()){n[0]=0;n[2]=1;n[4]=0;n[6]=1}c.setTexCoords(n);c.verticesIndices=new Uint16Array([2,1,0,3,1,2]);c.vertexNormals=new Float32Array([0,0,1,0,0,1,0,0,1,0,0,1]);c.tangents=new Float32Array([-1,0,0,-1,0,0,-1,0,0,-1,0,0]);c.biTangents==new Float32Array([0,-1,0,0,-1,0,0,-1,0,0,-1,0]);if(!u)u=new CGL.Mesh(l,c);else u.setGeom(c)}};Ops.Gl.Meshes.FullscreenRectangle_v2.prototype=new CABLES.Op;CABLES.OPS["fb70721a-eac2-4ff5-a5a2-5c59e2393972"]={f:Ops.Gl.Meshes.FullscreenRectangle_v2,objName:"Ops.Gl.Meshes.FullscreenRectangle_v2"};Ops.Gl.GradientTexture=function(){CABLES.Op.apply(this,arguments);const n=this;const e=n.attachments={};const T=n.inGradient("Gradient"),I=n.inValueSelect("Direction",["X","Y","XY","YX","Radial"],"X"),E=n.inValueBool("Smoothstep",false),L=n.inBool("Step",false),N=n.inBool("Flip",false),U=n.inBool("sRGB",false),R=n.inBool("Oklab",false),P=n.inValueInt("Size",256),M=n.inSwitch("filter",["nearest","linear","mipmap"],"linear"),k=n.inValueSelect("wrap",["clamp to edge","repeat","mirrored repeat"],"clamp to edge"),r=n.inArray("Gradient Array"),t=n.inTriggerButton("Randomize Colors"),w=n.outTexture("Texture"),B=n.outArray("Colors",null,3),G=n.outArray("Colors Pos",null,1);const V=n.patch.cgl;let i=null;T.setUiAttribs({editShortcut:true});k.onChange=M.onChange=L.onChange=N.onChange=U.onChange=R.onChange=P.onChange=T.onChange=E.onChange=I.onChange=r.onChange=a;T.set('{"keys" : [{"pos":0,"r":0,"g":0,"b":0},{"pos":1,"r":1,"g":1,"b":1}]}');n.onLoaded=a;t.onTriggered=()=>{const e=s();if(e){e.forEach(e=>{e.r=Math.random();e.g=Math.random();e.b=Math.random()});const t=JSON.stringify({keys:e});T.set(t)}};function D(e,t,n){let r=.4122214708*e+.5363325363*t+.0514459929*n;let i=.2119034982*e+.6806995451*t+.1073969566*n;let a=.0883024619*e+.2817188376*t+.6299787005*n;r=Math.cbrt(r);i=Math.cbrt(i);a=Math.cbrt(a);return[r*+.2104542553+i*+.793617785+a*-.0040720468,r*+1.9779984951+i*-2.428592205+a*+.4505937099,r*+.0259040371+i*+.7827717662+a*-.808675766]}function F(e,t,n){let r=e+t*+.3963377774+n*+.2158037573;let i=e+t*-.1055613458+n*-.0638541728;let a=e+t*-.0894841775+n*-1.291485548;r**=3;i**=3;a**=3;let s=r*+4.0767416621+i*-3.3077115913+a*+.2309699292;let o=r*-1.2684380046+i*+2.6097574011+a*-.3413193965;let l=r*-.0041960863+i*-.7034186147+a*+1.707614701;s=CABLES.clamp(s,0,1);o=CABLES.clamp(o,0,1);l=CABLES.clamp(l,0,1);return[s,o,l]}function j(e,t,n){e/=255;const r=.0031308;let i=12.92*e;let a=1.055*Math.pow(e,.41666)-.055;return(e{const e=s();if(e)o(e)},5)}function s(){let t=null;n.setUiError("nodata",null);n.setUiError("parse",null);if(Array.isArray(r.get())){t=r.get()}else{let e=null;if(!T.get()||T.get()===""){return null}try{e=JSON.parse(T.get())}catch(e){n.setUiError("parse","could not parse gradient data")}if(!e||!e.keys){n.setUiError("nodata","gradient no data");return null}t=e.keys}return t}function o(t){let i=Math.round(P.get());if(i<4)i=4;T.setUiAttribs({editShortcut:true,gradEditSmoothstep:E.get(),gradEditStep:L.get(),gradOklab:R.get()});let e=0;let n=0;if(k.get()=="repeat")e=CGL.Texture.WRAP_REPEAT;else if(k.get()=="mirrored repeat")e=CGL.Texture.WRAP_MIRRORED_REPEAT;else if(k.get()=="clamp to edge")e=CGL.Texture.WRAP_CLAMP_TO_EDGE;if(M.get()=="nearest")n=CGL.Texture.FILTER_NEAREST;else if(M.get()=="linear")n=CGL.Texture.FILTER_LINEAR;else if(M.get()=="mipmap")n=CGL.Texture.FILTER_MIPMAP;const r=new CGL.Texture(V);let a=new Uint8Array(i*4);for(let e=0;e=i*4)t=i*4-4;_[r*4+n*4*i+0]=a[t+0];_[r*4+n*4*i+1]=a[t+1];_[r*4+n*4*i+2]=a[t+2];_[r*4+n*4*i+3]=Math.round(255)}}a=_;r.initFromData(a,i,i,n,e)}if(I.get()=="XY"||I.get()=="YX"){const _=new Uint8Array(i*i*4);for(let r=0;r{O=P();_=true};a.onLinkChanged=u.onLinkChanged=f.onLinkChanged=v.onLinkChanged=s.onChange=c.onChange=d.onChange=b.onChange=o.onChange=p.onChange=g.onChange=y.onChange=M;t.onChange=n.onChange=r.onChange=()=>{A=null};function P(){let n=4;let r=4;let i=[];if(t.get()=="Biggest"||t.get()=="Smallest"){if(a.get())i.push([a.get().width,a.get().height,a.get().width*a.get().height]);if(u.get())i.push([u.get().width,u.get().height,u.get().width*u.get().height]);if(f.get())i.push([f.get().width,f.get().height,f.get().width*f.get().height]);if(v.get())i.push([v.get().width,v.get().height,v.get().width*v.get().height])}if(t.get()=="Biggest"){let t=0;for(let e=0;et){n=i[e][0];r=i[e][1];t=i[e][2]}}}else if(t.get()=="Smallest"){let t=e.patch.cgl.gl.MAX_TEXTURE_SIZE+1;for(let e=0;e{if(!A||_&&!e.patch.cgl.frameStore.shadowPass){if(!A)V();A.bgShader.popTextures();if(a.get())A.bgShader.pushTexture(C,a.get().tex);else A.bgShader.pushTexture(C,CGL.Texture.getEmptyTexture(S).tex);if(u.get())A.bgShader.pushTexture(T,u.get().tex);else A.bgShader.pushTexture(T,CGL.Texture.getEmptyTexture(S).tex);if(f.get())A.bgShader.pushTexture(I,f.get().tex);else A.bgShader.pushTexture(I,CGL.Texture.getEmptyTexture(S).tex);if(v.get())A.bgShader.pushTexture(E,v.get().tex);else A.bgShader.pushTexture(E,CGL.Texture.getEmptyTexture(S).tex);L.setValue(l.get());N.setValue(h.get());U.setValue(m.get());R.setValue(x.get());A.setSize(O[0],O[1]);G.setRef(A.copy(a.get()||u.get()||f.get()||v.get()||CGL.Texture.getEmptyTexture(S)));_=false}B.trigger()}};Ops.Gl.Textures.CombineTextures.prototype=new CABLES.Op;CABLES.OPS["5f33dd4a-a553-4f0f-b3b1-66a80cd240a7"]={f:Ops.Gl.Textures.CombineTextures,objName:"Ops.Gl.Textures.CombineTextures"};Ops.Gl.ImageCompose.ImageCompose_v4=function(){CABLES.Op.apply(this,arguments);const n=this;const e=n.attachments={imgcomp_frag:"IN vec2 texCoord;\nUNI vec4 bgColor;\nUNI sampler2D tex;\n#ifdef USE_UVTEX\nUNI sampler2D UVTex;\n#endif\n\nvoid main()\n{\n\n #ifndef USE_TEX\n outColor=bgColor;\n #endif\n #ifdef USE_TEX\n #ifndef USE_UVTEX\n outColor=texture(tex,texCoord);\n #else\n outColor=texture(tex,texture(UVTex,texCoord).xy);\n #endif\n #endif\n\n\n\n}\n"};const t=n.patch.cgl,r=n.inTrigger("Render"),i=n.inTexture("Base Texture"),a=n.inTexture("UV Texture"),s=n.inSwitch("Size",["Auto","Canvas","Manual"],"Auto"),o=n.inValueInt("Width",640),l=n.inValueInt("Height",480),u=n.inSwitch("Filter",["nearest","linear","mipmap"],"linear"),c=n.inValueSelect("Wrap",["clamp to edge","repeat","mirrored repeat"],"repeat"),p=n.inSwitch("Anisotropic",["0","1","2","4","8","16"],"0"),h=n.inDropDown("Pixel Format",CGL.Texture.PIXELFORMATS,CGL.Texture.PFORMATSTR_RGBA8UB),f=n.inValueSlider("R",0),d=n.inValueSlider("G",0),g=n.inValueSlider("B",0),m=n.inValueSlider("A",0),v=n.outTrigger("Next"),b=n.outTexture("texture_out",CGL.Texture.getEmptyTexture(t)),y=n.outNumber("Aspect Ratio"),x=n.outNumber("Texture Width"),k=n.outNumber("Texture Height");n.setPortGroup("Texture Size",[s,o,l]);n.setPortGroup("Texture Parameters",[c,p,u,h]);f.setUiAttribs({colorPick:true});n.setPortGroup("Color",[f,d,g,m]);n.toWorkPortsNeedToBeLinked(r);const w=[0,0,0,0];let S=null;let O=null;let _=true;let B=false;let A=null;let G=null;let V=null;let D=null;c.onChange=u.onChange=p.onChange=h.onChange=F;i.onLinkChanged=s.onChange=a.onChange=R;r.onTriggered=n.preRender=M;R();function C(){if(S)S.delete();if(O)O.delete();O=null;S=new CGL.TextureEffect(t,{isFloatingPointTexture:CGL.Texture.isPixelFormatFloat(h.get()),name:n.name});const e=Math.min(t.maxAnisotropic,parseFloat(p.get()));O=new CGL.Texture(t,{anisotropic:e,name:"image_compose_v2_"+n.id,pixelFormat:h.get(),filter:T(),wrap:I(),width:E(),height:L()});S.setSourceTexture(O);x.set(E());k.set(L());y.set(E()/L());b.set(CGL.Texture.getEmptyTexture(t));_=false;R()}function T(){if(u.get()=="nearest")return CGL.Texture.FILTER_NEAREST;else if(u.get()=="linear")return CGL.Texture.FILTER_LINEAR;else if(u.get()=="mipmap")return CGL.Texture.FILTER_MIPMAP}function I(){if(c.get()=="repeat")return CGL.Texture.WRAP_REPEAT;else if(c.get()=="mirrored repeat")return CGL.Texture.WRAP_MIRRORED_REPEAT;else if(c.get()=="clamp to edge")return CGL.Texture.WRAP_CLAMP_TO_EDGE}function E(){let e=0;if(i.get()&&s.get()=="Auto")e=i.get().width;else if(s.get()=="Auto"||s.get()=="Canvas")e=t.canvasWidth;else if(s.get()=="ViewPort")e=t.getViewPort()[2];else e=Math.ceil(o.get());return n.patch.cgl.checkTextureSize(e)}function L(){let e=0;if(i.get()&&s.get()=="Auto")e=i.get().height;else if(s.get()=="Auto"||s.get()=="Canvas")e=t.canvasHeight;else if(s.get()=="ViewPort")e=t.getViewPort()[3];else e=Math.ceil(l.get());return n.patch.cgl.checkTextureSize(e)}function F(){_=true}function j(){if((E()!=O.width||L()!=O.height||O.pixelFormat!=h.get()||O.filter!=T()||O.wrap!=I())&&(E()!==0&&L()!==0)){C();S.setSourceTexture(O);b.set(CGL.Texture.getEmptyTexture(t));b.set(O);N();P()}}function N(){let e=null;if(s.get()=="Manual"){e=null}else if(s.get()=="Auto"){if(i.get())e="Input Texture";else e="Canvas Size";e+=": "+E()+" x "+L()}let t=false;t=s.uiAttribs.info!=e;s.setUiAttribs({info:e});if(t)n.refreshParams()}function U(){if(A)A.toggleDefine("USE_TEX",i.isLinked());if(A)A.toggleDefine("USE_UVTEX",a.isLinked())}function R(){p.setUiAttribs({greyout:T()!=CGL.Texture.FILTER_MIPMAP});f.setUiAttribs({greyout:i.isLinked()});g.setUiAttribs({greyout:i.isLinked()});d.setUiAttribs({greyout:i.isLinked()});m.setUiAttribs({greyout:i.isLinked()});o.setUiAttribs({greyout:s.get()!="Manual"});l.setUiAttribs({greyout:s.get()!="Manual"});if(O)if(CGL.Texture.isPixelFormatFloat(h.get())&&T()==CGL.Texture.FILTER_MIPMAP)n.setUiError("fpmipmap","Don't use mipmap and 32bit at the same time, many systems do not support this.");else n.setUiError("fpmipmap",null);N();U();P()}function P(){if(O)if(i.isLinked()&&i.get()&&O.isFloatingPoint()!=i.get().isFloatingPoint())n.setUiError("textypediff","Warning: Mixing floating point and non floating point texture can result in data/precision loss",1);else n.setUiError("textypediff",null)}n.preRender=()=>{M()};function z(){if(!A){A=new CGL.Shader(t,"copytextureshader");A.setSource(A.getDefaultVertexShader(),e.imgcomp_frag);G=new CGL.Uniform(A,"t","tex",0);V=new CGL.Uniform(A,"t","UVTex",1);D=new CGL.Uniform(A,"4f","bgColor",f,d,g,m);U()}t.pushShader(A);t.currentTextureEffect.bind();if(i.get())t.setTexture(0,i.get().tex);if(a.get())t.setTexture(1,a.get().tex);t.currentTextureEffect.finish();t.popShader()}function M(){if(!S||_)C();t.pushBlend(false);j();const e=t.currentTextureEffect;t.currentTextureEffect=S;t.currentTextureEffect.imgCompVer=3;t.currentTextureEffect.width=o.get();t.currentTextureEffect.height=l.get();S.setSourceTexture(O);S.startEffect(i.get()||CGL.Texture.getEmptyTexture(t,B),true);z();v.trigger();t.pushViewPort(0,0,o.get(),l.get());S.endEffect();b.setRef(S.getCurrentSourceTexture());t.popViewPort();t.popBlend();t.currentTextureEffect=e}};Ops.Gl.ImageCompose.ImageCompose_v4.prototype=new CABLES.Op;CABLES.OPS["17212e2b-d692-464c-8f8d-2d511dd3410a"]={f:Ops.Gl.ImageCompose.ImageCompose_v4,objName:"Ops.Gl.ImageCompose.ImageCompose_v4"};Ops.Gl.ImageCompose.FastBlur_v2=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={blur_frag:"\nUNI sampler2D tex;\n#ifdef USE_MASK\n UNI sampler2D texMask;\n#endif\nUNI float amount;\nUNI float pass;\n\nIN vec2 texCoord;\n\nUNI float dirX;\nUNI float dirY;\nUNI float width;\nUNI float height;\n\nIN vec2 coord0;\nIN vec2 coord1;\nIN vec2 coord2;\nIN vec2 coord3;\nIN vec2 coord4;\nIN vec2 coord5;\nIN vec2 coord6;\n\n#ifdef HAS_MASK\n UNI sampler2D imageMask;\n#endif\n\nvoid main()\n{\n vec4 color = vec4(0.0);\n\n #ifdef USE_MASK\n #ifdef MASK_INVERT\n if(texture(texMask,texCoord).r<0.5)\n {\n outColor= texture(tex, texCoord);\n return;\n }\n #endif\n\n #ifndef MASK_INVERT\n if(texture(texMask,texCoord).r>0.5)\n {\n outColor= texture(tex, texCoord);\n return;\n }\n #endif\n #endif\n\n color += texture(tex, coord0) * 0.06927096443792478;\n color += texture(tex, coord1) * 0.1383328848652136;\n color += texture(tex, coord2) * 0.21920904690397863;\n color += texture(tex, coord3) * 0.14637421;\n color += texture(tex, coord4) * 0.21920904690397863;\n color += texture(tex, coord5) * 0.1383328848652136;\n color += texture(tex, coord6) * 0.06927096443795711;\n\n outColor= color;\n}",blur_vert:"\nIN vec3 vPosition;\nIN vec2 attrTexCoord;\nIN vec3 attrVertNormal;\nOUT vec2 texCoord;\nOUT vec3 norm;\nUNI mat4 projMatrix;\nUNI mat4 mvMatrix;\nUNI mat4 modelMatrix;\n\nUNI float pass;\nUNI float dirX;\nUNI float dirY;\nUNI float width;\nUNI float height;\n\nOUT vec2 coord0;\nOUT vec2 coord1;\nOUT vec2 coord2;\nOUT vec2 coord3;\nOUT vec2 coord4;\nOUT vec2 coord5;\nOUT vec2 coord6;\n\nvoid main()\n{\n texCoord=attrTexCoord;\n norm=attrVertNormal;\n vec4 pos=vec4(vPosition, 1.0);\n {{MODULE_VERTEX_POSITION}}\n\n vec2 dir=vec2(dirX,dirY);\n vec2 res=vec2( (1.) / width , (1.) / height )*dir;\n\n coord3= attrTexCoord;\n\n coord0= attrTexCoord + (-3.0368997744118595 * res);\n coord1= attrTexCoord + (-2.089778445362373 * res);\n coord2= attrTexCoord + (-1.2004366090034069 * res);\n coord4= attrTexCoord + (1.2004366090034069 * res);\n coord5= attrTexCoord + (2.089778445362373* res);\n coord6= attrTexCoord + (3.0368997744118595 * res);\n\n #ifdef CLAMP\n coord0=clamp(coord0,0.0,1.0);\n coord1=clamp(coord1,0.0,1.0);\n coord2=clamp(coord2,0.0,1.0);\n coord3=clamp(coord3,0.0,1.0);\n coord4=clamp(coord4,0.0,1.0);\n coord5=clamp(coord5,0.0,1.0);\n coord6=clamp(coord6,0.0,1.0);\n #endif\n\n gl_Position = projMatrix * mvMatrix * pos;\n}\n"};const n=e.inTrigger("render"),r=e.outTrigger("trigger"),i=e.inFloat("Passes",3),a=e.inBool("Clamp",false),s=e.inDropDown("direction",["both","vertical","horizontal"],"both"),o=e.inTexture("Mask"),l=e.inBool("Mask Invert",false);const u=e.patch.cgl;const c=new CGL.Shader(u,"fastblur");e.setPortGroup("Mask",[o,l]);c.setSource(t.blur_vert,t.blur_frag);const p=new CGL.Uniform(c,"t","tex",0),h=new CGL.Uniform(c,"f","dirX",0),f=new CGL.Uniform(c,"f","dirY",0),d=new CGL.Uniform(c,"f","width",0),g=new CGL.Uniform(c,"f","height",0),m=new CGL.Uniform(c,"f","pass",0),v=new CGL.Uniform(c,"f","amount",i.get()),b=new CGL.Uniform(c,"t","texMask",1);i.onChange=()=>{v.setValue(i.get())};let y=0;s.onChange=()=>{if(s.get()=="both")y=0;if(s.get()=="horizontal")y=1;if(s.get()=="vertical")y=2};a.onChange=()=>{c.toggleDefine("CLAMP",a.get())};l.onChange=o.onChange=x;x();function x(){c.toggleDefine("USE_MASK",o.isLinked());c.toggleDefine("MASK_INVERT",l.get());l.setUiAttribs({greyout:!o.isLinked()})}n.onTriggered=function(){if(!CGL.TextureEffect.checkOpInEffect(e,3))return;d.setValue(u.currentTextureEffect.getCurrentSourceTexture().width);g.setValue(u.currentTextureEffect.getCurrentSourceTexture().height);const t=i.get();if(o.get())u.setTexture(1,o.get().tex);for(let e=0;e{xe();V=true;d=true};I.onChange=()=>{d=true;if(R&&I.get()&&I.isLinked())R.setAttribute("attrColors",new Float32Array(I.get()),4,{instanced:true})};T.onChange=F.onChange=A.onChange=C.onChange=function(){d=true};e.onChange=_e;i.patch.addEventListener("variablesChanged",b);i.patch.addEventListener("FontLoadedMSDF",b);a.onChange=Se;xe();Oe();b();function xe(){h.toggleDefine("SDF",r.get());h.toggleDefine("SHADOW",X.get());h.toggleDefine("BORDER",s.get());h.toggleDefine("TEXTURE_COLOR",c.isLinked());h.toggleDefine("TEXTURE_MASK",p.isLinked());h.toggleDefine("HAS_ATTR_COLORS",I.isLinked());u.setUiAttribs({greyout:!s.get()});z.setUiAttribs({greyout:!s.get()});H.setUiAttribs({greyout:!s.get()});l.setUiAttribs({greyout:!s.get()});o.setUiAttribs({greyout:!s.get()})}function Se(){b();const e=re+a.get();L=null;f=null;N={};const t=i.patch.getVar(e);if(!t||!t.getValue()){L=null;i.warn("no varname",e);return}L=t.getValue().data;if(!L){return}const n=t.getValue().basename;const r=i.patch.getVar("font_tex_"+n);if(!r){f=null;L=null;return}f=r.getValue();for(let e=0;e0){E.pushShader(h);if(f[0])me.setValue([f[0].width,f[0].height]);if(f[0])E.setTexture(0,f[0].tex);else E.setTexture(0,CGL.Texture.getEmptyTexture(E).tex);if(f[1])E.setTexture(1,f[1].tex);else E.setTexture(1,CGL.Texture.getEmptyTexture(E).tex);if(f[2])E.setTexture(2,f[2].tex);else E.setTexture(2,CGL.Texture.getEmptyTexture(E).tex);if(f[3])E.setTexture(3,f[3].tex);else E.setTexture(3,CGL.Texture.getEmptyTexture(E).tex);if(c.get())E.setTexture(4,c.get().tex);if(p.get())E.setTexture(5,p.get().tex);E.pushModelMatrix();mat4.translate(E.mMatrix,E.mMatrix,ae);if(V)Ae();if(D)R.setAttribute("instMat",new Float32Array(D),16,{instanced:true});if(E.getShader())E.getShader().define("INSTANCING");if(!P){mat4.scale(E.mMatrix,E.mMatrix,se);R.render(E.getShader())}E.popModelMatrix();E.setTexture(0,null);E.popShader()}Z.trigger()};function Ce(e){return N[String(e)]||N["?"]||N._||N.X}function Te(){if(!L||!N){ne.set(0);return}const e=String(F.get()+"");if(!U){U=new CGL.Geometry("textmesh");U.vertices=[.5,.5,0,-.5,.5,0,.5,-.5,0,-.5,-.5,0];U.normals=[0,0,0,0,0,0,0,0,0,0,0,0];U.texCoords=new Float32Array([1,0,0,0,1,1,0,1]);U.verticesIndices=[0,1,2,2,1,3]}if(R)R.dispose();R=new CGL.Mesh(E,U);const i=e.split("\n");const a=[];const s=[];const o=[];const t=[];const l=[];const u=[];let c=0;const p=[];const h=.01;J.set(i.length);k=99999;w=-99999;B=99999;G=-99999;M=0;for(let e=0;e-1||p.get()&&p.get().indexOf(e)>-1||h.get()&&h.get().indexOf(e)>-1||f.get()&&f.get().indexOf(e)>-1){n()}};let t="";function n(){if(!u.get()||!c.get())return;S.length=0;o.patch.deleteVar("font_data_"+t);o.patch.deleteVar("font_tex_"+t);t=l.get();const i="font_data_"+l.get();const n="font_tex_"+l.get();o.patch.setVarValue(i,{});o.patch.setVarValue(n,S);o.patch.getVar(i).type="fontData";o.patch.getVar(n).type="fontTexture";b=y=false;O();o.patch.loading.finished(x);x=o.patch.loading.start("jsonFile",""+u.get(),o);o.setUiError("invaliddata",null);o.setUiError("jsonerr",null);o.setUiError("texurlerror",null);const e=o.patch.getFilePath(String(u.get()));v.patch.loading.addAssetLoadingTask(()=>{CABLES.ajax(e,(e,r,t)=>{if(e){o.logError(e);return}try{let t=r;if(typeof t==="string")t=JSON.parse(r);if(!t.chars||!t.info||!t.info.face){o.setUiError("invaliddata","data file is invalid");return}g.set(t.chars.length);let n="";for(let e=0;e"+e);o.patch.loading.finished(x);O();d.set(false)}})});for(let t=0;t<4;t++){const r=t;let e=c;if(t==1)e=p;if(t==2)e=h;if(t==3)e=f;if(!e.get())continue;const a=v.patch.loading.start("textureOp",e.get(),o);const s=o.patch.getFilePath(String(e.get()));CGL.Texture.load(v,s,function(e,t){if(e){o.setUiError("texurlerror","could not load texture");v.patch.loading.finished(a);y=false;return}S[r]=t;o.patch.setVarValue(n,null);o.patch.setVarValue(n,S);y=true;v.patch.loading.finished(a);O()},{filter:CGL.Texture.FILTER_LINEAR,flip:false})}}};Ops.Gl.FontMSDF_v2.prototype=new CABLES.Op;CABLES.OPS["6cbd5d67-25d5-4936-a2ad-3ee8ed478570"]={f:Ops.Gl.FontMSDF_v2,objName:"Ops.Gl.FontMSDF_v2"};Ops.Math.Incrementor=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inTriggerButton("Increment"),r=e.inTriggerButton("Decrement"),i=e.inBool("Limit",false),a=e.inValueInt("Length"),s=e.inTriggerButton("Reset"),o=e.inSwitch("Mode",["Rewind","Stop at Max"],"Rewind"),l=e.inValueInt("Default",0),u=e.outTrigger("Changed"),c=e.outNumber("Value"),p=e.outTrigger("Restarted");const h=0;const f=1;c.ignoreValueSerialize=true;a.set(10);let d=0;let g=h;c.set(0);a.onTriggered=s;l.onChange=v;s.onTriggered=v;i.onChange=m;m();o.onChange=()=>{if(o.get()=="Rewind"){g=h}if(o.get()=="Stop at Max"){g=f}};function m(){a.setUiAttribs({greyout:!i.get()})}function v(){c.set(null);d=l.get();c.set(d);p.trigger()}r.onTriggered=function(){d--;if(i.get()){if(g==h&&d<0)d=a.get()-1;if(g==f&&d<0)d=0}c.set(d);u.trigger()};n.onTriggered=function(){d++;if(i.get()){if(g==h&&d>=a.get()){d=0;p.trigger()}if(g==f&&d>=a.get())d=a.get()-1}c.set(d);u.trigger()}};Ops.Math.Incrementor.prototype=new CABLES.Op;CABLES.OPS["45cc0011-ada8-4423-8f5b-39a3810b8389"]={f:Ops.Math.Incrementor,objName:"Ops.Math.Incrementor"};Ops.Math.SmootherStep=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inValueFloat("val",0),r=e.inValueFloat("min",0),i=e.inValueFloat("max",1),a=e.outNumber("result");n.onChange=i.onChange=r.onChange=s;s();function s(){let e=Math.max(0,Math.min(1,(n.get()-r.get())/(i.get()-r.get())));a.set(e*e*e*(e*(e*6-15)+10)*(i.get()-r.get()))}};Ops.Math.SmootherStep.prototype=new CABLES.Op;CABLES.OPS["c66da84f-ff2f-45de-b3c2-557bdf1cb946"]={f:Ops.Math.SmootherStep,objName:"Ops.Math.SmootherStep"};Ops.String.StringCompose_v3=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inString("Format","hello $a, $b $c und $d"),r=e.inString("String A","world"),i=e.inString("String B",1),a=e.inString("String C",2),s=e.inString("String D",3),o=e.inString("String E"),l=e.inString("String F"),u=e.outString("Result");n.onChange=r.onChange=i.onChange=a.onChange=s.onChange=o.onChange=l.onChange=c;c();function c(){var e=n.get()||"";if(typeof e!="string")e="";e=e.replace(/\$a/g,r.get());e=e.replace(/\$b/g,i.get());e=e.replace(/\$c/g,a.get());e=e.replace(/\$d/g,s.get());e=e.replace(/\$e/g,o.get());e=e.replace(/\$f/g,l.get());u.set(e)}};Ops.String.StringCompose_v3.prototype=new CABLES.Op;CABLES.OPS["6afea9f4-728d-4f3c-9e75-62ddc1448bf0"]={f:Ops.String.StringCompose_v3,objName:"Ops.String.StringCompose_v3"};Ops.Gl.Meshes.Circle_v3=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inTrigger("render"),N=e.inValue("radius",.5),U=e.inValueSlider("innerRadius",0),R=e.inValueInt("segments",40),P=e.inValueSlider("percent",1),M=e.inValue("steps",0),k=e.inValueBool("invertSteps",false),w=e.inSwitch("mapping",["flat","round"]),B=e.inValueBool("Spline",false),r=e.inValueBool("Draw",true),i=e.outTrigger("trigger"),G=e.outObject("geometry",null,"geometry");e.setPortGroup("Size",[N,U]);e.setPortGroup("Display",[P,M,k]);e.toWorkShouldNotBeChild("Ops.Gl.TextureEffects.ImageCompose",CABLES.OP_PORT_TYPE_FUNCTION);r.setUiAttribs({title:"Render mesh"});w.set("flat");w.onChange=R.onChange=N.onChange=U.onChange=P.onChange=M.onChange=k.onChange=B.onChange=p;G.ignoreValueSerialize=true;const a=e.patch.cgl;let V=new CGL.Geometry("circle");let D=null;const s=-1;let o=0;let l=null;let F=true;n.onTriggered=u;e.preRender=()=>{u()};n.onLinkChanged=function(){if(!n.isLinked())G.set(null);else G.setRef(V)};function u(){if(F)c();if(!CGL.TextureEffect.checkOpNotInTextureEffect(e))return;l=e.patch.cg.getShader();if(!l)return;o=l.glPrimitive;if(B.get())l.glPrimitive=a.gl.LINE_STRIP;if(r.get()&&D)D.render(l);i.trigger();l.glPrimitive=o}function c(){const n=Math.max(3,Math.floor(R.get()));V.clear();const t=[];const r=[];const i=[];const a=[];const s=[];let o=0,l=0;let u=0,c=0;let p=0,h=0;let f=0,d=0;let g=0,m=0;let v=0,b=0;let y=0,x=0;let S=0,O=0;const _=Math.max(0,P.get());const A=[];if(B.get()){let e=0;let t=0;const C=[];for(o=0;o<=n*_;o++){l=360/n*o*CGL.DEG2RAD;S=Math.cos(l)*N.get();O=Math.sin(l)*N.get();x=.5;if(o>0){A.push(e);A.push(t);A.push(0);y=1-(o-1)/n;C.push(y,x)}A.push(S);A.push(O);A.push(0);e=S;t=O}V.setPointVertices(A)}else if(U.get()<=0){for(o=0;o<=n*_;o++){l=360/n*o*CGL.DEG2RAD;S=Math.cos(l)*N.get();O=Math.sin(l)*N.get();if(w.get()=="flat"){y=(Math.cos(l)+1)/2;x=1-(Math.sin(l)+1)/2;v=.5;b=.5}else if(w.get()=="round"){y=1-o/n;x=0;v=y;b=1}t.push([0,0,0],[u,c,0],[S,O,0]);r.push(v,b,p,h,y,x);i.push(0,0,1,0,0,1,0,0,1);a.push(1,0,0,1,0,0,1,0,0);s.push(0,-1,0,0,-1,0,0,-1,0);p=y;h=x;u=S;c=O}V=CGL.Geometry.buildFromFaces(t,"circle");V.vertexNormals=i;V.tangents=a;V.biTangents=s;V.texCoords=r}else{let e=0;const T=n*_;const I=0;for(o=0;o<=T;o++){e++;l=360/n*o*CGL.DEG2RAD;S=Math.cos(l)*N.get();O=Math.sin(l)*N.get();const E=Math.cos(l)*U.get()*N.get();const L=Math.sin(l)*U.get()*N.get();if(w.get()=="round"){y=1-o/n;x=0;v=y;b=1}if(M.get()===0||e%parseInt(M.get(),10)===0&&!k.get()||e%parseInt(M.get(),10)!==0&&k.get()){t.push([E,L,0],[u,c,0],[S,O,0]);t.push([f,d,0],[u,c,0],[E,L,0]);r.push(y,0,p,0,v,1,y,1,p,0,g,1);i.push(0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1);a.push(1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0);s.push(0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1)}g=v;m=b;p=y;h=x;u=S;c=O;f=E;d=L}V=CGL.Geometry.buildFromFaces(t,"circle");V.vertexNormals=i;V.tangents=a;V.biTangents=s;if(w.get()=="flat")V.mapTexCoords2d();else V.texCoords=r}G.setRef(V);if(V.vertices.length==0)return;if(D)D.dispose();D=null;D=e.patch.cg.createMesh(V,{opId:e.id});F=false}function p(){F=true}e.onDelete=function(){if(D)D.dispose()}};Ops.Gl.Meshes.Circle_v3.prototype=new CABLES.Op;CABLES.OPS["ae07830b-91c3-4cbe-a7d6-d3b737392c16"]={f:Ops.Gl.Meshes.Circle_v3,objName:"Ops.Gl.Meshes.Circle_v3"};Ops.Array.StringToArray_v2=function(){CABLES.Op.apply(this,arguments);const r=this;const e=r.attachments={};const i=r.inStringEditor("text","1,2,3"),a=r.inString("separator",","),s=r.inValueBool("Numbers",true),o=r.inValueBool("Trim",true),l=r.inBool("Split Lines",false),u=r.outArray("array"),c=r.outTrigger("Parsed"),p=r.outNumber("length");i.setUiAttribs({ignoreBigPort:true});i.onChange=a.onChange=s.onChange=o.onChange=t;l.onChange=()=>{a.setUiAttribs({greyout:l.get()});t()};t();function t(){if(!i.get()){u.set(null);u.set([]);p.set(0);return}let e=i.get();if(o.get()&&e){e=e.replace(/^\s+|\s+$/g,"");e=e.trim()}let n;let t=a.get();if(a.get()==="\\n")t="\n";if(l.get())n=e.split("\n");else n=e.split(t);if(n[n.length-1]==="")n.length-=1;p.set(n.length);if(o.get()){for(let e=0;e{r.fillStyle="#222";r.fillRect(i.x,i.y,i.width,i.height);r.save();r.scale(i.scale,i.scale);r.font="normal 10px sourceCodePro";r.fillStyle="#ccc";const a=g.get()||[];let s=1;if(g.get()===null)d.setUiAttrib({extendTitle:"null"});else if(g.get()===undefined)d.setUiAttrib({extendTitle:"undefined"});else d.setUiAttrib({extendTitle:"length: "+a.length});if(g.links.length>0&&g.links[0].getOtherPort(g))s=g.links[0].getOtherPort(g).uiAttribs.stride||1;let e=Math.floor(i.height/i.scale/10-1);let o=4;let l=m.get()*s;let n=[];for(let e=0;ea.length)continue;r.fillStyle="#666";const h=n/s;if(h>=0)r.fillText(h,i.x/i.scale+o,i.y/i.scale+10+(n-l)/s*10+o);for(let t=0;t0){const f=r.createLinearGradient(0,i.y/i.scale+5,0,i.y/i.scale+c);f.addColorStop(0,"#222");f.addColorStop(1,"rgba(34,34,34,0.0)");r.fillStyle=f;r.fillRect(i.x/i.scale,i.y/i.scale,2e5,c)}if(l+e*s");if(m.innerHTML!=e)m.innerHTML=e;c.set(null);c.set(m)}function _(){if(!m)return;m.setAttribute("style",a.get());S();c.set(null);c.set(m);if(!m.parentElement){v.appendChild(m)}P()}let A="";function C(){if(!m)return;const t=(i.get()||"").split(" ");for(let e=0;e{if(!t.get())i.remove();else l()};function s(){let t=r.get();if(t){let e=null;if(n.storage&&n.storage.blueprint&&n.storage.blueprint.patchId){e=n.storage.blueprint.patchId}t=t.replace(new RegExp("{{ASSETPATH}}","g"),n.patch.getAssetPath(e))}return t}function o(){i=n.patch.getDocument().getElementById(a);if(i){i.textContent=s()}else{i=n.patch.getDocument().createElement("style");i.type="text/css";i.id=a;i.textContent=e.css_spinner;i.classList.add("cablesEle");l()}}function l(){const e=n.patch.getDocument().getElementsByTagName("body")[0];e.appendChild(i)}n.onDelete=function(){i=n.patch.getDocument().getElementById(a);if(i)i.remove()}};Ops.Html.CSS_v2.prototype=new CABLES.Op;CABLES.OPS["a56d3edd-06ad-44ed-9810-dbf714600c67"]={f:Ops.Html.CSS_v2,objName:"Ops.Html.CSS_v2"};Ops.Html.TransformCSS3DElement=function(){CABLES.Op.apply(this,arguments);const r=this;const e=r.attachments={};const i=r.patch.cgl,t=["top-left","top-middle","top-right","center-left","center-middle","center-right","bottom-left","bottom-middle","bottom-right"],n=r.inTrigger("trigger"),a=r.inObject("DOMElement"),s=r.inValueSelect("origin",t,"center-middle"),o=r.outTrigger("next"),l=mat4.create(),u=vec3.create();r.uuid=CABLES.uuid();let c=null;let p=i.canvas.parentElement.querySelector('[data-provide="css3d"]');if(!p){p=document.createElement("div");p.dataset.op=r.id;p.style.position="absolute";p.style.top=p.style.left=0;p.style.width=p.style.height="100%";p.dataset.provide="css3d";p.style.zIndex=1e3;p.style.pointerEvents="none";p.style.perspectiveOrigin="center center";i.canvas.parentElement.appendChild(p);let e=document.createElement("style");e.dataset.op=r.id;e.type="text/css";e.textContent=[".cables-loading .cables-css3dview {visibility:hidden;pointer-events:none;backface-visibility:hidden;}",".cables-css3dview {position:absolute;left:0;top:0;width:100%;height:100%;transform-style:preserve-3d;}",".cables-css3dview > * {pointer-events:auto;}",".cables-css3dview.origin-top-left > * {}",".cables-css3dview.origin-top-middle > * {transform:translate3d(-50%,0,0);}",".cables-css3dview.origin-top-right > * {transform:translate3d(-100%,0,0);}",".cables-css3dview.origin-center-left > * {transform:translate3d(0,-50%,0);}",".cables-css3dview.origin-center-middle > * {transform:translate3d(-50%,-50%,0);}",".cables-css3dview.origin-center-right > * {transform:translate3d(-100%,-50%,0);}",".cables-css3dview.origin-bottom-left > * {transform:translate3d(0,-100%,0);}",".cables-css3dview.origin-bottom-middle > * {transform:translate3d(-50%,-100%,0);}",".cables-css3dview.origin-bottom-right > * {transform:translate3d(-100%,-100%,0);}"].join("\n");p.appendChild(e)}r.onDelete=function(){let e=p.querySelector('[data-ccs3did="'+r.uuid+'"]');if(e&&e.parentElement)e.parentElement.removeChild(e)};function h(e){let t=document.createElement("div");t.classList.add("cables-css3dview");t.dataset.css3did=r.uuid;t.appendChild(e);return t}a.onChange=function(e,t){r.onDelete();if(!t)return;p.appendChild(h(t));s.onChange()};s.onChange=function(){let e=a.get();if(!e||!e.parentElement)return;DOMTokenList.prototype.remove.apply(e.parentElement.classList,t.map(function(e){return"origin-"+e}));e.parentElement.classList.add("origin-"+s.get())};n.onTriggered=function(){let e=.5/(1/i.pMatrix[5])*i.gl.drawingBufferHeight/r.patch.cgl.pixelDensity;p.style.perspective=e+"px";let t=-2*i.gl.drawingBufferWidth/i.gl.drawingBufferHeight;vec3.set(u,t/i.gl.drawingBufferWidth*r.patch.cgl.pixelDensity,-2/i.gl.drawingBufferHeight*r.patch.cgl.pixelDensity,1);let n=a.get();if(n){mat4.multiply(l,i.vMatrix,i.mMatrix);mat4.scale(l,l,u);if(n.parentElement)n.parentElement.style.transform="translateZ("+e+"px) matrix3d("+l[0]+","+-l[1]+","+l[2]+","+l[3]+","+l[4]+","+-l[5]+","+l[6]+","+l[7]+","+l[8]+","+-l[9]+","+l[10]+","+l[11]+","+l[12]+","+-l[13]+","+l[14]+","+l[15]+") scaleX(-1) translate3d("+i.gl.drawingBufferWidth/2/r.patch.cgl.pixelDensity+"px,"+i.gl.drawingBufferHeight/2/r.patch.cgl.pixelDensity+"px"+",0"+")"}o.trigger();c=n};s.onChange();function f(e){if(!e)e=a.get();if(e&&e.parentElement)e.parentElement.style.transform=""}r.onDelete=function(){f(c)};a.onLinkChanged=function(){if(!a.isLinked())f(c)};r.addEventListener("onEnabledChange",function(e){if(!e)f()})};Ops.Html.TransformCSS3DElement.prototype=new CABLES.Op;CABLES.OPS["7b81ed97-6fb9-4044-a731-962a2a11db27"]={f:Ops.Html.TransformCSS3DElement,objName:"Ops.Html.TransformCSS3DElement"};Ops.Gl.CanvasInfo_v2=function(){CABLES.Op.apply(this,arguments);const t=this;const e=t.attachments={};const n=t.outNumber("width"),r=t.outNumber("height"),i=t.outNumber("Pixel Ratio"),a=t.outNumber("Pixel Width"),s=t.outNumber("Pixel Height"),o=t.inSwitch("Pixel Unit",["Display","CSS"],"Display"),l=t.outNumber("Aspect Ratio"),u=t.outBool("Landscape"),c=t.outObject("Canvas","element"),p=t.outObject("Canvas Parent","element");let h=t.patch.cgl;c.set(t.patch.cgl.canvas);p.set(t.patch.cgl.canvas.parentElement);h.on("resize",f);o.onChange=f;f();function f(){let e=1;if(o.get()=="CSS")e=t.patch.cgl.pixelDensity;r.set(h.canvasHeight);n.set(h.canvasWidth);s.set(h.canvasHeight*t.patch.cgl.pixelDensity);a.set(h.canvasWidth*t.patch.cgl.pixelDensity);i.set(t.patch.cgl.pixelDensity);l.set(h.canvasWidth/h.canvasHeight);u.set(h.canvasWidth>h.canvasHeight?1:0)}};Ops.Gl.CanvasInfo_v2.prototype=new CABLES.Op;CABLES.OPS["a249e025-ae2c-4fb1-99f1-f86bfe7d5fc4"]={f:Ops.Gl.CanvasInfo_v2,objName:"Ops.Gl.CanvasInfo_v2"};Ops.Math.Divide=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inValueFloat("number1",1),r=e.inValueFloat("number2",2),i=e.outNumber("result");e.setUiAttribs({mathTitle:true});n.onChange=r.onChange=a;a();function a(){i.set(n.get()/r.get())}};Ops.Math.Divide.prototype=new CABLES.Op;CABLES.OPS["86fcfd8c-038d-4b91-9820-a08114f6b7eb"]={f:Ops.Math.Divide,objName:"Ops.Math.Divide"};Ops.Html.CSSProperty_v2=function(){CABLES.Op.apply(this,arguments);const t=this;const e=t.attachments={};const n=t.inObject("Element"),r=t.inString("Property"),i=t.inFloat("Value"),a=t.inString("Value Suffix","px"),s=t.outObject("HTML Element");t.setPortGroup("Element",[n]);t.setPortGroup("Attributes",[r,i,a]);r.onChange=l;i.onChange=u;a.onChange=u;let o=null;n.onChange=n.onLinkChanged=function(){if(o&&o.style){o.style[r.get()]="initial"}u()};function l(){u();t.setUiAttrib({extendTitle:r.get()+""})}function u(){o=n.get();if(o&&o.style){const e=i.get()+a.get();try{if(o.style[r.get()]!=e)o.style[r.get()]=e}catch(e){t.logError(e)}}else{setTimeout(u,50)}s.set(n.get())}};Ops.Html.CSSProperty_v2.prototype=new CABLES.Op;CABLES.OPS["c179aa0e-b558-4130-8c2d-2deab2919a07"]={f:Ops.Html.CSSProperty_v2,objName:"Ops.Html.CSSProperty_v2"};Ops.Boolean.BoolToNumber_v2=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inBool("Use Value 1",false),r=e.inFloat("Value 0",0),i=e.inFloat("Value 1",1),a=e.outNumber("Out Value",0);r.onChange=i.onChange=n.onChange=s;function s(){const e=n.get();if(e){a.set(i.get())}else{a.set(r.get())}}};Ops.Boolean.BoolToNumber_v2.prototype=new CABLES.Op;CABLES.OPS["400eea7d-5a68-4dda-a94d-2bb2ee7c2331"]={f:Ops.Boolean.BoolToNumber_v2,objName:"Ops.Boolean.BoolToNumber_v2"};Ops.Html.HyperLink_v2=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inTriggerButton("Open"),r=e.inString("URL","https://cables.gl"),i=e.inString("Target Name","_self"),a=e.inString("Specs","");n.onTriggered=function(){window.open(r.get(),i.get(),a.get())}};Ops.Html.HyperLink_v2.prototype=new CABLES.Op;CABLES.OPS["a669d4f7-1e35-463c-bf8b-08c9f1b68e04"]={f:Ops.Html.HyperLink_v2,objName:"Ops.Html.HyperLink_v2"};Ops.Extension.OpenType.OpentypeFont=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inUrl("Font File",[".otf",".ttf",".woff",".woff2"]),r=e.outObject("Opentype Font",null,"opentype");n.onChange=async function(){const e=await opentype.load(n.get());r.set(e)}};Ops.Extension.OpenType.OpentypeFont.prototype=new CABLES.Op;CABLES.OPS["f85574bb-3869-4a14-8dcc-70414bd8cfcd"]={f:Ops.Extension.OpenType.OpentypeFont,objName:"Ops.Extension.OpenType.OpentypeFont"};Ops.Extension.OpenType.OpentypeToSvgPath=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const a=e.inObject("Opentype Font"),s=e.inString("Text","cables"),o=e.inFloat("Letter Spacing",0),l=e.outString("Path String");s.onChange=o.onChange=a.onChange=async function(){const e=a.get();if(!e||!e.getPath){l.set("");return}const n=e.getPaths(s.get(),0,0,72);let r="";let i=o.get();for(let t=0;t{let e=d.get();if(!e||e.length<2){m.set(null);return}e=e.replace(/([A-Z,a-z])/g," $1 ");const t=v(e);const o=[];t.forEach(({type:e,x:t,y:n,x1:r,y1:i,x2:a,y2:s})=>{switch(e){case"M":o.push(new b);o[o.length-1].moveTo({x:t,y:n});break;case"L":o[o.length-1].moveTo({x:t,y:n});break;case"C":o[o.length-1].cubicTo({x:t,y:n},{x:r,y:i},{x:a,y:s});break;case"Q":o[o.length-1].conicTo({x:t,y:n},{x:r,y:i});break;case"Z":o[o.length-1].close();break}});o.sort((e,t)=>{return Math.abs(t.area)-Math.abs(e.area)});const r=[];for(let n=0;n=0;--e){if(o[e].inside(o[n].points[0])&&o[n].area*o[e].area<0){t=o[e];break}}if(t){t.children.push(o[n])}else{r.push(o[n])}}const n=o.reduce((e,t)=>{return e+t.points.length},0);const i=new Float32Array(n*2);let a=0;const s=[];function l(e){const n=[];const t=[];e.points.forEach(({x:e,y:t})=>{return n.push(e,t)});e.children.forEach(e=>{e.children.forEach(l);t.push(n.length/2);e.points.forEach(({x:e,y:t})=>{return n.push(e,t)})});i.set(n,a*2);earcut(n,t).forEach(e=>{return s.push(e+a)});a+=n.length/2}r.forEach(l);const u=new Float32Array(n*3);let c=-99999;for(let e=0;e0){let t=n.shift();if(s.hasOwnProperty(t)){i=t}else{n.unshift(t)}a={type:i};s[i].forEach(e=>{t=n.shift();a[e]=parseFloat(t)});if(i==="M"){i="L"}else if(i==="m"){i="l"}r.push(a)}return r}const u=15;const o=1e-6;class b{constructor(){this.points=[];this.children=[];this.area=0;this.BEZIER_STEP_SIZE=n.get()}moveTo(e){this.points.push(e)}lineTo(e){this.points.push(e)}close(){let t=this.points[this.points.length-1];this.points.forEach(e=>{this.area+=.5*r(t,e);t=e})}conicTo(t,n){const r=this.points[this.points.length-1];const e=c(r,n)+c(n,t);const i=Math.max(2,Math.min(u,e/this.BEZIER_STEP_SIZE));for(let e=1;e<=i;++e){const a=e/i;this.points.push(p(p(r,n,a),p(n,t,a),a))}}cubicTo(t,n,r){const i=this.points[this.points.length-1];const e=c(i,n)+c(n,r)+c(r,t);const a=Math.max(2,Math.min(u,e/this.BEZIER_STEP_SIZE));for(let e=1;e<=a;++e){const s=e/a;const o=p(p(i,n,s),p(n,r,s),s);const l=p(p(n,r,s),p(r,t,s),s);this.points.push(p(o,l,s))}}inside(r){let i=0,a=this.points[this.points.length-1];this.points.forEach(e=>{const t=a.yr.y+o){if((n.x-t.x)*(r.y-t.y)>(r.x-t.x)*(n.y-t.y)){i+=1}}a=e});return i%2!==0}}function c(e,t){const n=e.x-t.x,r=e.y-t.y;return Math.sqrt(n*n+r*r)}function p(e,t,n){return{x:(1-n)*e.x+n*t.x,y:(1-n)*e.y+n*t.y}}function r(e,t){return e.x*t.y-e.y*t.x}};Ops.Graphics.Geometry.SvgPathToGeometry_v2.prototype=new CABLES.Op;CABLES.OPS["4267b3e7-1285-4a3e-acc8-ea92a72a6bc0"]={f:Ops.Graphics.Geometry.SvgPathToGeometry_v2,objName:"Ops.Graphics.Geometry.SvgPathToGeometry_v2"};Ops.Gl.RenderGeometry_v2=function(){CABLES.Op.apply(this,arguments);const t=this;const e=t.attachments={};const n=t.inTrigger("render"),r=t.inObject("Geometry",null,"geometry"),i=t.inBool("Render Mesh",true),a=t.inBool("Add Vertex Numbers",true),s=t.outTrigger("trigger");t.toWorkPortsNeedToBeLinked(r,n);r.ignoreValueSerialize=true;let o=null;let l=true;r.onLinkChanged=a.onChange=r.onChange=()=>{l=true};n.onTriggered=function(){if(l)u();if(o&&i.get())o.render(t.patch.cgl.getShader());s.trigger()};function u(){l=false;const e=r.get();if(e&&e.isGeometry){if(o){o.dispose();o=null}if(!o){o=new CGL.Mesh(t.patch.cgl,e);o.addVertexNumbers=a.get();o.setGeom(e)}}else{o=null}}};Ops.Gl.RenderGeometry_v2.prototype=new CABLES.Op;CABLES.OPS["0a9bdb39-8250-460e-8d99-50fe6825d956"]={f:Ops.Gl.RenderGeometry_v2,objName:"Ops.Gl.RenderGeometry_v2"};Ops.Graphics.Geometry.GeometryExtrude=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const p=e.inObject("Geometry",null,"geometry"),h=e.inFloat("Height",.5),f=e.inBool("Smooth",true),d=e.inBool("Walls",true),g=e.inBool("Top",true),m=e.inBool("Bottom",true),v=e.outObject("Result Geometry",null,"geometry");function b(t){let n=0;for(let e=0;e0}f.onChange=d.onChange=g.onChange=m.onChange=h.onChange=p.onChange=()=>{const i=p.get();if(!i){v.set(null);return}function t(t,n){let r=0;for(let e=0;e500||h===0)u=i.get()||0;else e=(performance.now()-h)/(performance.now()-h);h=performance.now();if(u!=u)u=0;if(g<=0)g=1e-4;const t=c-u;if(t>=0)u+=t/(d*e);else u+=t/(f*e);if(Math.abs(t)<1e-5)u=c;if(g!=g)u=0;if(u!=u||u==-Infinity||u==Infinity)u=i.get();if(p!=u){l.set(u);p=u}if(u==c&&!m){m=true;l.set(u)}a.trigger()}n.onTriggered=function(){O()}};Ops.Anim.Smooth.prototype=new CABLES.Op;CABLES.OPS["5677b5b5-753a-4fbf-9e91-64c81ec68a2f"]={f:Ops.Anim.Smooth,objName:"Ops.Anim.Smooth"};Ops.Math.MathExpression=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inFloat("A",0);const r=e.inFloat("B",1);const i=e.inFloat("C",2);const a=e.inFloat("D",3);e.setPortGroup("Parameters",[n,r,i,a]);const s=e.inString("Expression","a*(b+c+d)");e.setPortGroup("Expression",[s]);const o=e.outNumber("Result");const l=e.outBool("Expression Valid");let u=s.get();let c=false;const p=()=>{try{u=new Function("m","a","b","c","d",`with(m) { return ${s.get()} }`);c=true;h();l.set(c)}catch(e){c=false;l.set(c);if(e instanceof ReferenceError||e instanceof SyntaxError)return}};const h=()=>{if(c){o.set(u(Math,n.get(),r.get(),i.get(),a.get()));if(!s.get())o.set(0)}l.set(c)};n.onChange=r.onChange=i.onChange=a.onChange=h;s.onChange=p;p()};Ops.Math.MathExpression.prototype=new CABLES.Op;CABLES.OPS["d2343a1e-64ea-45b2-99ed-46e167bbdcd3"]={f:Ops.Math.MathExpression,objName:"Ops.Math.MathExpression"};Ops.Array.GateArray_v2=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inArray("Array in"),r=e.inValueBool("Pass Through",true),i=e.inSwitch("When False",["keep last array","null"],"keep last array"),a=e.outArray("Array Out");let s=null;function o(t){if(!t)return null;const n=[];n.length=t.length;for(let e=0;e=n){return undefined}var i=t.charCodeAt(r);var a;if(i>=55296&&i<=56319&&n>r+1){a=t.charCodeAt(r+1);if(a>=56320&&a<=57343){return(i-55296)*1024+a-56320+65536}}return i};if(e){e(String.prototype,"codePointAt",{value:t,configurable:true,writable:true})}else{String.prototype.codePointAt=t}})()}var P=0;var M=-3;function k(){this.table=new Uint16Array(16);this.trans=new Uint16Array(288)}function w(e,t){this.source=e;this.sourceIndex=0;this.tag=0;this.bitcount=0;this.dest=t;this.destLen=0;this.ltree=new k;this.dtree=new k}var B=new k;var F=new k;var j=new Uint8Array(30);var z=new Uint16Array(30);var H=new Uint8Array(30);var X=new Uint16Array(30);var Y=new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]);var W=new k;var h=new Uint8Array(288+32);function q(e,t,n,r){var i,a;for(i=0;i>>=1;return t}function f(e,t,n){if(!t){return n}while(e.bitcount<24){e.tag|=e.source[e.sourceIndex++]<>>16-t;e.tag>>>=t;e.bitcount-=t;return r+n}function $(e,t){while(e.bitcount<24){e.tag|=e.source[e.sourceIndex++]<>>=1;++i;n+=t.table[i];r-=t.table[i]}while(r>=0);e.tag=a;e.bitcount-=i;return t.trans[n+r]}function ee(e,t,n){var r,i,a;var s,o,l;r=f(e,5,257);i=f(e,5,1);a=f(e,4,4);for(s=0;s<19;++s){h[s]=0}for(s=0;s8){e.sourceIndex--;e.bitcount-=8}t=e.source[e.sourceIndex+1];t=256*t+e.source[e.sourceIndex];n=e.source[e.sourceIndex+3];n=256*n+e.source[e.sourceIndex+2];if(t!==(~n&65535)){return M}e.sourceIndex+=4;for(r=t;r;--r){e.dest[e.destLen++]=e.source[e.sourceIndex++]}e.bitcount=0;return P}function re(e,t){var n=new w(e,t);var r,i,a;do{r=J(n);i=f(n,2,0);switch(i){case 0:a=ne(n);break;case 1:a=te(n,B,F);break;case 2:ee(n,n.ltree,n.dtree);a=te(n,n.ltree,n.dtree);break;default:a=M}if(a!==P){throw new Error("Data error")}}while(!r);if(n.destLenthis.x2){this.x2=e}}if(typeof t==="number"){if(isNaN(this.y1)||isNaN(this.y2)){this.y1=t;this.y2=t}if(tthis.y2){this.y2=t}}};o.prototype.addX=function(e){this.addPoint(e,null)};o.prototype.addY=function(e){this.addPoint(null,e)};o.prototype.addBezier=function(e,t,n,r,i,a,s,o){var l=[e,t];var u=[n,r];var c=[i,a];var p=[s,o];this.addPoint(e,t);this.addPoint(s,o);for(var h=0;h<=1;h++){var f=6*l[h]-12*u[h]+6*c[h];var d=-3*l[h]+9*u[h]-9*c[h]+3*p[h];var g=3*u[h]-3*l[h];if(d===0){if(f===0){continue}var m=-g/f;if(0=0&&n>0){t+=" "}t+=i(r)}return t}var n="";for(var r=0;r=0&&e<=255,"Byte value should be between 0 and 255.");return[e]};l.BYTE=e(1);I.CHAR=function(e){return[e.charCodeAt(0)]};l.CHAR=e(1);I.CHARARRAY=function(e){if(typeof e==="undefined"){e="";console.warn("Undefined CHARARRAY encountered and treated as an empty string. This is probably caused by a missing glyph name.")}var t=[];for(var n=0;n>8&255,e&255]};l.USHORT=e(2);I.SHORT=function(e){if(e>=le){e=-(2*le-e)}return[e>>8&255,e&255]};l.SHORT=e(2);I.UINT24=function(e){return[e>>16&255,e>>8&255,e&255]};l.UINT24=e(3);I.ULONG=function(e){return[e>>24&255,e>>16&255,e>>8&255,e&255]};l.ULONG=e(4);I.LONG=function(e){if(e>=ue){e=-(2*ue-e)}return[e>>24&255,e>>16&255,e>>8&255,e&255]};l.LONG=e(4);I.FIXED=I.ULONG;l.FIXED=l.ULONG;I.FWORD=I.SHORT;l.FWORD=l.SHORT;I.UFWORD=I.USHORT;l.UFWORD=l.USHORT;I.LONGDATETIME=function(e){return[0,0,0,0,e>>24&255,e>>16&255,e>>8&255,e&255]};l.LONGDATETIME=e(8);I.TAG=function(e){_.argument(e.length===4,"Tag should be exactly 4 ASCII characters.");return[e.charCodeAt(0),e.charCodeAt(1),e.charCodeAt(2),e.charCodeAt(3)]};l.TAG=e(4);I.Card8=I.BYTE;l.Card8=l.BYTE;I.Card16=I.USHORT;l.Card16=l.USHORT;I.OffSize=I.BYTE;l.OffSize=l.BYTE;I.SID=I.USHORT;l.SID=l.USHORT;I.NUMBER=function(e){if(e>=-107&&e<=107){return[e+139]}else if(e>=108&&e<=1131){e=e-108;return[(e>>8)+247,e&255]}else if(e>=-1131&&e<=-108){e=-e-108;return[(e>>8)+251,e&255]}else if(e>=-32768&&e<=32767){return I.NUMBER16(e)}else{return I.NUMBER32(e)}};l.NUMBER=function(e){return I.NUMBER(e).length};I.NUMBER16=function(e){return[28,e>>8&255,e&255]};l.NUMBER16=e(3);I.NUMBER32=function(e){return[29,e>>24&255,e>>16&255,e>>8&255,e&255]};l.NUMBER32=e(5);I.REAL=function(e){var t=e.toString();var n=/\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/.exec(t);if(n){var r=parseFloat("1e"+((n[2]?+n[2]:0)+n[1].length));t=(Math.round(e*r)/r).toString()}var i="";for(var a=0,s=t.length;a>8&255;t[t.length]=r&255}return t};l.UTF16=function(e){return e.length*2};var pe={"x-mac-croatian":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®Š™´¨≠ŽØ∞±≤≥∆µ∂∑∏š∫ªºΩžø"+"¿¡¬√ƒ≈Ć«Č… ÀÃÕŒœĐ—“”‘’÷◊©⁄€‹›Æ»–·‚„‰ÂćÁčÈÍÎÏÌÓÔđÒÚÛÙıˆ˜¯πË˚¸Êæˇ","x-mac-cyrillic":"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°Ґ£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµґЈЄєЇїЉљЊњ"+"јЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю","x-mac-gaelic":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØḂ±≤≥ḃĊċḊḋḞḟĠġṀæø"+"ṁṖṗɼƒſṠ«»… ÀÃÕŒœ–—“”‘’ṡẛÿŸṪ€‹›Ŷŷṫ·Ỳỳ⁊ÂÊÁËÈÍÎÏÌÓÔ♣ÒÚÛÙıÝýŴŵẄẅẀẁẂẃ","x-mac-greek":"Ĺ²É³ÖÜ΅àâä΄¨çéèê룙î‰ôö¦€ùûü†ΓΔΘΛΞΠß®©ΣΪ§≠°·Α±≤≥¥ΒΕΖΗΙΚΜΦΫΨΩ"+"άΝ¬ΟΡ≈Τ«»… ΥΧΆΈœ–―“”‘’÷ΉΊΌΎέήίόΏύαβψδεφγηιξκλμνοπώρστθωςχυζϊϋΐΰ­","x-mac-icelandic":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûüÝ°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø"+"¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€ÐðÞþý·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-inuit":"ᐃᐄᐅᐆᐊᐋᐱᐲᐳᐴᐸᐹᑉᑎᑏᑐᑑᑕᑖᑦᑭᑮᑯᑰᑲᑳᒃᒋᒌᒍᒎᒐᒑ°ᒡᒥᒦ•¶ᒧ®©™ᒨᒪᒫᒻᓂᓃᓄᓅᓇᓈᓐᓯᓰᓱᓲᓴᓵᔅᓕᓖᓗ"+"ᓘᓚᓛᓪᔨᔩᔪᔫᔭ… ᔮᔾᕕᕖᕗ–—“”‘’ᕘᕙᕚᕝᕆᕇᕈᕉᕋᕌᕐᕿᖀᖁᖂᖃᖄᖅᖏᖐᖑᖒᖓᖔᖕᙱᙲᙳᙴᙵᙶᖖᖠᖡᖢᖣᖤᖥᖦᕼŁł","x-mac-ce":"ÄĀāÉĄÖÜáąČäčĆć鏟ĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅ"+"ņѬ√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ",macintosh:"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø"+"¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-romanian":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ĂȘ∞±≤≥¥µ∂∑∏π∫ªºΩăș"+"¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›Țț‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-turkish":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø"+"¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙˆ˜¯˘˙˚¸˝˛ˇ"};ce.MACSTRING=function(e,t,n,r){var i=pe[r];if(i===undefined){return undefined}var a="";for(var s=0;s=128){a=n[a];if(a===undefined){return undefined}}r[i]=a}return r};l.MACSTRING=function(e,t){var n=I.MACSTRING(e,t);if(n!==undefined){return n.length}else{return 0}};function ge(e){return e>=-128&&e<=127}function me(e,t,n){var r=0;var i=e.length;while(t>8&255,l+256&255)}return a}I.VARDELTAS=function(e){var t=0;var n=[];while(t=-128&&r<=127){t=ve(e,t,n)}else{t=be(e,t,n)}}return n};I.INDEX=function(e){var t=1;var n=[t];var r=[];for(var i=0;i>8;t[p+1]=h&255;t=t.concat(r[c])}return t};l.TABLE=function(e){var t=0;var n=e.fields.length;for(var r=0;r0){return new c(this.data,this.offset+t).parseStruct(e)}return undefined};c.prototype.parsePointer32=function(e){var t=this.parseOffset32();if(t>0){return new c(this.data,this.offset+t).parseStruct(e)}return undefined};c.prototype.parseListOfLists=function(e){var t=this.parseOffset16List();var n=t.length;var r=this.relativeOffset;var i=new Array(n);for(var a=0;a>1;t.skip("uShort",3);e.glyphIndexMap={};var s=new G.Parser(n,r+i+14);var o=new G.Parser(n,r+i+16+a*2);var l=new G.Parser(n,r+i+16+a*4);var u=new G.Parser(n,r+i+16+a*6);var c=r+i+16+a*8;for(var p=0;p=0;i-=1){var a=G.getUShort(e,t+4+i*8);var s=G.getUShort(e,t+4+i*8+2);if(a===3&&(s===0||s===1||s===10)||a===0&&(s===0||s===1||s===2||s===3||s===4)){r=G.getULong(e,t+4+i*8+4);break}}if(r===-1){throw new Error("No valid cmap sub-tables found.")}var o=new G.Parser(e,t+r);n.format=o.parseUShort();if(n.format===12){Ge(n,o)}else if(n.format===4){Ve(n,o,e,t,r)}else{throw new Error("Only format 4 and 12 cmap tables are supported (found format "+n.format+").")}return n}function Fe(e,t,n){e.segments.push({end:t,start:t,delta:-(t-n),offset:0,glyphIndex:n})}function je(e){e.segments.push({end:65535,start:65535,delta:1,offset:0})}function ze(e){var t=true;var n;for(n=e.length-1;n>0;n-=1){var r=e.get(n);if(r.unicode>65535){console.log("Adding CMAP format 12 (needed!)");t=false;break}}var i=[{name:"version",type:"USHORT",value:0},{name:"numTables",type:"USHORT",value:t?1:2},{name:"platformID",type:"USHORT",value:3},{name:"encodingID",type:"USHORT",value:1},{name:"offset",type:"ULONG",value:t?12:12+8}];if(!t){i=i.concat([{name:"cmap12PlatformID",type:"USHORT",value:3},{name:"cmap12EncodingID",type:"USHORT",value:10},{name:"cmap12Offset",type:"ULONG",value:0}])}i=i.concat([{name:"format",type:"USHORT",value:4},{name:"cmap4Length",type:"USHORT",value:0},{name:"language",type:"USHORT",value:0},{name:"segCountX2",type:"USHORT",value:0},{name:"searchRange",type:"USHORT",value:0},{name:"entrySelector",type:"USHORT",value:0},{name:"rangeShift",type:"USHORT",value:0}]);var a=new E.Table("cmap",i);a.segments=[];for(n=0;n>4;var s=i&15;if(a===n){break}t+=r[a];if(s===n){break}t+=r[s]}return parseFloat(t)}function ft(e,t){var n;var r;var i;var a;if(t===28){n=e.parseByte();r=e.parseByte();return n<<8|r}if(t===29){n=e.parseByte();r=e.parseByte();i=e.parseByte();a=e.parseByte();return n<<24|r<<16|i<<8|a}if(t===30){return ht(e)}if(t>=32&&t<=246){return t-139}if(t>=247&&t<=250){n=e.parseByte();return(t-247)*256+n+108}if(t>=251&&t<=254){n=e.parseByte();return-(t-251)*256-n-108}throw new Error("Invalid b0 "+t)}function dt(e){var t={};for(var n=0;n>1;O.length=0;A=true}function M(e){var t;var n;var r;var i;var a;var s;var o;var l;var u;var c;var p;var h;var f=0;while(f1&&!A){U=O.shift()+N;A=true}I+=O.pop();R(T,I);break;case 5:while(O.length>0){T+=O.shift();I+=O.shift();S.lineTo(T,I)}break;case 6:while(O.length>0){T+=O.shift();S.lineTo(T,I);if(O.length===0){break}I+=O.shift();S.lineTo(T,I)}break;case 7:while(O.length>0){I+=O.shift();S.lineTo(T,I);if(O.length===0){break}T+=O.shift();S.lineTo(T,I)}break;case 8:while(O.length>0){v=T+O.shift();b=I+O.shift();y=v+O.shift();x=b+O.shift();T=y+O.shift();I=x+O.shift();S.curveTo(v,b,y,x,T,I)}break;case 10:a=O.pop()+L;s=E[a];if(s){M(s)}break;case 11:return;case 12:d=e[f];f+=1;switch(d){case 35:v=T+O.shift();b=I+O.shift();y=v+O.shift();x=b+O.shift();o=y+O.shift();l=x+O.shift();u=o+O.shift();c=l+O.shift();p=u+O.shift();h=c+O.shift();T=p+O.shift();I=h+O.shift();O.shift();S.curveTo(v,b,y,x,o,l);S.curveTo(u,c,p,h,T,I);break;case 34:v=T+O.shift();b=I;y=v+O.shift();x=b+O.shift();o=y+O.shift();l=x;u=o+O.shift();c=x;p=u+O.shift();h=I;T=p+O.shift();S.curveTo(v,b,y,x,o,l);S.curveTo(u,c,p,h,T,I);break;case 36:v=T+O.shift();b=I+O.shift();y=v+O.shift();x=b+O.shift();o=y+O.shift();l=x;u=o+O.shift();c=x;p=u+O.shift();h=c+O.shift();T=p+O.shift();S.curveTo(v,b,y,x,o,l);S.curveTo(u,c,p,h,T,I);break;case 37:v=T+O.shift();b=I+O.shift();y=v+O.shift();x=b+O.shift();o=y+O.shift();l=x+O.shift();u=o+O.shift();c=l+O.shift();p=u+O.shift();h=c+O.shift();if(Math.abs(p-T)>Math.abs(h-I)){T=p+O.shift()}else{I=h+O.shift()}S.curveTo(v,b,y,x,o,l);S.curveTo(u,c,p,h,T,I);break;default:console.log("Glyph "+m.index+": unknown operator "+1200+d);O.length=0}break;case 14:if(O.length>0&&!A){U=O.shift()+N;A=true}if(C){S.closePath();C=false}break;case 18:P();break;case 19:case 20:P();f+=_+7>>3;break;case 21:if(O.length>2&&!A){U=O.shift()+N;A=true}I+=O.pop();T+=O.pop();R(T,I);break;case 22:if(O.length>1&&!A){U=O.shift()+N;A=true}T+=O.pop();R(T,I);break;case 23:P();break;case 24:while(O.length>2){v=T+O.shift();b=I+O.shift();y=v+O.shift();x=b+O.shift();T=y+O.shift();I=x+O.shift();S.curveTo(v,b,y,x,T,I)}T+=O.shift();I+=O.shift();S.lineTo(T,I);break;case 25:while(O.length>6){T+=O.shift();I+=O.shift();S.lineTo(T,I)}v=T+O.shift();b=I+O.shift();y=v+O.shift();x=b+O.shift();T=y+O.shift();I=x+O.shift();S.curveTo(v,b,y,x,T,I);break;case 26:if(O.length%2){T+=O.shift()}while(O.length>0){v=T;b=I+O.shift();y=v+O.shift();x=b+O.shift();T=y;I=x+O.shift();S.curveTo(v,b,y,x,T,I)}break;case 27:if(O.length%2){I+=O.shift()}while(O.length>0){v=T+O.shift();b=I;y=v+O.shift();x=b+O.shift();T=y+O.shift();I=x;S.curveTo(v,b,y,x,T,I)}break;case 28:t=e[f];n=e[f+1];O.push((t<<24|n<<16)>>16);f+=2;break;case 29:a=O.pop()+g.gsubrsBias;s=g.gsubrs[a];if(s){M(s)}break;case 30:while(O.length>0){v=T;b=I+O.shift();y=v+O.shift();x=b+O.shift();T=y+O.shift();I=x+(O.length===1?O.shift():0);S.curveTo(v,b,y,x,T,I);if(O.length===0){break}v=T+O.shift();b=I;y=v+O.shift();x=b+O.shift();I=x+O.shift();T=y+(O.length===1?O.shift():0);S.curveTo(v,b,y,x,T,I)}break;case 31:while(O.length>0){v=T+O.shift();b=I;y=v+O.shift();x=b+O.shift();I=x+O.shift();T=y+(O.length===1?O.shift():0);S.curveTo(v,b,y,x,T,I);if(O.length===0){break}v=T;b=I+O.shift();y=v+O.shift();x=b+O.shift();T=y+O.shift();I=x+(O.length===1?O.shift():0);S.curveTo(v,b,y,x,T,I)}break;default:if(d<32){console.log("Glyph "+m.index+": unknown operator "+d)}else if(d<247){O.push(d-139)}else if(d<251){t=e[f];f+=1;O.push((d-247)*256+t+108)}else if(d<255){t=e[f];f+=1;O.push(-(d-251)*256-t-108)}else{t=e[f];n=e[f+1];r=e[f+2];i=e[f+3];f+=4;O.push((t<<24|n<<16|r<<8|i)/65536)}}}}M(e);m.advanceWidth=U;return S}function It(e,t,n,r){var i=[];var a;var s=new G.Parser(e,t);var o=s.parseCard8();if(o===0){for(var l=0;l=r){throw new Error("CFF table CID Font FDSelect has bad FD index value "+a+" (FD count "+r+")")}i.push(a)}}else if(o===3){var u=s.parseCard16();var c=s.parseCard16();if(c!==0){throw new Error("CFF Table CID Font FDSelect format 3 range has bad initial GID "+c)}var p;for(var h=0;h=r){throw new Error("CFF table CID Font FDSelect has bad FD index value "+a+" (FD count "+r+")")}if(p>n){throw new Error("CFF Table CID Font FDSelect format 3 range has bad GID "+p)}for(;c=0){n=r}r=t.indexOf(e);if(r>=0){n=r+Xe.length}else{n=Xe.length+t.length;t.push(e)}return n}function Nt(){return new E.Record("Header",[{name:"major",type:"Card8",value:1},{name:"minor",type:"Card8",value:0},{name:"hdrSize",type:"Card8",value:4},{name:"major",type:"Card8",value:1}])}function Ut(e){var t=new E.Record("Name INDEX",[{name:"names",type:"INDEX",value:[]}]);t.names=[];for(var n=0;n=n.begin&&e=1){n.ulCodePageRange1=r.parseULong();n.ulCodePageRange2=r.parseULong()}if(n.version>=2){n.sxHeight=r.parseShort();n.sCapHeight=r.parseShort();n.usDefaultChar=r.parseUShort();n.usBreakChar=r.parseUShort();n.usMaxContent=r.parseUShort()}return n}function Tn(e){return new E.Table("OS/2",[{name:"version",type:"USHORT",value:3},{name:"xAvgCharWidth",type:"SHORT",value:0},{name:"usWeightClass",type:"USHORT",value:0},{name:"usWidthClass",type:"USHORT",value:0},{name:"fsType",type:"USHORT",value:0},{name:"ySubscriptXSize",type:"SHORT",value:650},{name:"ySubscriptYSize",type:"SHORT",value:699},{name:"ySubscriptXOffset",type:"SHORT",value:0},{name:"ySubscriptYOffset",type:"SHORT",value:140},{name:"ySuperscriptXSize",type:"SHORT",value:650},{name:"ySuperscriptYSize",type:"SHORT",value:699},{name:"ySuperscriptXOffset",type:"SHORT",value:0},{name:"ySuperscriptYOffset",type:"SHORT",value:479},{name:"yStrikeoutSize",type:"SHORT",value:49},{name:"yStrikeoutPosition",type:"SHORT",value:258},{name:"sFamilyClass",type:"SHORT",value:0},{name:"bFamilyType",type:"BYTE",value:0},{name:"bSerifStyle",type:"BYTE",value:0},{name:"bWeight",type:"BYTE",value:0},{name:"bProportion",type:"BYTE",value:0},{name:"bContrast",type:"BYTE",value:0},{name:"bStrokeVariation",type:"BYTE",value:0},{name:"bArmStyle",type:"BYTE",value:0},{name:"bLetterform",type:"BYTE",value:0},{name:"bMidline",type:"BYTE",value:0},{name:"bXHeight",type:"BYTE",value:0},{name:"ulUnicodeRange1",type:"ULONG",value:0},{name:"ulUnicodeRange2",type:"ULONG",value:0},{name:"ulUnicodeRange3",type:"ULONG",value:0},{name:"ulUnicodeRange4",type:"ULONG",value:0},{name:"achVendID",type:"CHARARRAY",value:"XXXX"},{name:"fsSelection",type:"USHORT",value:0},{name:"usFirstCharIndex",type:"USHORT",value:0},{name:"usLastCharIndex",type:"USHORT",value:0},{name:"sTypoAscender",type:"SHORT",value:0},{name:"sTypoDescender",type:"SHORT",value:0},{name:"sTypoLineGap",type:"SHORT",value:0},{name:"usWinAscent",type:"USHORT",value:0},{name:"usWinDescent",type:"USHORT",value:0},{name:"ulCodePageRange1",type:"ULONG",value:0},{name:"ulCodePageRange2",type:"ULONG",value:0},{name:"sxHeight",type:"SHORT",value:0},{name:"sCapHeight",type:"SHORT",value:0},{name:"usDefaultChar",type:"USHORT",value:0},{name:"usBreakChar",type:"USHORT",value:0},{name:"usMaxContext",type:"USHORT",value:0}],e)}var In={parse:Cn,make:Tn,unicodeRanges:_n,getUnicodeRange:An};function En(e,t){var n={};var r=new G.Parser(e,t);n.version=r.parseVersion();n.italicAngle=r.parseFixed();n.underlinePosition=r.parseShort();n.underlineThickness=r.parseShort();n.isFixedPitch=r.parseULong();n.minMemType42=r.parseULong();n.maxMemType42=r.parseULong();n.minMemType1=r.parseULong();n.maxMemType1=r.parseULong();switch(n.version){case 1:n.names=u.slice();break;case 2:n.numberOfGlyphs=r.parseUShort();n.glyphNameIndex=new Array(n.numberOfGlyphs);for(var i=0;i=u.length){var s=r.parseChar();n.names.push(r.parseString(s))}}break;case 2.5:n.numberOfGlyphs=r.parseUShort();n.offset=new Array(n.numberOfGlyphs);for(var o=0;ot.value.tag){return 1}else{return-1}});t.fields=t.fields.concat(r);t.fields=t.fields.concat(i);return t}function zn(e,t,n){for(var r=0;r0){var a=e.glyphs.get(i);return a.getMetrics()}}return n}function Hn(e){var t=0;for(var n=0;nm||l===undefined){if(m>0){l=m}}if(u 123 are reserved for internal usage")}if(g.name===".notdef"){continue}var b=g.getMetrics();t.push(b.xMin);n.push(b.yMin);r.push(b.xMax);i.push(b.yMax);s.push(b.leftSideBearing);o.push(b.rightSideBearing);a.push(g.advanceWidth)}var y={xMin:Math.min.apply(null,t),yMin:Math.min.apply(null,n),xMax:Math.max.apply(null,r),yMax:Math.max.apply(null,i),advanceWidthMax:Math.max.apply(null,a),advanceWidthAvg:Hn(a),minLeftSideBearing:Math.min.apply(null,s),maxLeftSideBearing:Math.max.apply(null,s),minRightSideBearing:Math.min.apply(null,o)};y.ascender=e.ascender;y.descender=e.descender;var x=Xt.make({flags:3,unitsPerEm:e.unitsPerEm,xMin:y.xMin,yMin:y.yMin,xMax:y.xMax,yMax:y.yMax,lowestRecPPEM:3,createdTimestamp:e.createdTimestamp});var S=qt.make({ascender:y.ascender,descender:y.descender,advanceWidthMax:y.advanceWidthMax,minLeftSideBearing:y.minLeftSideBearing,minRightSideBearing:y.minRightSideBearing,xMaxExtent:y.maxLeftSideBearing+(y.xMax-y.xMin),numberOfHMetrics:e.glyphs.length});var w=sn.make(e.glyphs.length);var B=In.make(Object.assign({xAvgCharWidth:Math.round(y.advanceWidthAvg),usFirstCharIndex:l,usLastCharIndex:u,ulUnicodeRange1:c,ulUnicodeRange2:p,ulUnicodeRange3:h,ulUnicodeRange4:f,sTypoAscender:y.ascender,sTypoDescender:y.descender,sTypoLineGap:0,usWinAscent:y.yMax,usWinDescent:Math.abs(y.yMin),ulCodePageRange1:1,sxHeight:zn(e,"xyvw",{yMax:Math.round(y.ascender/2)}).yMax,sCapHeight:zn(e,"HIKLEFJMNTZBDPRAGOQSUVWXY",y).yMax,usDefaultChar:e.hasChar(" ")?32:0,usBreakChar:e.hasChar(" ")?32:0},e.tables.os2));var G=$t.make(e.glyphs);var V=He.make(e.glyphs);var O=e.getEnglishName("fontFamily");var _=e.getEnglishName("fontSubfamily");var A=O+" "+_;var C=e.getEnglishName("postScriptName");if(!C){C=O.replace(/\s/g,"")+"-"+_}var T={};for(var I in e.names){T[I]=e.names[I]}if(!T.uniqueID){T.uniqueID={en:e.getEnglishName("manufacturer")+":"+A}}if(!T.postScriptName){T.postScriptName={en:C}}if(!T.preferredFamily){T.preferredFamily=e.names.fontFamily}if(!T.preferredSubfamily){T.preferredSubfamily=e.names.fontSubfamily}var E=[];var D=On.make(T,E);var L=E.length>0?nn.make(E):undefined;var F=Nn.make();var j=jt.make(e.glyphs,{version:e.getEnglishName("version"),fullName:A,familyName:O,weightName:_,postScriptName:C,unitsPerEm:e.unitsPerEm,fontBBox:[0,y.yMin,y.ascender,y.advanceWidthMax]});var N=e.metas&&Object.keys(e.metas).length>0?Gn.make(e.metas):undefined;var U=[x,S,w,B,D,V,F,j,G];if(L){U.push(L)}if(e.tables.gsub){U.push(kn.make(e.tables.gsub))}if(N){U.push(N)}var R=jn(U);var z=R.encode();var H=Dn(z);var P=R.fields;var M=false;for(var k=0;k>>1;var a=e[i].tag;if(a===t){return i}else if(a>>1;var a=e[i];if(a===t){return i}else if(a>>1;n=e[a];var s=n.start;if(s===t){return n}else if(s0){n=e[r-1];if(t>n.end){return 0}return n}}function Kn(e,t){this.font=e;this.tableName=t}Kn.prototype={searchTag:Wn,binSearch:qn,getTable:function(e){var t=this.font.tables[this.tableName];if(!t&&e){t=this.font.tables[this.tableName]=this.createDefaultTable()}return t},getScriptNames:function(){var e=this.getTable();if(!e){return[]}return e.scripts.map(function(e){return e.tag})},getDefaultScriptName:function(){var e=this.getTable();if(!e){return}var t=false;for(var n=0;n=0){return r[i].script}else if(t){var a={tag:e,script:{defaultLangSys:{reserved:0,reqFeatureIndex:65535,featureIndexes:[]},langSysRecords:[]}};r.splice(-1-i,0,a);return a.script}}},getLangSysTable:function(e,t,n){var r=this.getScriptTable(e,n);if(r){if(!t||t==="dflt"||t==="DFLT"){return r.defaultLangSys}var i=Wn(r.langSysRecords,t);if(i>=0){return r.langSysRecords[i].langSys}else if(n){var a={tag:t,langSys:{reserved:0,reqFeatureIndex:65535,featureIndexes:[]}};r.langSysRecords.splice(-1-i,0,a);return a.langSys}}},getFeatureTable:function(e,t,n,r){var i=this.getLangSysTable(e,t,r);if(i){var a;var s=i.featureIndexes;var o=this.font.tables[this.tableName].features;for(var l=0;l=o[u-1].tag,"Features must be added in alphabetical order.");a={tag:n,feature:{params:0,lookupListIndexes:[]}};o.push(a);s.push(u);return a.feature}}},getLookupTables:function(e,t,n,r,i){var a=this.getFeatureTable(e,t,n,i);var s=[];if(a){var o;var l=a.lookupListIndexes;var u=this.font.tables[this.tableName].lookups;for(var c=0;c=0?n:-1;case 2:var r=Zn(e.ranges,t);return r?r.index+t-r.start:-1}},expandCoverage:function(e){if(e.format===1){return e.glyphs}else{var t=[];var n=e.ranges;for(var r=0;r1,'Multiple: "by" must be an array of two or more ids');var i=this.getLookupTables(n,r,e,2,true)[0];var a=$n(i,1,{substFormat:1,coverage:{format:1,glyphs:[]},sequences:[]});_.assert(a.coverage.format===1,"Multiple: unable to modify coverage table format "+a.coverage.format);var s=t.sub;var o=this.binSearch(a.coverage.glyphs,s);if(o<0){o=-1-o;a.coverage.glyphs.splice(o,0,s);a.sequences.splice(o,0,0)}a.sequences[o]=t.by};t.prototype.addAlternate=function(e,t,n,r){var i=this.getLookupTables(n,r,e,3,true)[0];var a=$n(i,1,{substFormat:1,coverage:{format:1,glyphs:[]},alternateSets:[]});_.assert(a.coverage.format===1,"Alternate: unable to modify coverage table format "+a.coverage.format);var s=t.sub;var o=this.binSearch(a.coverage.glyphs,s);if(o<0){o=-1-o;a.coverage.glyphs.splice(o,0,s);a.alternateSets.splice(o,0,0)}a.alternateSets[o]=t.by};t.prototype.addLigature=function(e,t,n,r){var i=this.getLookupTables(n,r,e,4,true)[0];var a=i.subtables[0];if(!a){a={substFormat:1,coverage:{format:1,glyphs:[]},ligatureSets:[]};i.subtables[0]=a}_.assert(a.coverage.format===1,"Ligature: unable to modify coverage table format "+a.coverage.format);var s=t.sub[0];var o=t.sub.slice(1);var l={ligGlyph:t.by,components:o};var u=this.binSearch(a.coverage.glyphs,s);if(u>=0){var c=a.ligatureSets[u];for(var p=0;p0){a=e.parseByte();if((t&i)===0){a=-a}a=n+a}else{if((t&i)>0){a=n}else{a=n+e.parseShort()}}return a}function ar(e,t,n){var r=new G.Parser(t,n);e.numberOfContours=r.parseShort();e._xMin=r.parseShort();e._yMin=r.parseShort();e._xMax=r.parseShort();e._yMax=r.parseShort();var i;var a;if(e.numberOfContours>0){var s=e.endPointIndices=[];for(var o=0;o0){var p=r.parseByte();for(var h=0;h0){var f=[];var d;if(u>0){for(var g=0;g=0;f.push(d)}var m=0;for(var v=0;v0){if((i&2)>0){S.dx=r.parseShort();S.dy=r.parseShort()}else{S.matchedPoints=[r.parseUShort(),r.parseUShort()]}}else{if((i&2)>0){S.dx=r.parseChar();S.dy=r.parseChar()}else{S.matchedPoints=[r.parseByte(),r.parseByte()]}}if((i&8)>0){S.xScale=S.yScale=r.parseF2Dot14()}else if((i&64)>0){S.xScale=r.parseF2Dot14();S.yScale=r.parseF2Dot14()}else if((i&128)>0){S.xScale=r.parseF2Dot14();S.scale01=r.parseF2Dot14();S.scale10=r.parseF2Dot14();S.yScale=r.parseF2Dot14()}e.components.push(S);x=!!(i&32)}if(i&256){e.instructionLength=r.parseUShort();e.instructions=[];for(var O=0;Ot.points.length-1||r.matchedPoints[1]>i.points.length-1){throw Error("Matched points out of range in "+t.name)}var s=t.points[r.matchedPoints[0]];var o=i.points[r.matchedPoints[1]];var l={xScale:r.xScale,scale01:r.scale01,scale10:r.scale10,yScale:r.yScale,dx:0,dy:0};o=sr([o],l)[0];l.dx=s.x-o.x;l.dy=s.y-o.y;a=sr(i.points,l)}t.points=t.points.concat(a)}}}return lr(t.points)}function cr(e,t,n,r){var i=new A.GlyphSet(r);for(var a=0;a2){return}var n=this.font;var r=this._prepState;if(!r||r.ppem!==t){var i=this._fpgmState;if(!i){S.prototype=Lr;i=this._fpgmState=new S("fpgm",n.tables.fpgm);i.funcs=[];i.font=n;if(C.DEBUG){console.log("---EXEC FPGM---");i.step=-1}try{gr(i)}catch(e){console.log("Hinting error in FPGM:"+e);this._errorState=3;return}}S.prototype=i;r=this._prepState=new S("prep",n.tables.prep);r.ppem=t;var a=n.tables.cvt;if(a){var s=r.cvt=new Array(a.length);var o=t/n.unitsPerEm;for(var l=0;l1){return}try{return mr(e,r)}catch(e){if(this._errorState<1){console.log("Hinting error:"+e);console.log("Note: further hinting errors are silenced")}this._errorState=1;return undefined}};mr=function(e,t){var n=t.ppem/t.font.unitsPerEm;var r=n;var i=e.components;var a;var s;var o;S.prototype=t;if(!i){o=new S("glyf",e.instructions);if(C.DEBUG){console.log("---EXEC GLYPH---");o.step=-1}vr(e,o,n,r);s=o.gZone}else{var l=t.font;s=[];a=[];for(var u=0;u=176&&a<=183){r+=a-176+1}else if(a>=184&&a<=191){r+=(a-184+1)*2}else if(t&&i===1&&a===27){break}}while(i>0);e.ip=r}function Rr(e,t){if(C.DEBUG){console.log(t.step,"SVTCA["+e.axis+"]")}t.fv=t.pv=t.dpv=e}function Pr(e,t){if(C.DEBUG){console.log(t.step,"SPVTCA["+e.axis+"]")}t.pv=t.dpv=e}function Mr(e,t){if(C.DEBUG){console.log(t.step,"SFVTCA["+e.axis+"]")}t.fv=e}function kr(e,t){var n=t.stack;var r=n.pop();var i=n.pop();var a=t.z2[r];var s=t.z1[i];if(C.DEBUG){console.log("SPVTL["+e+"]",r,i)}var o;var l;if(!e){o=s.x-a.x;l=s.y-a.y}else{o=a.y-s.y;l=s.x-a.x}t.pv=t.dpv=Ir(o,l)}function wr(e,t){var n=t.stack;var r=n.pop();var i=n.pop();var a=t.z2[r];var s=t.z1[i];if(C.DEBUG){console.log("SFVTL["+e+"]",r,i)}var o;var l;if(!e){o=s.x-a.x;l=s.y-a.y}else{o=a.y-s.y;l=s.x-a.x}t.fv=Ir(o,l)}function Br(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"SPVFS[]",n,r)}e.pv=e.dpv=Ir(r,n)}function Gr(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"SPVFS[]",n,r)}e.fv=Ir(r,n)}function Vr(e){var t=e.stack;var n=e.pv;if(C.DEBUG){console.log(e.step,"GPV[]")}t.push(n.x*16384);t.push(n.y*16384)}function Dr(e){var t=e.stack;var n=e.fv;if(C.DEBUG){console.log(e.step,"GFV[]")}t.push(n.x*16384);t.push(n.y*16384)}function Fr(e){e.fv=e.pv;if(C.DEBUG){console.log(e.step,"SFVTPV[]")}}function jr(e){var t=e.stack;var n=t.pop();var r=t.pop();var i=t.pop();var a=t.pop();var s=t.pop();var o=e.z0;var l=e.z1;var u=o[n];var c=o[r];var p=l[i];var h=l[a];var f=e.z2[s];if(C.DEBUG){console.log("ISECT[], ",n,r,i,a,s)}var d=u.x;var g=u.y;var m=c.x;var v=c.y;var b=p.x;var y=p.y;var x=h.x;var S=h.y;var O=(d-m)*(y-S)-(g-v)*(b-x);var _=d*v-g*m;var A=b*S-y*x;f.x=(_*(b-x)-A*(d-m))/O;f.y=(_*(y-S)-A*(g-v))/O}function zr(e){e.rp0=e.stack.pop();if(C.DEBUG){console.log(e.step,"SRP0[]",e.rp0)}}function Hr(e){e.rp1=e.stack.pop();if(C.DEBUG){console.log(e.step,"SRP1[]",e.rp1)}}function Xr(e){e.rp2=e.stack.pop();if(C.DEBUG){console.log(e.step,"SRP2[]",e.rp2)}}function Yr(e){var t=e.stack.pop();if(C.DEBUG){console.log(e.step,"SZP0[]",t)}e.zp0=t;switch(t){case 0:if(!e.tZone){Nr(e)}e.z0=e.tZone;break;case 1:e.z0=e.gZone;break;default:throw new Error("Invalid zone pointer")}}function Wr(e){var t=e.stack.pop();if(C.DEBUG){console.log(e.step,"SZP1[]",t)}e.zp1=t;switch(t){case 0:if(!e.tZone){Nr(e)}e.z1=e.tZone;break;case 1:e.z1=e.gZone;break;default:throw new Error("Invalid zone pointer")}}function qr(e){var t=e.stack.pop();if(C.DEBUG){console.log(e.step,"SZP2[]",t)}e.zp2=t;switch(t){case 0:if(!e.tZone){Nr(e)}e.z2=e.tZone;break;case 1:e.z2=e.gZone;break;default:throw new Error("Invalid zone pointer")}}function Zr(e){var t=e.stack.pop();if(C.DEBUG){console.log(e.step,"SZPS[]",t)}e.zp0=e.zp1=e.zp2=t;switch(t){case 0:if(!e.tZone){Nr(e)}e.z0=e.z1=e.z2=e.tZone;break;case 1:e.z0=e.z1=e.z2=e.gZone;break;default:throw new Error("Invalid zone pointer")}}function Kr(e){e.loop=e.stack.pop();if(C.DEBUG){console.log(e.step,"SLOOP[]",e.loop)}}function Qr(e){if(C.DEBUG){console.log(e.step,"RTG[]")}e.round=xr}function Jr(e){if(C.DEBUG){console.log(e.step,"RTHG[]")}e.round=Or}function $r(e){var t=e.stack.pop();if(C.DEBUG){console.log(e.step,"SMD[]",t)}e.minDis=t/64}function ei(e){if(C.DEBUG){console.log(e.step,"ELSE[]")}Ur(e,false)}function ti(e){var t=e.stack.pop();if(C.DEBUG){console.log(e.step,"JMPR[]",t)}e.ip+=t-1}function ni(e){var t=e.stack.pop();if(C.DEBUG){console.log(e.step,"SCVTCI[]",t)}e.cvCutIn=t/64}function ri(e){var t=e.stack;if(C.DEBUG){console.log(e.step,"DUP[]")}t.push(t[t.length-1])}function ii(e){if(C.DEBUG){console.log(e.step,"POP[]")}e.stack.pop()}function ai(e){if(C.DEBUG){console.log(e.step,"CLEAR[]")}e.stack.length=0}function si(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"SWAP[]")}t.push(n);t.push(r)}function oi(e){var t=e.stack;if(C.DEBUG){console.log(e.step,"DEPTH[]")}t.push(t.length)}function li(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"LOOPCALL[]",n,r)}var i=e.ip;var a=e.prog;e.prog=e.funcs[n];for(var s=0;s1?"loop "+(t.loop-o)+": ":"")+"SHP["+(e?"rp1":"rp2")+"]",u)}}t.loop=1}function mi(e,t){var n=t.stack;var r=e?t.rp1:t.rp2;var i=(e?t.z0:t.z1)[r];var a=t.fv;var s=t.pv;var o=n.pop();var l=t.z2[t.contours[o]];var u=l;if(C.DEBUG){console.log(t.step,"SHC["+e+"]",o)}var c=s.distance(i,i,false,true);do{if(u!==i){a.setRelative(u,u,c,s)}u=u.nextPointOnContour}while(u!==l)}function vi(e,t){var n=t.stack;var r=e?t.rp1:t.rp2;var i=(e?t.z0:t.z1)[r];var a=t.fv;var s=t.pv;var o=n.pop();if(C.DEBUG){console.log(t.step,"SHZ["+e+"]",o)}var l;switch(o){case 0:l=t.tZone;break;case 1:l=t.gZone;break;default:throw new Error("Invalid zone")}var u;var c=s.distance(i,i,false,true);var p=l.length-2;for(var h=0;h1?"loop "+(e.loop-n)+": ":"")+"SHPIX[]",s,i)}r.setRelative(o,o,i);r.touch(o)}e.loop=1}function yi(e){var t=e.stack;var n=e.rp1;var r=e.rp2;var i=e.loop;var a=e.z0[n];var s=e.z1[r];var o=e.fv;var l=e.dpv;var u=e.z2;while(i--){var c=t.pop();var p=u[c];if(C.DEBUG){console.log(e.step,(e.loop>1?"loop "+(e.loop-i)+": ":"")+"IP[]",c,n,"<->",r)}o.interpolate(p,a,s,l);o.touch(p)}e.loop=1}function xi(e,t){var n=t.stack;var r=n.pop()/64;var i=n.pop();var a=t.z1[i];var s=t.z0[t.rp0];var o=t.fv;var l=t.pv;o.setRelative(a,s,r,l);o.touch(a);if(C.DEBUG){console.log(t.step,"MSIRP["+e+"]",r,i)}t.rp1=t.rp0;t.rp2=i;if(e){t.rp0=i}}function Si(e){var t=e.stack;var n=e.rp0;var r=e.z0[n];var i=e.loop;var a=e.fv;var s=e.pv;var o=e.z1;while(i--){var l=t.pop();var u=o[l];if(C.DEBUG){console.log(e.step,(e.loop>1?"loop "+(e.loop-i)+": ":"")+"ALIGNRP[]",l)}a.setRelative(u,r,0,s);a.touch(u)}e.loop=1}function Oi(e){if(C.DEBUG){console.log(e.step,"RTDG[]")}e.round=Sr}function _i(e,t){var n=t.stack;var r=n.pop();var i=n.pop();var a=t.z0[i];var s=t.fv;var o=t.pv;var l=t.cvt[r];if(C.DEBUG){console.log(t.step,"MIAP["+e+"]",r,"(",l,")",i)}var u=o.distance(a,Er);if(e){if(Math.abs(u-l)",o)}t.stack.push(Math.round(o*64))}function Ri(e){if(C.DEBUG){console.log(e.step,"MPPEM[]")}e.stack.push(e.ppem)}function Pi(e){if(C.DEBUG){console.log(e.step,"FLIPON[]")}e.autoFlip=true}function Mi(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"LT[]",n,r)}t.push(rn?1:0)}function Bi(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"GTEQ[]",n,r)}t.push(r>=n?1:0)}function Gi(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"EQ[]",n,r)}t.push(n===r?1:0)}function Vi(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"NEQ[]",n,r)}t.push(n!==r?1:0)}function Di(e){var t=e.stack;var n=t.pop();if(C.DEBUG){console.log(e.step,"ODD[]",n)}t.push(Math.trunc(n)%2?1:0)}function Fi(e){var t=e.stack;var n=t.pop();if(C.DEBUG){console.log(e.step,"EVEN[]",n)}t.push(Math.trunc(n)%2?0:1)}function ji(e){var t=e.stack.pop();if(C.DEBUG){console.log(e.step,"IF[]",t)}if(!t){Ur(e,true);if(C.DEBUG){console.log(e.step,"EIF[]")}}}function zi(e){if(C.DEBUG){console.log(e.step,"EIF[]")}}function Hi(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"AND[]",n,r)}t.push(n&&r?1:0)}function Xi(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"OR[]",n,r)}t.push(n||r?1:0)}function Yi(e){var t=e.stack;var n=t.pop();if(C.DEBUG){console.log(e.step,"NOT[]",n)}t.push(n?0:1)}function Wi(e,t){var n=t.stack;var r=n.pop();var i=t.fv;var a=t.pv;var s=t.ppem;var o=t.deltaBase+(e-1)*16;var l=t.deltaShift;var u=t.z0;if(C.DEBUG){console.log(t.step,"DELTAP["+e+"]",r,n)}for(var c=0;c>4);if(f!==s){continue}var d=(h&15)-8;if(d>=0){d++}if(C.DEBUG){console.log(t.step,"DELTAPFIX",p,"by",d*l)}var g=u[p];i.setRelative(g,g,d*l,a)}}function qi(e){var t=e.stack;var n=t.pop();if(C.DEBUG){console.log(e.step,"SDB[]",n)}e.deltaBase=n}function Zi(e){var t=e.stack;var n=t.pop();if(C.DEBUG){console.log(e.step,"SDS[]",n)}e.deltaShift=Math.pow(.5,n)}function Ki(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"ADD[]",n,r)}t.push(r+n)}function Qi(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"SUB[]",n,r)}t.push(r-n)}function Ji(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"DIV[]",n,r)}t.push(r*64/n)}function $i(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"MUL[]",n,r)}t.push(r*n/64)}function ea(e){var t=e.stack;var n=t.pop();if(C.DEBUG){console.log(e.step,"ABS[]",n)}t.push(Math.abs(n))}function ta(e){var t=e.stack;var n=t.pop();if(C.DEBUG){console.log(e.step,"NEG[]",n)}t.push(-n)}function na(e){var t=e.stack;var n=t.pop();if(C.DEBUG){console.log(e.step,"FLOOR[]",n)}t.push(Math.floor(n/64)*64)}function ra(e){var t=e.stack;var n=t.pop();if(C.DEBUG){console.log(e.step,"CEILING[]",n)}t.push(Math.ceil(n/64)*64)}function ia(e,t){var n=t.stack;var r=n.pop();if(C.DEBUG){console.log(t.step,"ROUND[]")}n.push(t.round(r/64)*64)}function aa(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"WCVTF[]",n,r)}e.cvt[r]=n*e.ppem/e.font.unitsPerEm}function sa(e,t){var n=t.stack;var r=n.pop();var i=t.ppem;var a=t.deltaBase+(e-1)*16;var s=t.deltaShift;if(C.DEBUG){console.log(t.step,"DELTAC["+e+"]",r,n)}for(var o=0;o>4);if(c!==i){continue}var p=(u&15)-8;if(p>=0){p++}var h=p*s;if(C.DEBUG){console.log(t.step,"DELTACFIX",l,"by",h)}t.cvt[l]+=h}}function oa(e){var t=e.stack.pop();if(C.DEBUG){console.log(e.step,"SROUND[]",t)}e.round=Cr;var n;switch(t&192){case 0:n=.5;break;case 64:n=1;break;case 128:n=2;break;default:throw new Error("invalid SROUND value")}e.srPeriod=n;switch(t&48){case 0:e.srPhase=0;break;case 16:e.srPhase=.25*n;break;case 32:e.srPhase=.5*n;break;case 48:e.srPhase=.75*n;break;default:throw new Error("invalid SROUND value")}t&=15;if(t===0){e.srThreshold=0}else{e.srThreshold=(t/8-.5)*n}}function la(e){var t=e.stack.pop();if(C.DEBUG){console.log(e.step,"S45ROUND[]",t)}e.round=Cr;var n;switch(t&192){case 0:n=Math.sqrt(2)/2;break;case 64:n=Math.sqrt(2);break;case 128:n=2*Math.sqrt(2);break;default:throw new Error("invalid S45ROUND value")}e.srPeriod=n;switch(t&48){case 0:e.srPhase=0;break;case 16:e.srPhase=.25*n;break;case 32:e.srPhase=.5*n;break;case 48:e.srPhase=.75*n;break;default:throw new Error("invalid S45ROUND value")}t&=15;if(t===0){e.srThreshold=0}else{e.srThreshold=(t/8-.5)*n}}function ua(e){if(C.DEBUG){console.log(e.step,"ROFF[]")}e.round=yr}function ca(e){if(C.DEBUG){console.log(e.step,"RUTG[]")}e.round=_r}function pa(e){if(C.DEBUG){console.log(e.step,"RDTG[]")}e.round=Ar}function ha(e){var t=e.stack.pop();if(C.DEBUG){console.log(e.step,"SCANCTRL[]",t)}}function fa(e,t){var n=t.stack;var r=n.pop();var i=n.pop();var a=t.z2[r];var s=t.z1[i];if(C.DEBUG){console.log(t.step,"SDPVTL["+e+"]",r,i)}var o;var l;if(!e){o=s.x-a.x;l=s.y-a.y}else{o=a.y-s.y;l=s.x-a.x}t.dpv=Ir(o,l)}function da(e){var t=e.stack;var n=t.pop();var r=0;if(C.DEBUG){console.log(e.step,"GETINFO[]",n)}if(n&1){r=35}if(n&32){r|=4096}t.push(r)}function ga(e){var t=e.stack;var n=t.pop();var r=t.pop();var i=t.pop();if(C.DEBUG){console.log(e.step,"ROLL[]")}t.push(r);t.push(n);t.push(i)}function ma(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"MAX[]",n,r)}t.push(Math.max(r,n))}function va(e){var t=e.stack;var n=t.pop();var r=t.pop();if(C.DEBUG){console.log(e.step,"MIN[]",n,r)}t.push(Math.min(r,n))}function ba(e){var t=e.stack.pop();if(C.DEBUG){console.log(e.step,"SCANTYPE[]",t)}}function ya(e){var t=e.stack.pop();var n=e.stack.pop();if(C.DEBUG){console.log(e.step,"INSTCTRL[]",t,n)}switch(t){case 1:e.inhibitGridFit=!!n;return;case 2:e.ignoreCvt=!!n;return;default:throw new Error("invalid INSTCTRL[] selector")}}function n(e,t){var n=t.stack;var r=t.prog;var i=t.ip;if(C.DEBUG){console.log(t.step,"PUSHB["+e+"]")}for(var a=0;a=0?1:-1;m=Math.abs(m);if(e){b=a.cvt[o];if(r&&Math.abs(m-b)":"_")+(r?"R":"_")+(i===0?"Gr":i===1?"Bl":i===2?"Wh":"")+"]",e?o+"("+a.cvt[o]+","+b+")":"",l,"(d =",g,"->",v*m,")")}a.rp1=a.rp0;a.rp2=l;if(t){a.rp0=l}}dr=[Rr.bind(undefined,v),Rr.bind(undefined,m),Pr.bind(undefined,v),Pr.bind(undefined,m),Mr.bind(undefined,v),Mr.bind(undefined,m),kr.bind(undefined,0),kr.bind(undefined,1),wr.bind(undefined,0),wr.bind(undefined,1),Br,Gr,Vr,Dr,Fr,jr,zr,Hr,Xr,Yr,Wr,qr,Zr,Kr,Qr,Jr,$r,ei,ti,ni,undefined,undefined,ri,ii,ai,si,oi,ci,pi,undefined,undefined,undefined,li,ui,hi,undefined,fi.bind(undefined,0),fi.bind(undefined,1),di.bind(undefined,v),di.bind(undefined,m),gi.bind(undefined,0),gi.bind(undefined,1),mi.bind(undefined,0),mi.bind(undefined,1),vi.bind(undefined,0),vi.bind(undefined,1),bi,yi,xi.bind(undefined,0),xi.bind(undefined,1),Si,Oi,_i.bind(undefined,0),_i.bind(undefined,1),Ai,Ci,Ti,Ii,Ei,Li,Ni.bind(undefined,0),Ni.bind(undefined,1),undefined,Ui.bind(undefined,0),Ui.bind(undefined,1),Ri,undefined,Pi,undefined,undefined,Mi,ki,wi,Bi,Gi,Vi,Di,Fi,ji,zi,Hi,Xi,Yi,Wi.bind(undefined,1),qi,Zi,Ki,Qi,Ji,$i,ea,ta,na,ra,ia.bind(undefined,0),ia.bind(undefined,1),ia.bind(undefined,2),ia.bind(undefined,3),undefined,undefined,undefined,undefined,aa,Wi.bind(undefined,2),Wi.bind(undefined,3),sa.bind(undefined,1),sa.bind(undefined,2),sa.bind(undefined,3),oa,la,undefined,undefined,ua,undefined,ca,pa,ii,ii,undefined,undefined,undefined,undefined,undefined,ha,fa.bind(undefined,0),fa.bind(undefined,1),da,undefined,ga,ma,va,ba,ya,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,n.bind(undefined,1),n.bind(undefined,2),n.bind(undefined,3),n.bind(undefined,4),n.bind(undefined,5),n.bind(undefined,6),n.bind(undefined,7),n.bind(undefined,8),r.bind(undefined,1),r.bind(undefined,2),r.bind(undefined,3),r.bind(undefined,4),r.bind(undefined,5),r.bind(undefined,6),r.bind(undefined,7),r.bind(undefined,8),s.bind(undefined,0,0,0,0,0),s.bind(undefined,0,0,0,0,1),s.bind(undefined,0,0,0,0,2),s.bind(undefined,0,0,0,0,3),s.bind(undefined,0,0,0,1,0),s.bind(undefined,0,0,0,1,1),s.bind(undefined,0,0,0,1,2),s.bind(undefined,0,0,0,1,3),s.bind(undefined,0,0,1,0,0),s.bind(undefined,0,0,1,0,1),s.bind(undefined,0,0,1,0,2),s.bind(undefined,0,0,1,0,3),s.bind(undefined,0,0,1,1,0),s.bind(undefined,0,0,1,1,1),s.bind(undefined,0,0,1,1,2),s.bind(undefined,0,0,1,1,3),s.bind(undefined,0,1,0,0,0),s.bind(undefined,0,1,0,0,1),s.bind(undefined,0,1,0,0,2),s.bind(undefined,0,1,0,0,3),s.bind(undefined,0,1,0,1,0),s.bind(undefined,0,1,0,1,1),s.bind(undefined,0,1,0,1,2),s.bind(undefined,0,1,0,1,3),s.bind(undefined,0,1,1,0,0),s.bind(undefined,0,1,1,0,1),s.bind(undefined,0,1,1,0,2),s.bind(undefined,0,1,1,0,3),s.bind(undefined,0,1,1,1,0),s.bind(undefined,0,1,1,1,1),s.bind(undefined,0,1,1,1,2),s.bind(undefined,0,1,1,1,3),s.bind(undefined,1,0,0,0,0),s.bind(undefined,1,0,0,0,1),s.bind(undefined,1,0,0,0,2),s.bind(undefined,1,0,0,0,3),s.bind(undefined,1,0,0,1,0),s.bind(undefined,1,0,0,1,1),s.bind(undefined,1,0,0,1,2),s.bind(undefined,1,0,0,1,3),s.bind(undefined,1,0,1,0,0),s.bind(undefined,1,0,1,0,1),s.bind(undefined,1,0,1,0,2),s.bind(undefined,1,0,1,0,3),s.bind(undefined,1,0,1,1,0),s.bind(undefined,1,0,1,1,1),s.bind(undefined,1,0,1,1,2),s.bind(undefined,1,0,1,1,3),s.bind(undefined,1,1,0,0,0),s.bind(undefined,1,1,0,0,1),s.bind(undefined,1,1,0,0,2),s.bind(undefined,1,1,0,0,3),s.bind(undefined,1,1,0,1,0),s.bind(undefined,1,1,0,1,1),s.bind(undefined,1,1,0,1,2),s.bind(undefined,1,1,0,1,3),s.bind(undefined,1,1,1,0,0),s.bind(undefined,1,1,1,0,1),s.bind(undefined,1,1,1,0,2),s.bind(undefined,1,1,1,0,3),s.bind(undefined,1,1,1,1,0),s.bind(undefined,1,1,1,1,1),s.bind(undefined,1,1,1,1,2),s.bind(undefined,1,1,1,1,3)];function xa(e){this.char=e;this.state={};this.activeState=null}function Sa(e,t,n){this.contextName=n;this.startIndex=e;this.endOffset=t}function Oa(e,t,n){this.contextName=e;this.openRange=null;this.ranges=[];this.checkStart=t;this.checkEnd=n}function L(e,t){this.context=e;this.index=t;this.length=e.length;this.current=e[t];this.backtrack=e.slice(0,t);this.lookahead=e.slice(t+1)}function _a(e){this.eventId=e;this.subscribers=[]}function Aa(n){var r=this;var e=["start","end","next","newToken","contextStart","contextEnd","insertToken","removeToken","removeRange","replaceToken","replaceRange","composeRUD","updateContextsRanges"];e.forEach(function(e){Object.defineProperty(r.events,e,{value:new _a(e)})});if(!!n){e.forEach(function(e){var t=n[e];if(typeof t==="function"){r.events[e].subscribe(t)}})}var t=["insertToken","removeToken","removeRange","replaceToken","replaceRange","composeRUD"];t.forEach(function(e){r.events[e].subscribe(r.updateContextsRanges)})}function b(e){this.tokens=[];this.registeredContexts={};this.contextCheckers=[];this.events={};this.registeredModifiers=[];Aa.call(this,e)}xa.prototype.setState=function(e,t){this.state[e]=t;this.activeState={key:e,value:this.state[e]};return this.activeState};xa.prototype.getState=function(e){return this.state[e]||null};b.prototype.inboundIndex=function(e){return e>=0&&e0&&e<=this.lookahead.length:return this.lookahead[e-1];default:return null}};b.prototype.rangeToText=function(e){if(e instanceof Sa){return this.getRangeTokens(e).map(function(e){return e.char}).join("")}};b.prototype.getText=function(){return this.tokens.map(function(e){return e.char}).join("")};b.prototype.getContext=function(e){var t=this.registeredContexts[e];return!!t?t:null};b.prototype.on=function(e,t){var n=this.events[e];if(!!n){return n.subscribe(t)}else{return null}};b.prototype.dispatch=function(e,t){var n=this;var r=this.events[e];if(r instanceof _a){r.subscribers.forEach(function(e){e.apply(n,t||[])})}};b.prototype.registerContextChecker=function(e,t,n){if(!!this.getContext(e)){return{FAIL:"context name '"+e+"' is already registered."}}if(typeof t!=="function"){return{FAIL:"missing context start check."}}if(typeof n!=="function"){return{FAIL:"missing context end check."}}var r=new Oa(e,t,n);this.registeredContexts[e]=r;this.contextCheckers.push(r);return r};b.prototype.getRangeTokens=function(e){var t=e.startIndex+e.endOffset;return[].concat(this.tokens.slice(e.startIndex,t))};b.prototype.getContextRanges=function(e){var t=this.getContext(e);if(!!t){return t.ranges}else{return{FAIL:"context checker '"+e+"' is not registered."}}};b.prototype.resetContextsRanges=function(){var e=this.registeredContexts;for(var t in e){if(e.hasOwnProperty(t)){var n=e[t];n.ranges=[]}}};b.prototype.updateContextsRanges=function(){this.resetContextsRanges();var e=this.tokens.map(function(e){return e.char});for(var t=0;t=i.start&&e<=i.end){var a=e-i.start;return i.index+a}}break;default:return-1}return-1}function Na(e,t){var n=La(e,t.coverage);if(n===-1){return null}return e+t.deltaGlyphId}function Ua(e,t){var n=La(e,t.coverage);if(n===-1){return null}return t.substitute[n]}function Ra(e,t){var n=[];for(var r=0;r=0;n--){var r=t[n];var i=Ca(r);var a=N(r);if(!i&&!a){return true}if(i){return false}}return false}function Za(e){if(Ca(e.current)){return false}for(var t=0;t0)}e("fontFamily");e("weightName");e("manufacturer");e("copyright");e("version");r(this.unitsPerEm>0)};V.prototype.toTables=function(){return Yn.fontToTable(this)};V.prototype.toBuffer=function(){console.warn("Font.toBuffer is deprecated. Use Font.toArrayBuffer instead.");return this.toArrayBuffer()};V.prototype.toArrayBuffer=function(){var e=this.toTables();var t=e.encode();var n=new ArrayBuffer(t.length);var r=new Uint8Array(n);for(var i=0;i=1.2){i.markGlyphSets=n.parsePointer(_s)}return i}var Cs={parse:As};var R=new Array(10);R[1]=function e(){var t=this.offset+this.relativeOffset;var n=this.parseUShort();if(n===1){return{posFormat:1,coverage:this.parsePointer(c.coverage),value:this.parseValueRecord()}}else if(n===2){return{posFormat:2,coverage:this.parsePointer(c.coverage),values:this.parseValueRecordList()}}_.assert(false,"0x"+t.toString(16)+": GPOS lookup type 1 format must be 1 or 2.")};R[2]=function e(){var t=this.offset+this.relativeOffset;var n=this.parseUShort();_.assert(n===1||n===2,"0x"+t.toString(16)+": GPOS lookup type 2 format must be 1 or 2.");var r=this.parsePointer(c.coverage);var i=this.parseUShort();var a=this.parseUShort();if(n===1){return{posFormat:n,coverage:r,valueFormat1:i,valueFormat2:a,pairSets:this.parseList(c.pointer(c.list(function(){return{secondGlyph:this.parseUShort(),value1:this.parseValueRecord(i),value2:this.parseValueRecord(a)}})))}}else if(n===2){var s=this.parsePointer(c.classDef);var o=this.parsePointer(c.classDef);var l=this.parseUShort();var u=this.parseUShort();return{posFormat:n,coverage:r,valueFormat1:i,valueFormat2:a,classDef1:s,classDef2:o,class1Count:l,class2Count:u,classRecords:this.parseList(l,c.list(u,function(){return{value1:this.parseValueRecord(i),value2:this.parseValueRecord(a)}}))}}};R[3]=function e(){return{error:"GPOS Lookup 3 not supported"}};R[4]=function e(){return{error:"GPOS Lookup 4 not supported"}};R[5]=function e(){return{error:"GPOS Lookup 5 not supported"}};R[6]=function e(){return{error:"GPOS Lookup 6 not supported"}};R[7]=function e(){return{error:"GPOS Lookup 7 not supported"}};R[8]=function e(){return{error:"GPOS Lookup 8 not supported"}};R[9]=function e(){return{error:"GPOS Lookup 9 not supported"}};function Ts(e,t){t=t||0;var n=new c(e,t);var r=n.parseVersion(1);_.argument(r===1||r===1.1,"Unsupported GPOS table version "+r);if(r===1){return{version:r,scripts:n.parseScriptList(),features:n.parseFeatureList(),lookups:n.parseLookupList(R)}}else{return{version:r,scripts:n.parseScriptList(),features:n.parseFeatureList(),lookups:n.parseLookupList(R),variations:n.parseFeatureVariationsList()}}}var Is=new Array(10);function Es(e){return new E.Table("GPOS",[{name:"version",type:"ULONG",value:65536},{name:"scripts",type:"TABLE",value:new E.ScriptList(e.scripts)},{name:"features",type:"TABLE",value:new E.FeatureList(e.features)},{name:"lookups",type:"TABLE",value:new E.LookupList(e.lookups,Is)}])}var Ls={parse:Ts,make:Es};function Ns(e){var t={};e.skip("uShort");var n=e.parseUShort();_.argument(n===0,"Unsupported kern sub-table version.");e.skip("uShort",2);var r=e.parseUShort();e.skip("uShort",3);for(var i=0;i1){console.warn("Only the first kern subtable is supported.")}e.skip("uLong");var r=e.parseUShort();var i=r&255;e.skip("uShort");if(i===0){var a=e.parseUShort();e.skip("uShort",3);for(var s=0;s80*n){o=u=e[0];l=c=e[1];for(var d=n;du)u=p;if(h>c)c=h}f=Math.max(u-o,c-l);f=f!==0?1/f:0}m(a,s,n,o,l,f);return s}function g(e,t,n,r,i){var a,s;if(i===M(e,t,n,r)>0){for(a=t;a=t;a-=r)s=U(a,e[a],e[a+1],s)}if(s&&o(s,s.next)){R(s);s=s.next}return s}function c(e,t){if(!e)return e;if(!t)t=e;var n=e,r;do{r=false;if(!n.steiner&&(o(n,n.next)||C(n.prev,n,n.next)===0)){R(n);n=t=n.prev;if(n===n.next)break;r=true}else{n=n.next}}while(r||n!==t);return t}function m(e,t,n,r,i,a,s){if(!e)return;if(!s&&a)S(e,r,i,a);var o=e,l,u;while(e.prev!==e.next){l=e.prev;u=e.next;if(a?h(e,r,i,a):p(e)){t.push(l.i/n);t.push(e.i/n);t.push(u.i/n);R(e);e=u.next;o=u.next;continue}e=u;if(e===o){if(!s){m(c(e),t,n,r,i,a,1)}else if(s===1){e=f(c(e),t,n);m(e,t,n,r,i,a,2)}else if(s===2){d(e,t,n,r,i,a)}break}}}function p(e){var t=e.prev,n=e,r=e.next;if(C(t,n,r)>=0)return false;var i=e.next.next;while(i!==e.prev){if(A(t.x,t.y,n.x,n.y,r.x,r.y,i.x,i.y)&&C(i.prev,i,i.next)>=0)return false;i=i.next}return true}function h(e,t,n,r){var i=e.prev,a=e,s=e.next;if(C(i,a,s)>=0)return false;var o=i.xa.x?i.x>s.x?i.x:s.x:a.x>s.x?a.x:s.x,c=i.y>a.y?i.y>s.y?i.y:s.y:a.y>s.y?a.y:s.y;var p=O(o,l,t,n,r),h=O(u,c,t,n,r);var f=e.prevZ,d=e.nextZ;while(f&&f.z>=p&&d&&d.z<=h){if(f!==e.prev&&f!==e.next&&A(i.x,i.y,a.x,a.y,s.x,s.y,f.x,f.y)&&C(f.prev,f,f.next)>=0)return false;f=f.prevZ;if(d!==e.prev&&d!==e.next&&A(i.x,i.y,a.x,a.y,s.x,s.y,d.x,d.y)&&C(d.prev,d,d.next)>=0)return false;d=d.nextZ}while(f&&f.z>=p){if(f!==e.prev&&f!==e.next&&A(i.x,i.y,a.x,a.y,s.x,s.y,f.x,f.y)&&C(f.prev,f,f.next)>=0)return false;f=f.prevZ}while(d&&d.z<=h){if(d!==e.prev&&d!==e.next&&A(i.x,i.y,a.x,a.y,s.x,s.y,d.x,d.y)&&C(d.prev,d,d.next)>=0)return false;d=d.nextZ}return true}function f(e,t,n){var r=e;do{var i=r.prev,a=r.next.next;if(!o(i,a)&&l(i,r,r.next,a)&&E(i,a)&&E(a,i)){t.push(i.i/n);t.push(r.i/n);t.push(a.i/n);R(r);R(r.next);r=e=a}r=r.next}while(r!==e);return c(r)}function d(e,t,n,r,i,a){var s=e;do{var o=s.next.next;while(o!==s.prev){if(s.i!==o.i&&u(s,o)){var l=N(s,o);s=c(s,s.next);l=c(l,l.next);m(s,t,n,r,i,a);m(l,t,n,r,i,a);return}o=o.next}s=s.next}while(s!==e)}function v(e,t,n,r){var i=[],a,s,o,l,u;for(a=0,s=t.length;a=n.next.y&&n.next.y!==n.y){var o=n.x+(i-n.y)*(n.next.x-n.x)/(n.next.y-n.y);if(o<=r&&o>a){a=o;if(o===r){if(i===n.y)return n;if(i===n.next.y)return n.next}s=n.x=n.x&&n.x>=u&&r!==n.x&&A(is.x||n.x===s.x&&x(s,n)))){s=n;p=h}}n=n.next}while(n!==l);return s}function x(e,t){return C(e.prev,e,t.prev)<0&&C(t.next,e,e.next)<0}function S(e,t,n,r){var i=e;do{if(i.z===null)i.z=O(i.x,i.y,t,n,r);i.prevZ=i.prev;i.nextZ=i.next;i=i.next}while(i!==e);i.prevZ.nextZ=null;i.prevZ=null;s(i)}function s(e){var t,n,r,i,a,s,o,l,u=1;do{n=e;e=null;a=null;s=0;while(n){s++;r=n;o=0;for(t=0;t0||l>0&&r){if(o!==0&&(l===0||!r||n.z<=r.z)){i=n;n=n.nextZ;o--}else{i=r;r=r.nextZ;l--}if(a)a.nextZ=i;else e=i;i.prevZ=a;a=i}n=r}a.nextZ=null;u*=2}while(s>1);return e}function O(e,t,n,r,i){e=32767*(e-n)*i;t=32767*(t-r)*i;e=(e|e<<8)&16711935;e=(e|e<<4)&252645135;e=(e|e<<2)&858993459;e=(e|e<<1)&1431655765;t=(t|t<<8)&16711935;t=(t|t<<4)&252645135;t=(t|t<<2)&858993459;t=(t|t<<1)&1431655765;return e|t<<1}function _(e){var t=e,n=e;do{if(t.x=0&&(e-s)*(r-o)-(n-s)*(t-o)>=0&&(n-s)*(a-o)-(i-s)*(r-o)>=0}function u(e,t){return e.next.i!==t.i&&e.prev.i!==t.i&&!i(e,t)&&(E(e,t)&&E(t,e)&&L(e,t)&&(C(e.prev,e,t.prev)||C(e,t.prev,t))||o(e,t)&&C(e.prev,e,e.next)>0&&C(t.prev,t,t.next)>0)}function C(e,t,n){return(t.y-e.y)*(n.x-t.x)-(t.x-e.x)*(n.y-t.y)}function o(e,t){return e.x===t.x&&e.y===t.y}function l(e,t,n,r){var i=I(C(e,t,n));var a=I(C(e,t,r));var s=I(C(n,r,e));var o=I(C(n,r,t));if(i!==a&&s!==o)return true;if(i===0&&T(e,n,t))return true;if(a===0&&T(e,r,t))return true;if(s===0&&T(n,e,r))return true;if(o===0&&T(n,t,r))return true;return false}function T(e,t,n){return t.x<=Math.max(e.x,n.x)&&t.x>=Math.min(e.x,n.x)&&t.y<=Math.max(e.y,n.y)&&t.y>=Math.min(e.y,n.y)}function I(e){return e>0?1:e<0?-1:0}function i(e,t){var n=e;do{if(n.i!==e.i&&n.next.i!==e.i&&n.i!==t.i&&n.next.i!==t.i&&l(n,n.next,e,t))return true;n=n.next}while(n!==e);return false}function E(e,t){return C(e.prev,e,e.next)<0?C(e,t,e.next)>=0&&C(e,e.prev,t)>=0:C(e,t,e.prev)<0||C(e,e.next,t)<0}function L(e,t){var n=e,r=false,i=(e.x+t.x)/2,a=(e.y+t.y)/2;do{if(n.y>a!==n.next.y>a&&n.next.y!==n.y&&i<(n.next.x-n.x)*(a-n.y)/(n.next.y-n.y)+n.x)r=!r;n=n.next}while(n!==e);return r}function N(e,t){var n=new P(e.i,e.x,e.y),r=new P(t.i,t.x,t.y),i=e.next,a=t.prev;e.next=t;t.prev=e;n.next=i;i.prev=n;r.next=n;n.prev=r;a.next=r;r.prev=a;return r}function U(e,t,n,r){var i=new P(e,t,n);if(!r){i.prev=i;i.next=i}else{i.next=r.next;i.prev=r;r.next.prev=i;r.next=i}return i}function R(e){e.next.prev=e.prev;e.prev.next=e.next;if(e.prevZ)e.prevZ.nextZ=e.nextZ;if(e.nextZ)e.nextZ.prevZ=e.prevZ}function P(e,t,n){this.i=e;this.x=t;this.y=n;this.prev=null;this.next=null;this.z=null;this.prevZ=null;this.nextZ=null;this.steiner=false}r.deviation=function(e,t,n,r){var i=t&&t.length;var a=i?t[0]*n:e.length;var s=Math.abs(M(e,0,a,n));if(i){for(var o=0,l=t.length;o0){r+=e[i-1].length;n.holes.push(r)}}return n}},{}]},{},[1])(1)});(()=>{"use strict";var e={};const s={ANIM:{EASINGS:["linear","absolute","smoothstep","smootherstep","Cubic In","Cubic Out","Cubic In Out","Expo In","Expo Out","Expo In Out","Sin In","Sin Out","Sin In Out","Quart In","Quart Out","Quart In Out","Quint In","Quint Out","Quint In Out","Back In","Back Out","Back In Out","Elastic In","Elastic Out","Bounce In","Bounce Out"],EASING_LINEAR:0,EASING_ABSOLUTE:1,EASING_SMOOTHSTEP:2,EASING_SMOOTHERSTEP:3,EASING_CUBICSPLINE:4,EASING_CUBIC_IN:5,EASING_CUBIC_OUT:6,EASING_CUBIC_INOUT:7,EASING_EXPO_IN:8,EASING_EXPO_OUT:9,EASING_EXPO_INOUT:10,EASING_SIN_IN:11,EASING_SIN_OUT:12,EASING_SIN_INOUT:13,EASING_BACK_IN:14,EASING_BACK_OUT:15,EASING_BACK_INOUT:16,EASING_ELASTIC_IN:17,EASING_ELASTIC_OUT:18,EASING_BOUNCE_IN:19,EASING_BOUNCE_OUT:21,EASING_QUART_IN:22,EASING_QUART_OUT:23,EASING_QUART_INOUT:24,EASING_QUINT_IN:25,EASING_QUINT_OUT:26,EASING_QUINT_INOUT:27},OP:{OP_PORT_TYPE_VALUE:0,OP_PORT_TYPE_NUMBER:0,OP_PORT_TYPE_FUNCTION:1,OP_PORT_TYPE_TRIGGER:1,OP_PORT_TYPE_OBJECT:2,OP_PORT_TYPE_TEXTURE:2,OP_PORT_TYPE_ARRAY:3,OP_PORT_TYPE_DYNAMIC:4,OP_PORT_TYPE_STRING:5,OP_VERSION_PREFIX:"_v"},PORT:{PORT_DIR_IN:0,PORT_DIR_OUT:1},PACO:{PACO_CLEAR:0,PACO_VALUECHANGE:1,PACO_OP_DELETE:2,PACO_UNLINK:3,PACO_LINK:4,PACO_LOAD:5,PACO_OP_CREATE:6,PACO_OP_ENABLE:7,PACO_OP_DISABLE:8,PACO_UIATTRIBS:9,PACO_VARIABLES:10,PACO_TRIGGERS:11,PACO_PORT_SETVARIABLE:12,PACO_PORT_SETANIMATED:13,PACO_PORT_ANIM_UPDATED:14,PACO_DESERIALIZE:15}};const t=class{constructor(t,e,n,r,i,a){this._valuePort=n;this._varNamePort=r;this._op=t;this._type=e;this._typeId=-1;this._triggerPort=i;this._nextPort=a;this._btnCreate=t.inTriggerButton("Create new variable");this._btnCreate.setUiAttribs({hidePort:true});this._btnCreate.onTriggered=this._createVar.bind(this);this._helper=t.inUiTriggerButtons("",["Rename"]);this._helper.setUiAttribs({hidePort:true});this._helper.onTriggered=e=>{if(e=="Rename")CABLES.CMD.PATCH.renameVariable(t.varName.get())};this._op.setPortGroup("Variable",[this._helper,this._varNamePort,this._btnCreate]);this._op.on("uiParamPanel",this._updateVarNamesDropdown.bind(this));this._op.patch.addEventListener("variablesChanged",this._updateName.bind(this));this._op.patch.addEventListener("variableRename",this._renameVar.bind(this));this._varNamePort.onChange=this._updateName.bind(this);this._isTexture=this._valuePort.uiAttribs.objType==="texture";this._valuePort.changeAlways=true;if(this._triggerPort){this._triggerPort.onTriggered=()=>{this._setVarValue(true)}}else{this._valuePort.onChange=this._setVarValue.bind(this)}this._op.init=()=>{this._updateName();if(!this._triggerPort)this._setVarValue();this._updateErrorUi()};if(e=="array")this._typeId=s.OP.OP_PORT_TYPE_ARRAY;else if(e=="object")this._typeId=s.OP.OP_PORT_TYPE_OBJECT;else if(e=="string")this._typeId=s.OP.OP_PORT_TYPE_STRING;else if(e=="texture")this._typeId=s.OP.OP_PORT_TYPE_TEXTURE;else this._typeId=s.OP.OP_PORT_TYPE_VALUE}_updateErrorUi(){if(CABLES.UI){if(!this._varNamePort.get())this._op.setUiError("novarname","no variable selected");else{if(this._op.hasUiErrors){this._op.setUiError("novarname",null)}}}}_updateName(){const e=this._varNamePort.get();this._op.setTitle("var set");this._op.setUiAttrib({extendTitle:"#"+e});this._updateErrorUi();const t=this._op.patch.getVar(e);if(t&&!t.type)t.type=this._type;if(!this._op.patch.hasVar(e)&&e!=0&&!this._triggerPort){this._setVarValue()}if(!this._op.patch.hasVar(e)&&e!=0&&this._triggerPort){if(this._type=="string")this._op.patch.setVarValue(e,"");else if(this._type=="number")this._op.patch.setVarValue(e,"");else this._op.patch.setVarValue(e,null)}if(this._op.isCurrentUiOp()){this._updateVarNamesDropdown();this._op.refreshParams()}this._updateDisplay();this._op.patch.emitEvent("opVariableNameChanged",this._op,this._varNamePort.get())}_createVar(){CABLES.CMD.PATCH.createVariable(this._op,this._type,()=>{this._updateName()})}_updateDisplay(){this._valuePort.setUiAttribs({greyout:!this._varNamePort.get()})}_updateVarNamesDropdown(){if(CABLES.UI&&CABLES.UI.loaded&&CABLES.UI.loaded){const e=CABLES.UI.uiProfiler.start("[vars] _updateVarNamesDropdown");const t=[];const n=this._op.patch.getVars();for(const r in n)if(n[r].type==this._type&&r!="0")t.push(r);this._varNamePort.uiAttribs.values=t;e.finish()}}_renameVar(e,t){if(e!=this._varNamePort.get())return;this._varNamePort.set(t);this._updateName()}_setVarValue(e){const t=this._varNamePort.get();if(!t)return;const n=this._valuePort.get();if(this._typeId==s.OP.OP_PORT_TYPE_VALUE||this._typeId==s.OP.OP_PORT_TYPE_STRING){this._op.patch.setVarValue(t,n)}else if(this._typeId==s.OP.OP_PORT_TYPE_ARRAY){this._arr=[];CABLES.copyArray(n,this._arr);this._op.patch.setVarValue(t,this._arr)}else{if(this._typeId==s.OP.OP_PORT_TYPE_OBJECT){if(this._isTexture)this._op.patch.setVarValue(t,CGL.Texture.getEmptyTexture(this._op.patch.cgl));else this._op.patch.setVarValue(t,null);if(n&&n.tex&&n._cgl&&!this._isTexture)this._op.setUiError("texobj","Dont use object variables for textures, use varSetTexture");else this._op.setUiError("texobj",null)}this._op.patch.setVarValue(t,n)}if(e&&this._nextPort)this._nextPort.trigger()}};const n=class{constructor(e,t,n,r){this._op=e;this._type=t;this._varnamePort=n;this._variable=null;this._valueOutPort=r;this._listenerId=null;this._op.on("uiParamPanel",this._updateVarNamesDropdown.bind(this));this._op.on("uiErrorChange",this._updateTitle.bind(this));this._op.patch.on("variableRename",this._renameVar.bind(this));this._op.patch.on("variableDeleted",e=>{if(this._op.isCurrentUiOp())this._op.refreshParams()});this._varnamePort.onChange=this._changeVar.bind(this);this._op.patch.addEventListener("variablesChanged",this._init.bind(this));this._op.onDelete=()=>{if(this._variable&&this._listenerId)this._variable.off(this._listenerId)};this._op.init=()=>{this._init()}}get variable(){return this._variable}_changeVar(){if(this._variable&&this._listenerId){this._variable.off(this._listenerId)}this._init()}_renameVar(e,t){if(e!=this._varnamePort.get())return;this._varnamePort.set(t);this._updateVarNamesDropdown();this._updateTitle();this._listenerId=this._variable.on("change",this._setValueOut.bind(this))}_updateVarNamesDropdown(){if(CABLES.UI&&CABLES.UI.loaded){const e=[];const t=this._op.patch.getVars();for(const n in t)if(t[n].type==this._type&&n!="0")e.push(n);this._op.varName.uiAttribs.values=e}}_setValueOut(e){if(this._valueOutPort)this._valueOutPort.set(e)}_updateTitle(){if(this._variable){this._op.setUiError("unknownvar",null);this._op.setTitle("var get");this._op.setUiAttrib({extendTitle:"#"+this._varnamePort.get()});if(this._valueOutPort)this._valueOutPort.set(this._variable.getValue())}else{this._op.setUiError("unknownvar","unknown variable! - there is no setVariable with this name ("+this._varnamePort.get()+")");this._op.setUiAttrib({extendTitle:"#invalid"});if(this._valueOutPort)this._valueOutPort.set(0)}}_init(){this._updateVarNamesDropdown();if(this._variable&&this._listenerId)this._variable.off(this._listenerId);this._variable=this._op.patch.getVar(this._op.varName.get());if(this._variable)this._listenerId=this._variable.on("change",this._setValueOut.bind(this));this._updateTitle();this._op.patch.emitEvent("opVariableNameChanged",this._op,this._varnamePort.get())}};CABLES.VarSetOpWrapper=t;CABLES.VarGetOpWrapper=n;((this.CABLES=this.CABLES||{}).COREMODULES=this.CABLES.COREMODULES||{}).Vargetset=e.Cables})();(()=>{"use strict";var e={};const n="Ops.Ui.SubPatchInput";const r="Ops.Ui.SubPatchOutput";const t=class{constructor(n,e){e=e||{};this._op=n;n.patchId=n.addInPort(new CABLES.Port(n,"patchId",CABLES.OP_PORT_TYPE_STRING,{display:"readonly",hidePort:true}));n.setUiAttribs({subPatchOp:{version:2}});if(n.uiAttribs.parentOfSubpatch){n.patchId.set(n.uiAttribs.parentOfSubpatch)}else{if(e.subId)n.patchId.set(e.subId);else n.patchId.set(CABLES.generateUUID())}n.patchId.onChange=()=>{if(e.subId)n.patchId.value=e.subId};n.patch.on("subpatchCreated",()=>{this.createInOutOps()});n.on("loadedValueSet",()=>{this.createInOutOps()});n.init=()=>{n.setStorage({subPatchVer:2})};n.loadDependencies=(e,t)=>{if(CABLES.UI){gui.serverOps.loadProjectDependencies(e,()=>{if(t)t()})}else if(t)t()};n.on("delete",()=>{if(n.patch.clearSubPatchCache)n.patch.clearSubPatchCache(this.patchId);const t=n.patch.ops;for(let e=t.length-1;e>=0;e--)if(t[e]&&t[e].uiAttribs&&t[e].uiAttribs.subPatch==n.patchId.get())n.patch.deleteOp(t[e].id)});this._op.isExposableSubpatchOp=()=>{return true}}get patchId(){return this._op.patchId.get()}createInOutOps(){if(this._op.patch.clearSubPatchCache)this._op.patch.clearSubPatchCache(this.patchId);let e=this._op.patch.getSubPatchOp(this.patchId,n);let t=this._op.patch.getSubPatchOp(this.patchId,r);if(!e)this._op.patch.addOp(n,{subPatch:this.patchId,translate:{x:0,y:0}});if(!t)this._op.patch.addOp(r,{subPatch:this.patchId,translate:{x:0,y:0}})}};CABLES.SubPatchOp=t;((this.CABLES=this.CABLES||{}).COREMODULES=this.CABLES.COREMODULES||{}).Subpatchop=e.Cables})();(()=>{"use strict";var e={};class c{constructor(e){this._logs=[];this.initiator=e}stack(e){console.info("["+this.initiator+"] ",e);console.log((new Error).stack)}groupCollapsed(e){console.groupCollapsed("["+this.initiator+"] "+e)}table(e){console.table(e)}groupEnd(){console.groupEnd()}error(e){console.error("["+this.initiator+"]",...arguments);if(window.gui)window.gui.emitEvent("coreLogEvent",this.initiator,"error",arguments)}info(e){console.error("["+this.initiator+"]",...arguments);if(window.gui)window.gui.emitEvent("coreLogEvent",this.initiator,"info",arguments)}warn(e){console.warn("["+this.initiator+"]",...arguments);if(window.gui)window.gui.emitEvent("coreLogEvent",this.initiator,"warn",arguments)}verbose(){if(CABLES.UI&&CABLES.UI.logFilter.shouldPrint(this.initiator,...arguments)||!CABLES.logSilent)console.log("["+this.initiator+"]",...arguments);if(window.gui)window.gui.emitEvent("coreLogEvent",this.initiator,"verbose",arguments)}log(e){if(CABLES.UI&&CABLES.UI.logFilter.shouldPrint(this.initiator,...arguments)||!CABLES.logSilent)console.log("["+this.initiator+"]",...arguments);if(window.gui)window.gui.emitEvent("coreLogEvent",this.initiator,"log",arguments)}userInteraction(e){}}const i={};i.float32Concat=function(e,t){if(!(e instanceof Float32Array))e=new Float32Array(e);if(!(t instanceof Float32Array))t=new Float32Array(t);const n=new Float32Array(e.length+t.length);n.set(e);n.set(t,e.length);return n};const w=function(e){let t=e.split(".")[e.split(".").length-1];if(t.contains(CONSTANTS.OP.OP_VERSION_PREFIX)){const n=t.split(CONSTANTS.OP.OP_VERSION_PREFIX)[1];t=t.substring(0,t.length-(CONSTANTS.OP.OP_VERSION_PREFIX+n).length)}return t};const B=function(t){for(let e=t.length-1;e>0;e--){const n=Math.floor(Math.seededRandom()*(e+1));const r=t[e];t[e]=t[n];t[n]=r}return t};const t={};const n=function(){let e=Math.random().toString(36).substr(2,9);if(t.hasOwnProperty(e))e=n();t[e]=true;return e};const G=null&&n;const r=function(){let n=(new Date).getTime();const e="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=(n+Math.random()*16)%16|0;n=Math.floor(n/16);return(e=="x"?t:t&3|8).toString(16)});return e};const V=null&&r;const D=null&&r;function a(e){for(const t in e){if(e[t]&&typeof objValue==="object"&&e[t].constructor===Object)e[t]=a(e[t]);if(e[t]===null||e[t]===undefined)delete e[t];else if(Array.isArray(e[t])&&e[t].length==0)delete e[t]}return e}const s=function(n,e="id"){let r=0;if(Array.prototype.reduce){r=n.split("").reduce((e,t)=>{e=(e<<5)-e+t.charCodeAt(0);return e&e},0)}else{if(n.length>0){for(let t=0;t=n)return i;if(e<=t)return r;let s=false;const o=Math.min(t,n);const l=Math.max(t,n);if(o!=t)s=true;let u=false;const c=Math.min(r,i);const p=Math.max(r,i);if(c!=r)u=true;let h=0;let f=0;if(s)h=(l-e)*(p-c)/(l-o);else h=(e-o)*(p-c)/(l-o);if(u)f=p-h;else f=h+c;if(!a)return f;if(a==1){e=Math.max(0,Math.min(1,(f-r)/(i-r)));return r+e*e*(3-2*e)*(i-r)}if(a==2){e=Math.max(0,Math.min(1,(f-r)/(i-r)));return r+e*e*e*(e*(e*6-15)+10)*(i-r)}return f};Math.randomSeed=1;Math.setRandomSeed=function(e){Math.randomSeed=e*50728129;if(e!=0){Math.randomSeed=Math.seededRandom()*17624813;Math.randomSeed=Math.seededRandom()*9737333}};Math.seededRandom=function(e,t){if(Math.randomSeed===0)Math.randomSeed=Math.random()*999;e=e||1;t=t||0;Math.randomSeed=(Math.randomSeed*9301+49297)%233280;const n=Math.randomSeed/233280;return t+n*(e-t)};i.isNumeric=function(e){return!isNaN(parseFloat(e))&&isFinite(e)};i.isArray=function(e){return Object.prototype.toString.call(e)==="[object Array]"};String.prototype.endl=function(){return this+"\n"};String.prototype.startsWith=function(e){return this.indexOf(e)===0};String.prototype.endsWith=String.prototype.endsWith||function(e){return this.match(e+"$")==e};String.prototype.contains=String.prototype.contains||function(e){return this.indexOf(e)>-1};const W=function(e){if(e.contains("?"))e+="&";else e+="?";return e+"cache="+CABLES.uuid()};const q=function(t,n){if(!t)return null;n=n||[];n.length=t.length;for(let e=0;e0){const r=n[n.length-1];let e=r.split("?");t=e[0]}return t||""};const J=function(e,t,n,r,i){u({url:e,cb:t,method:n,data:r,contenttype:i,sync:true})};const $=function(e,t,n,r,i,a,s={},o={}){const l={url:e,cb:t,method:n,data:r,contenttype:i,sync:false,jsonP:a,headers:s};if(o&&o.credentials)l.credentials=o.credentials;u(l)};const u=function(t){if(!t.hasOwnProperty("asynch"))t.asynch=true;let n;try{n=new XMLHttpRequest}catch(e){}n.onreadystatechange=function(){if(n.readyState!=4)return;if(t.cb){if(n.status==200||n.status==0)t.cb(false,n.responseText,n);else t.cb(true,n.responseText,n)}};try{n.open(t.method?t.method.toUpperCase():"GET",t.url,!t.sync)}catch(e){if(t.cb&&e)t.cb(true,e.msg,n)}if(typeof t.headers==="object"){const r=Object.keys(t.headers);for(let e=0;e>2];i+=l[(t[n]&3)<<4|t[n+1]>>4];i+=l[(t[n+1]&15)<<2|t[n+2]>>6];i+=l[t[n+2]&63]}if(r%3===2)i=i.substring(0,i.length-1)+"=";else if(r%3===1)i=i.substring(0,i.length-2)+"==";return i};const f=function(e){let t=e.length*.75,n=e.length,r,i=0,a,s,o,l;if(e[e.length-1]==="="){t--;if(e[e.length-2]==="=")t--}let u=new ArrayBuffer(t),c=new Uint8Array(u);for(r=0;r>4;c[i++]=(s&15)<<4|o>>2;c[i++]=(o&3)<<6|l&63}return u};class d{constructor(e){this._init();this._first=true;this._wireMesh=null;if(e)this.apply(e)}_init(){this._max=[-Number.MAX_VALUE,-Number.MAX_VALUE,-Number.MAX_VALUE];this._min=[Number.MAX_VALUE,Number.MAX_VALUE,Number.MAX_VALUE];this._center=[0,0,0];this._size=[0,0,0];this._maxAxis=0;this._first=true}get maxAxis(){return this._maxAxis||1}get size(){return this._size}get center(){return this._center}get x(){return this._center[0]}get y(){return this._center[1]}get z(){return this._center[2]}get minX(){return this._min[0]}get minY(){return this._min[1]}get minZ(){return this._min[2]}get maxX(){return this._max[0]}get maxY(){return this._max[1]}get maxZ(){return this._max[2]}apply(t,e){if(!t){return}if(t instanceof d){const n=t;this.applyPos(n.maxX,n.maxY,n.maxZ);this.applyPos(n.minX,n.minY,n.minZ)}else{for(let e=0;e4){console.log("itemsize wrong?",n,e);this._log.stack("itemsize");n=3}if(n==1)r="float";else if(n==2)r="vec2";else if(n==3)r="vec3";else if(n==4)r="vec4";const i={name:e,data:t,itemSize:n,type:r};this._attributes[e]=i};g.prototype.copyAttribute=function(e,t){const n=this.getAttribute(e);t.setAttribute(e,new Float32Array(n.data),n.itemSize)};g.prototype.setVertices=function(e){if(e instanceof Float32Array)this._vertices=e;else this._vertices=new Float32Array(e)};g.prototype.setTexCoords=function(e){if(e instanceof Float32Array)this.texCoords=e;else this.texCoords=new Float32Array(e)};g.prototype.calcNormals=function(e){const t={smooth:e};this.calculateNormals(t)};g.prototype.flipNormals=function(t,n,r){let i=vec3.create();if(t==undefined)t=1;if(n==undefined)n=1;if(r==undefined)r=1;for(let e=0;e0};this.removeEventListener=this.off=function(r,t){if(r===null||r===undefined)return;if(!t){const i=this._listeners[r];if(!i){this._log.log("could not find event...");return}let n=true;while(n){n=false;let t=-1;for(let e=0;e1)this.keys.splice(0,n);this._updateLastIndex()};C.prototype.clear=function(e){let t=0;if(e)t=this.getValue(e);this.keys.length=0;this._updateLastIndex();if(e)this.setValue(e,t);if(this.onChange!==null)this.onChange();this.emitEvent("onChange",this)};C.prototype.sortKeys=function(){this.keys.sort((e,t)=>{return parseFloat(e.time)-parseFloat(t.time)});this._updateLastIndex();this._needsSort=false;if(this.keys.length%1e3==0)console.log(this.name,this.keys.length)};C.prototype.getLength=function(){if(this.keys.length===0)return 0;return this.keys[this.keys.length-1].time};C.prototype.getKeyIndex=function(t){let n=0;let r=0;if(this._cachedIndex&&this.keys.length>this._cachedIndex&&t>=this.keys[this._cachedIndex].time)r=this._cachedIndex;for(let e=r;e=this.keys[e].time)n=e;if(this.keys[e].time>t){if(t!=0)this._cachedIndex=n;return n}}return n};C.prototype.setValue=function(t,n,r){let i=null;if(this.keys.length==0||t<=this.keys[this.keys.length-1].time)for(let e=0;e=this.keys.length)t=this.keys.length-1;return this.keys[t]};C.prototype.isFinished=function(e){if(this.keys.length<=0)return true;return e>this.keys[this.keys.length-1].time};C.prototype.isStarted=function(e){if(this.keys.length<=0)return false;return e>=this.keys[0].time};C.prototype.getValue=function(e){if(this.keys.length===0){return 0}if(this._needsSort)this.sortKeys();if(!this.loop&&e>this.keys[this._lastKeyIndex].time){if(this.keys[this._lastKeyIndex].cb&&!this.keys[this._lastKeyIndex].cbTriggered)this.keys[this._lastKeyIndex].trigger();return this.keys[this._lastKeyIndex].value}if(ethis.keys[this._lastKeyIndex].time){const s=e/this.keys[this._lastKeyIndex].time;if(s>this._timesLooped){this._timesLooped++;if(this.onLooped)this.onLooped()}e=(e-this.keys[0].time)%(this.keys[this._lastKeyIndex].time-this.keys[0].time);e+=this.keys[0].time}const t=this.getKeyIndex(e);if(t>=this._lastKeyIndex){if(this.keys[this._lastKeyIndex].cb&&!this.keys[this._lastKeyIndex].cbTriggered)this.keys[this._lastKeyIndex].trigger();return this.keys[this._lastKeyIndex].value}const n=t+1;const r=this.keys[t];const i=this.keys[n];if(r.cb&&!r.cbTriggered)r.trigger();if(!i)return-1;const a=(e-r.time)/(i.time-r.time);if(!r.ease)this.log._warn("has no ease",r,i);return r.ease(a,i)};C.prototype._updateLastIndex=function(){this._lastKeyIndex=this.keys.length-1};C.prototype.addKey=function(e){if(e.time===undefined){this.log.warn("key time undefined, ignoring!")}else{this.keys.push(e);if(this.onChange!==null)this.onChange();this.emitEvent("onChange",this)}this._updateLastIndex()};C.prototype.easingFromString=function(e){if(e=="linear")return v.ANIM.EASING_LINEAR;if(e=="absolute")return v.ANIM.EASING_ABSOLUTE;if(e=="smoothstep")return v.ANIM.EASING_SMOOTHSTEP;if(e=="smootherstep")return v.ANIM.EASING_SMOOTHERSTEP;if(e=="Cubic In")return v.ANIM.EASING_CUBIC_IN;if(e=="Cubic Out")return v.ANIM.EASING_CUBIC_OUT;if(e=="Cubic In Out")return v.ANIM.EASING_CUBIC_INOUT;if(e=="Expo In")return v.ANIM.EASING_EXPO_IN;if(e=="Expo Out")return v.ANIM.EASING_EXPO_OUT;if(e=="Expo In Out")return v.ANIM.EASING_EXPO_INOUT;if(e=="Sin In")return v.ANIM.EASING_SIN_IN;if(e=="Sin Out")return v.ANIM.EASING_SIN_OUT;if(e=="Sin In Out")return v.ANIM.EASING_SIN_INOUT;if(e=="Back In")return v.ANIM.EASING_BACK_IN;if(e=="Back Out")return v.ANIM.EASING_BACK_OUT;if(e=="Back In Out")return v.ANIM.EASING_BACK_INOUT;if(e=="Elastic In")return v.ANIM.EASING_ELASTIC_IN;if(e=="Elastic Out")return v.ANIM.EASING_ELASTIC_OUT;if(e=="Bounce In")return v.ANIM.EASING_BOUNCE_IN;if(e=="Bounce Out")return v.ANIM.EASING_BOUNCE_OUT;if(e=="Quart Out")return v.ANIM.EASING_QUART_OUT;if(e=="Quart In")return v.ANIM.EASING_QUART_IN;if(e=="Quart In Out")return v.ANIM.EASING_QUART_INOUT;if(e=="Quint Out")return v.ANIM.EASING_QUINT_OUT;if(e=="Quint In")return v.ANIM.EASING_QUINT_IN;if(e=="Quint In Out")return v.ANIM.EASING_QUINT_INOUT};C.prototype.createPort=function(e,t,n){const r=e.inDropDown(t,v.ANIM.EASINGS);r.set("linear");r.defaultValue="linear";r.onChange=function(){this.defaultEasing=this.easingFromString(r.get());this.emitEvent("onChangeDefaultEasing",this);if(n)n()}.bind(this);return r};C.slerpQuaternion=function(e,t,n,r,i,a){if(!C.slerpQuaternion.q1){C.slerpQuaternion.q1=quat.create();C.slerpQuaternion.q2=quat.create()}const s=n.getKeyIndex(e);let o=s+1;if(o>=n.keys.length)o=n.keys.length-1;if(s==o){quat.set(t,n.keys[s].value,r.keys[s].value,i.keys[s].value,a.keys[s].value)}else{const l=n.keys[s].time;const u=n.keys[o].time;const c=(e-l)/(u-l);quat.set(C.slerpQuaternion.q1,n.keys[s].value,r.keys[s].value,i.keys[s].value,a.keys[s].value);quat.set(C.slerpQuaternion.q2,n.keys[o].value,r.keys[o].value,i.keys[o].value,a.keys[o].value);quat.slerp(t,C.slerpQuaternion.q1,C.slerpQuaternion.q2,c)}return t};const T={Key:b};const I=function(e,t,n,r){m.apply(this);this.data={};this._log=new c("core_port");this.direction=v.PORT.PORT_DIR_IN;this.id=String(CABLES.simpleId());this._op=e;this.links=[];this.value=0;this.name=t;this.type=n||v.OP.OP_PORT_TYPE_VALUE;this.uiAttribs=r||{};this.anim=null;this._oldAnimVal=-5711;this.defaultValue=null;this._uiActiveState=true;this.ignoreValueSerialize=false;this.onLinkChanged=null;this.crashed=false;this._valueBeforeLink=null;this._lastAnimFrame=-1;this._animated=false;this.onValueChanged=null;this.onTriggered=null;this.onUiActiveStateChange=null;this.changeAlways=false;this.forceRefChange=false;this._useVariableName=null;this.activityCounter=0;this.apf=0;this.activityCounterStartFrame=0;this._tempLastUiValue=null;Object.defineProperty(this,"title",{get(){return this.uiAttribs.title||this.name}});Object.defineProperty(this,"parent",{get(){this._log.stack("use port.op, not .parent");return this._op}});Object.defineProperty(this,"op",{get(){return this._op}});Object.defineProperty(this,"val",{get(){this._log.warn("val getter deprecated!",this);this._log.stack("val getter deprecated");return this.get()},set(e){this._log.warn("val setter deprecated!",this);this._log.stack("val setter deprecated");this.setValue(e)}})};I.prototype.copyLinkedUiAttrib=function(e,t){if(!CABLES.UI)return;if(!this.isLinked())return;const n={};n[e]=this.links[0].getOtherPort(this).getUiAttrib(e);t.setUiAttribs(n)};I.prototype.getValueForDisplay=function(){let e=this.value;if(typeof this.value==="string"||this.value instanceof String){if(e.length>1e3){e=e.substring(0,999);e+="..."}if(this.uiAttribs&&this.uiAttribs.display=="boolnum"){e+=" - ";if(!this.value)e+="false";else e+="true"}e=e.replace(/[\u00A0-\u9999<>\&]/g,function(e){return"&#"+e.charCodeAt(0)+";"});if(e.length>100)e=e.substring(0,100)}else{e=this.value}return e};I.prototype.onAnimToggle=function(){};I.prototype._onAnimToggle=function(){this.onAnimToggle()};I.prototype.remove=function(){this.removeLinks();this._op.removePort(this)};I.prototype.setUiAttribs=function(e){let t=false;if(!this.uiAttribs)this.uiAttribs={};for(const n in e){if(e[n]===undefined){delete this.uiAttribs[n];continue}if(this.uiAttribs[n]!=e[n])t=true;this.uiAttribs[n]=e[n];if(n=="group"&&this.indexPort)this.indexPort.setUiAttribs({group:e[n]})}if(e.hasOwnProperty("expose"))this._op.patch.emitEvent("subpatchExpose",this._op.uiAttribs.subPatch);if(t)this.emitEvent("onUiAttrChange",e,this)};I.prototype.getUiAttribs=function(){return this.uiAttribs};I.prototype.getUiAttrib=function(e){if(!this.uiAttribs||!this.uiAttribs.hasOwnProperty(e)){return null}return this.uiAttribs[e]};I.prototype.get=function(){if(this._animated&&this._lastAnimFrame!=this._op.patch.getFrameNum()){this._lastAnimFrame=this._op.patch.getFrameNum();this.value=this.anim.getValue(this._op.patch.timer.getTime());this._oldAnimVal=this.value;this.forceChange()}return this.value};I.prototype.setRef=function(e){this.forceRefChange=true;this.set(e)};I.prototype.set=I.prototype.setValue=function(e){if(e===undefined)e=null;if(this._op.enabled&&!this.crashed){if(e!==this.value||this.changeAlways||this.type==v.OP.OP_PORT_TYPE_TEXTURE||this.type==v.OP.OP_PORT_TYPE_ARRAY){if(this._animated){this.anim.setValue(this._op.patch.timer.getTime(),e)}else{try{this.value=e;this.forceChange()}catch(e){this.crashed=true;this.op.crashed=true;console.log("crash",this.op.objName);this.setValue=function(e){};this.onTriggered=function(){};this._log.error("onvaluechanged exception cought",e);this._log.error(e.stack);this._log.warn("exception in: "+this._op.name);if(this._op.patch.isEditorMode())gui.showOpCrash(this._op);this._op.patch.emitEvent("exception",e,this._op);if(this._op.onError)this._op.onError(e)}if(this._op&&this._op.patch&&this._op.patch.isEditorMode()&&this.type==v.OP.OP_PORT_TYPE_TEXTURE)gui.texturePreview().updateTexturePort(this)}if(this.direction==v.PORT.PORT_DIR_OUT)for(let e=0;e{this._op.patch.emitEvent("portAnimUpdated",this._op,this,this.anim)});if(e.anim.loop)this.anim.loop=e.anim.loop;for(const t in e.anim.keys){this.anim.keys.push(new T.Key(e.anim.keys[t]))}this.anim.sortKeys()}};I.prototype.setInitialValue=function(e){if(this.op.preservedPortLinks[this.name]){for(let e=0;e0){e.links=[];for(const t in this.links){if(!this.links[t].ignoreInSerialize&&(this.links[t].portIn&&this.links[t].portOut))e.links.push(this.links[t].getSerialized())}}if(this.direction==v.PORT.PORT_DIR_IN&&this.links.length>0){for(const t in this.links){if(!this.links[t].portIn||!this.links[t].portOut)continue;const n=this.links[t].getOtherPort(this);if(n.op.isInBlueprint2&&this.op.isInBlueprint2){if(n.op.isInBlueprint2()&&!this.op.isInBlueprint2()){e.links=e.links||[];e.links.push(this.links[t].getSerialized())}}}}if(e.links&&e.links.length==0)delete e.links;if(this.type===v.OP.OP_PORT_TYPE_FUNCTION)delete e.value;if(this.type===v.OP.OP_PORT_TYPE_FUNCTION&&this.links.length==0)e=null;if(e&&Object.keys(e).length==1&&e.name)e=null;a(e);return e};I.prototype.shouldLink=function(){return true};I.prototype.removeLinks=function(){let e=0;while(this.links.length>0){e++;if(e>5e3){this._log.warn("could not delete links... / infinite loop");this.links.length=0;break}this.links[0].remove()}};I.prototype.removeLink=function(e){for(const t in this.links)if(this.links[t]==e)this.links.splice(t,1);if(this.direction==v.PORT.PORT_DIR_IN){if(this.type==v.OP.OP_PORT_TYPE_VALUE)this.setValue(this._valueBeforeLink||0);else this.setValue(this._valueBeforeLink||null)}if(CABLES.UI&&this._op.checkLinkTimeWarnings)this._op.checkLinkTimeWarnings();if(this.onLinkChanged)this.onLinkChanged();this.emitEvent("onLinkChanged");this._op.emitEvent("onLinkChanged")};I.prototype.getName=function(){return this.name};I.prototype.getTitle=function(){if(this.uiAttribs.title)return this.uiAttribs.title;return this.name};I.prototype.addLink=function(e){this._valueBeforeLink=this.value;this.links.push(e);if(CABLES.UI&&this._op.checkLinkTimeWarnings)this._op.checkLinkTimeWarnings();if(this.onLinkChanged)this.onLinkChanged();this.emitEvent("onLinkChanged");this._op.emitEvent("onLinkChanged")};I.prototype.getLinkTo=function(e){for(const t in this.links)if(this.links[t].portIn==e||this.links[t].portOut==e)return this.links[t]};I.prototype.removeLinkTo=function(e){for(const t in this.links){if(this.links[t].portIn==e||this.links[t].portOut==e){this.links[t].remove();if(CABLES.UI&&this._op.checkLinkTimeWarnings)this._op.checkLinkTimeWarnings();if(this.onLinkChanged)this.onLinkChanged();this.emitEvent("onLinkChanged");return}}};I.prototype.isLinkedTo=function(e){for(const t in this.links)if(this.links[t].portIn==e||this.links[t].portOut==e)return true;return false};I.prototype._activity=function(){this.activityCounter++};I.prototype.trigger=function(){const t=this.links.length;this._activity();if(t===0)return;if(!this._op.enabled)return;let n=null;try{for(let e=0;e{if(e!=this._useVariableName)return;this._useVariableName=t})};I.prototype.getVariableName=function(){return this._useVariableName};I.prototype.setVariable=function(e){this.setAnimated(false);const t={useVariable:false};if(this._variableIn&&this._varChangeListenerId){this._variableIn.off(this._varChangeListenerId);this._variableIn=null}if(e){this._variableIn=this._op.patch.getVar(e);if(!this._variableIn){this._log.warn("PORT VAR NOT FOUND!!!",e)}else{if(this.type==v.OP.OP_PORT_TYPE_OBJECT){this._varChangeListenerId=this._variableIn.on("change",()=>{this.set(null);this.set(this._variableIn.getValue())})}else{this._varChangeListenerId=this._variableIn.on("change",this.set.bind(this))}this.set(this._variableIn.getValue())}this._useVariableName=e;t.useVariable=true;t.variableName=this._useVariableName}else{t.variableName=this._useVariableName=null;t.useVariable=false}this.setUiAttribs(t);this._op.patch.emitEvent("portSetVariable",this._op,this,e)};I.prototype._handleNoTriggerOpAnimUpdates=function(e){let t=false;for(let e=0;e{this.updateAnim()});else this._op.patch.removeEventListener(this._notriggerAnimUpdate)}};I.prototype.setAnimated=function(e){if(this._animated!=e){this._animated=e;this._op._hasAnimPort=true;if(this._animated&&!this.anim){this.anim=new C({name:"port "+this.name});this.anim.addEventListener("onChange",()=>{this._op.patch.emitEvent("portAnimUpdated",this._op,this,this.anim)})}this._onAnimToggle()}this._handleNoTriggerOpAnimUpdates(e);if(!e){this.anim=null}this.setUiAttribs({isAnimated:this._animated})};I.prototype.toggleAnim=function(){this._animated=!this._animated;if(this._animated&&!this.anim){this.anim=new C({name:"port "+this.name});this.anim.addEventListener("onChange",()=>{this._op.patch.emitEvent("portAnimUpdated",this._op,this,this.anim)})}this.setAnimated(this._animated);this._onAnimToggle();this.setUiAttribs({isAnimated:this._animated})};I.prototype.getType=function(){return this.type};I.prototype.isLinked=function(){return this.links.length>0||this._animated||this._useVariableName!=null};I.prototype.isBoundToVar=function(){const e=this._useVariableName!=null;this.uiAttribs.boundToVar=e;return e};I.prototype.isAnimated=function(){return this._animated};I.prototype.isHidden=function(){return this.uiAttribs.hidePort};I.prototype._onTriggered=function(e){this._activity();this._op.updateAnims();if(this._op.enabled&&this.onTriggered)this.onTriggered(e)};I.prototype._onSetProfiling=function(e){this._op.patch.profiler.add("port",this);this.setValue(e);this._op.patch.profiler.add("port",null)};I.prototype._onTriggeredProfiling=function(){if(this._op.enabled&&this.onTriggered){this._op.patch.profiler.add("port",this);this.onTriggered();this._op.patch.profiler.add("port",null)}};I.prototype.getUiActiveState=function(){return this._uiActiveState};I.prototype.setUiActiveState=function(e){this._uiActiveState=e;if(this.onUiActiveStateChange)this.onUiActiveStateChange()};I.prototype.onValueChange=function(e){this.onChange=e};I.prototype.hidePort=function(){};I.portTypeNumberToString=function(e){if(e==v.OP.OP_PORT_TYPE_VALUE)return"value";if(e==v.OP.OP_PORT_TYPE_FUNCTION)return"function";if(e==v.OP.OP_PORT_TYPE_OBJECT)return"object";if(e==v.OP.OP_PORT_TYPE_ARRAY)return"array";if(e==v.OP.OP_PORT_TYPE_STRING)return"string";if(e==v.OP.OP_PORT_TYPE_DYNAMIC)return"dynamic";return"unknown"};class E{constructor(e,t,n,r,i,a,s,o,l,u){this._log=new c("cg_uniform");this._type=t;this._name=n;this._shader=e;this._value=1e-5;this._oldValue=null;this._port=null;this._structName=l;this._structUniformName=o;this._propertyName=u;this._shader._addUniform(this);this.needsUpdate=true;this.shaderType=null;this.comment=null;if(t=="f"){this.set=this.setValue=this.setValueF.bind(this);this.updateValue=this.updateValueF.bind(this)}else if(t=="f[]"){this.set=this.setValue=this.setValueArrayF.bind(this);this.updateValue=this.updateValueArrayF.bind(this)}else if(t=="2f[]"){this.set=this.setValue=this.setValueArray2F.bind(this);this.updateValue=this.updateValueArray2F.bind(this)}else if(t=="3f[]"){this.set=this.setValue=this.setValueArray3F.bind(this);this.updateValue=this.updateValueArray3F.bind(this)}else if(t=="4f[]"){this.set=this.setValue=this.setValueArray4F.bind(this);this.updateValue=this.updateValueArray4F.bind(this)}else if(t=="i"){this.set=this.setValue=this.setValueI.bind(this);this.updateValue=this.updateValueI.bind(this)}else if(t=="2i"){this.set=this.setValue=this.setValue2I.bind(this);this.updateValue=this.updateValue2I.bind(this)}else if(t=="3i"){this.set=this.setValue=this.setValue3I.bind(this);this.updateValue=this.updateValue3I.bind(this)}else if(t=="4i"){this.set=this.setValue=this.setValue4I.bind(this);this.updateValue=this.updateValue4I.bind(this)}else if(t=="b"){this.set=this.setValue=this.setValueBool.bind(this);this.updateValue=this.updateValueBool.bind(this)}else if(t=="4f"){this.set=this.setValue=this.setValue4F.bind(this);this.updateValue=this.updateValue4F.bind(this)}else if(t=="3f"){this.set=this.setValue=this.setValue3F.bind(this);this.updateValue=this.updateValue3F.bind(this)}else if(t=="2f"){this.set=this.setValue=this.setValue2F.bind(this);this.updateValue=this.updateValue2F.bind(this)}else if(t=="t"){this.set=this.setValue=this.setValueT.bind(this);this.updateValue=this.updateValueT.bind(this)}else if(t=="tc"){this.set=this.setValue=this.setValueT.bind(this);this.updateValue=this.updateValueT.bind(this)}else if(t=="t[]"){this.set=this.setValue=this.setValueArrayT.bind(this);this.updateValue=this.updateValueArrayT.bind(this)}else if(t=="m4"||t=="m4[]"){this.set=this.setValue=this.setValueM4.bind(this);this.updateValue=this.updateValueM4.bind(this)}else throw new Error("Unknown uniform type");if(typeof r=="object"&&r instanceof I){this._port=r;this._value=this._port.get();if(i&&a&&s){if(!(i instanceof I)||!(a instanceof I)||!(s instanceof I)){this._log.error("[cgl_uniform] mixed port/value parameter for vec4 ",this._name)}this._value=[0,0,0,0];this._port2=i;this._port3=a;this._port4=s;this._port.on("change",this.updateFromPort4f.bind(this));this._port2.on("change",this.updateFromPort4f.bind(this));this._port3.on("change",this.updateFromPort4f.bind(this));this._port4.on("change",this.updateFromPort4f.bind(this));this.updateFromPort4f()}else if(i&&a){if(!(i instanceof I)||!(a instanceof I)){this._log.error("[cgl_uniform] mixed port/value parameter for vec4 ",this._name)}this._value=[0,0,0];this._port2=i;this._port3=a;this._port.on("change",this.updateFromPort3f.bind(this));this._port2.on("change",this.updateFromPort3f.bind(this));this._port3.on("change",this.updateFromPort3f.bind(this));this.updateFromPort3f()}else if(i){if(!(i instanceof I)){this._log.error("[cgl_uniform] mixed port/value parameter for vec4 ",this._name)}this._value=[0,0];this._port2=i;this._port.on("change",this.updateFromPort2f.bind(this));this._port2.on("change",this.updateFromPort2f.bind(this));this.updateFromPort2f()}else{this._port.on("change",this.updateFromPort.bind(this))}}else this._value=r;this.setValue(this._value);this.needsUpdate=true}getType(){return this._type}getName(){return this._name}getValue(){return this._value}getShaderType(){return this.shaderType}isStructMember(){return!!this._structName}updateFromPort4f(){this._value[0]=this._port.get();this._value[1]=this._port2.get();this._value[2]=this._port3.get();this._value[3]=this._port4.get();this.setValue(this._value)}updateFromPort3f(){this._value[0]=this._port.get();this._value[1]=this._port2.get();this._value[2]=this._port3.get();this.setValue(this._value)}updateFromPort2f(){this._value[0]=this._port.get();this._value[1]=this._port2.get();this.setValue(this._value)}updateFromPort(){this.setValue(this._port.get())}}const L=E;class N extends L{constructor(e,t,n,r,i,a,s,o,l,u){super(e,t,n,r,i,a,s,o,l,u);this._loc=-1;this._cgl=e._cgl}get name(){return this._name}copy(e){const t=new N(e,this._type,this._name,this._value,this._port2,this._port3,this._port4,this._structUniformName,this._structName,this._propertyName);t.shaderType=this.shaderType;return t}getGlslTypeString(){return N.glslTypeString(this._type)}_isValidLoc(){return this._loc!=-1}resetLoc(){this._loc=-1;this.needsUpdate=true}bindTextures(){}getLoc(){return this._loc}updateFromPort4f(){this._value[0]=this._port.get();this._value[1]=this._port2.get();this._value[2]=this._port3.get();this._value[3]=this._port4.get();this.setValue(this._value)}updateFromPort3f(){this._value[0]=this._port.get();this._value[1]=this._port2.get();this._value[2]=this._port3.get();this.setValue(this._value)}updateFromPort2f(){this._value[0]=this._port.get();this._value[1]=this._port2.get();this.setValue(this._value)}updateFromPort(){this.setValue(this._port.get())}updateValueF(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;this._shader.getCgl().gl.uniform1f(this._loc,this._value);this._cgl.profileData.profileUniformCount++}setValueF(e){if(e!=this._value){this.needsUpdate=true;this._value=e}}updateValueI(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;this._shader.getCgl().gl.uniform1i(this._loc,this._value);this._cgl.profileData.profileUniformCount++}updateValue2I(){if(!this._value)return;if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}this._shader.getCgl().gl.uniform2i(this._loc,this._value[0],this._value[1]);this.needsUpdate=false;this._cgl.profileData.profileUniformCount++}updateValue3I(){if(!this._value)return;if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}this._shader.getCgl().gl.uniform3i(this._loc,this._value[0],this._value[1],this._value[2]);this.needsUpdate=false;this._cgl.profileData.profileUniformCount++}updateValue4I(){if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}this._shader.getCgl().gl.uniform4i(this._loc,this._value[0],this._value[1],this._value[2],this._value[3]);this._cgl.profileData.profileUniformCount++}setValueI(e){if(e!=this._value){this.needsUpdate=true;this._value=e}}setValue2I(e){if(!e)return;if(!this._oldValue){this._oldValue=[e[0]-1,1];this.needsUpdate=true}else if(e[0]!=this._oldValue[0]||e[1]!=this._oldValue[1]){this._oldValue[0]=e[0];this._oldValue[1]=e[1];this.needsUpdate=true}this._value=e}setValue3I(e){if(!e)return;if(!this._oldValue){this._oldValue=[e[0]-1,1,2];this.needsUpdate=true}else if(e[0]!=this._oldValue[0]||e[1]!=this._oldValue[1]||e[2]!=this._oldValue[2]){this._oldValue[0]=e[0];this._oldValue[1]=e[1];this._oldValue[2]=e[2];this.needsUpdate=true}this._value=e}setValue4I(e){this.needsUpdate=true;this._value=e||vec4.create()}updateValueBool(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;this._shader.getCgl().gl.uniform1i(this._loc,this._value?1:0);this._cgl.profileData.profileUniformCount++}setValueBool(e){if(e!=this._value){this.needsUpdate=true;this._value=e}}setValueArray4F(e){this.needsUpdate=true;this._value=e}updateValueArray4F(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;if(!this._value)return;this._shader.getCgl().gl.uniform4fv(this._loc,this._value);this._cgl.profileData.profileUniformCount++}setValueArray3F(e){this.needsUpdate=true;this._value=e}updateValueArray3F(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;if(!this._value)return;this._shader.getCgl().gl.uniform3fv(this._loc,this._value);this._cgl.profileData.profileUniformCount++}setValueArray2F(e){this.needsUpdate=true;this._value=e}updateValueArray2F(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;if(!this._value)return;this._shader.getCgl().gl.uniform2fv(this._loc,this._value);this._cgl.profileData.profileUniformCount++}setValueArrayF(e){this.needsUpdate=true;this._value=e}updateValueArrayF(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;if(!this._value)return;this._shader.getCgl().gl.uniform1fv(this._loc,this._value);this._cgl.profileData.profileUniformCount++}setValueArrayT(e){this.needsUpdate=true;this._value=e}updateValue3F(){if(!this._value)return;if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}this._shader.getCgl().gl.uniform3f(this._loc,this._value[0],this._value[1],this._value[2]);this.needsUpdate=false;this._cgl.profileData.profileUniformCount++}setValue3F(e){if(!e)return;if(!this._oldValue){this._oldValue=[e[0]-1,1,2];this.needsUpdate=true}else if(e[0]!=this._oldValue[0]||e[1]!=this._oldValue[1]||e[2]!=this._oldValue[2]){this._oldValue[0]=e[0];this._oldValue[1]=e[1];this._oldValue[2]=e[2];this.needsUpdate=true}this._value=e}updateValue2F(){if(!this._value)return;if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}this._shader.getCgl().gl.uniform2f(this._loc,this._value[0],this._value[1]);this.needsUpdate=false;this._cgl.profileData.profileUniformCount++}setValue2F(e){if(!e)return;if(!this._oldValue){this._oldValue=[e[0]-1,1];this.needsUpdate=true}else if(e[0]!=this._oldValue[0]||e[1]!=this._oldValue[1]){this._oldValue[0]=e[0];this._oldValue[1]=e[1];this.needsUpdate=true}this._value=e}updateValue4F(){if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}if(!this._value){this._log.warn("no value for uniform",this._name,this);this._value=[0,0,0,0]}this.needsUpdate=false;this._shader.getCgl().gl.uniform4f(this._loc,this._value[0],this._value[1],this._value[2],this._value[3]);this._cgl.profileData.profileUniformCount++}setValue4F(e){if(typeof this.value=="number")this.value=vec4.create();if(!e)return;if(!this._oldValue){this._oldValue=[e[0]-1,1,2,3];this.needsUpdate=true}else if(e[0]!=this._oldValue[0]||e[1]!=this._oldValue[1]||e[2]!=this._oldValue[2]||e[3]!=this._oldValue[3]){this._oldValue[0]=e[0];this._oldValue[1]=e[1];this._oldValue[2]=e[2];this.needsUpdate=true}this._value=e}updateValueM4(){if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}if(!this._value||this._value.length%16!=0)return console.log("this.name",this._name,this._value);this._shader.getCgl().gl.uniformMatrix4fv(this._loc,false,this._value);this._cgl.profileData.profileUniformCount++}setValueM4(e){this.needsUpdate=true;this._value=e||mat4.create()}updateValueArrayT(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;if(!this._value)return;this._shader.getCgl().gl.uniform1iv(this._loc,this._value);this._cgl.profileData.profileUniformCount++}updateValueT(){if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}this._cgl.profileData.profileUniformCount++;this._shader.getCgl().gl.uniform1i(this._loc,this._value);this.needsUpdate=false}setValueT(e){this.needsUpdate=true;this._value=e}}N.glslTypeString=e=>{if(e=="f")return"float";if(e=="b")return"bool";if(e=="i")return"int";if(e=="2i")return"ivec2";if(e=="2f")return"vec2";if(e=="3f")return"vec3";if(e=="4f")return"vec4";if(e=="m4")return"mat4";if(e=="t")return"sampler2D";if(e=="tc")return"samplerCube";if(e=="3f[]")return null;if(e=="m4[]")return null;if(e=="f[]")return null;console.warn("[CGL UNIFORM] unknown glsl type string ",e)};const U={SHADERVAR_VERTEX_POSITION:"vPosition",SHADERVAR_VERTEX_NUMBER:"attrVertIndex",SHADERVAR_VERTEX_NORMAL:"attrVertNormal",SHADERVAR_VERTEX_TEXCOORD:"attrTexCoord",SHADERVAR_INSTANCE_MMATRIX:"instMat",SHADERVAR_VERTEX_COLOR:"attrVertColor",SHADERVAR_INSTANCE_INDEX:"instanceIndex",SHADERVAR_UNI_PROJMAT:"projMatrix",SHADERVAR_UNI_VIEWMAT:"viewMatrix",SHADERVAR_UNI_MODELMAT:"modelMatrix",SHADERVAR_UNI_NORMALMAT:"normalMatrix",SHADERVAR_UNI_INVVIEWMAT:"inverseViewMatrix",SHADERVAR_UNI_INVPROJMAT:"invProjMatrix",SHADERVAR_UNI_MATERIALID:"materialId",SHADERVAR_UNI_OBJECTID:"objectId",SHADERVAR_UNI_VIEWPOS:"camPos"};const ne={BLEND_NONE:0,BLEND_NORMAL:1,BLEND_ADD:2,BLEND_SUB:3,BLEND_MUL:4};const re=180/Math.PI;const ie=Math.PI/180;const R={MATH:{DEG2RAD:ie,RAD2DEG:re},SHADER:U,BLEND_MODES:ne};function ae(e){e.prototype.hasFeedbacks=function(){return this._feedBacks.length>0};e.prototype.removeFeedbacks=function(e){if(!this._feedbacks)return;this._feedbacks.length=0;this._feedBacksChanged=true};e.prototype.setAttributeFeedback=function(){};e.prototype.setFeedback=function(e,t,n){let r={nameOut:t};let i=false;this.unBindFeedbacks();for(let e=0;e=t.length-1){this._log.log(this._cgl.canvas.id+" "+e.name+" buffersubdata out of bounds ?",t.length,r,n,e)}if(this._cgl.glVersion==1)this._cgl.gl.bufferSubData(this._cgl.gl.ARRAY_BUFFER,0,t);else this._cgl.gl.bufferSubData(this._cgl.gl.ARRAY_BUFFER,n*4,t,n,r-n)};M.prototype._resizeAttr=function(e,t){if(t.buffer)this._cgl.gl.deleteBuffer(t.buffer);t.buffer=this._cgl.gl.createBuffer();this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER,t.buffer);this._bufferArray(e,t);t.numItems=e.length/t.itemSize};M.prototype._bufferArray=function(e,t){let n=t.floatArray||null;if(!e)return;if(this._cgl.debugOneFrame){console.log("_bufferArray",e.length,t.name)}if(!(e instanceof Float32Array)){if(t&&n&&n.length==e.length){n.set(e)}else{n=new Float32Array(e);if(this._cgl.debugOneFrame){console.log("_bufferArray create new float32array",e.length,t.name)}if(e.length>1e4){this._cgl.profileData.profileNonTypedAttrib++;this._cgl.profileData.profileNonTypedAttribNames="("+this._name+":"+t.name+")"}}}else n=e;t.arrayLength=n.length;t.floatArray=null;this._cgl.gl.bufferData(this._cgl.gl.ARRAY_BUFFER,n,this._cgl.gl.DYNAMIC_DRAW)};M.prototype.addAttribute=M.prototype.updateAttribute=M.prototype.setAttribute=function(e,t,n,r){if(!t){this._log.error("mesh addAttribute - no array given! "+e);throw new Error}let i=null;let a=false;let s=0;const o=t.length/n;this._cgl.profileData.profileMeshAttributes+=o||0;if(typeof r=="function"){i=r}if(typeof r=="object"){if(r.cb)i=r.cb;if(r.instanced)a=r.instanced}if(e==R.SHADER.SHADERVAR_INSTANCE_MMATRIX)a=true;for(s=0;s0){this.setAttribute(R.SHADER.SHADERVAR_VERTEX_TEXCOORD,e.texCoords,2)}else{const t=new Float32Array(Math.round(e.vertices.length/3*2));this.setAttribute(R.SHADER.SHADERVAR_VERTEX_TEXCOORD,t,2)}};M.prototype.updateNormals=function(e){if(e.vertexNormals&&e.vertexNormals.length>0){this.setAttribute(R.SHADER.SHADERVAR_VERTEX_NORMAL,e.vertexNormals,3)}else{const t=new Float32Array(Math.round(e.vertices.length));this.setAttribute(R.SHADER.SHADERVAR_VERTEX_NORMAL,t,3)}};M.prototype._setVertexNumbers=function(e){if(!this._verticesNumbers||this._verticesNumbers.length!=this._numVerts||e){if(e)this._verticesNumbers=e;else{this._verticesNumbers=new Float32Array(this._numVerts);for(let e=0;e{if(!n.uniformNumVertices)n.uniformNumVertices=new N(n,"f","numVertices",this._numVerts);n.uniformNumVertices.setValue(this._numVerts)})}};M.prototype.setVertexIndices=function(t){if(!this._bufVerticesIndizes){this._log.warn("no bufVerticesIndizes: "+this._name);return}if(t.length>0){if(t instanceof Float32Array)this._log.warn("vertIndices float32Array: "+this._name);for(let e=0;e=this._numVerts){this._log.warn("invalid index in "+this._name,e,t[e]);return}}this._cgl.gl.bindBuffer(this._cgl.gl.ELEMENT_ARRAY_BUFFER,this._bufVerticesIndizes);if(t.length>65535){this.vertIndicesTyped=new Uint32Array(t);this._indexType=this._cgl.gl.UNSIGNED_INT}else if(t instanceof Uint32Array){this.vertIndicesTyped=t;this._indexType=this._cgl.gl.UNSIGNED_INT}else if(!(t instanceof Uint16Array)){this.vertIndicesTyped=new Uint16Array(t);this._indexType=this._cgl.gl.UNSIGNED_SHORT}else this.vertIndicesTyped=t;this._cgl.gl.bufferData(this._cgl.gl.ELEMENT_ARRAY_BUFFER,this.vertIndicesTyped,this._cgl.gl.DYNAMIC_DRAW);this._bufVerticesIndizes.itemSize=1;this._bufVerticesIndizes.numItems=t.length}else this._bufVerticesIndizes.numItems=0};M.prototype.setGeom=function(e,t){this._geom=e;if(e.glPrimitive!=null)this._glPrimitive=e.glPrimitive;if(this._geom&&this._geom.name)this._name="mesh "+this._geom.name;P.lastMesh=null;this._cgl.profileData.profileMeshSetGeom++;this._disposeAttributes();this.updateVertices(this._geom);this.setVertexIndices(this._geom.verticesIndices);if(this.addVertexNumbers)this._setVertexNumbers();const n=this._geom.getAttributes();const r={texCoords:R.SHADER.SHADERVAR_VERTEX_TEXCOORD,vertexNormals:R.SHADER.SHADERVAR_VERTEX_NORMAL,vertexColors:R.SHADER.SHADERVAR_VERTEX_COLOR,tangents:"attrTangent",biTangents:"attrBiTangent"};for(const i in n)if(n[i].data&&n[i].data.length)this.setAttribute(r[i]||i,n[i].data,n[i].itemSize);if(t){this._geom=null}};M.prototype._preBind=function(t){for(let e=0;ethis._lastAttrUpdate||n.length!=this._attributes.length){this._lastAttrUpdate=t.lastCompile;for(let e=0;e=0)this._cgl.gl.disableVertexAttribArray(t[e])}else{this._cgl.gl.vertexAttribDivisor(t[e],0);this._cgl.gl.vertexAttribDivisor(t[e]+1,0);this._cgl.gl.vertexAttribDivisor(t[e]+2,0);this._cgl.gl.vertexAttribDivisor(t[e]+3,0);this._cgl.gl.disableVertexAttribArray(t[e]+1);this._cgl.gl.disableVertexAttribArray(t[e]+2);this._cgl.gl.disableVertexAttribArray(t[e]+3)}}if(t[e]!=-1)this._cgl.gl.disableVertexAttribArray(t[e])}};M.prototype.meshChanged=function(){return this._cgl.lastMesh&&this._cgl.lastMesh!=this};M.prototype.printDebug=function(e){console.log("--attributes");for(let e=0;e Date: Mon, 15 Jul 2024 21:17:52 +0200 Subject: [PATCH 10/13] Moving over to Svelte5 --- dsp/main.js | 1 - index.html | 5 +- package-lock.json | 1925 ++++++++--------- package.json | 11 +- src/cables-ui.js | 10 + src/main.svelte | 0 .../DragBehavior.jsx | 0 .../Interface.jsx | 0 src/{ => previous-react-version}/Knob.jsx | 0 src/{ => previous-react-version}/Lockup.svg | 0 src/{ => previous-react-version}/index.css | 0 src/{ => previous-react-version}/main.jsx | 0 vite.config.js | 29 +- 13 files changed, 959 insertions(+), 1022 deletions(-) create mode 100644 src/cables-ui.js create mode 100644 src/main.svelte rename src/{ => previous-react-version}/DragBehavior.jsx (100%) rename src/{ => previous-react-version}/Interface.jsx (100%) rename src/{ => previous-react-version}/Knob.jsx (100%) rename src/{ => previous-react-version}/Lockup.svg (100%) rename src/{ => previous-react-version}/index.css (100%) rename src/{ => previous-react-version}/main.jsx (100%) diff --git a/dsp/main.js b/dsp/main.js index 8fa577b..3b89585 100644 --- a/dsp/main.js +++ b/dsp/main.js @@ -2,7 +2,6 @@ import {Renderer, el} from '@elemaudio/core'; import {RefMap} from './RefMap'; import srvb from './srvb'; - // This project demonstrates writing a small FDN reverb effect in Elementary. // // First, we initialize a custom Renderer instance that marshals our instruction diff --git a/index.html b/index.html index 483a97c..117648f 100644 --- a/index.html +++ b/index.html @@ -64,7 +64,7 @@ document.addEventListener("CABLES.jsLoaded", function (event) { - CABLES.patch = new CABLES.Patch({ + globalThis.CABLES.patch = new CABLES.Patch({ patch: CABLES.exportedPatch, "prefixAssetPath": "", "assetPath": "assets/", @@ -78,8 +78,11 @@ }); }); + + // disable rubberband effect on mobile devices document.getElementById('glcanvas').addEventListener('touchmove', (e)=>{ e.preventDefault(); }, false); + diff --git a/package-lock.json b/package-lock.json index f8a3141..61afc30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,24 +9,18 @@ "version": "0.0.0", "dependencies": { "@elemaudio/core": "^3.0.0", - "@heroicons/react": "^2.0.18", - "@use-gesture/react": "^10.2.27", "cpy-cli": "^4.2.0", "esbuild": "^0.17.8", "invariant": "^2.2.4", - "react": "^18.2.0", - "react-dom": "^18.2.0", "resize-observer-polyfill": "^1.5.1", "rimraf": "^5.0.0", "zustand": "^4.3.8" }, "devDependencies": { - "@types/react": "^18.0.37", - "@types/react-dom": "^18.0.11", - "@vitejs/plugin-react": "^4.0.0", "autoprefixer": "^10.4.14", "concurrently": "^8.2.2", "postcss": "^8.4.24", + "svelte": "^5.0.0-next.184", "tailwindcss": "^3.3.2", "vite": "^4.3.9", "zx": "^7.2.3" @@ -58,280 +52,37 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dependencies": { - "@babel/highlight": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz", - "integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", - "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helpers": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz", - "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz", - "integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.22.5", - "@babel/helper-validator-option": "^7.22.5", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz", - "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", - "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz", - "integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5" - }, + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz", - "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.22.5.tgz", - "integrity": "sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.22.5.tgz", - "integrity": "sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==", - "dev": true, + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/runtime": { @@ -346,55 +97,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz", - "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@elemaudio/core": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@elemaudio/core/-/core-3.0.0.tgz", @@ -735,14 +437,6 @@ "node": ">=12" } }, - "node_modules/@heroicons/react": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.0.18.tgz", - "integrity": "sha512-7TyMjRrZZMBPa+/5Y8lN0iyvUU/01PeMGX2+RE7cQWpEUIcb4QotzUObFkJDejj/HUH4qjP/eQ0gzzKs2f+6Yw==", - "peerDependencies": { - "react": ">= 16" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -785,14 +479,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -808,9 +502,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" @@ -823,21 +517,15 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -879,6 +567,12 @@ "node": ">=14" } }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, "node_modules/@types/fs-extra": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.3.tgz", @@ -917,82 +611,37 @@ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==" }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true - }, "node_modules/@types/ps-tree": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/ps-tree/-/ps-tree-1.1.4.tgz", "integrity": "sha512-CJyu2BqU/aZN/s8Ili3jiMctqXfTjCaWXirEcjRD8y1lUQZJ8eNohnal8+LXeWFs1VbdAOrCIdgATFsv+lnQ5Q==", "dev": true }, - "node_modules/@types/react": { - "version": "18.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.14.tgz", - "integrity": "sha512-A0zjq+QN/O0Kpe30hA1GidzyFjatVvrpIvWLxD+xv67Vt91TWWgco9IvrJBkeyHm1trGaFS/FSGqPlhyeZRm0g==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.6.tgz", - "integrity": "sha512-2et4PDvg6PVCyS7fuTc4gPoksV58bW0RwSxWKcPRcHZf0PRUGq03TKcD/rUHe3azfV6/5/biUBJw+HhCQjaP0A==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "dev": true - }, "node_modules/@types/which": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.1.tgz", "integrity": "sha512-OJWjr4k8gS1HXuOnCmQbBrQez+xqt/zqfp5PhgbKtsmEFEuojAg23arr+TiTZZ1TORdUF9RKXb/WKEpT1dwgSg==", "dev": true }, - "node_modules/@use-gesture/core": { - "version": "10.2.27", - "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.2.27.tgz", - "integrity": "sha512-V4XV7hn9GAD2MYu8yBBVi5iuWBsAMfjPRMsEVzoTNGYH72tf0kFP+OKqGKc8YJFQIJx6yj+AOqxmEHOmx2/MEA==" - }, - "node_modules/@use-gesture/react": { - "version": "10.2.27", - "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.2.27.tgz", - "integrity": "sha512-7E5vnWCxeslWlxwZ8uKIcnUZVMTRMZ8cvSnLLKF1NkyNb3PnNiAzoXM4G1vTKJKRhgOTeI6wK1YsEpwo9ABV5w==", - "dependencies": { - "@use-gesture/core": "10.2.27" + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" }, - "peerDependencies": { - "react": ">= 16.8.0" + "engines": { + "node": ">=0.4.0" } }, - "node_modules/@vitejs/plugin-react": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.1.tgz", - "integrity": "sha512-g25lL98essfeSj43HJ0o4DMp0325XK0ITkxpgChzJU/CyemgyChtlxfnRbjfwxDGCTRxTiXtQAsdebQXKMRSOA==", + "node_modules/acorn-typescript": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz", + "integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==", "dev": true, - "dependencies": { - "@babel/core": "^7.22.5", - "@babel/plugin-transform-react-jsx-self": "^7.22.5", - "@babel/plugin-transform-react-jsx-source": "^7.22.5", - "react-refresh": "^0.14.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, "peerDependencies": { - "vite": "^4.2.0" + "acorn": ">=8.9.0" } }, "node_modules/aggregate-error": { @@ -1054,6 +703,15 @@ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "dev": true }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, "node_modules/arrify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz", @@ -1098,6 +756,15 @@ "postcss": "^8.1.0" } }, + "node_modules/axobject-query": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", + "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1123,11 +790,11 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1534,12 +1201,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, "node_modules/cp-file": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-9.1.0.tgz", @@ -1621,12 +1282,6 @@ "node": ">=4" } }, - "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true - }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", @@ -1652,23 +1307,6 @@ "url": "https://opencollective.com/date-fns" } }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/decamelize": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", @@ -1711,6 +1349,15 @@ "node": ">=0.10.0" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -1817,6 +1464,22 @@ "node": ">=0.8.0" } }, + "node_modules/esm-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", + "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==", + "dev": true + }, + "node_modules/esrap": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.2.2.tgz", + "integrity": "sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1" + } + }, "node_modules/event-stream": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", @@ -1898,9 +1561,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2017,15 +1680,6 @@ "fx": "index.js" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -2090,15 +1744,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/globby": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.0.tgz", @@ -2290,6 +1935,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2326,35 +1980,11 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -2400,8 +2030,14 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, - "node_modules/locate-path": { - "version": "6.0.0", + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dependencies": { @@ -2431,13 +2067,13 @@ "loose-envify": "cli.js" } }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dev": true, "dependencies": { - "yallist": "^3.0.2" + "@jridgewell/sourcemap-codec": "^1.4.15" } }, "node_modules/make-dir": { @@ -2585,12 +2221,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -2603,9 +2233,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -2935,10 +2565,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -2970,9 +2599,9 @@ } }, "node_modules/postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "version": "8.4.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", + "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", "dev": true, "funding": [ { @@ -2989,9 +2618,9 @@ } ], "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -3166,6 +2795,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -3173,27 +2803,6 @@ "node": ">=0.10.0" } }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/react-refresh": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", - "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -3332,9 +2941,9 @@ } }, "node_modules/rollup": { - "version": "3.25.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.2.tgz", - "integrity": "sha512-VLnkxZMDr3jpxgtmS8pQZ0UvhslmF4ADq/9w4erkctbgjCqLW9oa89fJuXEs4ZmgyoF7Dm8rMDKSS5b5u2hHUg==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -3378,18 +2987,10 @@ "tslib": "^2.1.0" } }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -3450,9 +3051,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -3675,6 +3276,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svelte": { + "version": "5.0.0-next.184", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.0.0-next.184.tgz", + "integrity": "sha512-oHWNajXOytt/5s2Ark3o/CP7bHLx+o/QZjTkCtU1dECqSmYyGqrIsoZi0Cx0VBdXAHMqI+1/T70ppaL1cL7LEw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.1", + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.5", + "acorn": "^8.11.3", + "acorn-typescript": "^1.4.13", + "aria-query": "^5.3.0", + "axobject-query": "^4.0.0", + "esm-env": "^1.0.0", + "esrap": "^1.2.2", + "is-reference": "^3.0.2", + "locate-character": "^3.0.0", + "magic-string": "^0.30.5", + "zimmerframe": "^1.1.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/tailwindcss": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", @@ -3757,15 +3382,6 @@ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3878,14 +3494,14 @@ } }, "node_modules/vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", + "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", "dev": true, "dependencies": { - "esbuild": "^0.17.5", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" }, "bin": { "vite": "bin/vite.js" @@ -3893,12 +3509,16 @@ "engines": { "node": "^14.18.0 || >=16.0.0" }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", + "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", @@ -3911,6 +3531,9 @@ "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -3925,6 +3548,395 @@ } } }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, "node_modules/web-streams-polyfill": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", @@ -4089,12 +4101,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, "node_modules/yaml": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", @@ -4170,6 +4176,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zimmerframe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", + "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", + "dev": true + }, "node_modules/zustand": { "version": "4.3.8", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.8.tgz", @@ -4268,201 +4280,28 @@ } }, "@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", - "requires": { - "@babel/highlight": "^7.22.5" - } - }, - "@babel/compat-data": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz", - "integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==", - "dev": true - }, - "@babel/core": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", - "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helpers": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - } - }, - "@babel/generator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz", - "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz", - "integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.22.5", - "@babel/helper-validator-option": "^7.22.5", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", - "dev": true, - "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-module-transforms": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz", - "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", - "dev": true - }, - "@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", - "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", - "dev": true, + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "requires": { - "@babel/types": "^7.22.5" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" } }, - "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true - }, "@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==" - }, - "@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", - "dev": true - }, - "@babel/helpers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz", - "integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==", - "dev": true, - "requires": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5" - } + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==" }, "@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", - "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz", - "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==", - "dev": true - }, - "@babel/plugin-transform-react-jsx-self": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.22.5.tgz", - "integrity": "sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - } - }, - "@babel/plugin-transform-react-jsx-source": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.22.5.tgz", - "integrity": "sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==", - "dev": true, + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" } }, "@babel/runtime": { @@ -4474,46 +4313,6 @@ "regenerator-runtime": "^0.14.0" } }, - "@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" - } - }, - "@babel/traverse": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz", - "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "to-fast-properties": "^2.0.0" - } - }, "@elemaudio/core": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@elemaudio/core/-/core-3.0.0.tgz", @@ -4656,12 +4455,6 @@ "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", "optional": true }, - "@heroicons/react": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.0.18.tgz", - "integrity": "sha512-7TyMjRrZZMBPa+/5Y8lN0iyvUU/01PeMGX2+RE7cQWpEUIcb4QotzUObFkJDejj/HUH4qjP/eQ0gzzKs2f+6Yw==", - "requires": {} - }, "@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -4691,14 +4484,14 @@ } }, "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "requires": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" } }, "@jridgewell/resolve-uri": { @@ -4708,9 +4501,9 @@ "dev": true }, "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true }, "@jridgewell/sourcemap-codec": { @@ -4720,21 +4513,13 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - }, - "dependencies": { - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - } + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@nodelib/fs.scandir": { @@ -4766,6 +4551,12 @@ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "optional": true }, + "@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, "@types/fs-extra": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.3.tgz", @@ -4804,74 +4595,30 @@ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==" }, - "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true - }, "@types/ps-tree": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/ps-tree/-/ps-tree-1.1.4.tgz", "integrity": "sha512-CJyu2BqU/aZN/s8Ili3jiMctqXfTjCaWXirEcjRD8y1lUQZJ8eNohnal8+LXeWFs1VbdAOrCIdgATFsv+lnQ5Q==", "dev": true }, - "@types/react": { - "version": "18.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.14.tgz", - "integrity": "sha512-A0zjq+QN/O0Kpe30hA1GidzyFjatVvrpIvWLxD+xv67Vt91TWWgco9IvrJBkeyHm1trGaFS/FSGqPlhyeZRm0g==", - "dev": true, - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-dom": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.6.tgz", - "integrity": "sha512-2et4PDvg6PVCyS7fuTc4gPoksV58bW0RwSxWKcPRcHZf0PRUGq03TKcD/rUHe3azfV6/5/biUBJw+HhCQjaP0A==", - "dev": true, - "requires": { - "@types/react": "*" - } - }, - "@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "dev": true - }, "@types/which": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.1.tgz", "integrity": "sha512-OJWjr4k8gS1HXuOnCmQbBrQez+xqt/zqfp5PhgbKtsmEFEuojAg23arr+TiTZZ1TORdUF9RKXb/WKEpT1dwgSg==", "dev": true }, - "@use-gesture/core": { - "version": "10.2.27", - "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.2.27.tgz", - "integrity": "sha512-V4XV7hn9GAD2MYu8yBBVi5iuWBsAMfjPRMsEVzoTNGYH72tf0kFP+OKqGKc8YJFQIJx6yj+AOqxmEHOmx2/MEA==" - }, - "@use-gesture/react": { - "version": "10.2.27", - "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.2.27.tgz", - "integrity": "sha512-7E5vnWCxeslWlxwZ8uKIcnUZVMTRMZ8cvSnLLKF1NkyNb3PnNiAzoXM4G1vTKJKRhgOTeI6wK1YsEpwo9ABV5w==", - "requires": { - "@use-gesture/core": "10.2.27" - } + "acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true }, - "@vitejs/plugin-react": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.1.tgz", - "integrity": "sha512-g25lL98essfeSj43HJ0o4DMp0325XK0ITkxpgChzJU/CyemgyChtlxfnRbjfwxDGCTRxTiXtQAsdebQXKMRSOA==", + "acorn-typescript": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz", + "integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==", "dev": true, - "requires": { - "@babel/core": "^7.22.5", - "@babel/plugin-transform-react-jsx-self": "^7.22.5", - "@babel/plugin-transform-react-jsx-source": "^7.22.5", - "react-refresh": "^0.14.0" - } + "requires": {} }, "aggregate-error": { "version": "4.0.1", @@ -4917,6 +4664,15 @@ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "dev": true }, + "aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "requires": { + "dequal": "^2.0.3" + } + }, "arrify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz", @@ -4936,6 +4692,15 @@ "postcss-value-parser": "^4.2.0" } }, + "axobject-query": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", + "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "dev": true, + "requires": { + "dequal": "^2.0.3" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4958,11 +4723,11 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "browserslist": { @@ -5233,12 +4998,6 @@ } } }, - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, "cp-file": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-9.1.0.tgz", @@ -5290,12 +5049,6 @@ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true }, - "csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true - }, "data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", @@ -5311,15 +5064,6 @@ "@babel/runtime": "^7.21.0" } }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, "decamelize": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", @@ -5346,6 +5090,12 @@ } } }, + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true + }, "didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -5436,6 +5186,22 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, + "esm-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", + "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==", + "dev": true + }, + "esrap": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.2.2.tgz", + "integrity": "sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1" + } + }, "event-stream": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", @@ -5497,9 +5263,9 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "requires": { "to-regex-range": "^5.0.1" } @@ -5578,12 +5344,6 @@ "integrity": "sha512-rIYQBmx85Jfhd3pkSw06YPgvSvfTi022ZXTeFDkcCZGCs5nt3sjqFBGtcMFe1TR2S00RDz63be0ab5mhCiOLBw==", "dev": true }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -5629,12 +5389,6 @@ "is-glob": "^4.0.3" } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, "globby": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.0.tgz", @@ -5777,6 +5531,15 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==" }, + "is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5802,23 +5565,11 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -5850,6 +5601,12 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, + "locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -5872,13 +5629,13 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dev": true, "requires": { - "yallist": "^3.0.2" + "@jridgewell/sourcemap-codec": "^1.4.15" } }, "make-dir": { @@ -5982,12 +5739,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz", "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==" }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -6000,9 +5751,9 @@ } }, "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true }, "nested-error-stacks": { @@ -6217,10 +5968,9 @@ } }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" }, "picomatch": { "version": "2.3.1", @@ -6240,14 +5990,14 @@ "dev": true }, "postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "version": "8.4.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", + "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", "dev": true, "requires": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" } }, "postcss-import": { @@ -6341,25 +6091,11 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, "requires": { "loose-envify": "^1.1.0" } }, - "react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "requires": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - } - }, - "react-refresh": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", - "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", - "dev": true - }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -6453,9 +6189,9 @@ } }, "rollup": { - "version": "3.25.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.2.tgz", - "integrity": "sha512-VLnkxZMDr3jpxgtmS8pQZ0UvhslmF4ADq/9w4erkctbgjCqLW9oa89fJuXEs4ZmgyoF7Dm8rMDKSS5b5u2hHUg==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -6478,18 +6214,10 @@ "tslib": "^2.1.0" } }, - "scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "requires": { - "loose-envify": "^1.1.0" - } - }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" }, "shallowequal": { "version": "1.1.0", @@ -6526,9 +6254,9 @@ "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" }, "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "dev": true }, "spawn-command": { @@ -6694,6 +6422,27 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, + "svelte": { + "version": "5.0.0-next.184", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.0.0-next.184.tgz", + "integrity": "sha512-oHWNajXOytt/5s2Ark3o/CP7bHLx+o/QZjTkCtU1dECqSmYyGqrIsoZi0Cx0VBdXAHMqI+1/T70ppaL1cL7LEw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.1", + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.5", + "acorn": "^8.11.3", + "acorn-typescript": "^1.4.13", + "aria-query": "^5.3.0", + "axobject-query": "^4.0.0", + "esm-env": "^1.0.0", + "esrap": "^1.2.2", + "is-reference": "^3.0.2", + "locate-character": "^3.0.0", + "magic-string": "^0.30.5", + "zimmerframe": "^1.1.2" + } + }, "tailwindcss": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", @@ -6762,12 +6511,6 @@ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6843,15 +6586,201 @@ } }, "vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", + "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", "dev": true, "requires": { - "esbuild": "^0.17.5", + "esbuild": "^0.18.10", "fsevents": "~2.3.2", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "dependencies": { + "@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "dev": true, + "optional": true + }, + "esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + } } }, "web-streams-polyfill": { @@ -6964,12 +6893,6 @@ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, "yaml": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", @@ -7026,6 +6949,12 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" }, + "zimmerframe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", + "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", + "dev": true + }, "zustand": { "version": "4.3.8", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.8.tgz", diff --git a/package.json b/package.json index 7520247..e484d28 100644 --- a/package.json +++ b/package.json @@ -19,26 +19,21 @@ }, "dependencies": { "@elemaudio/core": "^3.0.0", - "@heroicons/react": "^2.0.18", - "@use-gesture/react": "^10.2.27", "cpy-cli": "^4.2.0", "esbuild": "^0.17.8", "invariant": "^2.2.4", - "react": "^18.2.0", - "react-dom": "^18.2.0", "resize-observer-polyfill": "^1.5.1", "rimraf": "^5.0.0", "zustand": "^4.3.8" }, "devDependencies": { - "@types/react": "^18.0.37", - "@types/react-dom": "^18.0.11", - "@vitejs/plugin-react": "^4.0.0", "autoprefixer": "^10.4.14", "concurrently": "^8.2.2", "postcss": "^8.4.24", + "svelte": "^5.0.0-next.184", "tailwindcss": "^3.3.2", "vite": "^4.3.9", - "zx": "^7.2.3" + "zx": "^7.2.3", + "vite-plugin-svelte": "^4.0.0-next.4" } } diff --git a/src/cables-ui.js b/src/cables-ui.js new file mode 100644 index 0000000..babea7b --- /dev/null +++ b/src/cables-ui.js @@ -0,0 +1,10 @@ +console.log( 'cables-ui loading' ); + +// const myVar = globalThis.CABLES.patch.getVar("ui_dialValues"); + +// if(myVar) { +// // will be called every time value changes +// myVar.on("change", (function(newValue) { +// console.log(newValue); +// })); +// } \ No newline at end of file diff --git a/src/main.svelte b/src/main.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/DragBehavior.jsx b/src/previous-react-version/DragBehavior.jsx similarity index 100% rename from src/DragBehavior.jsx rename to src/previous-react-version/DragBehavior.jsx diff --git a/src/Interface.jsx b/src/previous-react-version/Interface.jsx similarity index 100% rename from src/Interface.jsx rename to src/previous-react-version/Interface.jsx diff --git a/src/Knob.jsx b/src/previous-react-version/Knob.jsx similarity index 100% rename from src/Knob.jsx rename to src/previous-react-version/Knob.jsx diff --git a/src/Lockup.svg b/src/previous-react-version/Lockup.svg similarity index 100% rename from src/Lockup.svg rename to src/previous-react-version/Lockup.svg diff --git a/src/index.css b/src/previous-react-version/index.css similarity index 100% rename from src/index.css rename to src/previous-react-version/index.css diff --git a/src/main.jsx b/src/previous-react-version/main.jsx similarity index 100% rename from src/main.jsx rename to src/previous-react-version/main.jsx diff --git a/vite.config.js b/vite.config.js index 7aeb03e..83e1ab6 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,11 +1,5 @@ import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' - -import { execSync } from 'node:child_process' - -const currentCommit = execSync("git rev-parse --short HEAD").toString(); -const date = new Date(); -const dateString = `${date.getFullYear()}.${date.getMonth() + 1}.${date.getDate()}`; +import { svelte } from '@sveltejs/vite-plugin-svelte' // A helper plugin which specifically watches for changes to public/dsp.main.js, // which is built in a parallel watch job via esbuild during dev. @@ -17,8 +11,8 @@ const dateString = `${date.getFullYear()}.${date.getMonth() + 1}.${date.getDate( function pubDirReloadPlugin() { return { name: 'pubDirReload', - handleHotUpdate({file, modules, server}) { - if (file.includes('public/dsp.main.js')) { + handleHotUpdate({ file, modules, server }) { + if (file.includes('public/dsp.main.js' )) { server.ws.send({ type: 'custom', event: 'reload-dsp', @@ -30,12 +24,19 @@ function pubDirReloadPlugin() { }; } -// https://vitejs.dev/config/ +// related to the audio blanking error on some devices +// is the order of plugins important? export default defineConfig({ base: './', - define: { - __COMMIT_HASH__: JSON.stringify(currentCommit), - __BUILD_DATE__: JSON.stringify(dateString), + plugins: [ + svelte(), + pubDirReloadPlugin(), + ], + server: { + watch: { + // The paths to be added to the watch list + + } }, - plugins: [react(), pubDirReloadPlugin()], + }) From 855e0b32df2a76b9a8e1c48dcf95802b8069de00 Mon Sep 17 00:00:00 2001 From: NeverEngineLabs Date: Tue, 16 Jul 2024 11:54:20 +0200 Subject: [PATCH 11/13] Update README.md --- README.md | 94 +------------------------------------------------------ 1 file changed, 1 insertion(+), 93 deletions(-) diff --git a/README.md b/README.md index 5b360d9..922266a 100644 --- a/README.md +++ b/README.md @@ -1,93 +1 @@ -# SRVB - -SRVB is a small digital reverb audio plugin (VST3/AU) for MacOS and Windows. - -This project demonstrates one way to write an audio plugin using JavaScript and -familiar web technologies, and while there are several variants on this approach, -it is meant to be both a compelling example and a good starting point for audio -plugins made with a similar architecture. - -## Overview - -The software architecture in this plugin is much like [Tauri](https://tauri.app/) and similar to -[Electron](https://www.electronjs.org/). The user interface is a simple Vite, React, and Tailwind app -at the root of the repository, which is packaged into the plugin app bundle and loaded into a native -webview instance owned by the plugin at runtime. - -The audio processing algorithm in the `dsp/` directory is also written in -JavaScript using [Elementary](https://elementary.audio), and is run in a separate -engine which directs the underlying native plugin audio processing. The native -plugin itself provides the harness for these two frontend JavaScript bundles, -and interfaces with the plugin host (typically a DAW) to coordinate the user -interface and the audio processing loop. - -## Elementary - -If you're new to Elementary Audio, [Elementary](https://elementary.audio) is a JavaScript/C++ library for building audio applications. - -* **Declarative:** Elementary makes it simple to create interactive audio processes through functional, declarative programming. Describe your audio process as a function of your application state, and Elementary will efficiently update the underlying audio engine as necessary. -* **Dynamic:** Most audio processing frameworks and tools facilitate building static processes. But what happens as your audio requirements change throughout the user journey? Elementary is designed to facilitate and adapt to the dynamic nature of modern audio applications. -* **Portable:** By decoupling the JavaScript API from the underlying audio engine (the "what" from the "how"), Elementary enables writing portable applications. Whether the underlying engine is running in the browser, an audio plugin, or an embedded device, the JavaScript layer remains the same. - -Find more in the [Elementary repository on GitHub](https://github.com/elemaudio/elementary) and the documentation [on the website](https://elementary.audio/). - -## Getting Started - -### Dependencies - -Before running the following steps, please make sure you have the following dependencies installed and -available at the command line: - -* [CMake](https://cmake.org/) -* [Node.js](https://nodejs.org/en) -* Bash: the build steps below expect to run scripts in a Bash environment. For Windows machines, consider running the following steps in a Git Bash environment, or with WSL. - -Next, we fetch the SRVB project and its dependencies, - -```bash -# Clone the project with its submodules -git clone --recurse-submodules https://github.com/elemaudio/srvb.git -cd srvb - -# Install npm dependencies -npm install -``` - -### Develop -```bash -npm run dev -``` - -In develop mode, the native plugin is compiled to fetch its JavaScript assets from localhost, where subsequently we -run the Vite dev server to serve those assets. This arrangement enables Vite's hot reloading behavior for developing -the plugin while it's running inside a host. - -### Release -```bash -npm run build -``` - -In release builds, the JavaScript bundles are packaged into the plugin app bundle so that the resulting bundle -is relocatable, thereby enabling distribution to end users. - -### Troubleshooting - -* After a successful build with either `npm run dev` or `npm run build`, you - should have local plugin binaries built and copied into the correct - audio plugin directories on your machine. If you don't see them, look in - `./native/build/scripted/SRVB_artefacts` and copy them manually -* **Note**: the CMake build on Windows attempts to copy the VST3 plugin binary - into `C:\Program Files`, a step that requires admin permissions. Therefore - you should either run your build as an admin, or disable the copy plugin step - in `native/CMakeLists.txt` and manually copy the plugin binary after build. -* **Note**: especially on MacOS, certain plugin hosts such as Ableton Live have - strict security settings that prevent them from recognizing local unsigned - binaries. You'll want to either add a codesign step to your build, or - configure the security settings of your host to address this. - -## License - -[MIT](./LICENSE.md) - -This project also uses [JUCE](https://juce.com/), which is licensed GPLv3. Please consult JUCE's license -agreement if you intend to distribute your own plugin based on this template. +# Under construction From ff492281bd2f28cc2d67a2c2a3eeea8a36cea96e Mon Sep 17 00:00:00 2001 From: Cristian Vogel Date: Tue, 16 Jul 2024 11:58:44 +0200 Subject: [PATCH 12/13] Moved to private repository --- .gitignore | 1 + index.html | 111 +--- native/CMakeLists.txt | 136 +++- package-lock.json | 1097 +++++++++++++++++++++++++------- package.json | 7 +- src/App.svelte | 47 ++ src/cables-js/loader.svelte.js | 18 + src/cables-ui.js | 2 +- src/main.svelte | 0 src/main.ts | 7 + src/stores/NativeMessage.ts | 250 ++++++++ src/stores/WWTimer.ts | 55 ++ src/stores/stores.ts | 104 +++ src/types/index.d.ts | 1 + src/utils/utils.ts | 167 +++++ 15 files changed, 1653 insertions(+), 350 deletions(-) create mode 100644 src/App.svelte create mode 100644 src/cables-js/loader.svelte.js delete mode 100644 src/main.svelte create mode 100644 src/main.ts create mode 100644 src/stores/NativeMessage.ts create mode 100644 src/stores/WWTimer.ts create mode 100644 src/stores/stores.ts create mode 100644 src/types/index.d.ts create mode 100644 src/utils/utils.ts diff --git a/.gitignore b/.gitignore index 126959e..7792296 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ pnpm-debug.log* lerna-debug.log* # Builds +native node_modules build dist diff --git a/index.html b/index.html index 117648f..c9a1df2 100644 --- a/index.html +++ b/index.html @@ -1,88 +1,41 @@ - + Four GL Dials - - - - - - - - - - - - - + + + - - - +
    + + + diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index b25ac63..3862d5c 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 3.15) -project(Elem_SRVB VERSION 0.1.0) +project(NEL_SRVB VERSION 0.1.0) -set(TARGET_NAME SRVB) +set(TARGET_NAME NEL_SRVB) set(ASSETS_DIR ${CMAKE_SOURCE_DIR}/../dist/) option(JUCE_ENABLE_MODULE_SOURCE_GROUPS "Enable Module Source Groups" ON) @@ -12,34 +12,93 @@ option(ELEM_DEV_LOCALHOST "Run against localhost for static assets" OFF) add_subdirectory(juce) add_subdirectory(elementary/runtime) +if (WIN32) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(PC_ARCH "x64") + else() + set(PC_ARCH "x32") + endif() +endif() + juce_add_plugin(${TARGET_NAME} - BUNDLE_ID "audio.elementary.srvb" - COMPANY_NAME "Elementary Audio" - COMPANY_WEBSITE "https://www.elementary.audio" - COMPANY_EMAIL "nick@elementary.audio" - PLUGIN_MANUFACTURER_CODE Elem # A four-character manufacturer id with at least one upper-case character - PLUGIN_CODE Srvb # A unique four-character plugin id with at least one upper-case character + BUNDLE_ID "audio.neverenginelabs.NELShifterMesh" + COMPANY_NAME "NeverEngineLabs" + COMPANY_WEBSITE "https://neverenginelabs.com" + COMPANY_EMAIL "support@neverenginelabs.com" + PLUGIN_MANUFACTURER_CODE NVLB # A four-character manufacturer id with at least one upper-case character + PLUGIN_CODE ShRv # A unique four-character plugin id with at least one upper-case character COPY_PLUGIN_AFTER_BUILD FALSE # We enable this manually below after adding a copy step - APP_SANDBOX_ENABLED TRUE + APP_SANDBOX_ENABLED TRUE APP_SANDBOX_OPTIONS com.apple.security.network.client com.apple.security.files.user-selected.read-write FORMATS AU VST3 # The formats to build. Other valid formats are: AAX Unity VST AU AUv3 - PRODUCT_NAME ${TARGET_NAME}) # The name of the final executable, which can differ from the target name + PRODUCT_NAME "NELShifterMesh_${CMAKE_OSX_ARCHITECTURES}${PC_ARCH}_${BUILD_VERSION}") # The name of the final executable, which can differ from the target name + + # Keyzy Client Library + # Replace KeyzyClientLibraryX.X.X with your actual library version + +set(KeyzyClientLibrary_VERSION "v143") + +if(WIN32) + if(MSVC_VERSION EQUAL 1910) # VS 2017 + set(VS_VERSION "VS2017") + elseif(MSVC_VERSION EQUAL 1920) # VS 2019 + set(VS_VERSION "VS2019") + elseif(MSVC_VERSION GREATER_EQUAL 1930) # VS 2022 or later + set(VS_VERSION "VS2022") + endif() + + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(ARCH "64") + else() + set(ARCH "86") + endif() + + # Set MD or MT based on your project requirements + set(MD_MT "MD") + + set(DEBUG_OR_RELEASE "$<$:D>$<$:R>") + + set(LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/KeyzyClientLibrary/${VS_VERSION}/${DEBUG_OR_RELEASE}${ARCH}${MD_MT}_x64_${KeyzyClientLibrary_VERSION}) + + target_link_libraries(${TARGET_NAME} PRIVATE ${LIB_DIR}/Lib/KeyzyClient.lib) + +elseif(APPLE) + if(IOS) + set(LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/KeyzyClientLibrary/XcodeiOS) + else() + # Choose the correct library based on your target architectures + set(LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/KeyzyClientLibrary/XcodeAppleSiliconIntel64) + endif() + + find_library(KEYZY_CLIENT_LIB KeyzyClient PATHS ${LIB_DIR}/Lib) + if(NOT KEYZY_CLIENT_LIB) + message(FATAL_ERROR "KeyzyClient library not found") + endif() + target_link_libraries(${TARGET_NAME} PRIVATE ${KEYZY_CLIENT_LIB}) +endif() + +target_include_directories(${TARGET_NAME} PRIVATE + $) # Copy static assets post build if (NOT ELEM_DEV_LOCALHOST) get_target_property(ACTIVE_TARGETS ${TARGET_NAME} JUCE_ACTIVE_PLUGIN_TARGETS) - foreach(ACTIVE_TARGET IN LISTS ACTIVE_TARGETS) - message(STATUS "Adding resource copy step from ${ASSETS_DIR} for ${ACTIVE_TARGET}") - - get_target_property(ARTIFACT_FILE ${ACTIVE_TARGET} JUCE_PLUGIN_ARTEFACT_FILE) - set(RESOURCE_DIR "${ARTIFACT_FILE}/Contents/Resources/") - - add_custom_command(TARGET ${ACTIVE_TARGET} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rm -rf "${RESOURCE_DIR}/dist" - COMMAND ${CMAKE_COMMAND} -E make_directory "${RESOURCE_DIR}/dist" - COMMAND ${CMAKE_COMMAND} -E copy_directory "${ASSETS_DIR}" "${RESOURCE_DIR}/dist" - VERBATIM) - endforeach() +foreach(ACTIVE_TARGET IN LISTS ACTIVE_TARGETS) + message(STATUS "Adding resource copy step from ${ASSETS_DIR} for ${ACTIVE_TARGET}") + + get_target_property(ARTIFACT_FILE ${ACTIVE_TARGET} JUCE_PLUGIN_ARTEFACT_FILE) + set(RESOURCE_DIR "${ARTIFACT_FILE}/Contents/Resources/") + +add_custom_command(TARGET ${ACTIVE_TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E rm -rf "${RESOURCE_DIR}/dist" + COMMAND ${CMAKE_COMMAND} -E echo "Removed directory: ${RESOURCE_DIR}/dist" + COMMAND ${CMAKE_COMMAND} -E make_directory "${RESOURCE_DIR}/dist" + COMMAND ${CMAKE_COMMAND} -E echo "Created directory: ${RESOURCE_DIR}/dist" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${ASSETS_DIR}" "${RESOURCE_DIR}/dist" + COMMAND ${CMAKE_COMMAND} -E echo "Copied directory: ${ASSETS_DIR} to ${RESOURCE_DIR}/dist" + VERBATIM) + +endforeach() endif() # Enable copy step @@ -50,35 +109,42 @@ endif() target_sources(${TARGET_NAME} PRIVATE PluginProcessor.cpp - WebViewEditor.cpp) + WebViewEditor.cpp + ) target_include_directories(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/choc/gui - ${CMAKE_CURRENT_SOURCE_DIR}/choc/javascript) + ${CMAKE_CURRENT_SOURCE_DIR}/choc/javascript +) target_compile_features(${TARGET_NAME} PRIVATE cxx_std_17) -target_compile_definitions(${TARGET_NAME} + + target_compile_definitions(${TARGET_NAME} PRIVATE ELEM_DEV_LOCALHOST=${ELEM_DEV_LOCALHOST} JUCE_VST3_CAN_REPLACE_VST2=0 JUCE_USE_CURL=0) -target_link_libraries(${TARGET_NAME} + target_link_libraries(${TARGET_NAME} PRIVATE juce::juce_audio_basics - juce::juce_audio_devices - juce::juce_audio_plugin_client + # juce::juce_audio_devices + # juce::juce_audio_plugin_client juce::juce_audio_processors juce::juce_audio_utils - juce::juce_core - juce::juce_data_structures - juce::juce_dsp - juce::juce_events - juce::juce_graphics - juce::juce_gui_basics + # juce::juce_core + # juce::juce_data_structures + # juce::juce_dsp + # juce::juce_events + # juce::juce_graphics + # juce::juce_gui_basics juce::juce_gui_extra - runtime) + runtime + ) + + + diff --git a/package-lock.json b/package-lock.json index 61afc30..37ac7ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,15 +14,17 @@ "invariant": "^2.2.4", "resize-observer-polyfill": "^1.5.1", "rimraf": "^5.0.0", + "worker-timers": "^8.0.2", "zustand": "^4.3.8" }, "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.1.1", "autoprefixer": "^10.4.14", "concurrently": "^8.2.2", "postcss": "^8.4.24", "svelte": "^5.0.0-next.184", "tailwindcss": "^3.3.2", - "vite": "^4.3.9", + "vite": "^5.0.0", "zx": "^7.2.3" } }, @@ -86,10 +88,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", - "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", - "dev": true, + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -107,6 +108,22 @@ "shallowequal": "^1.1.0" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/android-arm": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", @@ -567,6 +584,265 @@ "node": ">=14" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.1.tgz", + "integrity": "sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.1.tgz", + "integrity": "sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.1.tgz", + "integrity": "sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.1.tgz", + "integrity": "sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.1.tgz", + "integrity": "sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.1.tgz", + "integrity": "sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.1.tgz", + "integrity": "sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.1.tgz", + "integrity": "sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.1.tgz", + "integrity": "sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.1.tgz", + "integrity": "sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.1.tgz", + "integrity": "sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.1.tgz", + "integrity": "sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.1.tgz", + "integrity": "sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.1.tgz", + "integrity": "sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.1.tgz", + "integrity": "sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.1.tgz", + "integrity": "sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.1.tgz", + "integrity": "sha512-rimpFEAboBBHIlzISibg94iP09k/KYdHgVhJlcsTfn7KMBhc70jFX/GRWkRdFCc2fdnk+4+Bdfej23cMDnJS6A==", + "dev": true, + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", + "debug": "^4.3.4", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.10", + "svelte-hmr": "^0.16.0", + "vitefu": "^0.2.5" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz", + "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte/node_modules/svelte-hmr": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", + "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", + "dev": true, + "engines": { + "node": "^12.20 || ^14.13.1 || >= 16" + }, + "peerDependencies": { + "svelte": "^3.19.0 || ^4.0.0" + } + }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -1307,6 +1583,23 @@ "url": "https://opencollective.com/date-fns" } }, + "node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/decamelize": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", @@ -1349,6 +1642,15 @@ "node": ">=0.10.0" } }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -1529,6 +1831,18 @@ "node": ">= 6" } }, + "node_modules/fast-unique-numbers": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-9.0.7.tgz", + "integrity": "sha512-K6hYNu8ZsVb7mwmd9OKxHmw4aLa+IFiBxt1e/FZVFFta94ZgNAHqIgUtDzd7AJaVoo/CoNTgr6sj1Dbj3PQPKg==", + "dependencies": { + "@babel/runtime": "^7.24.8", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.2.0" + } + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -1653,9 +1967,9 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -2016,6 +2330,15 @@ "node": ">=0.10.0" } }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -2221,6 +2544,12 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -2897,8 +3226,7 @@ "node_modules/regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", - "dev": true + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/require-directory": { "version": "2.1.1", @@ -2941,18 +3269,37 @@ } }, "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.1.tgz", + "integrity": "sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==", "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=14.18.0", + "node": ">=18.0.0", "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.18.1", + "@rollup/rollup-android-arm64": "4.18.1", + "@rollup/rollup-darwin-arm64": "4.18.1", + "@rollup/rollup-darwin-x64": "4.18.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.1", + "@rollup/rollup-linux-arm-musleabihf": "4.18.1", + "@rollup/rollup-linux-arm64-gnu": "4.18.1", + "@rollup/rollup-linux-arm64-musl": "4.18.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.1", + "@rollup/rollup-linux-riscv64-gnu": "4.18.1", + "@rollup/rollup-linux-s390x-gnu": "4.18.1", + "@rollup/rollup-linux-x64-gnu": "4.18.1", + "@rollup/rollup-linux-x64-musl": "4.18.1", + "@rollup/rollup-win32-arm64-msvc": "4.18.1", + "@rollup/rollup-win32-ia32-msvc": "4.18.1", + "@rollup/rollup-win32-x64-msvc": "4.18.1", "fsevents": "~2.3.2" } }, @@ -3420,10 +3767,9 @@ "dev": true }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/undici-types": { "version": "5.26.5", @@ -3494,29 +3840,29 @@ } }, "node_modules/vite": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", - "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.3.tgz", + "integrity": "sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==", "dev": true, "dependencies": { - "esbuild": "^0.18.10", - "postcss": "^8.4.27", - "rollup": "^3.27.1" + "esbuild": "^0.21.3", + "postcss": "^8.4.39", + "rollup": "^4.13.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "fsevents": "~2.3.2" + "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": ">= 14", + "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", @@ -3549,9 +3895,9 @@ } }, "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -3565,9 +3911,9 @@ } }, "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -3581,9 +3927,9 @@ } }, "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -3597,9 +3943,9 @@ } }, "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -3613,9 +3959,9 @@ } }, "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -3629,9 +3975,9 @@ } }, "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -3645,9 +3991,9 @@ } }, "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -3661,9 +4007,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -3677,9 +4023,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -3693,9 +4039,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -3709,9 +4055,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -3725,9 +4071,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -3741,9 +4087,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -3757,9 +4103,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -3773,9 +4119,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -3789,9 +4135,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -3805,9 +4151,9 @@ } }, "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -3821,9 +4167,9 @@ } }, "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -3837,9 +4183,9 @@ } }, "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -3853,9 +4199,9 @@ } }, "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -3869,9 +4215,9 @@ } }, "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -3885,9 +4231,9 @@ } }, "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -3901,9 +4247,9 @@ } }, "node_modules/vite/node_modules/esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "bin": { @@ -3913,28 +4259,43 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitefu": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "dev": true, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } } }, "node_modules/web-streams-polyfill": { @@ -3969,6 +4330,37 @@ "node": ">= 8" } }, + "node_modules/worker-timers": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.2.tgz", + "integrity": "sha512-Xna4rPTforH+a3/Kyukf9diO8MDdKY/nuDU77Ptx3SPi+2V/QfWGdwGUxVOk4oFyCnRoe71ZjH6axjyVWO5Nqw==", + "dependencies": { + "@babel/runtime": "^7.24.8", + "tslib": "^2.6.3", + "worker-timers-broker": "^7.0.3", + "worker-timers-worker": "^8.0.2" + } + }, + "node_modules/worker-timers-broker": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-7.0.3.tgz", + "integrity": "sha512-LG/xWCCOg6UwRnmAzy05wCvn3jIO60AcpT/CgG3TmaYK93+biainiivSVHGK6VEBeJzETrFAKZ9JgW8gkae+Ag==", + "dependencies": { + "@babel/runtime": "^7.24.8", + "fast-unique-numbers": "^9.0.7", + "tslib": "^2.6.3", + "worker-timers-worker": "^8.0.2" + } + }, + "node_modules/worker-timers-worker": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-8.0.2.tgz", + "integrity": "sha512-Bx8grqm3TyHLorTMBbtoL+fAMwTBgx+c4IiE23fCNinlUpqTISEa9UXR6GAjgHAB2GlZjNLgisLjx9a6CKFV3Q==", + "dependencies": { + "@babel/runtime": "^7.24.8", + "tslib": "^2.6.3" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -4305,10 +4697,9 @@ } }, "@babel/runtime": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", - "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", - "dev": true, + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", "requires": { "regenerator-runtime": "^0.14.0" } @@ -4323,6 +4714,13 @@ "shallowequal": "^1.1.0" } }, + "@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "dev": true, + "optional": true + }, "@esbuild/android-arm": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", @@ -4551,6 +4949,151 @@ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "optional": true }, + "@rollup/rollup-android-arm-eabi": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.1.tgz", + "integrity": "sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-android-arm64": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.1.tgz", + "integrity": "sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-arm64": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.1.tgz", + "integrity": "sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-x64": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.1.tgz", + "integrity": "sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.1.tgz", + "integrity": "sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-musleabihf": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.1.tgz", + "integrity": "sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.1.tgz", + "integrity": "sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-musl": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.1.tgz", + "integrity": "sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.1.tgz", + "integrity": "sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-riscv64-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.1.tgz", + "integrity": "sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-s390x-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.1.tgz", + "integrity": "sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.1.tgz", + "integrity": "sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-musl": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.1.tgz", + "integrity": "sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-arm64-msvc": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.1.tgz", + "integrity": "sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-ia32-msvc": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.1.tgz", + "integrity": "sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-x64-msvc": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.1.tgz", + "integrity": "sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==", + "dev": true, + "optional": true + }, + "@sveltejs/vite-plugin-svelte": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.1.tgz", + "integrity": "sha512-rimpFEAboBBHIlzISibg94iP09k/KYdHgVhJlcsTfn7KMBhc70jFX/GRWkRdFCc2fdnk+4+Bdfej23cMDnJS6A==", + "dev": true, + "requires": { + "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", + "debug": "^4.3.4", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.10", + "svelte-hmr": "^0.16.0", + "vitefu": "^0.2.5" + }, + "dependencies": { + "svelte-hmr": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", + "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", + "dev": true, + "requires": {} + } + } + }, + "@sveltejs/vite-plugin-svelte-inspector": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz", + "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, "@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -5064,6 +5607,15 @@ "@babel/runtime": "^7.21.0" } }, + "debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, "decamelize": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", @@ -5090,6 +5642,12 @@ } } }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true + }, "dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -5244,6 +5802,15 @@ } } }, + "fast-unique-numbers": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-9.0.7.tgz", + "integrity": "sha512-K6hYNu8ZsVb7mwmd9OKxHmw4aLa+IFiBxt1e/FZVFFta94ZgNAHqIgUtDzd7AJaVoo/CoNTgr6sj1Dbj3PQPKg==", + "requires": { + "@babel/runtime": "^7.24.8", + "tslib": "^2.6.3" + } + }, "fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -5327,9 +5894,9 @@ "dev": true }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "optional": true }, @@ -5590,6 +6157,12 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, + "kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true + }, "lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -5739,6 +6312,12 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz", "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==" }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -6161,8 +6740,7 @@ "regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", - "dev": true + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "require-directory": { "version": "2.1.1", @@ -6189,11 +6767,28 @@ } }, "rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.1.tgz", + "integrity": "sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==", "dev": true, "requires": { + "@rollup/rollup-android-arm-eabi": "4.18.1", + "@rollup/rollup-android-arm64": "4.18.1", + "@rollup/rollup-darwin-arm64": "4.18.1", + "@rollup/rollup-darwin-x64": "4.18.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.1", + "@rollup/rollup-linux-arm-musleabihf": "4.18.1", + "@rollup/rollup-linux-arm64-gnu": "4.18.1", + "@rollup/rollup-linux-arm64-musl": "4.18.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.1", + "@rollup/rollup-linux-riscv64-gnu": "4.18.1", + "@rollup/rollup-linux-s390x-gnu": "4.18.1", + "@rollup/rollup-linux-x64-gnu": "4.18.1", + "@rollup/rollup-linux-x64-musl": "4.18.1", + "@rollup/rollup-win32-arm64-msvc": "4.18.1", + "@rollup/rollup-win32-ia32-msvc": "4.18.1", + "@rollup/rollup-win32-x64-msvc": "4.18.1", + "@types/estree": "1.0.5", "fsevents": "~2.3.2" } }, @@ -6537,10 +7132,9 @@ "dev": true }, "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "undici-types": { "version": "5.26.5", @@ -6586,203 +7180,211 @@ } }, "vite": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", - "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.3.tgz", + "integrity": "sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==", "dev": true, "requires": { - "esbuild": "^0.18.10", - "fsevents": "~2.3.2", - "postcss": "^8.4.27", - "rollup": "^3.27.1" + "esbuild": "^0.21.3", + "fsevents": "~2.3.3", + "postcss": "^8.4.39", + "rollup": "^4.13.0" }, "dependencies": { "@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "dev": true, "optional": true }, "@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "dev": true, "optional": true }, "@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "dev": true, "optional": true }, "@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "dev": true, "optional": true }, "@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "dev": true, "optional": true }, "@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "dev": true, "optional": true }, "@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "dev": true, "optional": true }, "@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "dev": true, "optional": true }, "@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "dev": true, "optional": true }, "@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "dev": true, "optional": true }, "@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "dev": true, "optional": true }, "@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "dev": true, "optional": true }, "@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "dev": true, "optional": true }, "@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "dev": true, "optional": true }, "@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "dev": true, "optional": true }, "@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "dev": true, "optional": true }, "@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "dev": true, "optional": true }, "@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "dev": true, "optional": true }, "@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "dev": true, "optional": true }, "@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "dev": true, "optional": true }, "@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "dev": true, "optional": true }, "@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "dev": true, "optional": true }, "esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "requires": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } } } }, + "vitefu": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "dev": true, + "requires": {} + }, "web-streams-polyfill": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", @@ -6803,6 +7405,37 @@ "isexe": "^2.0.0" } }, + "worker-timers": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.2.tgz", + "integrity": "sha512-Xna4rPTforH+a3/Kyukf9diO8MDdKY/nuDU77Ptx3SPi+2V/QfWGdwGUxVOk4oFyCnRoe71ZjH6axjyVWO5Nqw==", + "requires": { + "@babel/runtime": "^7.24.8", + "tslib": "^2.6.3", + "worker-timers-broker": "^7.0.3", + "worker-timers-worker": "^8.0.2" + } + }, + "worker-timers-broker": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-7.0.3.tgz", + "integrity": "sha512-LG/xWCCOg6UwRnmAzy05wCvn3jIO60AcpT/CgG3TmaYK93+biainiivSVHGK6VEBeJzETrFAKZ9JgW8gkae+Ag==", + "requires": { + "@babel/runtime": "^7.24.8", + "fast-unique-numbers": "^9.0.7", + "tslib": "^2.6.3", + "worker-timers-worker": "^8.0.2" + } + }, + "worker-timers-worker": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-8.0.2.tgz", + "integrity": "sha512-Bx8grqm3TyHLorTMBbtoL+fAMwTBgx+c4IiE23fCNinlUpqTISEa9UXR6GAjgHAB2GlZjNLgisLjx9a6CKFV3Q==", + "requires": { + "@babel/runtime": "^7.24.8", + "tslib": "^2.6.3" + } + }, "wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", diff --git a/package.json b/package.json index e484d28..7883378 100644 --- a/package.json +++ b/package.json @@ -24,16 +24,17 @@ "invariant": "^2.2.4", "resize-observer-polyfill": "^1.5.1", "rimraf": "^5.0.0", + "worker-timers": "^8.0.2", "zustand": "^4.3.8" }, "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.1.1", "autoprefixer": "^10.4.14", "concurrently": "^8.2.2", "postcss": "^8.4.24", "svelte": "^5.0.0-next.184", "tailwindcss": "^3.3.2", - "vite": "^4.3.9", - "zx": "^7.2.3", - "vite-plugin-svelte": "^4.0.0-next.4" + "vite": "^5.0.0", + "zx": "^7.2.3" } } diff --git a/src/App.svelte b/src/App.svelte new file mode 100644 index 0000000..35d5fa4 --- /dev/null +++ b/src/App.svelte @@ -0,0 +1,47 @@ + + + + + + + + + +{#if cablesLoaded } + { timers[2].start( ()=> timedOut = true ) } + {#if !timedOut} +
    NEL SRVB
    + {/if} +{:else} +
    Loading...
    +{/if} + + \ No newline at end of file diff --git a/src/cables-js/loader.svelte.js b/src/cables-js/loader.svelte.js new file mode 100644 index 0000000..2672ebc --- /dev/null +++ b/src/cables-js/loader.svelte.js @@ -0,0 +1,18 @@ + + +document.addEventListener("CABLES.jsLoaded", function () { + // Now CABLES is defined, proceed with initialization + CABLES.patch = new CABLES.Patch({ + patch: CABLES.exportedPatch, + prefixAssetPath: "", + assetPath: "assets/", + jsPath: "js/", + glCanvasId: "glcanvas", + glCanvasResizeToWindow: true, + onError: (e)=> console.error(e) , + onPatchLoaded: ()=> console.log("Patch loaded") , + onFinishedLoading: ()=> console.log("Cables done loading"), + canvas: { alpha: true, premultipliedAlpha: true }, // make canvas transparent + }); + }); + diff --git a/src/cables-ui.js b/src/cables-ui.js index babea7b..4c7bbc9 100644 --- a/src/cables-ui.js +++ b/src/cables-ui.js @@ -1,4 +1,4 @@ -console.log( 'cables-ui loading' ); +// console.log( 'cables-ui loading' ); // const myVar = globalThis.CABLES.patch.getVar("ui_dialValues"); diff --git a/src/main.svelte b/src/main.svelte deleted file mode 100644 index e69de29..0000000 diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..b0a33cf --- /dev/null +++ b/src/main.ts @@ -0,0 +1,7 @@ + +import { mount } from 'svelte'; +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById("app") }); + +export default app; diff --git a/src/stores/NativeMessage.ts b/src/stores/NativeMessage.ts new file mode 100644 index 0000000..baa80c1 --- /dev/null +++ b/src/stores/NativeMessage.ts @@ -0,0 +1,250 @@ +export declare var globalThis: any; + +import { get } from "svelte/store"; +import type { + NEL_Preset, + MessagesToHost, +} from "../../types"; + +import { getValueFromEntries } from "../utils/utils"; +import { + HostState, + LicenseStatus, + HostInfo, + LICENSE_VALIDATED, +} from "./stores"; + + +/** ━━━━━━━ generated doc ━━━━━━━ + * `processHostState` is a function that processes and denormalizes parameter values sent from the host. + * It receives these values via the `__receiveStateChange__` global function. + * @param state - The state object received from the host. + * + * `MessageToHost` is an object that contains callable functions for interfacing with the Host code. + * + * `stashMeshState` is a function that manually gets the current state key of each storage slot and serializes it for persistentState storage in the host plugin. + * + * `requestParamValueUpdate` is a function that updates parameter values in the host. + * @param paramId - The ID of the parameter to update. + * @param value - The new value of the parameter. + * + * `requestReady` is a function that sends a ready message to the host. + * + * `requestUnlock` is a function that sends an unlock message to the KeyZey handler. + * @param serial - The serial number for unlocking. + * + * `__setMeshStateInHost` is a function that stores any persistent UI state in the host. + * @param dataToPersist - The data to persist in the host. + * + * `__bindHotReload` is a function that hot reloads the DSP during development. + * + * `RegisterMessagesFromHost` is a function that registers the message handlers for receiving and processing messages from the host. + * It sets up global functions that handle state changes, mesh state changes, license activation, error handling, and host information. + */ + + +/** ━━━━━━━ + * Main method for processing and denormalizing parameter values sent from the host + * received via the `__receiveStateChange__` global function. + * @param state - The state object received from the host. + */ + +function processHostState(state: any) { + // ━━━━━━━ + // Parse the state object and convert it to an array of key-value pairs + let parsedEntries: Array<[string, any]> = []; + try { + parsedEntries = Object.entries(JSON.parse(state)); + } catch (e) { + console.warn("Bad state received", parsedEntries); + } + const processedEntries: Map = new Map(parsedEntries); + // ━━━━━━━ + // denormalize the full range type, shift, and climb parameters + processedEntries.set( + "type", + getValueFromEntries(processedEntries, "type") * 2 - 1 + ); + processedEntries.set( + "shift", + getValueFromEntries(processedEntries, "shift") * 2 - 1 + ); + processedEntries.set( + "climb", + getValueFromEntries(processedEntries, "climb") * 2 - 1 + ); + + /** ━━━━━━━ + * Finally, assign the processed entries as Map ) + * to the HostState store which triggers observer / subscribers + * across the View code updating parameter values. + **/ + HostState.set(new Map(processedEntries)); +} + +/** ━━━━━━━ + * Callable functions for interfacing with the Host code. + **/ +export const MessageToHost: MessagesToHost = { + /** ━━━━━━━ + * Manually get the current state key of each storage slot and serialize for + * persistentState storage in the host plugin. We need to stash and retrieve the view state + * as the WebView is destroyed when the user closes the plugin window. + * The solution must also work for preset store/recall originating from DAW Host. + **/ + stashMeshState: function () { + let dataToPersist = { + nodeStates: get(UI_NodesData).map((data) => get(data.state) as string), + presets: get(UI_NodesData).map((data) => { + if (!data.preset) return {} as NEL_Preset; + let parameters = Array.from(data.preset.parameters.entries()); + return { ...data.preset, parameters } as unknown as NEL_Preset; + }), + license: get(LicenseStatus), + viewOptions: get(ViewOptions), + }; + this.__setMeshStateInHost(dataToPersist); + }, + + /** ━━━━━━━ + * Update parameter values in the host. + * @param paramId - The ID of the parameter to update. + * @param value - The new value of the parameter. + */ + requestParamValueUpdate: function (paramId: string, value: number) { + if (typeof globalThis.__postNativeMessage__ === "function") { + if (paramId === "type" || paramId === "shift" || paramId === "climb") { + value = (value + 1) / 2; + } + globalThis.__postNativeMessage__("setParameterValue", { + paramId, + value, + }); + } + }, + + /** ━━━━━━━ + * Send a ready message to the host. + */ + requestReady: function () { + if (typeof globalThis.__postNativeMessage__ === "function") { + globalThis.__postNativeMessage__("ready", {}); + } + }, + + /** ━━━━━━━ + * Send an unlock message to the KeyZey handler. + * @param serial - The serial number for unlocking. + */ + requestUnlock: function (serial: string = "") { + if (get(LicenseStatus) !== LICENSE_VALIDATED) { + console.count("Requesting unlock"); + if (typeof globalThis.__postNativeMessage__ === "function") { + globalThis.__postNativeMessage__("unlock", { serial }); + } + } + }, + + /** ━━━━━━━ + * Store any persistent UI state in the host. + * @param dataToPersist - The data to persist in the host. + */ + __setMeshStateInHost: function (dataToPersist: any) { + if (typeof globalThis.__postNativeMessage__ === "function") { + globalThis.__postNativeMessage__( + "setMeshState", + JSON.stringify(dataToPersist) + ); + } + }, + + /** ━━━━━━━ + * Hot reload the DSP during development. + */ + __bindHotReload: function () { + if (process.env.NODE_ENV !== "production") { + import.meta.hot?.on("reload-dsp", () => { + // console.log("Sending reload dsp message"); + + if (typeof globalThis.__postNativeMessage__ === "function") { + globalThis.__postNativeMessage__("reload"); + } + }); + } + }, +}; + +/** ━━━━━━━ + * Registers the message handlers for receiving and processing messages from the host. + * This function sets up global functions that handle state changes, mesh state changes, + * license activation, error handling, and host information. + */ + +export function RegisterMessagesFromHost() { + /** ━━━━━━━ + * Handles the state change received from the host. + * @param state - The host state change object. + */ + globalThis.__receiveStateChange__ = function (state: any) { + processHostState(state); + }; + + /** ━━━━━━━ + * Handles the mesh state change received from the host. + * @param meshState - The mesh state object. + */ + globalThis.__receiveMeshStateChange__ = function (meshState: any) { + let incomingMeshState: IncomingMeshState; + try { + incomingMeshState = JSON.parse(JSON.parse(meshState).meshState); + } catch (e) { + // console.log("Invalid mesh state (rcv)", meshState, e); + LicenseStatus.set("Mesh state error. Contact support."); + return; + } + if (typeof incomingMeshState !== "object") return; + + if (!incomingMeshState.license) { + MessageToHost.requestUnlock(); + } else { + LicenseStatus.set(incomingMeshState.license); + MessageToHost.stashMeshState(); + } + + if (incomingMeshState.nodeStates && incomingMeshState.presets) { + MeshStateIncoming.set(incomingMeshState); + } + + UI_needsUpdate.set(true); + }; + + /** ━━━━━━━ + * Handles the unlock status received from the host. + * @param status - The unlock status string. + */ + globalThis.__onUnlock__ = function (status: string | undefined) { + LicenseStatus.set(status || "License not valid"); + if (status === LICENSE_VALIDATED) { + globalThis.__postNativeMessage__("ready", {}); + MessageToHost.stashMeshState(); + } + }; + + /** ━━━━━━━ + * Handles the DAW name received from the host. + * @param message - The host information object. + */ + globalThis.__hostInfo__ = function (message: string) { + HostInfo.set(message); + // console.log("Host Info: ", message); + }; + + /** ━━━━━━━ + * DEV: Handles an error received from the host. + * @param error - The error object. + */ + globalThis.__receiveError__ = function (error: any) { + ConsoleText.set("Error: " + error); + }; +} + \ No newline at end of file diff --git a/src/stores/WWTimer.ts b/src/stores/WWTimer.ts new file mode 100644 index 0000000..5a83115 --- /dev/null +++ b/src/stores/WWTimer.ts @@ -0,0 +1,55 @@ +import { setInterval, setTimeout, clearTimeout } from 'worker-timers' + +// ui related +export class WWTimer { + // Existing members + private startTime: number | null = null; + private timeoutId: number | any; + private duration: number; + public isRunning: boolean = false; + // New member to track if the timer is running + + + constructor(duration: number) { + this.duration = duration; + } + + // Starts the timer + start(callback: () => void): void { + if (this.isRunning) { // Check if the timer is already running + return; + } + this.isRunning = true; // Update isRunning state + this.startTime = Date.now(); + this.timeoutId = setTimeout(() => { + callback(); + this.reset(); + }, this.duration); + } + + // Resets the timer + reset(): void { + if (this.timeoutId !== null) { + clearTimeout(this.timeoutId); + this.timeoutId = null; + } + this.startTime = null; + this.isRunning = false; // Update isRunning state + } + + // Sets a new duration for the timer + setDuration(newDuration: number): void { + this.duration = newDuration; + // If the timer is running, restart it with the new duration + if (this.isRunning) { // Use isRunning to check if the timer is active + this.reset(); + this.start(() => { + console.log("Timer finished after duration update"); + }); + } + } + + get stopped(): boolean { + return !this.isRunning; + } + } \ No newline at end of file diff --git a/src/stores/stores.ts b/src/stores/stores.ts new file mode 100644 index 0000000..d133f9e --- /dev/null +++ b/src/stores/stores.ts @@ -0,0 +1,104 @@ +//@ts-nocheck +/** typescript disabled for now */ + +//#region IMPORTS +import type { + LocalManifest, + HostParameter, + NEL_ControlsMap, + NEL_NodeUserData, +} from "../types/index"; + + +//#endregion + + +//#region CONSTANTS +export const UNCHECKED_LICENSE_STATUS = "Checking"; +export const LICENSE_VALIDATED = "Valid"; + // UI MANIFEST + // 📍 Extended version of public/manifest.json --- keep them in sync! +export const manifest: LocalManifest = { + window: { width: 575, height: 930 }, + parameters: [ + { paramId: "blend", name: "Blend", min: 0.0, max: 1.0, defaultValue: 0.0, group: "shifter" }, + { paramId: "shift", name: "Shift", min: -1.0, max: 1.0, defaultValue: 0.0, group: "shifter" }, + { paramId: "type", name: "Type", min: -1.0, max: 1.0, defaultValue: -1.0, group: "shifter" }, + { paramId: "climb", name: "Climb", min: -1.0, max: 1.0, defaultValue: -1.0, group: "feedback" }, + { paramId: "ladder", name: "Ladder", min: 0.0, max: 1.0, defaultValue: 0.0, group: "feedback" }, + { paramId: "stride", name: "Stride", min: 0.0, max: 1.0, defaultValue: 0.25, group: "feedback" }, + { paramId: "gain", name: "Gain", min: 0.0, max: 1.0, defaultValue: 0.25, group: "feedback" }, + { paramId: "size", name: "Size", min: 0.0, max: 1.0, defaultValue: 0.125, group: "reverb" }, + { paramId: "decay", name: "Decay", min: 0.0, max: 1.0, defaultValue: 0.15, group: "reverb" }, + { paramId: "mod", name: "Mod", min: 0.0, max: 1.0, defaultValue: 0.125, group: "reverb" }, + { paramId: "mix", name: "Mix", min: 0.0, max: 1.0, defaultValue: 0.25, group: "reverb" }, + ] +}; +export const NUMBER_HOSTPARAMS = manifest.parameters.length; +//#endregion + + + +//#region LICENSE ACTIVATION + +export const LicenseStatus: string = $state(UNCHECKED_LICENSE_STATUS); + +//#endregion + + +//#region AUDIO PARAMS +//---- registered audio parameters ------------------- +export const ParamDefsHost: HostParameter[] = $state( manifest.parameters); +// registered audio parameters for UI +export const ParamIds: string[] = $state(manifest.parameters.map((p: HostParameter) => p.paramId)); + +//#endregion + +//#region UI STATE MACHINES, CONTROLS + + +// we only need to store the user data, not the whole mesh +export const UI_NodesData: NEL_NodeUserData[] = $state([]); +export const focusedNodeParams: NEL_ControlsMap = $state(new Map()); + + +// Explicit refresh of the stored presets +export const UI_StoredPresetsRefresh: boolean = $state(false); +export const UI_needsUpdate: boolean = $state(true); +export const UI_asyncReady: boolean = $state(false); +// Sidebar controls +export const UI_Controls: NEL_ControlsMap = $state(new Map()); + +//#endregion + +//#region RAYCASTER & PICKING + +// Global export of current RayCast target +export const CurrentPickedId: number = $state(0); +export const CurrentFocusId: number = $state(0); +export const ActiveId: number = $state(0); +export const MouseDownWindow: boolean = $state(false); + +//#endregion + +//#region USER INTERACTION + +export const ConsoleText: string = $state("Console:"); +export const ShiftPressed: boolean = $state(false); +export const BillboardText: string = $state(""); + +//#endregion + +//#region HOST STATE +export const MeshStateIncoming: any = $state(); +export const HostState: Map = $state( new Map()); +export const ErrorStore: any = $state(); + +//#endregion + +//#region MISC + +export const PixelDensity: number = $state(2); +export const HostInfo: string = $state(''); + +//#endregion \ No newline at end of file diff --git a/src/types/index.d.ts b/src/types/index.d.ts new file mode 100644 index 0000000..65b3dba --- /dev/null +++ b/src/types/index.d.ts @@ -0,0 +1 @@ +// todo diff --git a/src/utils/utils.ts b/src/utils/utils.ts new file mode 100644 index 0000000..7f034b1 --- /dev/null +++ b/src/utils/utils.ts @@ -0,0 +1,167 @@ +import type { Vec } from "@thi.ng/vectors"; +import type { UI_Slider, NEL_ControlsMap, NEL_Preset } from "../../types"; +import type { InstancedMesh, Object3D } from "three"; + + +// This function extracts the 'value' property from each UI_Slider +// object in the UI_ControlsMap and returns them as an array of type Vec. +export function extractValuesFrom(view: NEL_ControlsMap): Vec { + return Array.from(view.values()).map((slider) => slider.value) as Vec; +} + + // Helper function to get the value from the tuple that results from deserializing the host state object + export function getValueFromEntries(entries: any, key: string): number { + let result = 0; + try { + result = entries.find(([k]: [string]) => k === key)[1]; + } catch { (e:any) => + console.warn("Error setting state entries on key ", key, e.message); + } + return result; +} + +// filter out params that are not registered with the host +export function onlyRegisteredParams( + view: NEL_ControlsMap +): Map { + let onlyRegisteredParams = new Map( + [...view].filter(([key, value]) => value.isRegistered) + ); + return onlyRegisteredParams; +} + +// Convert an array of UI_ControlsMap to +// serializable structure (array of objects) +export function serialisePresets(arrayOfPresets: Array) { + if (!arrayOfPresets) return {}; + let parametersMap: Map + const result = arrayOfPresets.map((preset) => { + if (preset === undefined) return {}; + parametersMap = preset.parameters; + let obj: { [key: string]: UI_Slider } = {}; + preset.parameters.forEach((settings, key, map) => { + obj[key] = settings; + }); + return obj; + }); + return result; +} + +// Convert an array of objects to an array of UI_ControlsMap (Map) +export function deserialisePresets( + arrayOfObjects: { [key: string]: UI_Slider }[] +) { + const result = arrayOfObjects.map((presetObj) => { + let presetMap = new Map(); + for (let key in presetObj) { + presetMap.set(key, presetObj[key]); + } + return presetMap; + }); + return result; +} + +// sample and hold function +export function sampleAndHold(value: number, hold: boolean) { + let heldValue: number = 0; + return function () { + if (hold) { + heldValue = value; + } + return heldValue; + }; +} + +// utility functions for generating the grid array and an iterator for it +export const fillArrayUsing = ( + arr: any[], + start: number, + end: number, + step: number, + value: number +) => { + for (let i = start; i <= end; i += step) { + arr.push(value); + } + return arr; +}; + +export const arrayIterator = (arr: any[]) => arr.values(); + +// utility functions for BufferGeometry transformations +export function scaleXYZ(vertices: Float32Array, scale: number) { + const resizedVertices = vertices.map((v) => v * scale); + return resizedVertices; +} + +export function scaleWidth(vertices: Float32Array, scale: number) { + const resizedVertices = new Float32Array(vertices.length); + for (let i = 0; i < vertices.length; i += 3) { + resizedVertices[i] = vertices[i] * scale; + resizedVertices[i + 1] = vertices[i + 1]; + resizedVertices[i + 2] = vertices[i + 2]; + } + return resizedVertices; +} + +export function scaleHeight(vertices: Float32Array, scale: number) { + const resizedVertices = new Float32Array(vertices.length); + for (let i = 0; i < vertices.length; i += 3) { + resizedVertices[i] = vertices[i]; + resizedVertices[i + 1] = vertices[i + 1] * scale; + resizedVertices[i + 2] = vertices[i + 2]; + } + return resizedVertices; +} + +export function offsetXY( + vertices: Float32Array, + offsetX: number, + offsetY: number +) { + const offsetVertices = new Float32Array(vertices.length); + + for (let i = 0; i < vertices.length; i += 3) { + offsetVertices[i] = vertices[i] + offsetX; + offsetVertices[i + 1] = vertices[i + 1] + offsetY; + offsetVertices[i + 2] = vertices[i + 2]; + } + return offsetVertices; +} + +export function retrieveNodeFromInstancedMesh (o: any | null, instanceId: number) : Object3D | null { + if (o) { + const parentMesh: InstancedMesh = o; + const node: Object3D = parentMesh.instances.current[instanceId]; + return node; + } + return null; +} + +class ShiftRegister { + currentState: T | null; + previousState: T | null; + + constructor(initialState: T | null) { + this.currentState = initialState; + this.previousState = null; + } + + updateState(newState: T) { + this.previousState = this.currentState; + this.currentState = newState; + } + + isStateChanged() { + return this.currentState !== this.previousState; + } + + fastCompare(): boolean { + if (this.currentState === null || this.previousState === null) { return true; } + return JSON.stringify(this.currentState) !== JSON.stringify(this.previousState); + } +} + +export function shiftRegister(initialState: T | null) { + return new ShiftRegister(initialState); +} \ No newline at end of file From 8261d81d9b7cd221a6962bbbdc0d842514d17dfe Mon Sep 17 00:00:00 2001 From: Cristian Vogel Date: Tue, 16 Jul 2024 12:11:06 +0200 Subject: [PATCH 13/13] First commit --- .gitmodules | 1 + native/CMakeLists.txt | 4 +- native/PluginProcessor.cpp | 562 ++++++++++++++++++++++++------------- native/PluginProcessor.h | 269 ++++++++++++++++-- native/WebViewEditor.cpp | 152 +++++----- native/WebViewEditor.h | 32 ++- 6 files changed, 731 insertions(+), 289 deletions(-) diff --git a/.gitmodules b/.gitmodules index 27490bf..bd547be 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,4 @@ [submodule "choc"] path = native/choc url = https://github.com/cristianvogel/choc + branch = cristians-edits diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index 3862d5c..d1bf4a4 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -21,11 +21,11 @@ if (WIN32) endif() juce_add_plugin(${TARGET_NAME} - BUNDLE_ID "audio.neverenginelabs.NELShifterMesh" + BUNDLE_ID "audio.neverenginelabs.NEL_SRVB" COMPANY_NAME "NeverEngineLabs" COMPANY_WEBSITE "https://neverenginelabs.com" COMPANY_EMAIL "support@neverenginelabs.com" - PLUGIN_MANUFACTURER_CODE NVLB # A four-character manufacturer id with at least one upper-case character + PLUGIN_MANUFACTURER_CODE NLVB # A four-character manufacturer id with at least one upper-case character PLUGIN_CODE ShRv # A unique four-character plugin id with at least one upper-case character COPY_PLUGIN_AFTER_BUILD FALSE # We enable this manually below after adding a copy step APP_SANDBOX_ENABLED TRUE diff --git a/native/PluginProcessor.cpp b/native/PluginProcessor.cpp index 2b7ab85..2de7224 100644 --- a/native/PluginProcessor.cpp +++ b/native/PluginProcessor.cpp @@ -3,19 +3,18 @@ #include - //============================================================================== // A quick helper for locating bundled asset files juce::File getAssetsDirectory() { #if JUCE_MAC auto assetsDir = juce::File::getSpecialLocation(juce::File::SpecialLocationType::currentApplicationFile) - .getChildFile("Contents/Resources/dist"); + .getChildFile("Contents/Resources/dist"); #elif JUCE_WINDOWS auto assetsDir = juce::File::getSpecialLocation(juce::File::SpecialLocationType::currentExecutableFile) // Plugin.vst3/Contents//Plugin.vst3 - .getParentDirectory() // Plugin.vst3/Contents// - .getParentDirectory() // Plugin.vst3/Contents/ - .getChildFile("Resources/dist"); + .getParentDirectory() // Plugin.vst3/Contents// + .getParentDirectory() // Plugin.vst3/Contents/ + .getChildFile("Resources/dist"); #else #error "We only support Mac and Windows here yet." #endif @@ -25,10 +24,11 @@ juce::File getAssetsDirectory() //============================================================================== EffectsPluginProcessor::EffectsPluginProcessor() - : AudioProcessor (BusesProperties() - .withInput ("Input", juce::AudioChannelSet::stereo(), true) - .withOutput ("Output", juce::AudioChannelSet::stereo(), true)) - , jsContext(choc::javascript::createQuickJSContext()) + : AudioProcessor(BusesProperties() + .withInput("Input", juce::AudioChannelSet::stereo(), true) + .withOutput("Output", juce::AudioChannelSet::stereo(), true)), + jsContext(choc::javascript::createQuickJSContext()), + jsContext2(choc::javascript::createQuickJSContext()) { // Initialize parameters from the manifest file #if ELEM_DEV_LOCALHOST @@ -43,55 +43,146 @@ EffectsPluginProcessor::EffectsPluginProcessor() auto manifestFileContents = manifestFile.loadFileAsString().toStdString(); #endif - auto manifest = elem::js::parseJSON(manifestFileContents); + const auto manifest = elem::js::parseJSON(manifestFileContents); if (!manifest.isObject()) return; - auto parameters = manifest.getWithDefault("parameters", elem::js::Array()); + const auto parameters = manifest.getWithDefault("parameters", elem::js::Array()); + createParameters(parameters); - for (size_t i = 0; i < parameters.size(); ++i) { - auto descrip = parameters[i]; + // The view state property has to have some value so that when state is loaded + // from the host, the key exists and is populated. + meshState.insert_or_assign(MESH_STATE_PROPERTY, "{}" ); +} - if (!descrip.isObject()) +EffectsPluginProcessor::~EffectsPluginProcessor() +{ + for (auto &p : getParameters()) + { + p->removeListener(this); + } +} + +//============================================================================== +void EffectsPluginProcessor::createParameters(const std::vector ¶meters) +{ + for (const auto ¶meter : parameters) + { + if (!parameter.isObject()) continue; - auto paramId = descrip.getWithDefault("paramId", elem::js::String("unknown")); - auto name = descrip.getWithDefault("name", elem::js::String("Unknown")); - auto minValue = descrip.getWithDefault("min", elem::js::Number(0)); - auto maxValue = descrip.getWithDefault("max", elem::js::Number(1)); - auto defValue = descrip.getWithDefault("defaultValue", elem::js::Number(0)); + auto paramId = parameter.getWithDefault("paramId", elem::js::String("unknown")); + auto name = parameter.getWithDefault("name", elem::js::String("Unknown")); + auto minValue = parameter.getWithDefault("min", elem::js::Number(0)); + auto maxValue = parameter.getWithDefault("max", elem::js::Number(1)); + auto defaultValue = parameter.getWithDefault("defaultValue", elem::js::Number(0)); + auto step = parameter.getWithDefault("step", elem::js::Number(0)); - auto* p = new juce::AudioParameterFloat( + auto *p = new juce::AudioParameterFloat( juce::ParameterID(paramId, 1), name, - {static_cast(minValue), static_cast(maxValue)}, - defValue - ); + {static_cast(minValue), static_cast(maxValue), static_cast(step)}, + static_cast(defaultValue)); + + // Keep a map from parameter ID to the juce audio parameter + // to avoid looping over the parameter list every time one changes + parameterMap.insert({paramId, p}); p->addListener(this); addParameter(p); // Push a new ParameterReadout onto the list to represent this parameter - paramReadouts.emplace_back(ParameterReadout { static_cast(defValue), false }); + parameterReadouts.emplace_back(ParameterReadout{static_cast(defaultValue), false}); // Update our state object with the default parameter value - state.insert_or_assign(paramId, defValue); + state.insert_or_assign(paramId, defaultValue); } } -EffectsPluginProcessor::~EffectsPluginProcessor() +juce::AudioProcessorEditor *EffectsPluginProcessor::createEditor() { - for (auto& p : getParameters()) + const auto editor = new WebViewEditor(this, getAssetsDirectory(), 905, 600); + + + // ----------- + // semi-online license activation + // ----------- + // From docs: + // You may need to use semi-online activation without giving a serial number. + // First two cases are: + // 1- You may choose to renew weekly the offline license of the users with Semi Online activation. + // You don't want to ask the serial number again and again. + // 2- You may set Offline License Life (recommended) to 30 days. After 30 days, the offline license + // will be INVALID. Then you will need to activate it again without a serial number. + editor->handleUnlockEvent = [this](choc::value::Value &v) { - p->removeListener(this); - } -} + const bool hasSerial = v.hasObjectMember("serial") && v["serial"].isString() && v["serial"].getString().length() > 0; + bool shouldActivate = licenseStatus != Keyzy::LicenseStatus::VALID; -//============================================================================== -juce::AudioProcessorEditor* EffectsPluginProcessor::createEditor() -{ - return new WebViewEditor(this, getAssetsDirectory(), 800, 704); + if (!hasSerial && shouldActivate) + { + licenseStatus = licenseActivator.activateSemiOnline(); + } + else if (hasSerial && shouldActivate && hasSerial) + { + const auto serial = v["serial"].getString(); + licenseStatus = licenseActivator.activateSemiOnline(serial.data()); + } + + sendJavascriptToUI("globalThis.__onUnlock__('" + unlock::errorStatuses(licenseStatus) + "')"); + // also send back the current host info + juce::PluginHostType hostType; + std::string hostDescription = static_cast(hostType.getHostDescription()); + sendJavascriptToUI("globalThis.__hostInfo__('" + hostDescription + "')"); + }; + + editor->ready = [this]() + { + // Flush the error log queue to the UI + while (!errorLogQueue.empty()) + { + auto sent = sendJavascriptToUI(errorLogQueue.front()); + errorLogQueue.pop(); + } + dispatchStateChange(); + dispatchMeshStateChange(); + }; + + + // When setting a parameter value, we simply tell the host. This will in turn fire + // a parameterValueChanged event, which will catch and propagate through dispatching + // a state change event + editor->setParameterValue = [this](const std::string ¶mId, float value) + { + if (parameterMap.count(paramId) > 0) + { + parameterMap[paramId]->setValueNotifyingHost(value); + } + }; + + editor->setMeshState = [this](choc::value::Value &v) + { + meshState.insert_or_assign(MESH_STATE_PROPERTY, v.toString()); + dispatchStateChange(); + // dispatchMeshStateChange(); <--- was causing feedback loop! + }; + + + + +#if ELEM_DEV_LOCALHOST + editor->reload = [this]() + { + initJavaScriptEngine(); + initSecondJavaScriptEngine(); + dispatchStateChange(); + dispatchMeshStateChange(); + }; + +#endif + + return editor; } bool EffectsPluginProcessor::hasEditor() const @@ -102,7 +193,7 @@ bool EffectsPluginProcessor::hasEditor() const //============================================================================== const juce::String EffectsPluginProcessor::getName() const { - return JucePlugin_Name; + return "NELShifterMesh"; } bool EffectsPluginProcessor::acceptsMidi() const @@ -122,14 +213,14 @@ bool EffectsPluginProcessor::isMidiEffect() const double EffectsPluginProcessor::getTailLengthSeconds() const { - return 0.0; + return 3.0; } //============================================================================== int EffectsPluginProcessor::getNumPrograms() { - return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs, - // so this should be at least 1, even if you're not really implementing programs. + return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs, + // so this should be at least 1, even if you're not really implementing programs. } int EffectsPluginProcessor::getCurrentProgram() @@ -137,12 +228,12 @@ int EffectsPluginProcessor::getCurrentProgram() return 0; } -void EffectsPluginProcessor::setCurrentProgram (int /* index */) {} -const juce::String EffectsPluginProcessor::getProgramName (int /* index */) { return {}; } -void EffectsPluginProcessor::changeProgramName (int /* index */, const juce::String& /* newName */) {} +void EffectsPluginProcessor::setCurrentProgram(int /* index */) {} +const juce::String EffectsPluginProcessor::getProgramName(int /* index */) { return {}; } +void EffectsPluginProcessor::changeProgramName(int /* index */, const juce::String & /* newName */) {} //============================================================================== -void EffectsPluginProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) +void EffectsPluginProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) { // Some hosts call `prepareToPlay` on the real-time thread, some call it on the main thread. // To address the discrepancy, we check whether anything has changed since our last known @@ -151,11 +242,12 @@ void EffectsPluginProcessor::prepareToPlay (double sampleRate, int samplesPerBlo // // JUCE will synchronously handle the async update if it understands // that we're already on the main thread. - if (sampleRate != lastKnownSampleRate || samplesPerBlock != lastKnownBlockSize) { + if (sampleRate != lastKnownSampleRate || samplesPerBlock != lastKnownBlockSize) + { lastKnownSampleRate = sampleRate; lastKnownBlockSize = samplesPerBlock; - shouldInitialize.store(true); + runtimeSwapRequired.store(true); } // Now that the environment is set up, push our current state @@ -168,42 +260,59 @@ void EffectsPluginProcessor::releaseResources() // spare memory, etc. } -bool EffectsPluginProcessor::isBusesLayoutSupported (const AudioProcessor::BusesLayout& layouts) const +bool EffectsPluginProcessor::isBusesLayoutSupported(const AudioProcessor::BusesLayout &layouts) const { return true; } -void EffectsPluginProcessor::processBlock (juce::AudioBuffer& buffer, juce::MidiBuffer& /* midiMessages */) +void EffectsPluginProcessor::processBlock(juce::AudioBuffer &buffer, juce::MidiBuffer & /* midiMessages */) { + + // If the license is invalid, we clear the buffer and return + if (licenseStatus != Keyzy::LicenseStatus::VALID) + { + buffer.clear(); + return; + } + // Copy the input so that our input and output buffers are distinct scratchBuffer.makeCopyOf(buffer, true); - // Clear the output buffer to prevent any garbage if our runtime isn't ready - buffer.clear(); - // Process the elementary runtime - if (runtime != nullptr) { + if (runtime != nullptr && !runtimeSwapRequired) + + { runtime->process( - const_cast(scratchBuffer.getArrayOfWritePointers()), + const_cast(scratchBuffer.getArrayOfWritePointers()), getTotalNumInputChannels(), - const_cast(buffer.getArrayOfWritePointers()), + const_cast(buffer.getArrayOfWritePointers()), buffer.getNumChannels(), buffer.getNumSamples(), - nullptr - ); + nullptr); + } + else + { + // Clear the output buffer to prevent any garbage if our runtime isn't ready + buffer.clear(); + } + + if (runtimeSwapRequired) + { + shouldInitialize.store(true); + triggerAsyncUpdate(); } } -void EffectsPluginProcessor::parameterValueChanged (int parameterIndex, float newValue) +void EffectsPluginProcessor::parameterValueChanged(int parameterIndex, float newValue) { // Mark the updated parameter value in the dirty list - auto& pr = *std::next(paramReadouts.begin(), parameterIndex); + auto &readout = *std::next(parameterReadouts.begin(), parameterIndex); - pr.store({ newValue, true }); + readout.store({newValue, true}); triggerAsyncUpdate(); } -void EffectsPluginProcessor::parameterGestureChanged (int, bool) +void EffectsPluginProcessor::parameterGestureChanged(int, bool) { // Not implemented } @@ -213,33 +322,35 @@ void EffectsPluginProcessor::handleAsyncUpdate() { // First things first, we check the flag to identify if we should initialize the Elementary // runtime and engine. - if (shouldInitialize.exchange(false)) { - // TODO: This is definitely not thread-safe! It could delete a Runtime instance while - // the real-time thread is using it. Depends on when the host will call prepareToPlay. + if (shouldInitialize.exchange(false)) + { runtime = std::make_unique>(lastKnownSampleRate, lastKnownBlockSize); initJavaScriptEngine(); + initSecondJavaScriptEngine(); + runtimeSwapRequired.store(false); } // Next we iterate over the current parameter values to update our local state // object, which we in turn dispatch into the JavaScript engine - auto& params = getParameters(); + auto ¶ms = getParameters(); // Reduce over the changed parameters to resolve our updated processor state - for (size_t i = 0; i < paramReadouts.size(); ++i) + for (size_t i = 0; i < parameterReadouts.size(); ++i) { // We atomically exchange an arbitrary value with a dirty flag false, because // we know that the next time we exchange, if the dirty flag is still false, the // value can be considered arbitrary. Only when we exchange and find the dirty flag // true do we consider the value as having been written by the processor since // we last looked. - auto& current = *std::next(paramReadouts.begin(), i); - auto pr = current.exchange({0.0f, false}); + auto ¤t = *std::next(parameterReadouts.begin(), i); + const auto pr = current.exchange({0.0f, false}); if (pr.dirty) { - if (auto* pf = dynamic_cast(params[i])) { + if (const auto *pf = dynamic_cast(params[i])) + { auto paramId = pf->paramID.toStdString(); - state.insert_or_assign(paramId, elem::js::Number(pr.value)); + state.insert_or_assign(paramId, static_cast(pr.value)); } } } @@ -252,183 +363,256 @@ void EffectsPluginProcessor::initJavaScriptEngine() jsContext = choc::javascript::createQuickJSContext(); // Install some native interop functions in our JavaScript environment - jsContext.registerFunction("__postNativeMessage__", [this](choc::javascript::ArgumentList args) { - auto const batch = elem::js::parseJSON(args[0]->toString()); - auto const rc = runtime->applyInstructions(batch); + jsContext.registerFunction(NATIVE_MESSAGE_FUNCTION_NAME, [this](choc::javascript::ArgumentList args) + { + const auto batch = elem::js::parseJSON(args[0]->toString()); + const auto rc = runtime->applyInstructions(batch); if (rc != elem::ReturnCode::Ok()) { dispatchError("Runtime Error", elem::ReturnCode::describe(rc)); } - return choc::value::Value(); - }); - - jsContext.registerFunction("__log__", [this](choc::javascript::ArgumentList args) { - const auto* kDispatchScript = R"script( -(function() { - console.log(...JSON.parse(%)); - return true; -})(); -)script"; - - // Forward logs to the editor if it's available; then logs show up in one place. - // - // If not available, we fall back to std out. - if (auto* editor = static_cast(getActiveEditor())) { - auto v = choc::value::createEmptyArray(); - - for (size_t i = 0; i < args.numArgs; ++i) { - v.addArrayElement(*args[i]); - } - - auto expr = juce::String(kDispatchScript).replace("%", elem::js::serialize(choc::json::toString(v))).toStdString(); - editor->getWebViewPtr()->evaluateJavascript(expr); - } else { - for (size_t i = 0; i < args.numArgs; ++i) { - DBG(choc::json::toString(*args[i])); - } - } - - return choc::value::Value(); - }); + return choc::value::Value(); }); // A simple shim to write various console operations to our native __log__ handler - jsContext.evaluate(R"shim( -(function() { - if (typeof globalThis.console === 'undefined') { - globalThis.console = { - log(...args) { - __log__('[embedded:log]', ...args); - }, - warn(...args) { - __log__('[embedded:warn]', ...args); - }, - error(...args) { - __log__('[embedded:error]', ...args); - } - }; - } -})(); - )shim"); + jsContext.evaluateExpression(jsFunctions::consoleLogScript); - // Load and evaluate our Elementary js main file -#if ELEM_DEV_LOCALHOST - auto dspEntryFile = juce::URL("http://localhost:5173/dsp.main.js"); - auto dspEntryFileContents = dspEntryFile.readEntireTextStream().toStdString(); -#else - auto dspEntryFile = getAssetsDirectory().getChildFile("dsp.main.js"); + const auto dspEntryFileContents = loadDspEntryFileContents(); - if (!dspEntryFile.existsAsFile()) + if (dspEntryFileContents.has_value()) + { + jsContext.evaluateExpression(dspEntryFileContents.value()); + } + else + { return; - - auto dspEntryFileContents = dspEntryFile.loadFileAsString().toStdString(); -#endif - jsContext.evaluate(dspEntryFileContents); + } // Re-hydrate from current state - const auto* kHydrateScript = R"script( -(function() { - if (typeof globalThis.__receiveHydrationData__ !== 'function') - return false; + const auto expr = serialize(jsFunctions::hydrateScript, runtime->snapshot()); + jsContext.evaluateExpression(expr); +} + +void EffectsPluginProcessor::initSecondJavaScriptEngine() +{ + jsContext2 = choc::javascript::createQuickJSContext(); + + // Install some native interop functions in our JavaScript environment + jsContext2.registerFunction(NATIVE_MESSAGE_FUNCTION_NAME, [this](choc::javascript::ArgumentList args) + { + const auto batch = elem::js::parseJSON(args[0]->toString()); + + // const auto rc = runtime->applyInstructions(batch); + // if (rc != elem::ReturnCode::Ok()) { + // dispatchError("Runtime Error", elem::ReturnCode::describe(rc)); + // } - globalThis.__receiveHydrationData__(%); - return true; -})(); -)script"; + return choc::value::Value(); }); - auto expr = juce::String(kHydrateScript).replace("%", elem::js::serialize(elem::js::serialize(runtime->snapshot()))).toStdString(); - jsContext.evaluate(expr); + + const auto patchEntryFileContents = loadPatchEntryFileContents(); + + if (patchEntryFileContents.has_value()) + { + jsContext2.evaluateExpression(patchEntryFileContents.value()); + } + else + { + return; + } + + } void EffectsPluginProcessor::dispatchStateChange() { - const auto* kDispatchScript = R"script( -(function() { - if (typeof globalThis.__receiveStateChange__ !== 'function') - return false; - - globalThis.__receiveStateChange__(%); - return true; -})(); -)script"; - // Need the double serialize here to correctly form the string script. The first // serialize produces the payload we want, the second serialize ensures we can replace // the % character in the above block and produce a valid javascript expression. auto localState = state; - localState.insert_or_assign("sampleRate", lastKnownSampleRate); - - auto expr = juce::String(kDispatchScript).replace("%", elem::js::serialize(elem::js::serialize(localState))).toStdString(); - + localState.insert_or_assign(SAMPLE_RATE_PROPERTY, lastKnownSampleRate); + const auto expr = serialize(jsFunctions::dispatchScript, localState); // First we try to dispatch to the UI if it's available, because running this step will // just involve placing a message in a queue. - if (auto* editor = static_cast(getActiveEditor())) { - editor->getWebViewPtr()->evaluateJavascript(expr); + sendJavascriptToUI(expr); + // Next we dispatch to the local engine which will evaluate any necessary JavaScript synchronously + // here on the main thread + try + { + jsContext.evaluateExpression(expr); + } + catch (std::exception &e) + { + dispatchError("DSP JS:", e.what()); } +} +void EffectsPluginProcessor::dispatchMeshStateChange() +{ + // Need the double serialize here to correctly form the string script. The first + // serialize produces the payload we want, the second serialize ensures we can replace + // the % character in the above block and produce a valid javascript expression. + auto localState = meshState; + const auto expr = serialize(jsFunctions::dispatchMeshStateScript, localState); + // First we try to dispatch to the UI if it's available, because running this step will + // just involve placing a message in a queue. + sendJavascriptToUI(expr); // Next we dispatch to the local engine which will evaluate any necessary JavaScript synchronously // here on the main thread - jsContext.evaluate(expr); + try + { + jsContext.evaluateExpression(expr); + } + catch (std::exception &e) + { + dispatchError("DSP JS:", e.what()); + } } -void EffectsPluginProcessor::dispatchError(std::string const& name, std::string const& message) +void EffectsPluginProcessor::dispatchError(std::string const &name, std::string const &message) { - const auto* kDispatchScript = R"script( -(function() { - if (typeof globalThis.__receiveError__ !== 'function') - return false; - - let e = new Error(%); - e.name = @; - - globalThis.__receiveError__(e); - return true; -})(); -)script"; - // Need the serialize here to correctly form the string script. - auto expr = juce::String(kDispatchScript).replace("@", elem::js::serialize(name)).replace("%", elem::js::serialize(message)).toStdString(); + const auto expr = juce::String(jsFunctions::errorScript).replace("@", elem::js::serialize(name)).replace("%", elem::js::serialize(message)).toStdString(); // First we try to dispatch to the UI if it's available, because running this step will // just involve placing a message in a queue. - if (auto* editor = static_cast(getActiveEditor())) { - editor->getWebViewPtr()->evaluateJavascript(expr); + if (!sendJavascriptToUI(expr)) + { + if (errorLogQueue.size() == MAX_ERROR_LOG_QUEUE_SIZE) + { + errorLogQueue.pop(); + } + errorLogQueue.push(expr); } // Next we dispatch to the local engine which will evaluate any necessary JavaScript synchronously // here on the main thread - jsContext.evaluate(expr); + jsContext.evaluateExpression(expr); +} + +std::optional EffectsPluginProcessor::loadDspEntryFileContents() const +{ + // Load and evaluate our Elementary js main file +#if ELEM_DEV_LOCALHOST + auto dspEntryFile = juce::URL("http://localhost:5173/dsp.main.js"); + auto dspEntryFileContents = dspEntryFile.readEntireTextStream().toStdString(); +#else + auto dspEntryFile = getAssetsDirectory().getChildFile(MAIN_DSP_JS_FILE); + + if (!dspEntryFile.existsAsFile()) + return std::nullopt; + + auto dspEntryFileContents = dspEntryFile.loadFileAsString().toStdString(); +#endif + + return dspEntryFileContents; +} + +std::optional EffectsPluginProcessor::loadPatchEntryFileContents() const +{ + // Load and evaluate our Elementary js main file +#if ELEM_DEV_LOCALHOST + auto patchEntryFile = juce::URL("http://localhost:5173/patch.main.js"); + auto patchEntryFileContents = patchEntryFile.readEntireTextStream().toStdString(); +#else + auto patchEntryFile = getAssetsDirectory().getChildFile(MAIN_PATCH_JS_FILE); + + if (!patchEntryFile.existsAsFile()) + return std::nullopt; + + auto patchEntryFileContents = patchEntryFile.loadFileAsString().toStdString(); +#endif + + return patchEntryFileContents; +} + + +bool EffectsPluginProcessor::sendJavascriptToUI(const std::string &expr) const +{ + if (const auto *editor = dynamic_cast(getActiveEditor())) + { + editor->executeJavascript(expr); + return true; + } + return false; +} + +std::string EffectsPluginProcessor::serialize(const std::string &function, const elem::js::Object &data, const juce::String &replacementChar) +{ + return juce::String(function).replace(replacementChar, elem::js::serialize(elem::js::serialize(data))).toStdString(); +} + +std::string EffectsPluginProcessor::serialize(const std::string &function, const choc::value::Value &data, const juce::String &replacementChar) +{ + return juce::String(function).replace(replacementChar, choc::json::toString(data)).toStdString(); } //============================================================================== -void EffectsPluginProcessor::getStateInformation (juce::MemoryBlock& destData) +void EffectsPluginProcessor::getStateInformation(juce::MemoryBlock &destData) { - auto serialized = elem::js::serialize(state); - destData.replaceAll((void *) serialized.c_str(), serialized.size()); + + // serialise the secondary store for meshData + // then insert it into the data to be stored by the host + state.insert_or_assign(MESH_STATE_PROPERTY, meshState.at(MESH_STATE_PROPERTY)); + // seriliase the whole package + const auto serializedState = elem::js::serialize(state); + // stash + destData.replaceAll((void *)serializedState.c_str(), serializedState.size()); + // remove the meshData from the active param state updates + // so the meshData doesn't get sent on every update + state.erase(MESH_STATE_PROPERTY); } -void EffectsPluginProcessor::setStateInformation (const void* data, int sizeInBytes) +void EffectsPluginProcessor::setStateInformation(const void *data, int sizeInBytes) { - try { - auto str = std::string(static_cast(data), sizeInBytes); - auto parsed = elem::js::parseJSON(str); + auto parsed = elem::js::parseJSON("{}"); + // restore the data the host stashed previously + const auto jsonString = std::string(static_cast(data), sizeInBytes); + // try to deserialise the whole stashed data string + try + { + parsed = elem::js::parseJSON(jsonString); + } + catch (...) + { + dispatchError("Stored data error:", parsed.toString()); + } + + // try to re-assign the local stores from the stashed data + try + { auto o = parsed.getObject(); - for (auto &i: o) { - std::map::iterator it; - it = state.find(i.first); - if (it != state.end()) { - state.insert_or_assign(i.first, i.second); + for (auto &[key, value] : o) + { + if (key != MESH_STATE_PROPERTY) + { + if (state.count(key) > 0) + { + state.insert_or_assign(key, value); + } + } + else + { + meshState.insert_or_assign(MESH_STATE_PROPERTY, value); } } - } catch(...) { + dispatchStateChange(); + dispatchMeshStateChange(); + } + + catch (...) + { // Failed to parse the incoming state, or the state we did parse was not actually - // an object type. How you handle it is up to you, here we just ignore it + // an object type. How you handle it is up to you. + dispatchError("State Error", "Failed to restore mesh!"); } + + } //============================================================================== // This creates new instances of the plugin.. -juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter() +juce::AudioProcessor *JUCE_CALLTYPE createPluginFilter() { return new EffectsPluginProcessor(); } diff --git a/native/PluginProcessor.h b/native/PluginProcessor.h index d828257..efe4129 100644 --- a/native/PluginProcessor.h +++ b/native/PluginProcessor.h @@ -6,6 +6,7 @@ #include #include +#include //============================================================================== class EffectsPluginProcessor @@ -14,21 +15,23 @@ class EffectsPluginProcessor private juce::AsyncUpdater { public: + void createParameters(const std::vector ¶meters); + //============================================================================== EffectsPluginProcessor(); ~EffectsPluginProcessor() override; //============================================================================== - juce::AudioProcessorEditor* createEditor() override; + juce::AudioProcessorEditor *createEditor() override; bool hasEditor() const override; //============================================================================== - void prepareToPlay (double sampleRate, int samplesPerBlock) override; + void prepareToPlay(double sampleRate, int samplesPerBlock) override; void releaseResources() override; - bool isBusesLayoutSupported (const juce::AudioProcessor::BusesLayout& layouts) const override; + bool isBusesLayoutSupported(const juce::AudioProcessor::BusesLayout &layouts) const override; - void processBlock (juce::AudioBuffer&, juce::MidiBuffer&) override; + void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override; //============================================================================== const juce::String getName() const override; @@ -41,55 +44,289 @@ class EffectsPluginProcessor //============================================================================== int getNumPrograms() override; int getCurrentProgram() override; - void setCurrentProgram (int index) override; - const juce::String getProgramName (int index) override; - void changeProgramName (int index, const juce::String& newName) override; + void setCurrentProgram(int index) override; + const juce::String getProgramName(int index) override; + void changeProgramName(int index, const juce::String &newName) override; //============================================================================== - void getStateInformation (juce::MemoryBlock& destData) override; - void setStateInformation (const void* data, int sizeInBytes) override; + void getStateInformation(juce::MemoryBlock &destData) override; + void setStateInformation(const void *data, int sizeInBytes) override; //============================================================================== /** Implement the AudioProcessorParameter::Listener interface. */ - void parameterValueChanged (int parameterIndex, float newValue) override; - void parameterGestureChanged (int parameterIndex, bool gestureIsStarting) override; + void parameterValueChanged(int parameterIndex, float newValue) override; + void parameterGestureChanged(int parameterIndex, bool gestureIsStarting) override; //============================================================================== /** Implement the AsyncUpdater interface. */ void handleAsyncUpdate() override; //============================================================================== + /** Internal helper for initializing the embedded JS engine. */ void initJavaScriptEngine(); + void initSecondJavaScriptEngine(); /** Internal helper for propagating processor state changes. */ void dispatchStateChange(); - void dispatchError(std::string const& name, std::string const& message); + + /** INternal helper for mesh data view state changes */ + void dispatchMeshStateChange(); + + /** error to UI */ + void dispatchError(std::string const &name, std::string const &message); private: + std::string MESH_STATE_PROPERTY = "meshState"; + + std::string MAIN_DSP_JS_FILE = "dsp.main.js"; + + std::string MAIN_PATCH_JS_FILE = "patch.main.js"; + + std::string SAMPLE_RATE_PROPERTY = "sampleRate"; + + std::string NATIVE_MESSAGE_FUNCTION_NAME = "__postNativeMessage__"; + + std::string LOG_FUNCTION_NAME = "__log__"; + + // The maximum number of error messages to keep in the queue + size_t MAX_ERROR_LOG_QUEUE_SIZE = 200; + + std::optional loadDspEntryFileContents() const; + + std::optional loadPatchEntryFileContents() const; + + /** + * + * @param expr javascript expression to evaluate in the view context + * @return true if the view exists, false if not + */ + bool sendJavascriptToUI(const std::string &expr) const; + + static std::string serialize(const std::string &function, const elem::js::Object &data, const juce::String &replacementChar = "%"); + static std::string serialize(const std::string &function, const choc::value::Value &data, const juce::String &replacementChar = "%"); + //============================================================================== - std::atomic shouldInitialize { false }; + std::atomic runtimeSwapRequired{false}; + std::atomic shouldInitialize{false}; double lastKnownSampleRate = 0; int lastKnownBlockSize = 0; + //===== js stores and context ==// elem::js::Object state; + elem::js::Object meshState; choc::javascript::Context jsContext; + choc::javascript::Context jsContext2; juce::AudioBuffer scratchBuffer; std::unique_ptr> runtime; + std::map parameterMap; + std::queue errorLogQueue; + //============================================================================== // A simple "dirty list" abstraction here for propagating realtime parameter // value changes - struct ParameterReadout { + struct ParameterReadout + { float value = 0; bool dirty = false; }; - std::list> paramReadouts; + std::list> parameterReadouts; static_assert(std::atomic::is_always_lock_free); //============================================================================== - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EffectsPluginProcessor) + // Keyzy License Activator + // Keyzy::ProductData productData{"YOUR_APP_ID", "YOUR_API_KEY", "YOUR_PRODUCT_CODE", "YOUR_CRYPTION_KEY"}; + + Keyzy::ProductData productData // hidden + Keyzy::KeyzyLicenseActivator licenseActivator{productData}; + Keyzy::LicenseStatus licenseStatus = Keyzy::LicenseStatus::NOT_AUTHORIZED; + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EffectsPluginProcessor) }; + +namespace unlock +{ + inline std::string errorStatuses(Keyzy::LicenseStatus status) + { + switch (status) + { + case Keyzy::LicenseStatus::EXPIRED: + return "Expired"; + + case Keyzy::LicenseStatus::INVALID: + return "Invalid"; + + case Keyzy::LicenseStatus::NOT_AUTHORIZED: + return "Not authorized"; + + case Keyzy::LicenseStatus::SERIAL_INVALID: + return "Serial invalid"; + + case Keyzy::LicenseStatus::PRODUCT_NOT_EXIST: + return "Product does not exist"; + + case Keyzy::LicenseStatus::PRODUCT_NOT_EXIST_FOR_USER: + return "Product does not exist"; + + case Keyzy::LicenseStatus::PRODUCT_NOT_ACTIVE: + return "Product is not active"; + + case Keyzy::LicenseStatus::SKU_NOT_EXIST: + return "SKU does not exist"; + + case Keyzy::LicenseStatus::SKU_NOT_ACTIVE: + return "SKU is not active"; + + case Keyzy::LicenseStatus::REACHED_MAX_NUMBER_OF_HOST: + return "Reached maximum number of host"; + + case Keyzy::LicenseStatus::PRODUCT_NOT_EXIST_FOR_SKU: + return "Product does not exist for this SKU"; + + case Keyzy::LicenseStatus::ACTIVATION_DEACTIVATED: + return "Activation is deactivated"; + + case Keyzy::LicenseStatus::SUBSCRIPTION_LICENSE_EXPIRED: + return "Subscription license expired!"; + + case Keyzy::LicenseStatus::SUBSCRIPTION_LICENSE_NOT_STARTED: + return "Subscription license not started!"; + + case Keyzy::LicenseStatus::TRIAL_LICENSE_EXPIRED: + return "Trial license expired!"; + + case Keyzy::LicenseStatus::TRIAL_LICENSE_NOT_STARTED: + return "Trial license not started!"; + + case Keyzy::LicenseStatus::CANNOT_KEEP_SERIAL: + return "Cannot keep serial!"; + + case Keyzy::LicenseStatus::CANNOT_KEEP_LICENSE_FILE: + return "Cannot keep license file!"; + + case Keyzy::LicenseStatus::ACTIVATION_DELETED: + return "Activation deleted!"; + + case Keyzy::LicenseStatus::CLIENT_SERIAL_DOES_NOT_EXIST: + return "Client serial does not exist!"; + + case Keyzy::LicenseStatus::CONNECTION_ERROR: + return "Connection Error!"; + + case Keyzy::LicenseStatus::TOO_MANY_REQUESTS: + return "Too Many Requests!"; + + case Keyzy::LicenseStatus::NO_ACTIVE_SUBSCRIPTION: + return "No Active Subscription!"; + + case Keyzy::LicenseStatus::CURRENT_LICENSE_DOES_NOT_EXIST: + return "Current license does not exist!"; + + case Keyzy::LicenseStatus::UPGRADE_LICENSE_DOES_NOT_EXIST: + return "Upgrade license does not exist!"; + + case Keyzy::LicenseStatus::UPGRADE_LICENSE_DOES_NOT_MATCH: + return "Upgrade license does not match for upgrade with current license!"; + + case Keyzy::LicenseStatus::ANOTHER_TRIAL_LICENSE_ALREADY_ACTIVATED: + return "Another trial license has already been activated on this device!"; + + case Keyzy::LicenseStatus::SKU_NUMBER_VALIDATION: + return "sku_number parameter cannot be validated!"; + + case Keyzy::LicenseStatus::PRODUCT_CODE_VALIDATION: + return "product_code parameter cannot be validated!"; + + case Keyzy::LicenseStatus::NAME_VALIDATION: + return "name parameter cannot be validated!"; + + case Keyzy::LicenseStatus::EMAIL_VALIDATION: + return "email parameter cannot be validated!"; + + case Keyzy::LicenseStatus::NO_FREE_LICENSES: + return "You do not have any free licenses for this sku. Please generate new licenses for this sku!"; + + case Keyzy::LicenseStatus::NAME_OR_EMAIL_VALIDATION: + return "Either the name or email filed must be filled!"; + + case Keyzy::LicenseStatus::LICENSE_NOT_EXIST_NOT_ASSIGNED_DEALER_ALREADY_DEPOSITED: + return "The license does not exist or is not assigned to a dealer or is already deposited!"; + + case Keyzy::LicenseStatus::VALID: // Just in case + return "Valid"; + + default: + return "Unknown"; + } + } +} + +namespace jsFunctions +{ + inline auto consoleLogScript = R"shim( +(function() { + if (typeof globalThis.console === 'undefined') { + globalThis.console = { + log(...args) { + __log__('[embedded:log]', ...args); + }, + warn(...args) { + __log__('[embedded:warn]', ...args); + }, + error(...args) { + __log__('[embedded:error]', ...args); + } + }; + } +})(); + )shim"; + + inline auto hydrateScript = R"script( +(function() { + if (typeof globalThis.__receiveHydrationData__ !== 'function') + return false; + + globalThis.__receiveHydrationData__(%); + return true; +})(); +)script"; + + inline auto dispatchScript = R"script( +(function() { + if (typeof globalThis.__receiveStateChange__ !== 'function') + return false; + + globalThis.__receiveStateChange__(%); + return true; +})(); +)script"; + + //// seperated for Mesh state send + inline auto dispatchMeshStateScript = R"script( +(function() { + if (typeof globalThis.__receiveMeshStateChange__ !== 'function') + return false; + + globalThis.__receiveMeshStateChange__(%); + return true; +})(); +)script"; + + inline auto errorScript = R"script( +(function() { + if (typeof globalThis.__receiveError__ !== 'function') + return false; + + let e = new Error(%); + e.name = @; + + globalThis.__receiveError__(e); + return true; +})(); +)script"; +} diff --git a/native/WebViewEditor.cpp b/native/WebViewEditor.cpp index 5a39609..a2873ba 100644 --- a/native/WebViewEditor.cpp +++ b/native/WebViewEditor.cpp @@ -1,22 +1,23 @@ #include "PluginProcessor.h" #include "WebViewEditor.h" - // A helper for reading numbers from a choc::Value, which seems to opportunistically parse // JSON numbers into ints or 32-bit floats whenever it wants. -double numberFromChocValue(const choc::value::ValueView& v) { +double numberFromChocValue(const choc::value::ValueView &v) +{ return ( - v.isFloat32() ? (double) v.getFloat32() - : (v.isFloat64() ? v.getFloat64() - : (v.isInt32() ? (double) v.getInt32() - : (double) v.getInt64()))); + v.isFloat32() ? (double)v.getFloat32() + : (v.isFloat64() ? v.getFloat64() + : (v.isInt32() ? (double)v.getInt32() + : (double)v.getInt64()))); } -std::string getMimeType(std::string const& ext) { - static std::unordered_map mimeTypes { - { ".html", "text/html" }, - { ".js", "application/javascript" }, - { ".css", "text/css" }, +std::string getMimeType(std::string const &ext) +{ + static std::unordered_map mimeTypes{ + {".html", "text/html"}, + {".js", "application/javascript"}, + {".css", "text/css"}, }; if (mimeTypes.count(ext) > 0) @@ -26,19 +27,22 @@ std::string getMimeType(std::string const& ext) { } //============================================================================== -WebViewEditor::WebViewEditor(juce::AudioProcessor* proc, juce::File const& assetDirectory, int width, int height) +WebViewEditor::WebViewEditor(juce::AudioProcessor *proc, juce::File const &assetDirectory, int width, int height) : juce::AudioProcessorEditor(proc) { - setSize(720, 444); + setSize(width, height); + setResizable(true, false); choc::ui::WebView::Options opts; #if JUCE_DEBUG - opts.enableDebugMode = true; + opts.enableDebugMode = false; #endif -#if ! ELEM_DEV_LOCALHOST - opts.fetchResource = [=](const choc::ui::WebView::Options::Path& p) -> std::optional { +#if !ELEM_DEV_LOCALHOST + opts.enableDebugMode = false; + opts.fetchResource = [=](const choc::ui::WebView::Options::Path &p) -> std::optional + { auto relPath = "." + (p == "/" ? "/index.html" : p); auto f = assetDirectory.getChildFile(relPath); juce::MemoryBlock mb; @@ -46,93 +50,95 @@ WebViewEditor::WebViewEditor(juce::AudioProcessor* proc, juce::File const& asset if (!f.existsAsFile() || !f.loadFileAsData(mb)) return {}; - return choc::ui::WebView::Options::Resource { - std::vector(mb.begin(), mb.end()), - getMimeType(f.getFileExtension().toStdString()) - }; + return choc::ui::WebView::Options::Resource{ + std::string(mb.begin(), mb.end()), + getMimeType(f.getFileExtension().toStdString())}; + + + + + }; #endif - webView = std::make_unique(opts); + webView = std::make_unique(opts); #if JUCE_MAC - viewContainer.setView(webView->getViewHandle()); + viewContainer.setView(webView->getViewHandle()); #elif JUCE_WINDOWS viewContainer.setHWND(webView->getViewHandle()); #else #error "We only support MacOS and Windows here yet." #endif - addAndMakeVisible(viewContainer); - viewContainer.setBounds({0, 0, 720, 440}); + addAndMakeVisible(viewContainer); + viewContainer.setBounds({0, 0, 905, 600}); - // Install message passing handlers - webView->bind("__postNativeMessage__", [=](const choc::value::ValueView& args) -> choc::value::Value { + // Install message passing handlers + webView->bind(POST_NATIVE_MESSAGE, [=](const choc::value::ValueView &args) -> choc::value::Value + { if (args.isArray()) { - auto eventName = args[0].getString(); + const auto eventName = args[0].getString(); // When the webView loads it should send a message telling us that it has established // its message-passing hooks and is ready for a state dispatch - if (eventName == "ready") { - if (auto* ptr = dynamic_cast(getAudioProcessor())) { - ptr->dispatchStateChange(); - } + if (eventName == READY_EVENT) { + ready(); } -#if ELEM_DEV_LOCALHOST - if (eventName == "reload") { - if (auto* ptr = dynamic_cast(getAudioProcessor())) { - ptr->initJavaScriptEngine(); - ptr->dispatchStateChange(); - } + if (eventName == RELOAD_EVENT) { + reload(); } -#endif - if (eventName == "setParameterValue" && args.size() > 1) { + if (eventName == SET_PARAMETER_VALUE && args.size() > 1) { return handleSetParameterValueEvent(args[1]); } + + if (eventName == SET_MESH_STATE && args.size() > 1) { + // Take a copy of the value and pass it to the view state change handler. + auto value = choc::value::Value(args[1]); + setMeshState(value); + } + + // For Keyzy send an unlock event with an object containing the serial number + if (eventName == UNLOCK_EVENT && args.size() > 1) { + auto value = choc::value::Value(args[1]); + handleUnlockEvent(value); + } } - return {}; - }); + return {}; + }); #if ELEM_DEV_LOCALHOST - webView->navigate("http://localhost:5173"); + webView->navigate("http://localhost:5173"); #endif -} + } -choc::ui::WebView* WebViewEditor::getWebViewPtr() -{ - return webView.get(); -} + void WebViewEditor::paint(juce::Graphics &g) + { + } -void WebViewEditor::paint (juce::Graphics& g) -{ -} + void WebViewEditor::resized() + { + viewContainer.setBounds(getLocalBounds()); + } -void WebViewEditor::resized() -{ - viewContainer.setBounds(getLocalBounds()); -} + void WebViewEditor::executeJavascript(const std::string &script) const + { + webView->evaluateJavascript(script); + } -//============================================================================== -choc::value::Value WebViewEditor::handleSetParameterValueEvent(const choc::value::ValueView& e) { - // When setting a parameter value, we simply tell the host. This will in turn fire - // a parameterValueChanged event, which will catch and propagate through dispatching - // a state change event - if (e.isObject() && e.hasObjectMember("paramId") && e.hasObjectMember("value")) { - auto const& paramId = e["paramId"].getString(); - double const v = numberFromChocValue(e["value"]); - - for (auto& p : getAudioProcessor()->getParameters()) { - if (auto* pf = dynamic_cast(p)) { - if (pf->paramID.toStdString() == paramId) { - pf->setValueNotifyingHost(v); - break; - } - } + //============================================================================== + choc::value::Value WebViewEditor::handleSetParameterValueEvent(const choc::value::ValueView &e) const + { + if (e.isObject() && e.hasObjectMember("paramId") && e.hasObjectMember("value")) + { + auto const ¶mId = e["paramId"].getString(); + double const v = numberFromChocValue(e["value"]); + + setParameterValue(std::string{paramId}, static_cast(v)); } - } - return choc::value::Value(); -} + return {}; + } diff --git a/native/WebViewEditor.h b/native/WebViewEditor.h index 5504d10..9a9c1ed 100644 --- a/native/WebViewEditor.h +++ b/native/WebViewEditor.h @@ -5,7 +5,6 @@ #include - //============================================================================== // A simple juce::AudioProcessorEditor that holds a choc::WebView and sets the // WebView instance to cover the entire region of the editor. @@ -13,20 +12,35 @@ class WebViewEditor : public juce::AudioProcessorEditor { public: //============================================================================== - WebViewEditor(juce::AudioProcessor* proc, juce::File const& assetDirectory, int width, int height); + WebViewEditor(juce::AudioProcessor *proc, juce::File const &assetDirectory, int width, int height); + + //============================================================================== + void paint(juce::Graphics &g) override; + void resized() override; //============================================================================== - choc::ui::WebView* getWebViewPtr(); + // Keyzy + std::function handleUnlockEvent = [](choc::value::Value &) {}; //============================================================================== - void paint (juce::Graphics& g) override; - void resized() override; + std::function setMeshState = [](choc::value::Value &) {}; + std::function setParameterValue = [](const std::string &, float) {}; + std::function reload = []() {}; + std::function ready = []() {}; + + void executeJavascript(const std::string &script) const; private: - //============================================================================== - choc::value::Value handleSetParameterValueEvent(const choc::value::ValueView& e); + std::string POST_NATIVE_MESSAGE = "__postNativeMessage__"; + std::string READY_EVENT = "ready"; + std::string RELOAD_EVENT = "reload"; + std::string SET_PARAMETER_VALUE = "setParameterValue"; + std::string SET_MESH_STATE = "setMeshState"; + std::string UNLOCK_EVENT = "unlock"; + std::string HOST_INFO = "hostInfo"; + + choc::value::Value handleSetParameterValueEvent(const choc::value::ValueView &e) const; - //============================================================================== std::unique_ptr webView; #if JUCE_MAC @@ -34,6 +48,6 @@ class WebViewEditor : public juce::AudioProcessorEditor #elif JUCE_WINDOWS juce::HWNDComponent viewContainer; #else - #error "We only support MacOS and Windows here yet." +#error "We only support MacOS and Windows here yet." #endif };