You've already forked ParticleEffectForUGUI
mirror of
https://github.com/mob-sakai/ParticleEffectForUGUI.git
synced 2026-05-15 04:30:09 +00:00
Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d56c94636 | ||
|
|
fe179c0f0f | ||
|
|
df2f3caafb | ||
|
|
1c8c65d25e | ||
|
|
a9461ecb4d | ||
|
|
38aec2ea1a | ||
|
|
bb2d588e0c | ||
|
|
078005a1a7 | ||
|
|
0cff50ef69 | ||
|
|
0da652520c | ||
|
|
4199492e3a | ||
|
|
1f88bb255e | ||
|
|
e3791866b7 | ||
|
|
6dfbdae38d | ||
|
|
b63220b871 | ||
|
|
3fd2bea599 | ||
|
|
925af0b604 | ||
|
|
d1a1e23e50 | ||
|
|
47ee45cbbe | ||
|
|
1b0110320b | ||
|
|
a1ca74f854 | ||
|
|
8276684c3b | ||
|
|
67de3d1bd3 | ||
|
|
90d966e659 | ||
|
|
0036b03d12 | ||
|
|
934f4b8f1c | ||
|
|
fe4fcc5ddd | ||
|
|
072aac521b | ||
|
|
95235a929b | ||
|
|
1a748f19d0 | ||
|
|
f9ce2c6c96 | ||
|
|
abe09485f6 | ||
|
|
253fb52650 | ||
|
|
3544c593e2 | ||
|
|
4faf151c87 | ||
|
|
afe00a1dde | ||
|
|
c1e3d68f60 | ||
|
|
a1ea8785bc | ||
|
|
2ee69d0424 | ||
|
|
2c1ac4b5e9 | ||
|
|
5f255ec6cd | ||
|
|
1b678c68c6 | ||
|
|
5ff6ec815a | ||
|
|
0ee1671246 | ||
|
|
6a7f08c056 | ||
|
|
1ce4e31a96 | ||
|
|
c08f0d492f | ||
|
|
7069b396e4 |
28
.github/workflows/release.yml
vendored
28
.github/workflows/release.yml
vendored
@@ -1,12 +1,12 @@
|
|||||||
name: 🔖 Release
|
name: 🔖 Release
|
||||||
|
run-name: 🔖 Release (${{ github.ref_name }})
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- release
|
- release
|
||||||
- release-preview
|
- release-*
|
||||||
- release-v4
|
|
||||||
tags-ignore:
|
tags-ignore:
|
||||||
- "**"
|
- "**"
|
||||||
|
|
||||||
@@ -27,10 +27,10 @@ jobs:
|
|||||||
split_to: ${{ steps.summary.outputs.split_to }}
|
split_to: ${{ steps.summary.outputs.split_to }}
|
||||||
steps:
|
steps:
|
||||||
- name: 🚚 Checkout (${{ github.ref_name }})
|
- name: 🚚 Checkout (${{ github.ref_name }})
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: 🔖 Run semantic release
|
- name: 🔖 Run semantic release
|
||||||
uses: cycjimmy/semantic-release-action@v4
|
uses: cycjimmy/semantic-release-action@v5
|
||||||
id: release
|
id: release
|
||||||
with:
|
with:
|
||||||
working_directory: Packages/src
|
working_directory: Packages/src
|
||||||
@@ -38,7 +38,7 @@ jobs:
|
|||||||
@semantic-release/changelog
|
@semantic-release/changelog
|
||||||
@semantic-release/git
|
@semantic-release/git
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
- id: summary
|
- id: summary
|
||||||
run: |
|
run: |
|
||||||
@@ -50,14 +50,12 @@ jobs:
|
|||||||
if [ '${{ steps.release.outputs.new_release_published }}' = 'false' ]; then
|
if [ '${{ steps.release.outputs.new_release_published }}' = 'false' ]; then
|
||||||
echo "No new release published." | tee -a $GITHUB_STEP_SUMMARY
|
echo "No new release published." | tee -a $GITHUB_STEP_SUMMARY
|
||||||
elif [ '${{ github.ref_name }}' = 'release' ]; then
|
elif [ '${{ github.ref_name }}' = 'release' ]; then
|
||||||
echo "merge_to=develop" | tee -a $GITHUB_OUTPUT
|
echo "merge_to=develop" | tee -a $GITHUB_OUTPUT $GITHUB_STEP_SUMMARY
|
||||||
echo "split_to=main" | tee -a $GITHUB_OUTPUT
|
echo "split_to=main" | tee -a $GITHUB_OUTPUT $GITHUB_STEP_SUMMARY
|
||||||
elif [ '${{ github.ref_name }}' = 'release-preview' ]; then
|
else
|
||||||
echo "merge_to=develop-preview" | tee -a $GITHUB_OUTPUT
|
channel=$(echo ${{ github.ref_name }} | sed 's/^release-//')
|
||||||
echo "split_to=preview" | tee -a $GITHUB_OUTPUT
|
echo "merge_to=develop-${channel}" | tee -a $GITHUB_OUTPUT $GITHUB_STEP_SUMMARY
|
||||||
elif [ '${{ github.ref_name }}' = 'release-4.x' ]; then
|
echo "split_to=${channel}" | tee -a $GITHUB_OUTPUT $GITHUB_STEP_SUMMARY
|
||||||
echo "merge_to=develop-4.x" | tee -a $GITHUB_OUTPUT
|
|
||||||
echo "split_to=4.x" | tee -a $GITHUB_OUTPUT
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
merge-to:
|
merge-to:
|
||||||
@@ -69,7 +67,7 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- name: 🚚 Checkout (${{ needs.release.outputs.merge_to }})
|
- name: 🚚 Checkout (${{ needs.release.outputs.merge_to }})
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
ref: ${{ needs.release.outputs.merge_to }}
|
ref: ${{ needs.release.outputs.merge_to }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
@@ -90,7 +88,7 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- name: 🚚 Checkout (${{ needs.release.outputs.tag }})
|
- name: 🚚 Checkout (${{ needs.release.outputs.tag }})
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
ref: ${{ needs.release.outputs.tag }}
|
ref: ${{ needs.release.outputs.tag }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|||||||
77
.github/workflows/test.yml
vendored
77
.github/workflows/test.yml
vendored
@@ -3,28 +3,37 @@
|
|||||||
# UNITY_EMAIL: Unity user email to login
|
# UNITY_EMAIL: Unity user email to login
|
||||||
# UNITY_PASSWORD: Unity user password to login
|
# UNITY_PASSWORD: Unity user password to login
|
||||||
name: 🧪 Test
|
name: 🧪 Test
|
||||||
|
run-name: 🧪 Test (${{ github.event.pull_request.title || github.ref_name }})
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# MINIMUM_VERSION: The minimum version of Unity.
|
# MINIMUM_VERSION: The minimum version of Unity.
|
||||||
MINIMUM_VERSION: 2019.4
|
MINIMUM_VERSION: 2019.4
|
||||||
# EXCLUDE_FILTER: The excluded versions of Unity.
|
# EXCLUDE_FILTER: The excluded versions of Unity.
|
||||||
EXCLUDE_FILTER: '(2020.2.0)'
|
EXCLUDE_FILTER: "(2020.2.0|2021.1|2023.3)"
|
||||||
|
PROJECT_PATH: .
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
usePeriodVersions:
|
||||||
|
description: "Use the period versions (.0f1, .10f1, 20f1, ...)."
|
||||||
|
required: false
|
||||||
|
default: "true"
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- develop
|
- develop
|
||||||
- develop-preview
|
- "develop-*"
|
||||||
- develop-4.x
|
|
||||||
tags:
|
tags:
|
||||||
- "!*"
|
- "!*"
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- "*.md"
|
- "**.md"
|
||||||
pull_request:
|
pull_request_target:
|
||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
|
- reopened
|
||||||
- synchronize
|
- synchronize
|
||||||
|
paths-ignore:
|
||||||
|
- "**.md"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
setup:
|
setup:
|
||||||
@@ -37,9 +46,12 @@ jobs:
|
|||||||
id: setup
|
id: setup
|
||||||
run: |
|
run: |
|
||||||
echo "==== Target Unity Versions ===="
|
echo "==== Target Unity Versions ===="
|
||||||
LATEST_VERSIONS=`npx unity-changeset list --versions --latest-patch --min ${MINIMUM_VERSION} --json --all`
|
LATEST_VERSIONS=`npx unity-changeset@latest list --versions --latest-patch --min ${MINIMUM_VERSION} --json --all`
|
||||||
# ADDITIONAL_VERSIONS=`npx unity-changeset list --versions --grep '0f' --min ${MINIMUM_VERSION} --json`
|
if [ "${{ inputs.usePeriodVersions }}" = "true" ]; then
|
||||||
ADDITIONAL_VERSIONS=[]
|
ADDITIONAL_VERSIONS=`npx unity-changeset list --versions --grep '0f' --min ${MINIMUM_VERSION} --json`
|
||||||
|
else
|
||||||
|
ADDITIONAL_VERSIONS=[]
|
||||||
|
fi
|
||||||
|
|
||||||
VERSIONS=`echo "[${LATEST_VERSIONS}, ${ADDITIONAL_VERSIONS}]" \
|
VERSIONS=`echo "[${LATEST_VERSIONS}, ${ADDITIONAL_VERSIONS}]" \
|
||||||
| jq -c '[ flatten | sort | unique | .[] | select( test("${{ env.EXCLUDE_FILTER }}") | not ) ]'`
|
| jq -c '[ flatten | sort | unique | .[] | select( test("${{ env.EXCLUDE_FILTER }}") | not ) ]'`
|
||||||
@@ -48,40 +60,57 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
name: 🧪 Run tests
|
name: 🧪 Run tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
|
||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
permissions:
|
permissions:
|
||||||
checks: write
|
checks: write
|
||||||
contents: read
|
contents: read
|
||||||
needs: setup
|
needs: setup
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
max-parallel: 4
|
max-parallel: 6
|
||||||
matrix:
|
matrix:
|
||||||
unityVersion: ${{ fromJson(needs.setup.outputs.unityVersions) }}
|
unityVersion: ${{ fromJson(needs.setup.outputs.unityVersions) }}
|
||||||
steps:
|
steps:
|
||||||
- name: 🚚 Checkout
|
- name: 🚚 Checkout ($${{ github.ref }})
|
||||||
uses: actions/checkout@v4
|
if: github.event_name == 'push'
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: 🚚 Checkout pull request (pull_request_target)
|
||||||
|
if: github.event_name == 'pull_request_target'
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: 🚚 Marge pull request (pull_request_target)
|
||||||
|
if: github.event_name == 'pull_request_target'
|
||||||
|
run: |
|
||||||
|
git config user.name "GitHub Actions"
|
||||||
|
git config user.email "actions@github.com"
|
||||||
|
git rebase ${{ github.event.pull_request.base.sha }}
|
||||||
|
git log --oneline -n 10
|
||||||
|
|
||||||
- name: 📥 Cache library
|
- name: 📥 Cache library
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: Library
|
path: ${{ env.PROJECT_PATH }}/Library
|
||||||
key: Library-${{ matrix.unityVersion }}-${{ github.sha }}
|
key: ${{ env.PROJECT_PATH }}-Library-${{ matrix.unityVersion }}-${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
Library-${{ matrix.unityVersion }}-
|
${{ env.PROJECT_PATH }}-Library-${{ matrix.unityVersion }}-
|
||||||
Library-
|
${{ env.PROJECT_PATH }}-Library-
|
||||||
|
|
||||||
- name: 🛠️ Build Unity Project
|
- name: 🛠️ Build Unity Project (Test)
|
||||||
uses: game-ci/unity-builder@v4
|
uses: game-ci/unity-builder@main
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
with:
|
with:
|
||||||
customImage: ghcr.io/mob-sakai/unity3d:${{ matrix.unityVersion }}
|
customImage: ghcr.io/mob-sakai/unity3d:${{ matrix.unityVersion }}
|
||||||
targetPlatform: StandaloneLinux64
|
targetPlatform: StandaloneLinux64
|
||||||
allowDirtyBuild: true
|
allowDirtyBuild: true
|
||||||
customParameters: -nographics
|
customParameters: -nographics
|
||||||
|
projectPath: ${{ env.PROJECT_PATH }}
|
||||||
|
env:
|
||||||
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
|
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
|
|
||||||
- name: 🧪 Run tests
|
- name: 🧪 Run tests
|
||||||
uses: game-ci/unity-test-runner@v4
|
uses: game-ci/unity-test-runner@v4
|
||||||
@@ -92,4 +121,8 @@ jobs:
|
|||||||
customParameters: -nographics
|
customParameters: -nographics
|
||||||
checkName: ${{ matrix.unityVersion }} Test Results
|
checkName: ${{ matrix.unityVersion }} Test Results
|
||||||
githubToken: ${{ github.token }}
|
githubToken: ${{ github.token }}
|
||||||
coverageOptions: "dontClear;generateHtmlReport;generateBadgeReport;pathFilters:+**/Packages/src/**;assemblyFilters:+<packages>,-*.Editor,-*.Test"
|
projectPath: ${{ env.PROJECT_PATH }}
|
||||||
|
env:
|
||||||
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
|
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
|
|||||||
7046
Assets/Demo/Cartoon FX & War FX Demo/CFXRF Demo.unity
Normal file
7046
Assets/Demo/Cartoon FX & War FX Demo/CFXRF Demo.unity
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e34a092899a9547189add96707de1b5a
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
@@ -80,7 +80,11 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
.SelectMany(x => x.GetTypes())
|
.SelectMany(x => x.GetTypes())
|
||||||
.FirstOrDefault(x => x.Name == typeName);
|
.FirstOrDefault(x => x.Name == typeName);
|
||||||
|
|
||||||
|
#if UNITY_2023_2_OR_NEWER
|
||||||
|
return type == null ? null : FindFirstObjectByType(type);
|
||||||
|
#else
|
||||||
return type == null ? null : FindObjectOfType(type);
|
return type == null ? null : FindObjectOfType(type);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCanvasWidth(int width)
|
public void SetCanvasWidth(int width)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Coffee.UIParticleInternal;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Serialization;
|
using UnityEngine.Serialization;
|
||||||
|
|
||||||
@@ -46,11 +47,7 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
if (!flag)
|
if (!flag)
|
||||||
{
|
{
|
||||||
#if UNITY_2023_1_OR_NEWER
|
foreach (var ps in Misc.FindObjectsOfType<ParticleSystem>())
|
||||||
foreach (var ps in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
|
||||||
#else
|
|
||||||
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
ps.Play(false);
|
ps.Play(false);
|
||||||
}
|
}
|
||||||
@@ -79,11 +76,7 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void ParticleSystem_SetScale(float scale)
|
public void ParticleSystem_SetScale(float scale)
|
||||||
{
|
{
|
||||||
#if UNITY_2023_1_OR_NEWER
|
foreach (var ps in Misc.FindObjectsOfType<ParticleSystem>())
|
||||||
foreach (var ps in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
|
||||||
#else
|
|
||||||
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
ps.transform.localScale = new Vector3(scale, scale, scale);
|
ps.transform.localScale = new Vector3(scale, scale, scale);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,12 @@ MonoBehaviour:
|
|||||||
m_EnabledInEditor: 1
|
m_EnabledInEditor: 1
|
||||||
m_AlwaysIncludeAssembly: 1
|
m_AlwaysIncludeAssembly: 1
|
||||||
m_InstantiateOnLoad: 1
|
m_InstantiateOnLoad: 1
|
||||||
m_Prefab: {fileID: 7211429669315726685, guid: b73940fc30a2f4eb9a73783e9c1f8da6,
|
m_Prefab: {fileID: 4567906826058368312, guid: 7cebff2d255b9433cbe23b243c193329,
|
||||||
type: 3}
|
type: 3}
|
||||||
m_Interval: 0.5
|
m_Interval: 0.5
|
||||||
m_Anchor: 0
|
m_Anchor: 0
|
||||||
m_Width: 750
|
m_Width: 750
|
||||||
|
m_HelpUrl: https://github.com/mob-sakai/ParticleEffectForUGUI
|
||||||
m_CustomMonitorItems:
|
m_CustomMonitorItems:
|
||||||
- m_Format: Screen:{0}x{1}
|
- m_Format: Screen:{0}x{1}
|
||||||
m_Arg0:
|
m_Arg0:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
16
Assets/ProjectSettings/UIParticleProjectSettings.asset
Normal file
16
Assets/ProjectSettings/UIParticleProjectSettings.asset
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: f22a23b9d98e440478697f4adf30e61c, type: 3}
|
||||||
|
m_Name: UIParticleProjectSettings
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_EnableLinearToGamma: 1
|
||||||
|
m_HideGeneratedObjects: 1
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a5b9278dfbd194d04b1c6ae7031928c1
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"com.coffee.development": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/Development",
|
||||||
|
"com.coffee.minimal-resource": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/MinimalResource",
|
||||||
"com.coffee.nano-monitor": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
|
"com.coffee.nano-monitor": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
|
||||||
"com.unity.ide.rider": "3.0.31",
|
"com.unity.ide.rider": "3.0.31",
|
||||||
"com.unity.test-framework": "1.1.33",
|
"com.unity.test-framework": "1.1.33",
|
||||||
|
|||||||
@@ -1,5 +1,19 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"com.coffee.development": {
|
||||||
|
"version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/Development",
|
||||||
|
"depth": 0,
|
||||||
|
"source": "git",
|
||||||
|
"dependencies": {},
|
||||||
|
"hash": "3c280f1a8f4db5038b881ff07f270efd9638fa31"
|
||||||
|
},
|
||||||
|
"com.coffee.minimal-resource": {
|
||||||
|
"version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/MinimalResource",
|
||||||
|
"depth": 0,
|
||||||
|
"source": "git",
|
||||||
|
"dependencies": {},
|
||||||
|
"hash": "3c280f1a8f4db5038b881ff07f270efd9638fa31"
|
||||||
|
},
|
||||||
"com.coffee.nano-monitor": {
|
"com.coffee.nano-monitor": {
|
||||||
"version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
|
"version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
|
||||||
"depth": 0,
|
"depth": 0,
|
||||||
@@ -7,7 +21,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"com.unity.ugui": "1.0.0"
|
"com.unity.ugui": "1.0.0"
|
||||||
},
|
},
|
||||||
"hash": "c51e4514c9ab944915a639433ee52342e55a644e"
|
"hash": "3c280f1a8f4db5038b881ff07f270efd9638fa31"
|
||||||
},
|
},
|
||||||
"com.coffee.ui-particle": {
|
"com.coffee.ui-particle": {
|
||||||
"version": "file:src",
|
"version": "file:src",
|
||||||
|
|||||||
1
Packages/src/.coffee.internal.sed
Normal file
1
Packages/src/.coffee.internal.sed
Normal file
@@ -0,0 +1 @@
|
|||||||
|
s/Coffee.Internal/Coffee.UIParticleInternal/g
|
||||||
@@ -1,3 +1,97 @@
|
|||||||
|
## [4.11.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.2...v4.11.3) (2025-10-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix icon ([a9461ec](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a9461ecb4d40d7fe878e12465d6e38faae7ae65b))
|
||||||
|
* fix URL link in README ([1c8c65d](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1c8c65d25e7f6fe7b1d20da4461333df8fc7578e)), closes [#376](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/376)
|
||||||
|
* fix: second and subsequent bursts not displayed when world simulation and non-looping ([df2f3ca](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/df2f3caafbe279f1457d74f8183cb561ac14aa17)), closes [#326](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/326)
|
||||||
|
* UIParticle in canvas with 0f-0.01f alpha value does not start to play until alpha value is greater than 0.01f, causes play calls to be delayed unintentionally if canvas alpha value is set to mentioned value range ([38aec2e](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/38aec2ea1afd77677d629c86665a3342d92e49d9))
|
||||||
|
|
||||||
|
## [4.11.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.1...v4.11.2) (2025-03-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* IL2CPP build fails on older versions of Unity ([0da6525](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0da652520cd165b43de7404c0b0ab1fbcf9349d1))
|
||||||
|
* NRE on enable ([0cff50e](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0cff50ef696aa53fb7c46a9a737b7cf3a05b7b9b)), closes [#359](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/359)
|
||||||
|
|
||||||
|
## [4.11.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.0...v4.11.1) (2025-02-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* component icons will no longer be displayed in the scene view ([6dfbdae](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/6dfbdae38d3822ab9c2c6f0e4ca1ca32ee98a239))
|
||||||
|
|
||||||
|
# [4.11.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.7...v4.11.0) (2025-02-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add 'TimeScaleMultiplier' option ([925af0b](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/925af0b6046f65f23a778f67cefa8ff9cbedb513))
|
||||||
|
|
||||||
|
## [4.10.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.6...v4.10.7) (2025-01-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* editor crashed on exit play mode (editor, windows) ([47ee45c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/47ee45cbbe651a8f87ca2b8a3948f8b88db8211e)), closes [#351](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/351)
|
||||||
|
|
||||||
|
## [4.10.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.5...v4.10.6) (2025-01-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* sub-emitter particles may not render correctly in certain scenarios ([8276684](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/8276684c3b1646f0490ed64557547ba15281664a)), closes [#348](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/348)
|
||||||
|
* sub-emitter's `inherit velocity` module doubles at runtime ([67de3d1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/67de3d1bd3e16dc9b564625cb990c53d75769506)), closes [#349](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/349)
|
||||||
|
|
||||||
|
## [4.10.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.4...v4.10.5) (2024-12-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* '3D' scale toggle in the inspector does not keep on reload ([934f4b8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/934f4b8f1c61f8ff20228d0ebcea9f636a3758ed)), closes [#346](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/346)
|
||||||
|
|
||||||
|
## [4.10.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.3...v4.10.4) (2024-12-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* rendering issues when playing with opening a prefab stage ([95235a9](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/95235a929b82cf681365ed6eba837d857f83e3d2)), closes [#345](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/345)
|
||||||
|
|
||||||
|
## [4.10.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.2...v4.10.3) (2024-11-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* if not configured as a preloaded asset, the project settings asset will be regenerated ([abe0948](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/abe09485f65dd4efd18e74675e752e0213bdf3be)), closes [#342](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/342)
|
||||||
|
|
||||||
|
## [4.10.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.1...v4.10.2) (2024-11-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* trail incorrect offset ([afe00a1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/afe00a1dde80eb1c0a7bb668b75f4c3733d3fa43)), closes [#335](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/335)
|
||||||
|
|
||||||
|
## [4.10.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.0...v4.10.1) (2024-09-29)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* mainTex will be ignored ([2ee69d0](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/2ee69d04245fabce185f67dc9bd68c870e556564))
|
||||||
|
|
||||||
|
# [4.10.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.9.1...v4.10.0) (2024-09-29)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* component icon is not set ([5ff6ec8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/5ff6ec815a174de5d3f16d424f1204c60912a8d8))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add project settings ([1ce4e31](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1ce4e31a9681bf1a201d2723c8d97e07ecc16592))
|
||||||
|
|
||||||
## [4.9.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.9.0...v4.9.1) (2024-08-07)
|
## [4.9.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.9.0...v4.9.1) (2024-08-07)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using UnityEditorInternal;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Profiling;
|
using UnityEngine.Profiling;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using Coffee.UIParticleExtensions;
|
using Coffee.UIParticleInternal;
|
||||||
#if UNITY_2021_2_OR_NEWER
|
#if UNITY_2021_2_OR_NEWER
|
||||||
using UnityEditor.Overlays;
|
using UnityEditor.Overlays;
|
||||||
#else
|
#else
|
||||||
@@ -17,6 +17,7 @@ using Object = UnityEngine.Object;
|
|||||||
#endif
|
#endif
|
||||||
#if UNITY_2021_2_OR_NEWER
|
#if UNITY_2021_2_OR_NEWER
|
||||||
using UnityEditor.SceneManagement;
|
using UnityEditor.SceneManagement;
|
||||||
|
|
||||||
#elif UNITY_2018_3_OR_NEWER
|
#elif UNITY_2018_3_OR_NEWER
|
||||||
using UnityEditor.Experimental.SceneManagement;
|
using UnityEditor.Experimental.SceneManagement;
|
||||||
#endif
|
#endif
|
||||||
@@ -27,6 +28,11 @@ namespace Coffee.UIExtensions
|
|||||||
[CanEditMultipleObjects]
|
[CanEditMultipleObjects]
|
||||||
internal class UIParticleEditor : GraphicEditor
|
internal class UIParticleEditor : GraphicEditor
|
||||||
{
|
{
|
||||||
|
internal class State : ScriptableSingleton<State>
|
||||||
|
{
|
||||||
|
public bool is3DScaleMode;
|
||||||
|
}
|
||||||
|
|
||||||
//################################
|
//################################
|
||||||
// Constant or Static Members.
|
// Constant or Static Members.
|
||||||
//################################
|
//################################
|
||||||
@@ -45,7 +51,6 @@ namespace Coffee.UIExtensions
|
|||||||
private static readonly GUIContent s_ContentPrimary = new GUIContent("Primary");
|
private static readonly GUIContent s_ContentPrimary = new GUIContent("Primary");
|
||||||
private static readonly Regex s_RegexBuiltInGuid = new Regex(@"^0{16}.0{15}$", RegexOptions.Compiled);
|
private static readonly Regex s_RegexBuiltInGuid = new Regex(@"^0{16}.0{15}$", RegexOptions.Compiled);
|
||||||
private static readonly List<Material> s_TempMaterials = new List<Material>();
|
private static readonly List<Material> s_TempMaterials = new List<Material>();
|
||||||
private static bool s_XYZMode;
|
|
||||||
|
|
||||||
private SerializedProperty _maskable;
|
private SerializedProperty _maskable;
|
||||||
private SerializedProperty _scale3D;
|
private SerializedProperty _scale3D;
|
||||||
@@ -57,8 +62,10 @@ namespace Coffee.UIExtensions
|
|||||||
private SerializedProperty _autoScalingMode;
|
private SerializedProperty _autoScalingMode;
|
||||||
private SerializedProperty _useCustomView;
|
private SerializedProperty _useCustomView;
|
||||||
private SerializedProperty _customViewSize;
|
private SerializedProperty _customViewSize;
|
||||||
|
private SerializedProperty _timeScaleMultiplier;
|
||||||
private ReorderableList _ro;
|
private ReorderableList _ro;
|
||||||
private bool _showMax;
|
private bool _showMax;
|
||||||
|
private bool _is3DScaleMode;
|
||||||
|
|
||||||
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
|
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
|
||||||
#if UNITY_2018 || UNITY_2019
|
#if UNITY_2018 || UNITY_2019
|
||||||
@@ -94,6 +101,7 @@ namespace Coffee.UIExtensions
|
|||||||
_autoScalingMode = serializedObject.FindProperty("m_AutoScalingMode");
|
_autoScalingMode = serializedObject.FindProperty("m_AutoScalingMode");
|
||||||
_useCustomView = serializedObject.FindProperty("m_UseCustomView");
|
_useCustomView = serializedObject.FindProperty("m_UseCustomView");
|
||||||
_customViewSize = serializedObject.FindProperty("m_CustomViewSize");
|
_customViewSize = serializedObject.FindProperty("m_CustomViewSize");
|
||||||
|
_timeScaleMultiplier = serializedObject.FindProperty("m_TimeScaleMultiplier");
|
||||||
|
|
||||||
var sp = serializedObject.FindProperty("m_Particles");
|
var sp = serializedObject.FindProperty("m_Particles");
|
||||||
_ro = new ReorderableList(sp.serializedObject, sp, true, true, true, true)
|
_ro = new ReorderableList(sp.serializedObject, sp, true, true, true, true)
|
||||||
@@ -162,6 +170,19 @@ namespace Coffee.UIExtensions
|
|||||||
uip.RefreshParticles(uip.particles);
|
uip.RefreshParticles(uip.particles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize 3D scale mode.
|
||||||
|
_is3DScaleMode = State.instance.is3DScaleMode;
|
||||||
|
if (!_is3DScaleMode)
|
||||||
|
{
|
||||||
|
var x = _scale3D.FindPropertyRelative("x");
|
||||||
|
var y = _scale3D.FindPropertyRelative("y");
|
||||||
|
var z = _scale3D.FindPropertyRelative("z");
|
||||||
|
_is3DScaleMode = !Mathf.Approximately(x.floatValue, y.floatValue) ||
|
||||||
|
!Mathf.Approximately(y.floatValue, z.floatValue) ||
|
||||||
|
y.hasMultipleDifferentValues ||
|
||||||
|
z.hasMultipleDifferentValues;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -180,7 +201,11 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
// Scale
|
// Scale
|
||||||
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
|
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
|
||||||
s_XYZMode = DrawFloatOrVector3Field(_scale3D, s_XYZMode);
|
if (DrawFloatOrVector3Field(_scale3D, _is3DScaleMode) != _is3DScaleMode)
|
||||||
|
{
|
||||||
|
State.instance.is3DScaleMode = _is3DScaleMode = !_is3DScaleMode;
|
||||||
|
}
|
||||||
|
|
||||||
EditorGUI.EndDisabledGroup();
|
EditorGUI.EndDisabledGroup();
|
||||||
|
|
||||||
// AnimatableProperties
|
// AnimatableProperties
|
||||||
@@ -221,6 +246,9 @@ namespace Coffee.UIExtensions
|
|||||||
_customViewSize.floatValue = Mathf.Max(0.1f, _customViewSize.floatValue);
|
_customViewSize.floatValue = Mathf.Max(0.1f, _customViewSize.floatValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Time Scale Multiplier
|
||||||
|
EditorGUILayout.PropertyField(_timeScaleMultiplier);
|
||||||
|
|
||||||
// Target ParticleSystems.
|
// Target ParticleSystems.
|
||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
_ro.DoLayoutList();
|
_ro.DoLayoutList();
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 418 B |
@@ -34,6 +34,7 @@ You can render, mask, and sort your `ParticleSystems` for UI without the need fo
|
|||||||
- [Usage with `Mask` or `RectMask2D` Component](#usage-with-mask-or-rectmask2d-component)
|
- [Usage with `Mask` or `RectMask2D` Component](#usage-with-mask-or-rectmask2d-component)
|
||||||
- [Usage with Script](#usage-with-script)
|
- [Usage with Script](#usage-with-script)
|
||||||
- [Component: UIParticleAttractor](#component-uiparticleattractor)
|
- [Component: UIParticleAttractor](#component-uiparticleattractor)
|
||||||
|
- [Project Settings](#project-settings)
|
||||||
- [🛠 Development Note](#-development-note)
|
- [🛠 Development Note](#-development-note)
|
||||||
- [Compares the Baking mesh approach with the conventional approach](#compares-the-baking-mesh-approach-with-the-conventional-approach)
|
- [Compares the Baking mesh approach with the conventional approach](#compares-the-baking-mesh-approach-with-the-conventional-approach)
|
||||||
- [Performance test results](#performance-test-results)
|
- [Performance test results](#performance-test-results)
|
||||||
@@ -143,7 +144,7 @@ _This package requires **Unity 2018.3 or later**._
|
|||||||
|
|
||||||
#### Install as Embedded Package
|
#### Install as Embedded Package
|
||||||
|
|
||||||
1. Download a source code zip file from [Releases](https://github.com/mob-sakai/ParticleEffectForUGUI.git/releases) and extract it.
|
1. Download a source code zip file from [Releases](https://github.com/mob-sakai/ParticleEffectForUGUI/releases) and extract it.
|
||||||
2. Place it in your project's `Packages` directory.
|
2. Place it in your project's `Packages` directory.
|
||||||

|

|
||||||
- If you want to fix bugs or add features, install it as an embedded package.
|
- If you want to fix bugs or add features, install it as an embedded package.
|
||||||
@@ -157,7 +158,7 @@ _This package requires **Unity 2018.3 or later**._
|
|||||||
|
|
||||||
`UIParticle` controls the ParticleSystems that are attached to its own game objects and child game objects.
|
`UIParticle` controls the ParticleSystems that are attached to its own game objects and child game objects.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- **Maskable**: Does this graphic allow maskable.
|
- **Maskable**: Does this graphic allow maskable.
|
||||||
- **Scale**: Scale the rendering particles. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.
|
- **Scale**: Scale the rendering particles. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.
|
||||||
@@ -179,6 +180,7 @@ _This package requires **Unity 2018.3 or later**._
|
|||||||
- **UIParticle:** UIParticle.scale will be adjusted.
|
- **UIParticle:** UIParticle.scale will be adjusted.
|
||||||
- **Use Custom View:** Use this if the particles are not displayed correctly due to min/max particle size.
|
- **Use Custom View:** Use this if the particles are not displayed correctly due to min/max particle size.
|
||||||
- **Custom view size:** Change the bake view size.
|
- **Custom view size:** Change the bake view size.
|
||||||
|
- **Time Scale Multiplier:** Time scale multiplier.
|
||||||
- **Rendering Order**: The ParticleSystem list to be rendered. You can change the order and the materials.
|
- **Rendering Order**: The ParticleSystem list to be rendered. You can change the order and the materials.
|
||||||
|
|
||||||
**NOTE:** Press the `Refresh` button to reconstruct the rendering order based on children ParticleSystem's sorting order
|
**NOTE:** Press the `Refresh` button to reconstruct the rendering order based on children ParticleSystem's sorting order
|
||||||
@@ -209,7 +211,7 @@ and z-position.
|
|||||||
If you want to mask particles, set a stencil-supported shader (such as `UI/UIAdditive`) to the material for
|
If you want to mask particles, set a stencil-supported shader (such as `UI/UIAdditive`) to the material for
|
||||||
ParticleSystem.
|
ParticleSystem.
|
||||||
If you use some custom shaders, see
|
If you use some custom shaders, see
|
||||||
the [How to Make a Custom Shader to Support Mask/RectMask2D Component](#how-to-make-a-custom-shader-to-support-maskrectmask2d-component)
|
the [How to Make a Custom Shader to Support Mask/RectMask2D Component](#how-to-make-a-custom-shader-to-support-mask-and-rectmask2d-component)
|
||||||
section.
|
section.
|
||||||
|
|
||||||

|

|
||||||
@@ -256,6 +258,14 @@ uiParticle.Stop();
|
|||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
|
### Project Settings
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- Click `Edit > Project Settings` to open the Project Settings window and then select `UI > UI Particle` category.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
## 🛠 Development Note
|
## 🛠 Development Note
|
||||||
|
|
||||||
### Compares the Baking mesh approach with the conventional approach
|
### Compares the Baking mesh approach with the conventional approach
|
||||||
|
|||||||
BIN
Packages/src/Runtime/Coffee.UIParticle.R.dll
Normal file
BIN
Packages/src/Runtime/Coffee.UIParticle.R.dll
Normal file
Binary file not shown.
33
Packages/src/Runtime/Coffee.UIParticle.R.dll.meta
Normal file
33
Packages/src/Runtime/Coffee.UIParticle.R.dll.meta
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4d73b3825bf044d418ae21bb331d3902
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 1
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
- first:
|
||||||
|
Windows Store Apps: WindowsStoreApps
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 7a55e246f37df405bac88eac692e3a86
|
guid: 53aa3f36032944b3fb1455e774c52396
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: b73940fc30a2f4eb9a73783e9c1f8da6
|
guid: 8cf8018dee45a4c42a19eec890eaa5b1
|
||||||
PrefabImporter:
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
134
Packages/src/Runtime/Internal/Extensions/CanvasExtensions.cs
Normal file
134
Packages/src/Runtime/Internal/Extensions/CanvasExtensions.cs
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
#if UNITY_2021_3_0 || UNITY_2021_3_1 || UNITY_2021_3_2 || UNITY_2021_3_3 || UNITY_2021_3_4 || UNITY_2021_3_5 || UNITY_2021_3_6 || UNITY_2021_3_7 || UNITY_2021_3_8 || UNITY_2021_3_9
|
||||||
|
#elif UNITY_2021_3_10 || UNITY_2021_3_11 || UNITY_2021_3_12 || UNITY_2021_3_13 || UNITY_2021_3_14 || UNITY_2021_3_15 || UNITY_2021_3_16 || UNITY_2021_3_17 || UNITY_2021_3_18 || UNITY_2021_3_19
|
||||||
|
#elif UNITY_2021_3_20 || UNITY_2021_3_21 || UNITY_2021_3_22 || UNITY_2021_3_23 || UNITY_2021_3_24 || UNITY_2021_3_25 || UNITY_2021_3_26 || UNITY_2021_3_27 || UNITY_2021_3_28 || UNITY_2021_3_29
|
||||||
|
#elif UNITY_2021_3_30 || UNITY_2021_3_31 || UNITY_2021_3_32 || UNITY_2021_3_33
|
||||||
|
#elif UNITY_2022_2_0 || UNITY_2022_2_1 || UNITY_2022_2_2 || UNITY_2022_2_3 || UNITY_2022_2_4 || UNITY_2022_2_5 || UNITY_2022_2_6 || UNITY_2022_2_7 || UNITY_2022_2_8 || UNITY_2022_2_9
|
||||||
|
#elif UNITY_2022_2_10 || UNITY_2022_2_11 || UNITY_2022_2_12 || UNITY_2022_2_13 || UNITY_2022_2_14
|
||||||
|
#elif UNITY_2021_3 || UNITY_2022_2 || UNITY_2022_3 || UNITY_2023_2_OR_NEWER
|
||||||
|
#define CANVAS_SUPPORT_ALWAYS_GAMMA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Profiling;
|
||||||
|
#if UNITY_MODULE_VR
|
||||||
|
using UnityEngine.XR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal static class CanvasExtensions
|
||||||
|
{
|
||||||
|
public static bool ShouldGammaToLinearInShader(this Canvas canvas)
|
||||||
|
{
|
||||||
|
return QualitySettings.activeColorSpace == ColorSpace.Linear &&
|
||||||
|
#if CANVAS_SUPPORT_ALWAYS_GAMMA
|
||||||
|
canvas.vertexColorAlwaysGammaSpace;
|
||||||
|
#else
|
||||||
|
false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ShouldGammaToLinearInMesh(this Canvas canvas)
|
||||||
|
{
|
||||||
|
return QualitySettings.activeColorSpace == ColorSpace.Linear &&
|
||||||
|
#if CANVAS_SUPPORT_ALWAYS_GAMMA
|
||||||
|
!canvas.vertexColorAlwaysGammaSpace;
|
||||||
|
#else
|
||||||
|
true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsStereoCanvas(this Canvas canvas)
|
||||||
|
{
|
||||||
|
#if UNITY_MODULE_VR
|
||||||
|
if (FrameCache.TryGet<bool>(canvas, nameof(IsStereoCanvas), out var stereo)) return stereo;
|
||||||
|
|
||||||
|
stereo =
|
||||||
|
canvas != null && canvas.renderMode != RenderMode.ScreenSpaceOverlay && canvas.worldCamera != null
|
||||||
|
&& XRSettings.enabled && !string.IsNullOrEmpty(XRSettings.loadedDeviceName);
|
||||||
|
FrameCache.Set(canvas, nameof(IsStereoCanvas), stereo);
|
||||||
|
return stereo;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the view-projection matrix for a Canvas.
|
||||||
|
/// </summary>
|
||||||
|
public static void GetViewProjectionMatrix(this Canvas canvas, out Matrix4x4 vpMatrix)
|
||||||
|
{
|
||||||
|
canvas.GetViewProjectionMatrix(Camera.MonoOrStereoscopicEye.Mono, out vpMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the view-projection matrix for a Canvas.
|
||||||
|
/// </summary>
|
||||||
|
public static void GetViewProjectionMatrix(this Canvas canvas, Camera.MonoOrStereoscopicEye eye,
|
||||||
|
out Matrix4x4 vpMatrix)
|
||||||
|
{
|
||||||
|
if (FrameCache.TryGet(canvas, nameof(GetViewProjectionMatrix), out vpMatrix)) return;
|
||||||
|
|
||||||
|
canvas.GetViewProjectionMatrix(eye, out var viewMatrix, out var projectionMatrix);
|
||||||
|
vpMatrix = viewMatrix * projectionMatrix;
|
||||||
|
FrameCache.Set(canvas, nameof(GetViewProjectionMatrix), vpMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the view and projection matrices for a Canvas.
|
||||||
|
/// </summary>
|
||||||
|
public static void GetViewProjectionMatrix(this Canvas canvas, out Matrix4x4 vMatrix, out Matrix4x4 pMatrix)
|
||||||
|
{
|
||||||
|
canvas.GetViewProjectionMatrix(Camera.MonoOrStereoscopicEye.Mono, out vMatrix, out pMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the view and projection matrices for a Canvas.
|
||||||
|
/// </summary>
|
||||||
|
public static void GetViewProjectionMatrix(this Canvas canvas, Camera.MonoOrStereoscopicEye eye,
|
||||||
|
out Matrix4x4 vMatrix, out Matrix4x4 pMatrix)
|
||||||
|
{
|
||||||
|
if (FrameCache.TryGet(canvas, "GetViewMatrix", (int)eye, out vMatrix) &&
|
||||||
|
FrameCache.TryGet(canvas, "GetProjectionMatrix", (int)eye, out pMatrix))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get view and projection matrices.
|
||||||
|
Profiler.BeginSample("(COF)[CanvasExt] GetViewProjectionMatrix");
|
||||||
|
var rootCanvas = canvas.rootCanvas;
|
||||||
|
var cam = rootCanvas.worldCamera;
|
||||||
|
if (rootCanvas && rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay && cam)
|
||||||
|
{
|
||||||
|
if (eye == Camera.MonoOrStereoscopicEye.Mono)
|
||||||
|
{
|
||||||
|
vMatrix = cam.worldToCameraMatrix;
|
||||||
|
pMatrix = GL.GetGPUProjectionMatrix(cam.projectionMatrix, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pMatrix = cam.GetStereoProjectionMatrix((Camera.StereoscopicEye)eye);
|
||||||
|
vMatrix = cam.GetStereoViewMatrix((Camera.StereoscopicEye)eye);
|
||||||
|
pMatrix = GL.GetGPUProjectionMatrix(pMatrix, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var pos = rootCanvas.transform.position;
|
||||||
|
vMatrix = Matrix4x4.TRS(
|
||||||
|
new Vector3(-pos.x, -pos.y, -1000),
|
||||||
|
Quaternion.identity,
|
||||||
|
new Vector3(1, 1, -1f));
|
||||||
|
pMatrix = Matrix4x4.TRS(
|
||||||
|
new Vector3(0, 0, -1),
|
||||||
|
Quaternion.identity,
|
||||||
|
new Vector3(1 / pos.x, 1 / pos.y, -2 / 10000f));
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameCache.Set(canvas, "GetViewMatrix", (int)eye, vMatrix);
|
||||||
|
FrameCache.Set(canvas, "GetProjectionMatrix", (int)eye, pMatrix);
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: b0beae5bb1cb142b9ab90dc0d371f026
|
guid: 9dd767b8c0f95478386e7d5079cd44df
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Profiling;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal static class Color32Extensions
|
||||||
|
{
|
||||||
|
private static readonly List<Color32> s_Colors = new List<Color32>();
|
||||||
|
private static byte[] s_LinearToGammaLut;
|
||||||
|
private static byte[] s_GammaToLinearLut;
|
||||||
|
|
||||||
|
public static byte LinearToGamma(this byte self)
|
||||||
|
{
|
||||||
|
if (s_LinearToGammaLut == null)
|
||||||
|
{
|
||||||
|
s_LinearToGammaLut = new byte[256];
|
||||||
|
for (var i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
s_LinearToGammaLut[i] = (byte)(Mathf.LinearToGammaSpace(i / 255f) * 255f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_LinearToGammaLut[self];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte GammaToLinear(this byte self)
|
||||||
|
{
|
||||||
|
if (s_GammaToLinearLut == null)
|
||||||
|
{
|
||||||
|
s_GammaToLinearLut = new byte[256];
|
||||||
|
for (var i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
s_GammaToLinearLut[i] = (byte)(Mathf.GammaToLinearSpace(i / 255f) * 255f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_GammaToLinearLut[self];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LinearToGamma(this Mesh self)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[ColorExt] LinearToGamma (Mesh)");
|
||||||
|
self.GetColors(s_Colors);
|
||||||
|
var count = s_Colors.Count;
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var c = s_Colors[i];
|
||||||
|
c.r = c.r.LinearToGamma();
|
||||||
|
c.g = c.g.LinearToGamma();
|
||||||
|
c.b = c.b.LinearToGamma();
|
||||||
|
s_Colors[i] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.SetColors(s_Colors);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GammaToLinear(this Mesh self)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[ColorExt] GammaToLinear (Mesh)");
|
||||||
|
self.GetColors(s_Colors);
|
||||||
|
var count = s_Colors.Count;
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var c = s_Colors[i];
|
||||||
|
c.r = c.r.GammaToLinear();
|
||||||
|
c.g = c.g.GammaToLinear();
|
||||||
|
c.b = c.b.GammaToLinear();
|
||||||
|
s_Colors[i] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.SetColors(s_Colors);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: d188d31b140094ebc84a9caafbc7ac71
|
guid: 0ef431b9df32c410ea5fa46be81def6b
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
227
Packages/src/Runtime/Internal/Extensions/ComponentExtensions.cs
Normal file
227
Packages/src/Runtime/Internal/Extensions/ComponentExtensions.cs
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Profiling;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for Component class.
|
||||||
|
/// </summary>
|
||||||
|
internal static class ComponentExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get components in children of a specific type in the hierarchy of a GameObject.
|
||||||
|
/// </summary>
|
||||||
|
public static T[] GetComponentsInChildren<T>(this Component self, int depth)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
var results = InternalListPool<T>.Rent();
|
||||||
|
self.GetComponentsInChildren_Internal(results, depth);
|
||||||
|
var array = results.ToArray();
|
||||||
|
InternalListPool<T>.Return(ref results);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get components in children of a specific type in the hierarchy of a GameObject.
|
||||||
|
/// </summary>
|
||||||
|
public static void GetComponentsInChildren<T>(this Component self, List<T> results, int depth)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
results.Clear();
|
||||||
|
self.GetComponentsInChildren_Internal(results, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetComponentsInChildren_Internal<T>(this Component self, List<T> results, int depth)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
if (!self || results == null || depth < 0) return;
|
||||||
|
|
||||||
|
var tr = self.transform;
|
||||||
|
if (tr.TryGetComponent<T>(out var t))
|
||||||
|
{
|
||||||
|
results.Add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depth - 1 < 0) return;
|
||||||
|
var childCount = tr.childCount;
|
||||||
|
for (var i = 0; i < childCount; i++)
|
||||||
|
{
|
||||||
|
tr.GetChild(i).GetComponentsInChildren_Internal(results, depth - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get or add a component of a specific type to a GameObject.
|
||||||
|
/// </summary>
|
||||||
|
public static T GetOrAddComponent<T>(this Component self) where T : Component
|
||||||
|
{
|
||||||
|
if (!self) return null;
|
||||||
|
return self.TryGetComponent<T>(out var component)
|
||||||
|
? component
|
||||||
|
: self.gameObject.AddComponent<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the root component of a specific type in the hierarchy of a GameObject.
|
||||||
|
/// </summary>
|
||||||
|
public static T GetRootComponent<T>(this Component self) where T : Component
|
||||||
|
{
|
||||||
|
T component = null;
|
||||||
|
var transform = self.transform;
|
||||||
|
while (transform)
|
||||||
|
{
|
||||||
|
if (transform.TryGetComponent<T>(out var c))
|
||||||
|
{
|
||||||
|
component = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
transform = transform.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a component of a specific type in the parent hierarchy of a GameObject.
|
||||||
|
/// </summary>
|
||||||
|
public static T GetComponentInParent<T>(this Component self, bool includeSelf, Transform stopAfter,
|
||||||
|
Predicate<T> valid)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
var tr = includeSelf ? self.transform : self.transform.parent;
|
||||||
|
while (tr)
|
||||||
|
{
|
||||||
|
if (tr.TryGetComponent<T>(out var c) && valid(c)) return c;
|
||||||
|
if (tr == stopAfter) return null;
|
||||||
|
tr = tr.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a component of a specific type to the children of a GameObject.
|
||||||
|
/// </summary>
|
||||||
|
public static void AddComponentOnChildren<T>(this Component self, HideFlags hideFlags, bool includeSelf)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
if (self == null) return;
|
||||||
|
|
||||||
|
Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Self");
|
||||||
|
if (includeSelf && !self.TryGetComponent<T>(out _))
|
||||||
|
{
|
||||||
|
var c = self.gameObject.AddComponent<T>();
|
||||||
|
c.hideFlags = hideFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
|
||||||
|
Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Child");
|
||||||
|
var childCount = self.transform.childCount;
|
||||||
|
for (var i = 0; i < childCount; i++)
|
||||||
|
{
|
||||||
|
var child = self.transform.GetChild(i);
|
||||||
|
if (child.TryGetComponent<T>(out _)) continue;
|
||||||
|
|
||||||
|
var c = child.gameObject.AddComponent<T>();
|
||||||
|
c.hideFlags = hideFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a component of a specific type to the children of a GameObject.
|
||||||
|
/// </summary>
|
||||||
|
public static void AddComponentOnChildren<T>(this Component self, bool includeSelf)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
if (self == null) return;
|
||||||
|
|
||||||
|
Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Self");
|
||||||
|
if (includeSelf && !self.TryGetComponent<T>(out _))
|
||||||
|
{
|
||||||
|
self.gameObject.AddComponent<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
|
||||||
|
Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Child");
|
||||||
|
var childCount = self.transform.childCount;
|
||||||
|
for (var i = 0; i < childCount; i++)
|
||||||
|
{
|
||||||
|
var child = self.transform.GetChild(i);
|
||||||
|
if (child.TryGetComponent<T>(out _)) continue;
|
||||||
|
|
||||||
|
child.gameObject.AddComponent<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !UNITY_2021_2_OR_NEWER && !UNITY_2020_3_45 && !UNITY_2020_3_46 && !UNITY_2020_3_47 && !UNITY_2020_3_48
|
||||||
|
public static T GetComponentInParent<T>(this Component self, bool includeInactive) where T : Component
|
||||||
|
{
|
||||||
|
if (!self) return null;
|
||||||
|
if (!includeInactive) return self.GetComponentInParent<T>();
|
||||||
|
|
||||||
|
var current = self.transform;
|
||||||
|
while (current)
|
||||||
|
{
|
||||||
|
if (current.TryGetComponent<T>(out var c)) return c;
|
||||||
|
current = current.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
/// <summary>
|
||||||
|
/// Verify whether it can be converted to the specified component.
|
||||||
|
/// </summary>
|
||||||
|
internal static bool CanConvertTo<T>(this Object context) where T : MonoBehaviour
|
||||||
|
{
|
||||||
|
return context && context.GetType() != typeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert to the specified component.
|
||||||
|
/// </summary>
|
||||||
|
internal static void ConvertTo<T>(this Object context) where T : MonoBehaviour
|
||||||
|
{
|
||||||
|
var target = context as MonoBehaviour;
|
||||||
|
if (target == null) return;
|
||||||
|
|
||||||
|
var so = new SerializedObject(target);
|
||||||
|
so.Update();
|
||||||
|
|
||||||
|
var oldEnable = target.enabled;
|
||||||
|
target.enabled = false;
|
||||||
|
|
||||||
|
// Find MonoScript of the specified component.
|
||||||
|
foreach (var script in MonoImporter.GetAllRuntimeMonoScripts())
|
||||||
|
{
|
||||||
|
if (script.GetClass() != typeof(T))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set 'm_Script' to convert.
|
||||||
|
so.FindProperty("m_Script").objectReferenceValue = script;
|
||||||
|
so.ApplyModifiedProperties();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (so.targetObject is MonoBehaviour mb)
|
||||||
|
{
|
||||||
|
mb.enabled = oldEnable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8455ee485a5ee4cacbdf558f66af65fb
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
60
Packages/src/Runtime/Internal/Extensions/SpriteExtensions.cs
Normal file
60
Packages/src/Runtime/Internal/Extensions/SpriteExtensions.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.U2D;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
using System.Reflection;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for Sprite class.
|
||||||
|
/// </summary>
|
||||||
|
internal static class SpriteExtensions
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
private static readonly Type s_SpriteEditorExtensionType =
|
||||||
|
Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
|
||||||
|
?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor");
|
||||||
|
|
||||||
|
private static readonly Func<Sprite, Texture2D> s_GetActiveAtlasTextureMethod =
|
||||||
|
(Func<Sprite, Texture2D>)Delegate.CreateDelegate(typeof(Func<Sprite, Texture2D>),
|
||||||
|
s_SpriteEditorExtensionType
|
||||||
|
.GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic));
|
||||||
|
|
||||||
|
private static readonly Func<Sprite, SpriteAtlas> s_GetActiveAtlasMethod =
|
||||||
|
(Func<Sprite, SpriteAtlas>)Delegate.CreateDelegate(typeof(Func<Sprite, SpriteAtlas>),
|
||||||
|
s_SpriteEditorExtensionType
|
||||||
|
.GetMethod("GetActiveAtlas", BindingFlags.Static | BindingFlags.NonPublic));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the actual texture of a sprite in play mode or edit mode.
|
||||||
|
/// </summary>
|
||||||
|
public static Texture2D GetActualTexture(this Sprite self)
|
||||||
|
{
|
||||||
|
if (!self) return null;
|
||||||
|
|
||||||
|
var ret = s_GetActiveAtlasTextureMethod(self);
|
||||||
|
return ret ? ret : self.texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the active sprite atlas of a sprite in play mode or edit mode.
|
||||||
|
/// </summary>
|
||||||
|
public static SpriteAtlas GetActiveAtlas(this Sprite self)
|
||||||
|
{
|
||||||
|
if (!self) return null;
|
||||||
|
|
||||||
|
return s_GetActiveAtlasMethod(self);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/// <summary>
|
||||||
|
/// Get the actual texture of a sprite in play mode.
|
||||||
|
/// </summary>
|
||||||
|
internal static Texture2D GetActualTexture(this Sprite self)
|
||||||
|
{
|
||||||
|
return self ? self.texture : null;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a7a2e11131111447cb7fc0394a14da65
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal static class Vector3Extensions
|
||||||
|
{
|
||||||
|
public static Vector3 Inverse(this Vector3 self)
|
||||||
|
{
|
||||||
|
self.x = Mathf.Approximately(self.x, 0) ? 1 : 1 / self.x;
|
||||||
|
self.y = Mathf.Approximately(self.y, 0) ? 1 : 1 / self.y;
|
||||||
|
self.z = Mathf.Approximately(self.z, 0) ? 1 : 1 / self.z;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 GetScaled(this Vector3 self, Vector3 other1)
|
||||||
|
{
|
||||||
|
self.Scale(other1);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2)
|
||||||
|
{
|
||||||
|
self.Scale(other1);
|
||||||
|
self.Scale(other2);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2, Vector3 other3)
|
||||||
|
{
|
||||||
|
self.Scale(other1);
|
||||||
|
self.Scale(other2);
|
||||||
|
self.Scale(other3);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsVisible(this Vector3 self)
|
||||||
|
{
|
||||||
|
return 0 < Mathf.Abs(self.x * self.y * self.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsVisible2D(this Vector3 self)
|
||||||
|
{
|
||||||
|
return 0 < Mathf.Abs(self.x * self.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6a7b5fb989e4b48c8bc7ecce834060f5
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Packages/src/Runtime/Internal/ProjectSettings.meta
Normal file
8
Packages/src/Runtime/Internal/ProjectSettings.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 398e06c9985ad4291a95f0749c2927fb
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
using System.IO;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Build;
|
||||||
|
using UnityEditor.Build.Reporting;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
public abstract class PreloadedProjectSettings : ScriptableObject
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
{
|
||||||
|
private class Postprocessor : AssetPostprocessor
|
||||||
|
{
|
||||||
|
private static void OnPostprocessAllAssets(string[] _, string[] __, string[] ___, string[] ____)
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PreprocessBuildWithReport : IPreprocessBuildWithReport
|
||||||
|
{
|
||||||
|
int IOrderedCallback.callbackOrder => 0;
|
||||||
|
|
||||||
|
void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Initialize()
|
||||||
|
{
|
||||||
|
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
|
||||||
|
{
|
||||||
|
var defaultSettings = GetDefaultSettings(t);
|
||||||
|
if (!defaultSettings)
|
||||||
|
{
|
||||||
|
// When create a new instance, automatically set it as default settings.
|
||||||
|
defaultSettings = CreateInstance(t) as PreloadedProjectSettings;
|
||||||
|
SetDefaultSettings(defaultSettings);
|
||||||
|
}
|
||||||
|
else if (GetPreloadedSettings(t).Length != 1)
|
||||||
|
{
|
||||||
|
SetDefaultSettings(defaultSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defaultSettings)
|
||||||
|
{
|
||||||
|
defaultSettings.OnInitialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static string GetDefaultName(Type type, bool nicify)
|
||||||
|
{
|
||||||
|
var typeName = type.Name;
|
||||||
|
return nicify
|
||||||
|
? ObjectNames.NicifyVariableName(typeName)
|
||||||
|
: typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object[] GetPreloadedSettings(Type type)
|
||||||
|
{
|
||||||
|
return PlayerSettings.GetPreloadedAssets()
|
||||||
|
.Where(x => x && x.GetType() == type)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static PreloadedProjectSettings GetDefaultSettings(Type type)
|
||||||
|
{
|
||||||
|
return GetPreloadedSettings(type).FirstOrDefault() as PreloadedProjectSettings
|
||||||
|
?? AssetDatabase.FindAssets($"t:{nameof(PreloadedProjectSettings)}")
|
||||||
|
.Select(AssetDatabase.GUIDToAssetPath)
|
||||||
|
.Select(AssetDatabase.LoadAssetAtPath<PreloadedProjectSettings>)
|
||||||
|
.FirstOrDefault(x => x && x.GetType() == type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void SetDefaultSettings(PreloadedProjectSettings asset)
|
||||||
|
{
|
||||||
|
if (!asset) return;
|
||||||
|
|
||||||
|
var type = asset.GetType();
|
||||||
|
if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(asset)))
|
||||||
|
{
|
||||||
|
if (!AssetDatabase.IsValidFolder("Assets/ProjectSettings"))
|
||||||
|
{
|
||||||
|
AssetDatabase.CreateFolder("Assets", "ProjectSettings");
|
||||||
|
}
|
||||||
|
|
||||||
|
var assetPath = $"Assets/ProjectSettings/{GetDefaultName(type, false)}.asset";
|
||||||
|
assetPath = AssetDatabase.GenerateUniqueAssetPath(assetPath);
|
||||||
|
if (!File.Exists(assetPath))
|
||||||
|
{
|
||||||
|
AssetDatabase.CreateAsset(asset, assetPath);
|
||||||
|
asset.OnCreateAsset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
|
||||||
|
var projectSettings = GetPreloadedSettings(type);
|
||||||
|
PlayerSettings.SetPreloadedAssets(preloadedAssets
|
||||||
|
.Where(x => x)
|
||||||
|
.Except(projectSettings.Except(new[] { asset }))
|
||||||
|
.Append(asset)
|
||||||
|
.Distinct()
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnCreateAsset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnInitialize()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public abstract class PreloadedProjectSettings<T> : PreloadedProjectSettings
|
||||||
|
where T : PreloadedProjectSettings<T>
|
||||||
|
{
|
||||||
|
private static T s_Instance;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
private string _jsonText;
|
||||||
|
|
||||||
|
public static bool hasInstance => s_Instance;
|
||||||
|
|
||||||
|
public static T instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (s_Instance) return s_Instance;
|
||||||
|
|
||||||
|
s_Instance = GetDefaultSettings(typeof(T)) as T;
|
||||||
|
if (s_Instance) return s_Instance;
|
||||||
|
|
||||||
|
s_Instance = CreateInstance<T>();
|
||||||
|
if (!s_Instance)
|
||||||
|
{
|
||||||
|
s_Instance = null;
|
||||||
|
return s_Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDefaultSettings(s_Instance);
|
||||||
|
return s_Instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case PlayModeStateChange.ExitingEditMode:
|
||||||
|
_jsonText = EditorJsonUtility.ToJson(this);
|
||||||
|
break;
|
||||||
|
case PlayModeStateChange.ExitingPlayMode:
|
||||||
|
if (_jsonText != null)
|
||||||
|
{
|
||||||
|
EditorJsonUtility.FromJsonOverwrite(_jsonText, this);
|
||||||
|
_jsonText = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
public static T instance => s_Instance ? s_Instance : s_Instance = CreateInstance<T>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This function is called when the object becomes enabled and active.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnEnable()
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
var isDefaultSettings = !s_Instance || s_Instance == this || GetDefaultSettings(typeof(T)) == this;
|
||||||
|
if (!isDefaultSettings)
|
||||||
|
{
|
||||||
|
DestroyImmediate(this, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (s_Instance) return;
|
||||||
|
s_Instance = this as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This function is called when the behaviour becomes disabled.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnDisable()
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
|
||||||
|
#endif
|
||||||
|
if (s_Instance != this) return;
|
||||||
|
|
||||||
|
s_Instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
protected sealed class PreloadedProjectSettingsProvider : SettingsProvider
|
||||||
|
{
|
||||||
|
private Editor _editor;
|
||||||
|
private PreloadedProjectSettings<T> _target;
|
||||||
|
|
||||||
|
public PreloadedProjectSettingsProvider(string path) : base(path, SettingsScope.Project)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnGUI(string searchContext)
|
||||||
|
{
|
||||||
|
if (!_target)
|
||||||
|
{
|
||||||
|
if (_editor)
|
||||||
|
{
|
||||||
|
DestroyImmediate(_editor);
|
||||||
|
_editor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_target = instance;
|
||||||
|
_editor = Editor.CreateEditor(_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
_editor.OnInspectorGUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 790ea008741dc411497c8794745319eb
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Packages/src/Runtime/Internal/Utilities.meta
Normal file
8
Packages/src/Runtime/Internal/Utilities.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1b2877595f27c4a70a426991d515434f
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
89
Packages/src/Runtime/Internal/Utilities/FastAction.cs
Executable file
89
Packages/src/Runtime/Internal/Utilities/FastAction.cs
Executable file
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Profiling;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for a fast action.
|
||||||
|
/// </summary>
|
||||||
|
internal class FastActionBase<T>
|
||||||
|
{
|
||||||
|
private static readonly InternalObjectPool<LinkedListNode<T>> s_NodePool =
|
||||||
|
new InternalObjectPool<LinkedListNode<T>>(() => new LinkedListNode<T>(default), _ => true,
|
||||||
|
x => x.Value = default);
|
||||||
|
|
||||||
|
private readonly LinkedList<T> _delegates = new LinkedList<T>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a delegate to the action.
|
||||||
|
/// </summary>
|
||||||
|
public void Add(T rhs)
|
||||||
|
{
|
||||||
|
if (rhs == null) return;
|
||||||
|
Profiler.BeginSample("(COF)[FastAction] Add Action");
|
||||||
|
var node = s_NodePool.Rent();
|
||||||
|
node.Value = rhs;
|
||||||
|
_delegates.AddLast(node);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a delegate from the action.
|
||||||
|
/// </summary>
|
||||||
|
public void Remove(T rhs)
|
||||||
|
{
|
||||||
|
if (rhs == null) return;
|
||||||
|
Profiler.BeginSample("(COF)[FastAction] Remove Action");
|
||||||
|
var node = _delegates.Find(rhs);
|
||||||
|
if (node != null)
|
||||||
|
{
|
||||||
|
_delegates.Remove(node);
|
||||||
|
s_NodePool.Return(ref node);
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the action with a callback function.
|
||||||
|
/// </summary>
|
||||||
|
protected void Invoke(Action<T> callback)
|
||||||
|
{
|
||||||
|
var node = _delegates.First;
|
||||||
|
while (node != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
callback(node.Value);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.LogException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
node = node.Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_delegates.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A fast action without parameters.
|
||||||
|
/// </summary>
|
||||||
|
internal class FastAction : FastActionBase<Action>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invoke all the registered delegates.
|
||||||
|
/// </summary>
|
||||||
|
public void Invoke()
|
||||||
|
{
|
||||||
|
Invoke(action => action.Invoke());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/Internal/Utilities/FastAction.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/FastAction.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a7c8c268a827b4787a8e050f1fe95ad5
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
101
Packages/src/Runtime/Internal/Utilities/FrameCache.cs
Normal file
101
Packages/src/Runtime/Internal/Utilities/FrameCache.cs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal static class FrameCache
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<Type, IFrameCache> s_Caches = new Dictionary<Type, IFrameCache>();
|
||||||
|
|
||||||
|
static FrameCache()
|
||||||
|
{
|
||||||
|
s_Caches.Clear();
|
||||||
|
UIExtraCallbacks.onLateAfterCanvasRebuild += ClearAllCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
|
private static void Clear()
|
||||||
|
{
|
||||||
|
s_Caches.Clear();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to retrieve a value from the frame cache with a specified key.
|
||||||
|
/// </summary>
|
||||||
|
public static bool TryGet<T>(object key1, string key2, out T result)
|
||||||
|
{
|
||||||
|
return GetFrameCache<T>().TryGet((key1.GetHashCode(), key2.GetHashCode()), out result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to retrieve a value from the frame cache with a specified key.
|
||||||
|
/// </summary>
|
||||||
|
public static bool TryGet<T>(object key1, string key2, int key3, out T result)
|
||||||
|
{
|
||||||
|
return GetFrameCache<T>().TryGet((key1.GetHashCode(), key2.GetHashCode() + key3), out result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets a value in the frame cache with a specified key.
|
||||||
|
/// </summary>
|
||||||
|
public static void Set<T>(object key1, string key2, T result)
|
||||||
|
{
|
||||||
|
GetFrameCache<T>().Set((key1.GetHashCode(), key2.GetHashCode()), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets a value in the frame cache with a specified key.
|
||||||
|
/// </summary>
|
||||||
|
public static void Set<T>(object key1, string key2, int key3, T result)
|
||||||
|
{
|
||||||
|
GetFrameCache<T>().Set((key1.GetHashCode(), key2.GetHashCode() + key3), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ClearAllCache()
|
||||||
|
{
|
||||||
|
foreach (var cache in s_Caches.Values)
|
||||||
|
{
|
||||||
|
cache.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FrameCacheContainer<T> GetFrameCache<T>()
|
||||||
|
{
|
||||||
|
var t = typeof(T);
|
||||||
|
if (s_Caches.TryGetValue(t, out var frameCache)) return frameCache as FrameCacheContainer<T>;
|
||||||
|
|
||||||
|
frameCache = new FrameCacheContainer<T>();
|
||||||
|
s_Caches.Add(t, frameCache);
|
||||||
|
|
||||||
|
return (FrameCacheContainer<T>)frameCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface IFrameCache
|
||||||
|
{
|
||||||
|
void Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FrameCacheContainer<T> : IFrameCache
|
||||||
|
{
|
||||||
|
private readonly Dictionary<(int, int), T> _caches = new Dictionary<(int, int), T>();
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_caches.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGet((int, int) key, out T result)
|
||||||
|
{
|
||||||
|
return _caches.TryGetValue(key, out result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set((int, int) key, T result)
|
||||||
|
{
|
||||||
|
_caches[key] = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/Internal/Utilities/FrameCache.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/FrameCache.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5f129e3b07ffb4d3bbb4cc5f6bd94087
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
254
Packages/src/Runtime/Internal/Utilities/Logging.cs
Normal file
254
Packages/src/Runtime/Internal/Utilities/Logging.cs
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
#else
|
||||||
|
using Conditional = System.Diagnostics.ConditionalAttribute;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal static class Logging
|
||||||
|
{
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
private const string k_DisableSymbol = "DISABLE_COFFEE_LOGGER";
|
||||||
|
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
private static void Log_Internal(LogType type, object tag, object message, Object context)
|
||||||
|
{
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
AppendTag(s_Sb, tag);
|
||||||
|
s_Sb.Append(message);
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case LogType.Error:
|
||||||
|
case LogType.Assert:
|
||||||
|
case LogType.Exception:
|
||||||
|
Debug.LogError(s_Sb, context);
|
||||||
|
break;
|
||||||
|
case LogType.Warning:
|
||||||
|
Debug.LogWarning(s_Sb, context);
|
||||||
|
break;
|
||||||
|
case LogType.Log:
|
||||||
|
Debug.Log(s_Sb, context);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_Sb.Length = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
public static void LogIf(bool enable, object tag, object message, Object context = null)
|
||||||
|
{
|
||||||
|
if (!enable) return;
|
||||||
|
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
public static void Log(object tag, object message, Object context = null)
|
||||||
|
{
|
||||||
|
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
public static void LogWarning(object tag, object message, Object context = null)
|
||||||
|
{
|
||||||
|
Log_Internal(LogType.Warning, tag, message, context ? context : tag as Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogError(object tag, object message, Object context = null)
|
||||||
|
{
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
Log_Internal(LogType.Error, tag, message, context ? context : tag as Object);
|
||||||
|
#else
|
||||||
|
Debug.LogError($"{tag}: {message}", context);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
public static void LogMulticast(Type type, string fieldName, object instance = null, string message = null)
|
||||||
|
{
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
AppendTag(s_Sb, instance ?? type);
|
||||||
|
|
||||||
|
var handler = type
|
||||||
|
.GetField(fieldName,
|
||||||
|
BindingFlags.Static | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic)
|
||||||
|
?.GetValue(instance);
|
||||||
|
|
||||||
|
var list = ((MulticastDelegate)handler)?.GetInvocationList() ?? Array.Empty<Delegate>();
|
||||||
|
s_Sb.Append("<color=orange>");
|
||||||
|
s_Sb.Append(type.Name);
|
||||||
|
s_Sb.Append(".");
|
||||||
|
s_Sb.Append(fieldName);
|
||||||
|
s_Sb.Append(" has ");
|
||||||
|
s_Sb.Append(list.Length);
|
||||||
|
s_Sb.Append(" callbacks");
|
||||||
|
if (message != null)
|
||||||
|
{
|
||||||
|
s_Sb.Append(" (");
|
||||||
|
s_Sb.Append(message);
|
||||||
|
s_Sb.Append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
s_Sb.Append(":</color>");
|
||||||
|
|
||||||
|
for (var i = 0; i < list.Length; i++)
|
||||||
|
{
|
||||||
|
s_Sb.Append("\n - ");
|
||||||
|
s_Sb.Append(list[i].Method.DeclaringType?.Name);
|
||||||
|
s_Sb.Append(".");
|
||||||
|
s_Sb.Append(list[i].Method.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log(s_Sb);
|
||||||
|
s_Sb.Length = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
private static void AppendTag(StringBuilder sb, object tag)
|
||||||
|
{
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sb.Append("f");
|
||||||
|
sb.Append(Time.frameCount);
|
||||||
|
sb.Append(":<color=#");
|
||||||
|
AppendReadableCode(sb, tag);
|
||||||
|
sb.Append("><b>[");
|
||||||
|
|
||||||
|
switch (tag)
|
||||||
|
{
|
||||||
|
case string name:
|
||||||
|
sb.Append(name);
|
||||||
|
break;
|
||||||
|
case Type type:
|
||||||
|
AppendType(sb, type);
|
||||||
|
break;
|
||||||
|
case Object uObject:
|
||||||
|
AppendType(sb, tag.GetType());
|
||||||
|
sb.Append(" #");
|
||||||
|
sb.Append(uObject.name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
AppendType(sb, tag.GetType());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append("]</b></color> ");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
sb.Append("f");
|
||||||
|
sb.Append(Time.frameCount);
|
||||||
|
sb.Append(":<b>[");
|
||||||
|
sb.Append(tag);
|
||||||
|
sb.Append("]</b> ");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
private static void AppendType(StringBuilder sb, Type type)
|
||||||
|
{
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
if (s_TypeNameCache.TryGetValue(type, out var name))
|
||||||
|
{
|
||||||
|
sb.Append(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// New type found
|
||||||
|
var start = sb.Length;
|
||||||
|
if (0 < start && sb[start - 1] == '<' && (type.Name == "Material" || type.Name == "Color"))
|
||||||
|
{
|
||||||
|
sb.Append('@');
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(type.Name);
|
||||||
|
if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
sb.Length -= 2;
|
||||||
|
sb.Append("<");
|
||||||
|
foreach (var gType in type.GetGenericArguments())
|
||||||
|
{
|
||||||
|
AppendType(sb, gType);
|
||||||
|
sb.Append(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Length -= 2;
|
||||||
|
sb.Append(">");
|
||||||
|
}
|
||||||
|
|
||||||
|
s_TypeNameCache.Add(type, sb.ToString(start, sb.Length - start));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !ENABLE_COFFEE_LOGGER
|
||||||
|
[Conditional(k_DisableSymbol)]
|
||||||
|
#endif
|
||||||
|
private static void AppendReadableCode(StringBuilder sb, object tag)
|
||||||
|
{
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
int hash;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (tag)
|
||||||
|
{
|
||||||
|
case string text:
|
||||||
|
hash = text.GetHashCode();
|
||||||
|
break;
|
||||||
|
case Type type:
|
||||||
|
type = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
|
||||||
|
hash = type.FullName?.GetHashCode() ?? 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
hash = tag.GetType().FullName?.GetHashCode() ?? 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
sb.Append("FFFFFF");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = hash & (s_Codes.Length - 1);
|
||||||
|
if (s_Codes[hash] == null)
|
||||||
|
{
|
||||||
|
var hue = hash / (float)s_Codes.Length;
|
||||||
|
var modifier = 1f - Mathf.Clamp01(Mathf.Abs(hue - 0.65f) / 0.2f);
|
||||||
|
var saturation = 0.7f + modifier * -0.2f;
|
||||||
|
var value = 0.8f + modifier * 0.3f;
|
||||||
|
s_Codes[hash] = ColorUtility.ToHtmlStringRGB(Color.HSVToRGB(hue, saturation, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(s_Codes[hash]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_COFFEE_LOGGER
|
||||||
|
private static readonly StringBuilder s_Sb = new StringBuilder();
|
||||||
|
private static readonly string[] s_Codes = new string[64];
|
||||||
|
private static readonly Dictionary<Type, string> s_TypeNameCache = new Dictionary<Type, string>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/Internal/Utilities/Logging.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/Logging.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8255313895da84e7cbdc876be3795334
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Profiling;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides functionality to manage materials.
|
||||||
|
/// </summary>
|
||||||
|
internal static class MaterialRepository
|
||||||
|
{
|
||||||
|
private static readonly ObjectRepository<Material> s_Repository = new ObjectRepository<Material>();
|
||||||
|
|
||||||
|
public static int count => s_Repository.count;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
|
public static void Clear()
|
||||||
|
{
|
||||||
|
s_Repository.Clear();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a cached material based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
public static bool Valid(Hash128 hash, Material material)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[MaterialRegistry] Valid");
|
||||||
|
var ret = s_Repository.Valid(hash, material);
|
||||||
|
Profiler.EndSample();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or retrieves a cached material based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
public static void Get(Hash128 hash, ref Material material, Func<Material> onCreate)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||||
|
s_Repository.Get(hash, ref material, onCreate);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or retrieves a cached material based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
public static void Get(Hash128 hash, ref Material material, string shaderName)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||||
|
s_Repository.Get(hash, ref material, x => new Material(Shader.Find(x))
|
||||||
|
{
|
||||||
|
hideFlags = HideFlags.DontSave | HideFlags.NotEditable
|
||||||
|
}, shaderName);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or retrieves a cached material based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
public static void Get(Hash128 hash, ref Material material, string shaderName, string[] keywords)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||||
|
s_Repository.Get(hash, ref material, x => new Material(Shader.Find(x.shaderName))
|
||||||
|
{
|
||||||
|
hideFlags = HideFlags.DontSave | HideFlags.NotEditable,
|
||||||
|
shaderKeywords = x.keywords
|
||||||
|
}, (shaderName, keywords));
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or retrieves a cached material based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
public static void Get<T>(Hash128 hash, ref Material material, Func<T, Material> onCreate, T source)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||||
|
s_Repository.Get(hash, ref material, onCreate, source);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a soft mask material from the cache.
|
||||||
|
/// </summary>
|
||||||
|
public static void Release(ref Material material)
|
||||||
|
{
|
||||||
|
Profiler.BeginSample("(COF)[MaterialRepository] Release");
|
||||||
|
s_Repository.Release(ref material);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 702912f2ee2ec49bb8003a64151ae4f7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
132
Packages/src/Runtime/Internal/Utilities/Misc.cs
Normal file
132
Packages/src/Runtime/Internal/Utilities/Misc.cs
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
#if UNITY_2021_2_OR_NEWER
|
||||||
|
using UnityEditor.SceneManagement;
|
||||||
|
#else
|
||||||
|
using UnityEditor.Experimental.SceneManagement;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal static class Misc
|
||||||
|
{
|
||||||
|
public static T[] FindObjectsOfType<T>() where T : Object
|
||||||
|
{
|
||||||
|
#if UNITY_2023_1_OR_NEWER
|
||||||
|
return Object.FindObjectsByType<T>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||||
|
#else
|
||||||
|
return Object.FindObjectsOfType<T>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Destroy(Object obj)
|
||||||
|
{
|
||||||
|
if (!obj) return;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (!Application.isPlaying)
|
||||||
|
{
|
||||||
|
Object.DestroyImmediate(obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Object.Destroy(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DestroyImmediate(Object obj)
|
||||||
|
{
|
||||||
|
if (!obj) return;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (Application.isEditor)
|
||||||
|
{
|
||||||
|
Object.DestroyImmediate(obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Object.Destroy(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Conditional("UNITY_EDITOR")]
|
||||||
|
public static void SetDirty(Object obj)
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (!obj) return;
|
||||||
|
EditorUtility.SetDirty(obj);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
public static T[] GetAllComponentsInPrefabStage<T>() where T : Component
|
||||||
|
{
|
||||||
|
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||||
|
if (prefabStage == null) return Array.Empty<T>();
|
||||||
|
|
||||||
|
return prefabStage.prefabContentsRoot.GetComponentsInChildren<T>(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool isBatchOrBuilding => Application.isBatchMode || BuildPipeline.isBuildingPlayer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[Conditional("UNITY_EDITOR")]
|
||||||
|
public static void QueuePlayerLoopUpdate()
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (!EditorApplication.isPlaying)
|
||||||
|
{
|
||||||
|
EditorApplication.QueuePlayerLoopUpdate();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !UNITY_2021_2_OR_NEWER
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
[Conditional("UNITY_EDITOR")]
|
||||||
|
internal class IconAttribute : Attribute
|
||||||
|
{
|
||||||
|
private readonly string _path;
|
||||||
|
|
||||||
|
public IconAttribute(string path)
|
||||||
|
{
|
||||||
|
_path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
private static Action<Object, Texture2D> s_SetIconForObject = typeof(EditorGUIUtility)
|
||||||
|
.GetMethod("SetIconForObject", BindingFlags.Static | BindingFlags.NonPublic)
|
||||||
|
.CreateDelegate(typeof(Action<Object, Texture2D>), null) as Action<Object, Texture2D>;
|
||||||
|
|
||||||
|
[InitializeOnLoadMethod]
|
||||||
|
private static void InitializeOnLoadMethod()
|
||||||
|
{
|
||||||
|
if (Misc.isBatchOrBuilding) return;
|
||||||
|
|
||||||
|
var types = TypeCache.GetTypesWithAttribute<IconAttribute>();
|
||||||
|
var scripts = MonoImporter.GetAllRuntimeMonoScripts();
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
var script = scripts.FirstOrDefault(x => x.GetClass() == type);
|
||||||
|
if (!script) continue;
|
||||||
|
|
||||||
|
var path = type.GetCustomAttribute<IconAttribute>()?._path;
|
||||||
|
var icon = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
|
||||||
|
if (!icon) continue;
|
||||||
|
|
||||||
|
s_SetIconForObject(script, icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/Internal/Utilities/Misc.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/Misc.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 182319ecc315e4858b119764af0fbcb0
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
154
Packages/src/Runtime/Internal/Utilities/ObjectPool.cs
Normal file
154
Packages/src/Runtime/Internal/Utilities/ObjectPool.cs
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Object pool.
|
||||||
|
/// </summary>
|
||||||
|
internal class InternalObjectPool<T> where T : class
|
||||||
|
{
|
||||||
|
#if UNITY_2021_1_OR_NEWER
|
||||||
|
private readonly Predicate<T> _onValid; // Delegate for checking if instances are valid
|
||||||
|
private readonly UnityEngine.Pool.ObjectPool<T> _pool;
|
||||||
|
|
||||||
|
public InternalObjectPool(Func<T> onCreate, Predicate<T> onValid, Action<T> onReturn)
|
||||||
|
{
|
||||||
|
_pool = new UnityEngine.Pool.ObjectPool<T>(onCreate, null, onReturn);
|
||||||
|
_onValid = onValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rent an instance from the pool.
|
||||||
|
/// When you no longer need it, return it with <see cref="Return" />.
|
||||||
|
/// </summary>
|
||||||
|
public T Rent()
|
||||||
|
{
|
||||||
|
while (0 < _pool.CountInactive)
|
||||||
|
{
|
||||||
|
var instance = _pool.Get();
|
||||||
|
if (_onValid(instance))
|
||||||
|
{
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no instances in the pool, create a new one.
|
||||||
|
Logging.Log(this, $"A new instance is created (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
|
||||||
|
return _pool.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return an instance to the pool and assign null.
|
||||||
|
/// Be sure to return the instance obtained with <see cref="Rent" /> with this method.
|
||||||
|
/// </summary>
|
||||||
|
public void Return(ref T instance)
|
||||||
|
{
|
||||||
|
if (instance == null) return; // Ignore if already pooled or null.
|
||||||
|
|
||||||
|
_pool.Release(instance);
|
||||||
|
Logging.Log(this, $"An instance is released (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
|
||||||
|
instance = default; // Set the reference to null.
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
private readonly Func<T> _onCreate; // Delegate for creating instances
|
||||||
|
private readonly Action<T> _onReturn; // Delegate for returning instances to the pool
|
||||||
|
private readonly Predicate<T> _onValid; // Delegate for checking if instances are valid
|
||||||
|
private readonly Stack<T> _pool = new Stack<T>(32); // Object pool
|
||||||
|
private int _count; // Total count of created instances
|
||||||
|
|
||||||
|
public InternalObjectPool(Func<T> onCreate, Predicate<T> onValid, Action<T> onReturn)
|
||||||
|
{
|
||||||
|
_onCreate = onCreate;
|
||||||
|
_onValid = onValid;
|
||||||
|
_onReturn = onReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rent an instance from the pool.
|
||||||
|
/// When you no longer need it, return it with <see cref="Return" />.
|
||||||
|
/// </summary>
|
||||||
|
public T Rent()
|
||||||
|
{
|
||||||
|
while (0 < _pool.Count)
|
||||||
|
{
|
||||||
|
var instance = _pool.Pop();
|
||||||
|
if (_onValid(instance))
|
||||||
|
{
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no instances in the pool, create a new one.
|
||||||
|
Logging.Log(this, $"A new instance is created (pooled: {_pool.Count}, created: {++_count}).");
|
||||||
|
return _onCreate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return an instance to the pool and assign null.
|
||||||
|
/// Be sure to return the instance obtained with <see cref="Rent" /> with this method.
|
||||||
|
/// </summary>
|
||||||
|
public void Return(ref T instance)
|
||||||
|
{
|
||||||
|
if (instance == null || _pool.Contains(instance)) return; // Ignore if already pooled or null.
|
||||||
|
|
||||||
|
_onReturn(instance); // Return the instance to the pool.
|
||||||
|
_pool.Push(instance);
|
||||||
|
Logging.Log(this, $"An instance is released (pooled: {_pool.Count}, created: {_count}).");
|
||||||
|
instance = default; // Set the reference to null.
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Object pool for <see cref="List{T}" />.
|
||||||
|
/// </summary>
|
||||||
|
internal static class InternalListPool<T>
|
||||||
|
{
|
||||||
|
#if UNITY_2021_1_OR_NEWER
|
||||||
|
/// <summary>
|
||||||
|
/// Rent an instance from the pool.
|
||||||
|
/// When you no longer need it, return it with <see cref="Return" />.
|
||||||
|
/// </summary>
|
||||||
|
public static List<T> Rent()
|
||||||
|
{
|
||||||
|
return UnityEngine.Pool.ListPool<T>.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return an instance to the pool and assign null.
|
||||||
|
/// Be sure to return the instance obtained with <see cref="Rent" /> with this method.
|
||||||
|
/// </summary>
|
||||||
|
public static void Return(ref List<T> toRelease)
|
||||||
|
{
|
||||||
|
if (toRelease != null)
|
||||||
|
{
|
||||||
|
UnityEngine.Pool.ListPool<T>.Release(toRelease);
|
||||||
|
}
|
||||||
|
|
||||||
|
toRelease = null;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
private static readonly InternalObjectPool<List<T>> s_ListPool =
|
||||||
|
new InternalObjectPool<List<T>>(() => new List<T>(), _ => true, x => x.Clear());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rent an instance from the pool.
|
||||||
|
/// When you no longer need it, return it with <see cref="Return" />.
|
||||||
|
/// </summary>
|
||||||
|
public static List<T> Rent()
|
||||||
|
{
|
||||||
|
return s_ListPool.Rent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return an instance to the pool and assign null.
|
||||||
|
/// Be sure to return the instance obtained with <see cref="Rent" /> with this method.
|
||||||
|
/// </summary>
|
||||||
|
public static void Return(ref List<T> toRelease)
|
||||||
|
{
|
||||||
|
s_ListPool.Return(ref toRelease);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/Internal/Utilities/ObjectPool.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/ObjectPool.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 632cb1ba34e6a4e80b55a32bb63ca369
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
209
Packages/src/Runtime/Internal/Utilities/ObjectRepository.cs
Normal file
209
Packages/src/Runtime/Internal/Utilities/ObjectRepository.cs
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Profiling;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
internal class ObjectRepository<T> where T : Object
|
||||||
|
{
|
||||||
|
private readonly Dictionary<Hash128, Entry> _cache = new Dictionary<Hash128, Entry>(8);
|
||||||
|
private readonly Dictionary<int, Hash128> _objectKey = new Dictionary<int, Hash128>(8);
|
||||||
|
private readonly string _name;
|
||||||
|
private readonly Action<T> _onRelease;
|
||||||
|
private readonly Stack<Entry> _pool = new Stack<Entry>(8);
|
||||||
|
|
||||||
|
public ObjectRepository(Action<T> onRelease = null)
|
||||||
|
{
|
||||||
|
_name = $"{typeof(T).Name}Repository";
|
||||||
|
if (onRelease == null)
|
||||||
|
{
|
||||||
|
_onRelease = x =>
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (!Application.isPlaying)
|
||||||
|
{
|
||||||
|
Object.DestroyImmediate(x, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Object.Destroy(x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_onRelease = onRelease;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
_pool.Push(new Entry());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int count => _cache.Count;
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
foreach (var kv in _cache)
|
||||||
|
{
|
||||||
|
var entry = kv.Value;
|
||||||
|
if (entry == null) continue;
|
||||||
|
|
||||||
|
entry.Release(_onRelease);
|
||||||
|
_pool.Push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cache.Clear();
|
||||||
|
_objectKey.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Valid(Hash128 hash, T obj)
|
||||||
|
{
|
||||||
|
return _cache.TryGetValue(hash, out var entry) && entry.storedObject == obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or retrieves a cached object based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
public void Get(Hash128 hash, ref T obj, Func<T> onCreate)
|
||||||
|
{
|
||||||
|
if (GetFromCache(hash, ref obj)) return;
|
||||||
|
Add(hash, ref obj, onCreate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or retrieves a cached object based on the hash.
|
||||||
|
/// </summary>
|
||||||
|
public void Get<TS>(Hash128 hash, ref T obj, Func<TS, T> onCreate, TS source)
|
||||||
|
{
|
||||||
|
if (GetFromCache(hash, ref obj)) return;
|
||||||
|
Add(hash, ref obj, onCreate(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool GetFromCache(Hash128 hash, ref T obj)
|
||||||
|
{
|
||||||
|
// Find existing entry.
|
||||||
|
Profiler.BeginSample("(COF)[ObjectRepository] GetFromCache");
|
||||||
|
if (_cache.TryGetValue(hash, out var entry))
|
||||||
|
{
|
||||||
|
if (!entry.storedObject)
|
||||||
|
{
|
||||||
|
Release(ref entry.storedObject);
|
||||||
|
Profiler.EndSample();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.storedObject != obj)
|
||||||
|
{
|
||||||
|
// if the object is different, release the old one.
|
||||||
|
Release(ref obj);
|
||||||
|
++entry.reference;
|
||||||
|
obj = entry.storedObject;
|
||||||
|
Logging.Log(_name, $"Get(total#{count}): {entry}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Profiler.EndSample();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Add(Hash128 hash, ref T obj, T newObject)
|
||||||
|
{
|
||||||
|
if (!newObject)
|
||||||
|
{
|
||||||
|
Release(ref obj);
|
||||||
|
obj = newObject;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and add a new entry.
|
||||||
|
Profiler.BeginSample("(COF)[ObjectRepository] Add");
|
||||||
|
var newEntry = 0 < _pool.Count ? _pool.Pop() : new Entry();
|
||||||
|
newEntry.storedObject = newObject;
|
||||||
|
newEntry.hash = hash;
|
||||||
|
newEntry.reference = 1;
|
||||||
|
_cache[hash] = newEntry;
|
||||||
|
_objectKey[newObject.GetInstanceID()] = hash;
|
||||||
|
Logging.Log(_name, $"<color=#03c700>Add</color>(total#{count}): {newEntry}");
|
||||||
|
Release(ref obj);
|
||||||
|
obj = newObject;
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Release a object.
|
||||||
|
/// </summary>
|
||||||
|
public void Release(ref T obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(obj, null)) return;
|
||||||
|
|
||||||
|
// Find and release the entry.
|
||||||
|
Profiler.BeginSample("(COF)[ObjectRepository] Release");
|
||||||
|
var id = obj.GetInstanceID();
|
||||||
|
if (_objectKey.TryGetValue(id, out var hash)
|
||||||
|
&& _cache.TryGetValue(hash, out var entry))
|
||||||
|
{
|
||||||
|
entry.reference--;
|
||||||
|
if (entry.reference <= 0 || !entry.storedObject)
|
||||||
|
{
|
||||||
|
Remove(entry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(_name, $"Release(total#{_cache.Count}): {entry}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(_name, $"Release(total#{_cache.Count}): <color=red>Already released: {obj}</color>");
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = null;
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Remove(Entry entry)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(entry, null)) return;
|
||||||
|
|
||||||
|
Profiler.BeginSample("(COF)[ObjectRepository] Remove");
|
||||||
|
_cache.Remove(entry.hash);
|
||||||
|
_objectKey.Remove(entry.storedObject.GetInstanceID());
|
||||||
|
_pool.Push(entry);
|
||||||
|
entry.reference = 0;
|
||||||
|
Logging.Log(_name, $"<color=#f29e03>Remove</color>(total#{_cache.Count}): {entry}");
|
||||||
|
entry.Release(_onRelease);
|
||||||
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Entry
|
||||||
|
{
|
||||||
|
public Hash128 hash;
|
||||||
|
public int reference;
|
||||||
|
public T storedObject;
|
||||||
|
|
||||||
|
public void Release(Action<T> onRelease)
|
||||||
|
{
|
||||||
|
reference = 0;
|
||||||
|
if (storedObject)
|
||||||
|
{
|
||||||
|
onRelease?.Invoke(storedObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
storedObject = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"h{(uint)hash.GetHashCode()} (refs#{reference}), {storedObject}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a713d67bdb31e45e296e5f18460717e2
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
115
Packages/src/Runtime/Internal/Utilities/UIExtraCallbacks.cs
Executable file
115
Packages/src/Runtime/Internal/Utilities/UIExtraCallbacks.cs
Executable file
@@ -0,0 +1,115 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides additional callbacks related to canvas and UI system.
|
||||||
|
/// </summary>
|
||||||
|
internal static class UIExtraCallbacks
|
||||||
|
{
|
||||||
|
private static bool s_IsInitializedAfterCanvasRebuild;
|
||||||
|
private static readonly FastAction s_AfterCanvasRebuildAction = new FastAction();
|
||||||
|
private static readonly FastAction s_LateAfterCanvasRebuildAction = new FastAction();
|
||||||
|
private static readonly FastAction s_BeforeCanvasRebuildAction = new FastAction();
|
||||||
|
private static readonly FastAction s_OnScreenSizeChangedAction = new FastAction();
|
||||||
|
private static Vector2Int s_LastScreenSize;
|
||||||
|
|
||||||
|
static UIExtraCallbacks()
|
||||||
|
{
|
||||||
|
Canvas.willRenderCanvases += OnBeforeCanvasRebuild;
|
||||||
|
Logging.LogMulticast(typeof(Canvas), "willRenderCanvases", message: "ctor");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event that occurs after canvas rebuilds.
|
||||||
|
/// </summary>
|
||||||
|
public static event Action onLateAfterCanvasRebuild
|
||||||
|
{
|
||||||
|
add => s_LateAfterCanvasRebuildAction.Add(value);
|
||||||
|
remove => s_LateAfterCanvasRebuildAction.Remove(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event that occurs before canvas rebuilds.
|
||||||
|
/// </summary>
|
||||||
|
public static event Action onBeforeCanvasRebuild
|
||||||
|
{
|
||||||
|
add => s_BeforeCanvasRebuildAction.Add(value);
|
||||||
|
remove => s_BeforeCanvasRebuildAction.Remove(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event that occurs after canvas rebuilds.
|
||||||
|
/// </summary>
|
||||||
|
public static event Action onAfterCanvasRebuild
|
||||||
|
{
|
||||||
|
add => s_AfterCanvasRebuildAction.Add(value);
|
||||||
|
remove => s_AfterCanvasRebuildAction.Remove(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event that occurs when the screen size changes.
|
||||||
|
/// </summary>
|
||||||
|
public static event Action onScreenSizeChanged
|
||||||
|
{
|
||||||
|
add => s_OnScreenSizeChangedAction.Add(value);
|
||||||
|
remove => s_OnScreenSizeChangedAction.Remove(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the UIExtraCallbacks to ensure proper event handling.
|
||||||
|
/// </summary>
|
||||||
|
private static void InitializeAfterCanvasRebuild()
|
||||||
|
{
|
||||||
|
if (s_IsInitializedAfterCanvasRebuild) return;
|
||||||
|
s_IsInitializedAfterCanvasRebuild = true;
|
||||||
|
|
||||||
|
CanvasUpdateRegistry.IsRebuildingLayout();
|
||||||
|
Canvas.willRenderCanvases += OnAfterCanvasRebuild;
|
||||||
|
Logging.LogMulticast(typeof(Canvas), "willRenderCanvases",
|
||||||
|
message: "InitializeAfterCanvasRebuild");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
[InitializeOnLoadMethod]
|
||||||
|
#endif
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||||
|
private static void InitializeOnLoad()
|
||||||
|
{
|
||||||
|
Canvas.willRenderCanvases -= OnAfterCanvasRebuild;
|
||||||
|
s_IsInitializedAfterCanvasRebuild = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Callback method called before canvas rebuilds.
|
||||||
|
/// </summary>
|
||||||
|
private static void OnBeforeCanvasRebuild()
|
||||||
|
{
|
||||||
|
var screenSize = new Vector2Int(Screen.width, Screen.height);
|
||||||
|
if (s_LastScreenSize != screenSize)
|
||||||
|
{
|
||||||
|
if (s_LastScreenSize != default)
|
||||||
|
{
|
||||||
|
s_OnScreenSizeChangedAction.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
s_LastScreenSize = screenSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_BeforeCanvasRebuildAction.Invoke();
|
||||||
|
InitializeAfterCanvasRebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Callback method called after canvas rebuilds.
|
||||||
|
/// </summary>
|
||||||
|
private static void OnAfterCanvasRebuild()
|
||||||
|
{
|
||||||
|
s_AfterCanvasRebuildAction.Invoke();
|
||||||
|
s_LateAfterCanvasRebuildAction.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9ea318e6e3e6c46aa97c72e28230bdc9
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Coffee.UIParticleExtensions
|
|
||||||
{
|
|
||||||
internal class ModifiedMaterial
|
|
||||||
{
|
|
||||||
private static readonly List<MatEntry> s_Entries = new List<MatEntry>();
|
|
||||||
|
|
||||||
public static Material Add(Material baseMat, Texture texture, int id, int props)
|
|
||||||
{
|
|
||||||
MatEntry e;
|
|
||||||
for (var i = 0; i < s_Entries.Count; i++)
|
|
||||||
{
|
|
||||||
e = s_Entries[i];
|
|
||||||
if (e.baseMat != baseMat || e.texture != texture || e.id != id || e.props != props) continue;
|
|
||||||
++e.count;
|
|
||||||
return e.customMat;
|
|
||||||
}
|
|
||||||
|
|
||||||
e = new MatEntry
|
|
||||||
{
|
|
||||||
count = 1,
|
|
||||||
baseMat = baseMat,
|
|
||||||
texture = texture,
|
|
||||||
id = id,
|
|
||||||
props = props,
|
|
||||||
customMat = new Material(baseMat)
|
|
||||||
{
|
|
||||||
name = $"{baseMat.name}_{id}",
|
|
||||||
hideFlags = HideFlags.DontSave | HideFlags.NotEditable,
|
|
||||||
mainTexture = texture ? texture : baseMat.mainTexture
|
|
||||||
}
|
|
||||||
};
|
|
||||||
s_Entries.Add(e);
|
|
||||||
//Debug.LogFormat(">>>> ModifiedMaterial.Add -> count = count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count, baseMat, texture, id);
|
|
||||||
return e.customMat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Remove(Material customMat)
|
|
||||||
{
|
|
||||||
if (!customMat) return;
|
|
||||||
|
|
||||||
for (var i = 0; i < s_Entries.Count; ++i)
|
|
||||||
{
|
|
||||||
var e = s_Entries[i];
|
|
||||||
if (e.customMat != customMat) continue;
|
|
||||||
if (--e.count == 0)
|
|
||||||
{
|
|
||||||
//Debug.LogFormat(">>>> ModifiedMaterial.Remove -> count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count - 1, e.customMat, e.texture, e.id);
|
|
||||||
Misc.DestroyImmediate(e.customMat);
|
|
||||||
e.customMat = null;
|
|
||||||
e.baseMat = null;
|
|
||||||
e.texture = null;
|
|
||||||
s_Entries.RemoveAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MatEntry
|
|
||||||
{
|
|
||||||
public Material baseMat;
|
|
||||||
public int count;
|
|
||||||
public Material customMat;
|
|
||||||
public int id;
|
|
||||||
public int props;
|
|
||||||
public Texture texture;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Coffee.UIParticleExtensions;
|
using Coffee.UIParticleInternal;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Rendering;
|
using UnityEngine.Rendering;
|
||||||
using UnityEngine.Serialization;
|
using UnityEngine.Serialization;
|
||||||
@@ -9,12 +9,15 @@ using UnityEngine.UI;
|
|||||||
using Random = UnityEngine.Random;
|
using Random = UnityEngine.Random;
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")]
|
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")]
|
||||||
|
[assembly: InternalsVisibleTo("Coffee.UIParticle.PerformanceDemo")]
|
||||||
|
[assembly: InternalsVisibleTo("Coffee.UIParticle.Demo")]
|
||||||
|
|
||||||
namespace Coffee.UIExtensions
|
namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Render maskable and sortable particle effect ,without Camera, RenderTexture or Canvas.
|
/// Render maskable and sortable particle effect ,without Camera, RenderTexture or Canvas.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Icon("Packages/com.coffee.ui-particle/Editor/UIParticleIcon.png")]
|
||||||
[ExecuteAlways]
|
[ExecuteAlways]
|
||||||
[RequireComponent(typeof(RectTransform))]
|
[RequireComponent(typeof(RectTransform))]
|
||||||
[RequireComponent(typeof(CanvasRenderer))]
|
[RequireComponent(typeof(CanvasRenderer))]
|
||||||
@@ -117,9 +120,12 @@ namespace Coffee.UIExtensions
|
|||||||
"Change the bake view size.")]
|
"Change the bake view size.")]
|
||||||
private float m_CustomViewSize = 10;
|
private float m_CustomViewSize = 10;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("Time scale multiplier.")]
|
||||||
|
private float m_TimeScaleMultiplier = 1;
|
||||||
|
|
||||||
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
|
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
|
||||||
private Camera _bakeCamera;
|
private Camera _bakeCamera;
|
||||||
private Canvas _canvas;
|
|
||||||
private int _groupId;
|
private int _groupId;
|
||||||
private bool _isScaleStored;
|
private bool _isScaleStored;
|
||||||
private Vector3 _storedScale;
|
private Vector3 _storedScale;
|
||||||
@@ -256,6 +262,15 @@ namespace Coffee.UIExtensions
|
|||||||
set => m_CustomViewSize = Mathf.Max(0.1f, value);
|
set => m_CustomViewSize = Mathf.Max(0.1f, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time scale multiplier.
|
||||||
|
/// </summary>
|
||||||
|
public float timeScaleMultiplier
|
||||||
|
{
|
||||||
|
get => m_TimeScaleMultiplier;
|
||||||
|
set => m_TimeScaleMultiplier = value;
|
||||||
|
}
|
||||||
|
|
||||||
internal bool useMeshSharing => m_MeshSharing != MeshSharing.None;
|
internal bool useMeshSharing => m_MeshSharing != MeshSharing.None;
|
||||||
|
|
||||||
internal bool isPrimary =>
|
internal bool isPrimary =>
|
||||||
@@ -576,17 +591,19 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
var ps = particleSystems[i];
|
var ps = particleSystems[i];
|
||||||
if (!ps) continue;
|
if (!ps) continue;
|
||||||
GetRenderer(j++).Set(this, ps, false);
|
|
||||||
|
var mainEmitter = ps.GetMainEmitter(particleSystems);
|
||||||
|
GetRenderer(j++).Set(this, ps, false, mainEmitter);
|
||||||
|
|
||||||
// If the trail is enabled, set it additionally.
|
// If the trail is enabled, set it additionally.
|
||||||
if (ps.trails.enabled)
|
if (ps.trails.enabled)
|
||||||
{
|
{
|
||||||
GetRenderer(j++).Set(this, ps, true);
|
GetRenderer(j++).Set(this, ps, true, mainEmitter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void UpdateTransformScale(Vector3 ratio)
|
internal void UpdateTransformScale()
|
||||||
{
|
{
|
||||||
_tracker.Clear();
|
_tracker.Clear();
|
||||||
canvasScale = canvas.rootCanvas.transform.localScale.Inverse();
|
canvasScale = canvas.rootCanvas.transform.localScale.Inverse();
|
||||||
@@ -610,7 +627,7 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
_tracker.Add(this, rectTransform, DrivenTransformProperties.Scale);
|
_tracker.Add(this, rectTransform, DrivenTransformProperties.Scale);
|
||||||
var newScale = parentScale.GetScaled(ratio).Inverse();
|
var newScale = parentScale.Inverse();
|
||||||
if (currentScale != newScale)
|
if (currentScale != newScale)
|
||||||
{
|
{
|
||||||
transform.localScale = newScale;
|
transform.localScale = newScale;
|
||||||
@@ -733,7 +750,7 @@ namespace Coffee.UIExtensions
|
|||||||
_bakeCamera.useOcclusionCulling = false;
|
_bakeCamera.useOcclusionCulling = false;
|
||||||
|
|
||||||
_bakeCamera.gameObject.SetActive(false);
|
_bakeCamera.gameObject.SetActive(false);
|
||||||
_bakeCamera.gameObject.hideFlags = HideFlags.HideAndDontSave;
|
_bakeCamera.gameObject.hideFlags = UIParticleProjectSettings.globalHideFlags;
|
||||||
|
|
||||||
return _bakeCamera;
|
return _bakeCamera;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ MonoImporter:
|
|||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
defaultReferences: []
|
defaultReferences: []
|
||||||
executionOrder: 0
|
executionOrder: 0
|
||||||
icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
|
icon: {instanceID: 0}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
assetBundleVariant:
|
assetBundleVariant:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Coffee.UIParticleExtensions;
|
using Coffee.UIParticleInternal;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ namespace Coffee.UIExtensions
|
|||||||
// Collect UIParticle if needed (same size as m_ParticleSystems)
|
// Collect UIParticle if needed (same size as m_ParticleSystems)
|
||||||
CollectUIParticlesIfNeeded();
|
CollectUIParticlesIfNeeded();
|
||||||
|
|
||||||
for (var particleIndex = 0; particleIndex < this.m_ParticleSystems.Count; particleIndex++)
|
for (var particleIndex = 0; particleIndex < m_ParticleSystems.Count; particleIndex++)
|
||||||
{
|
{
|
||||||
var particleSystem = m_ParticleSystems[particleIndex];
|
var particleSystem = m_ParticleSystems[particleIndex];
|
||||||
|
|
||||||
@@ -163,21 +163,21 @@ namespace Coffee.UIExtensions
|
|||||||
particleSystem.GetParticles(particles, count);
|
particleSystem.GetParticles(particles, count);
|
||||||
|
|
||||||
var uiParticle = _uiParticles[particleIndex];
|
var uiParticle = _uiParticles[particleIndex];
|
||||||
var dstPos = this.GetDestinationPosition(uiParticle, particleSystem);
|
var dstPos = GetDestinationPosition(uiParticle, particleSystem);
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
// Attracted
|
// Attracted
|
||||||
var p = particles[i];
|
var p = particles[i];
|
||||||
if (0f < p.remainingLifetime && Vector3.Distance(p.position, dstPos) < this.m_DestinationRadius)
|
if (0f < p.remainingLifetime && Vector3.Distance(p.position, dstPos) < m_DestinationRadius)
|
||||||
{
|
{
|
||||||
p.remainingLifetime = 0f;
|
p.remainingLifetime = 0f;
|
||||||
particles[i] = p;
|
particles[i] = p;
|
||||||
|
|
||||||
if (this.m_OnAttracted != null)
|
if (m_OnAttracted != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.m_OnAttracted.Invoke();
|
m_OnAttracted.Invoke();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -189,7 +189,7 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calc attracting time
|
// Calc attracting time
|
||||||
var delayTime = p.startLifetime * this.m_DelayRate;
|
var delayTime = p.startLifetime * m_DelayRate;
|
||||||
var duration = p.startLifetime - delayTime;
|
var duration = p.startLifetime - delayTime;
|
||||||
var time = Mathf.Max(0, p.startLifetime - p.remainingLifetime - delayTime);
|
var time = Mathf.Max(0, p.startLifetime - p.remainingLifetime - delayTime);
|
||||||
|
|
||||||
@@ -197,7 +197,7 @@ namespace Coffee.UIExtensions
|
|||||||
if (time <= 0) continue;
|
if (time <= 0) continue;
|
||||||
|
|
||||||
// Attract
|
// Attract
|
||||||
p.position = this.GetAttractedPosition(p.position, dstPos, duration, time);
|
p.position = GetAttractedPosition(p.position, dstPos, duration, time);
|
||||||
p.velocity *= 0.5f;
|
p.velocity *= 0.5f;
|
||||||
particles[i] = p;
|
particles[i] = p;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ MonoImporter:
|
|||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
defaultReferences: []
|
defaultReferences: []
|
||||||
executionOrder: 0
|
executionOrder: 0
|
||||||
icon: {instanceID: 0}
|
icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
assetBundleVariant:
|
assetBundleVariant:
|
||||||
|
|||||||
40
Packages/src/Runtime/UIParticleProjectSettings.cs
Normal file
40
Packages/src/Runtime/UIParticleProjectSettings.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma warning disable CS0414
|
||||||
|
using Coffee.UIParticleInternal;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Coffee.UIExtensions
|
||||||
|
{
|
||||||
|
public class UIParticleProjectSettings : PreloadedProjectSettings<UIParticleProjectSettings>
|
||||||
|
{
|
||||||
|
[Header("Setting")]
|
||||||
|
[SerializeField]
|
||||||
|
internal bool m_EnableLinearToGamma = true;
|
||||||
|
|
||||||
|
public static bool enableLinearToGamma
|
||||||
|
{
|
||||||
|
get => instance.m_EnableLinearToGamma;
|
||||||
|
set => instance.m_EnableLinearToGamma = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Header("Editor")]
|
||||||
|
[Tooltip("Hide the automatically generated objects.\n" +
|
||||||
|
" - UIParticleRenderer\n" +
|
||||||
|
" - UIParticle BakingCamera")]
|
||||||
|
[SerializeField]
|
||||||
|
private bool m_HideGeneratedObjects = true;
|
||||||
|
|
||||||
|
public static HideFlags globalHideFlags => instance.m_HideGeneratedObjects
|
||||||
|
? HideFlags.DontSave | HideFlags.NotEditable | HideFlags.HideInHierarchy | HideFlags.HideInInspector
|
||||||
|
: HideFlags.DontSave | HideFlags.NotEditable;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
[SettingsProvider]
|
||||||
|
private static SettingsProvider CreateSettingsProvider()
|
||||||
|
{
|
||||||
|
return new PreloadedProjectSettingsProvider("Project/UI/UI Particle");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/UIParticleProjectSettings.cs.meta
Normal file
11
Packages/src/Runtime/UIParticleProjectSettings.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f22a23b9d98e440478697f4adf30e61c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
#endif
|
#endif
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Coffee.UIParticleExtensions;
|
using Coffee.UIParticleInternal;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Profiling;
|
using UnityEngine.Profiling;
|
||||||
@@ -15,25 +15,23 @@ using UnityEngine.UI;
|
|||||||
|
|
||||||
namespace Coffee.UIExtensions
|
namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
|
[Icon("Packages/com.coffee.ui-particle/Editor/UIParticleIcon.png")]
|
||||||
[ExecuteAlways]
|
[ExecuteAlways]
|
||||||
[RequireComponent(typeof(RectTransform))]
|
[RequireComponent(typeof(RectTransform))]
|
||||||
[RequireComponent(typeof(CanvasRenderer))]
|
[RequireComponent(typeof(CanvasRenderer))]
|
||||||
[AddComponentMenu("")]
|
[AddComponentMenu("")]
|
||||||
internal class UIParticleRenderer : MaskableGraphic
|
internal class UIParticleRenderer : MaskableGraphic
|
||||||
{
|
{
|
||||||
private static readonly List<Component> s_Components = new List<Component>();
|
|
||||||
private static readonly CombineInstance[] s_CombineInstances = { new CombineInstance() };
|
private static readonly CombineInstance[] s_CombineInstances = { new CombineInstance() };
|
||||||
private static readonly List<Material> s_Materials = new List<Material>(2);
|
private static readonly List<Material> s_Materials = new List<Material>(2);
|
||||||
private static MaterialPropertyBlock s_Mpb;
|
private static MaterialPropertyBlock s_Mpb;
|
||||||
private static readonly List<UIParticleRenderer> s_Renderers = new List<UIParticleRenderer>();
|
|
||||||
private static readonly List<Color32> s_Colors = new List<Color32>();
|
|
||||||
private static readonly Vector3[] s_Corners = new Vector3[4];
|
private static readonly Vector3[] s_Corners = new Vector3[4];
|
||||||
private Material _currentMaterialForRendering;
|
|
||||||
private bool _delay;
|
private bool _delay;
|
||||||
private int _index;
|
private int _index;
|
||||||
private bool _isPrevStored;
|
private bool _isPrevStored;
|
||||||
private bool _isTrail;
|
private bool _isTrail;
|
||||||
private Bounds _lastBounds;
|
private Bounds _lastBounds;
|
||||||
|
private Material _materialForRendering;
|
||||||
private Material _modifiedMaterial;
|
private Material _modifiedMaterial;
|
||||||
private UIParticle _parent;
|
private UIParticle _parent;
|
||||||
private ParticleSystem _particleSystem;
|
private ParticleSystem _particleSystem;
|
||||||
@@ -43,6 +41,7 @@ namespace Coffee.UIExtensions
|
|||||||
private Vector2Int _prevScreenSize;
|
private Vector2Int _prevScreenSize;
|
||||||
private bool _preWarm;
|
private bool _preWarm;
|
||||||
private ParticleSystemRenderer _renderer;
|
private ParticleSystemRenderer _renderer;
|
||||||
|
private ParticleSystem _mainEmitter;
|
||||||
|
|
||||||
public override Texture mainTexture => _isTrail ? null : _particleSystem.GetTextureForSprite();
|
public override Texture mainTexture => _isTrail ? null : _particleSystem.GetTextureForSprite();
|
||||||
|
|
||||||
@@ -92,6 +91,19 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Material materialForRendering
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_materialForRendering)
|
||||||
|
{
|
||||||
|
_materialForRendering = base.materialForRendering;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _materialForRendering;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Reset(int index = -1)
|
public void Reset(int index = -1)
|
||||||
{
|
{
|
||||||
if (_renderer)
|
if (_renderer)
|
||||||
@@ -102,6 +114,7 @@ namespace Coffee.UIExtensions
|
|||||||
_parent = null;
|
_parent = null;
|
||||||
_particleSystem = null;
|
_particleSystem = null;
|
||||||
_renderer = null;
|
_renderer = null;
|
||||||
|
_mainEmitter = null;
|
||||||
if (0 <= index)
|
if (0 <= index)
|
||||||
{
|
{
|
||||||
_index = index;
|
_index = index;
|
||||||
@@ -117,9 +130,8 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
MaterialRepository.Release(ref _modifiedMaterial);
|
||||||
_modifiedMaterial = null;
|
_materialForRendering = null;
|
||||||
_currentMaterialForRendering = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,6 +139,7 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
base.OnEnable();
|
base.OnEnable();
|
||||||
|
|
||||||
|
hideFlags = UIParticleProjectSettings.globalHideFlags;
|
||||||
if (!s_CombineInstances[0].mesh)
|
if (!s_CombineInstances[0].mesh)
|
||||||
{
|
{
|
||||||
s_CombineInstances[0].mesh = new Mesh
|
s_CombineInstances[0].mesh = new Mesh
|
||||||
@@ -135,17 +148,14 @@ namespace Coffee.UIExtensions
|
|||||||
hideFlags = HideFlags.HideAndDontSave
|
hideFlags = HideFlags.HideAndDontSave
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentMaterialForRendering = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDisable()
|
protected override void OnDisable()
|
||||||
{
|
{
|
||||||
base.OnDisable();
|
base.OnDisable();
|
||||||
|
|
||||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
MaterialRepository.Release(ref _modifiedMaterial);
|
||||||
_modifiedMaterial = null;
|
_materialForRendering = null;
|
||||||
_currentMaterialForRendering = null;
|
|
||||||
_isPrevStored = false;
|
_isPrevStored = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +164,7 @@ namespace Coffee.UIExtensions
|
|||||||
// Create renderer object.
|
// Create renderer object.
|
||||||
var go = new GameObject("[generated] UIParticleRenderer", typeof(UIParticleRenderer))
|
var go = new GameObject("[generated] UIParticleRenderer", typeof(UIParticleRenderer))
|
||||||
{
|
{
|
||||||
hideFlags = HideFlags.HideAndDontSave,
|
hideFlags = UIParticleProjectSettings.globalHideFlags,
|
||||||
layer = parent.gameObject.layer
|
layer = parent.gameObject.layer
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -178,12 +188,9 @@ namespace Coffee.UIExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public override Material GetModifiedMaterial(Material baseMaterial)
|
public override Material GetModifiedMaterial(Material baseMaterial)
|
||||||
{
|
{
|
||||||
_currentMaterialForRendering = null;
|
|
||||||
|
|
||||||
if (!IsActive() || !_parent)
|
if (!IsActive() || !_parent)
|
||||||
{
|
{
|
||||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
MaterialRepository.Release(ref _modifiedMaterial);
|
||||||
_modifiedMaterial = null;
|
|
||||||
return baseMaterial;
|
return baseMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,26 +200,33 @@ namespace Coffee.UIExtensions
|
|||||||
var texture = mainTexture;
|
var texture = mainTexture;
|
||||||
if (texture == null && _parent.m_AnimatableProperties.Length == 0)
|
if (texture == null && _parent.m_AnimatableProperties.Length == 0)
|
||||||
{
|
{
|
||||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
MaterialRepository.Release(ref _modifiedMaterial);
|
||||||
_modifiedMaterial = null;
|
|
||||||
return modifiedMaterial;
|
return modifiedMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
var hash = new Hash128(
|
||||||
var id = _parent.m_AnimatableProperties.Length == 0 ? 0 : GetInstanceID();
|
modifiedMaterial ? (uint)modifiedMaterial.GetInstanceID() : 0,
|
||||||
|
texture ? (uint)texture.GetInstanceID() : 0,
|
||||||
|
0 < _parent.m_AnimatableProperties.Length ? (uint)GetInstanceID() : 0,
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
var props = EditorJsonUtility.ToJson(modifiedMaterial).GetHashCode();
|
(uint)EditorJsonUtility.ToJson(modifiedMaterial).GetHashCode()
|
||||||
#else
|
#else
|
||||||
var props = 0;
|
0
|
||||||
#endif
|
#endif
|
||||||
modifiedMaterial = ModifiedMaterial.Add(modifiedMaterial, texture, id, props);
|
);
|
||||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
if (!MaterialRepository.Valid(hash, _modifiedMaterial))
|
||||||
_modifiedMaterial = modifiedMaterial;
|
{
|
||||||
|
MaterialRepository.Get(hash, ref _modifiedMaterial, x => new Material(x.mat)
|
||||||
|
{
|
||||||
|
hideFlags = HideFlags.HideAndDontSave,
|
||||||
|
mainTexture = x.texture ? x.texture : x.mat.mainTexture
|
||||||
|
}, (mat: modifiedMaterial, texture));
|
||||||
|
}
|
||||||
|
|
||||||
return modifiedMaterial;
|
return _modifiedMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Set(UIParticle parent, ParticleSystem ps, bool isTrail)
|
public void Set(UIParticle parent, ParticleSystem ps, bool isTrail, ParticleSystem mainEmitter)
|
||||||
{
|
{
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
maskable = parent.maskable;
|
maskable = parent.maskable;
|
||||||
@@ -235,10 +249,7 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
ps.TryGetComponent(out _renderer);
|
ps.TryGetComponent(out _renderer);
|
||||||
_renderer.enabled = false;
|
_renderer.enabled = false;
|
||||||
|
|
||||||
//_emitter = emitter;
|
|
||||||
_isTrail = isTrail;
|
_isTrail = isTrail;
|
||||||
|
|
||||||
_renderer.GetSharedMaterials(s_Materials);
|
_renderer.GetSharedMaterials(s_Materials);
|
||||||
material = s_Materials[isTrail ? 1 : 0];
|
material = s_Materials[isTrail ? 1 : 0];
|
||||||
s_Materials.Clear();
|
s_Materials.Clear();
|
||||||
@@ -255,6 +266,7 @@ namespace Coffee.UIExtensions
|
|||||||
_prevScreenSize = new Vector2Int(Screen.width, Screen.height);
|
_prevScreenSize = new Vector2Int(Screen.width, Screen.height);
|
||||||
_prevCanvasScale = canvas ? canvas.scaleFactor : 1f;
|
_prevCanvasScale = canvas ? canvas.scaleFactor : 1f;
|
||||||
_delay = true;
|
_delay = true;
|
||||||
|
_mainEmitter = mainEmitter;
|
||||||
|
|
||||||
canvasRenderer.SetTexture(null);
|
canvasRenderer.SetTexture(null);
|
||||||
|
|
||||||
@@ -271,10 +283,6 @@ namespace Coffee.UIExtensions
|
|||||||
|| !transform.lossyScale.GetScaled(_parent.scale3DForCalc).IsVisible() // Scale is not visible.
|
|| !transform.lossyScale.GetScaled(_parent.scale3DForCalc).IsVisible() // Scale is not visible.
|
||||||
|| (!_particleSystem.IsAlive() && !_particleSystem.isPlaying) // No particle.
|
|| (!_particleSystem.IsAlive() && !_particleSystem.isPlaying) // No particle.
|
||||||
|| (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled.
|
|| (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled.
|
||||||
#if UNITY_2018_3_OR_NEWER
|
|
||||||
|| canvasRenderer.GetInheritedAlpha() <
|
|
||||||
0.01f // #102: Do not bake particle system to mesh when the alpha is zero.
|
|
||||||
#endif
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Clear Mesh");
|
Profiler.BeginSample("[UIParticleRenderer] Clear Mesh");
|
||||||
@@ -292,7 +300,7 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
// Simulate particles.
|
// Simulate particles.
|
||||||
Profiler.BeginSample("[UIParticle] Bake Mesh > Simulate Particles");
|
Profiler.BeginSample("[UIParticle] Bake Mesh > Simulate Particles");
|
||||||
if (!_isTrail && _parent.canSimulate)
|
if (!_isTrail && _parent.canSimulate && !_mainEmitter)
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (!Application.isPlaying)
|
if (!Application.isPlaying)
|
||||||
@@ -303,6 +311,13 @@ namespace Coffee.UIExtensions
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
ResolveResolutionChange(psPos, scale);
|
ResolveResolutionChange(psPos, scale);
|
||||||
|
|
||||||
|
// fix: second and subsequent bursts not displayed when world simulation and non-looping. (#326)
|
||||||
|
if (!_particleSystem.IsLocalSpace() && !main.loop && _particleSystem.time == 0)
|
||||||
|
{
|
||||||
|
_delay = true;
|
||||||
|
}
|
||||||
|
|
||||||
Simulate(scale, _parent.isPaused || _delay);
|
Simulate(scale, _parent.isPaused || _delay);
|
||||||
|
|
||||||
if (_delay && !_parent.isPaused)
|
if (_delay && !_parent.isPaused)
|
||||||
@@ -405,95 +420,67 @@ namespace Coffee.UIExtensions
|
|||||||
_lastBounds = bounds;
|
_lastBounds = bounds;
|
||||||
|
|
||||||
// Convert linear color to gamma color.
|
// Convert linear color to gamma color.
|
||||||
if (QualitySettings.activeColorSpace == ColorSpace.Linear)
|
if (UIParticleProjectSettings.enableLinearToGamma && canvas.ShouldGammaToLinearInMesh())
|
||||||
{
|
{
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Convert Linear to Gamma");
|
workerMesh.LinearToGamma();
|
||||||
workerMesh.GetColors(s_Colors);
|
|
||||||
var count_c = s_Colors.Count;
|
|
||||||
for (var i = 0; i < count_c; i++)
|
|
||||||
{
|
|
||||||
var c = s_Colors[i];
|
|
||||||
c.r = c.r.LinearToGamma();
|
|
||||||
c.g = c.g.LinearToGamma();
|
|
||||||
c.b = c.b.LinearToGamma();
|
|
||||||
s_Colors[i] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
workerMesh.SetColors(s_Colors);
|
|
||||||
Profiler.EndSample();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GetComponents(typeof(IMeshModifier), s_Components);
|
var components = InternalListPool<Component>.Rent();
|
||||||
for (var i = 0; i < s_Components.Count; i++)
|
GetComponents(typeof(IMeshModifier), components);
|
||||||
|
for (var i = 0; i < components.Count; i++)
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0618 // Type or member is obsolete
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
((IMeshModifier)s_Components[i]).ModifyMesh(workerMesh);
|
((IMeshModifier)components[i]).ModifyMesh(workerMesh);
|
||||||
#pragma warning restore CS0618 // Type or member is obsolete
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
}
|
}
|
||||||
|
|
||||||
s_Components.Clear();
|
InternalListPool<Component>.Return(ref components);
|
||||||
}
|
}
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
|
||||||
|
|
||||||
// Get grouped renderers.
|
|
||||||
s_Renderers.Clear();
|
|
||||||
if (_parent.useMeshSharing)
|
|
||||||
{
|
|
||||||
UIParticleUpdater.GetGroupedRenderers(_parent.groupId, _index, s_Renderers);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set mesh to the CanvasRenderer.
|
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
|
|
||||||
for (var i = 0; i < s_Renderers.Count; i++)
|
|
||||||
{
|
|
||||||
if (s_Renderers[i] == this) continue;
|
|
||||||
s_Renderers[i].canvasRenderer.SetMesh(workerMesh);
|
|
||||||
s_Renderers[i]._lastBounds = _lastBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_parent.canRender)
|
|
||||||
{
|
|
||||||
workerMesh.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
canvasRenderer.SetMesh(workerMesh);
|
|
||||||
Profiler.EndSample();
|
|
||||||
|
|
||||||
// Update animatable material properties.
|
// Update animatable material properties.
|
||||||
Profiler.BeginSample("[UIParticleRenderer] Update Animatable Material Properties");
|
Profiler.BeginSample("[UIParticleRenderer] Update Animatable Material Properties");
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
if (_modifiedMaterial != material)
|
|
||||||
{
|
|
||||||
_renderer.GetSharedMaterials(s_Materials);
|
|
||||||
material = s_Materials[_isTrail ? 1 : 0];
|
|
||||||
s_Materials.Clear();
|
|
||||||
SetMaterialDirty();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UpdateMaterialProperties();
|
UpdateMaterialProperties();
|
||||||
|
Profiler.EndSample();
|
||||||
|
|
||||||
|
// Get grouped renderers.
|
||||||
|
Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
|
||||||
|
var renderers = InternalListPool<UIParticleRenderer>.Rent();
|
||||||
if (_parent.useMeshSharing)
|
if (_parent.useMeshSharing)
|
||||||
{
|
{
|
||||||
if (!_currentMaterialForRendering)
|
UIParticleUpdater.GetGroupedRenderers(_parent.groupId, _index, renderers);
|
||||||
{
|
}
|
||||||
_currentMaterialForRendering = materialForRendering;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < s_Renderers.Count; i++)
|
for (var i = 0; i < renderers.Count; i++)
|
||||||
{
|
{
|
||||||
if (s_Renderers[i] == this) continue;
|
var r = renderers[i];
|
||||||
|
if (r == this) continue;
|
||||||
|
|
||||||
s_Renderers[i].canvasRenderer.materialCount = 1;
|
r.canvasRenderer.SetMesh(workerMesh);
|
||||||
s_Renderers[i].canvasRenderer.SetMaterial(_currentMaterialForRendering, 0);
|
r._lastBounds = _lastBounds;
|
||||||
}
|
r.canvasRenderer.materialCount = 1;
|
||||||
|
r.canvasRenderer.SetMaterial(materialForRendering, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalListPool<UIParticleRenderer>.Return(ref renderers);
|
||||||
|
|
||||||
|
if (_parent.canRender)
|
||||||
|
{
|
||||||
|
canvasRenderer.SetMesh(workerMesh);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
workerMesh.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
s_Renderers.Clear();
|
public override void SetMaterialDirty()
|
||||||
|
{
|
||||||
|
_materialForRendering = null;
|
||||||
|
base.SetMaterialDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -559,6 +546,30 @@ namespace Coffee.UIExtensions
|
|||||||
return Matrix4x4.Translate(psPos)
|
return Matrix4x4.Translate(psPos)
|
||||||
* Matrix4x4.Scale(scale);
|
* Matrix4x4.Scale(scale);
|
||||||
case ParticleSystemSimulationSpace.World:
|
case ParticleSystemSimulationSpace.World:
|
||||||
|
if (_isTrail)
|
||||||
|
{
|
||||||
|
return Matrix4x4.Translate(psPos)
|
||||||
|
* Matrix4x4.Scale(scale)
|
||||||
|
* Matrix4x4.Translate(-psPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_mainEmitter)
|
||||||
|
{
|
||||||
|
if (_mainEmitter.IsLocalSpace())
|
||||||
|
{
|
||||||
|
return Matrix4x4.Translate(psPos)
|
||||||
|
* Matrix4x4.Scale(scale)
|
||||||
|
* Matrix4x4.Translate(-psPos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
psPos = _particleSystem.transform.position - _mainEmitter.transform.position;
|
||||||
|
return Matrix4x4.Translate(psPos)
|
||||||
|
* Matrix4x4.Scale(scale)
|
||||||
|
* Matrix4x4.Translate(-psPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Matrix4x4.Scale(scale);
|
return Matrix4x4.Scale(scale);
|
||||||
case ParticleSystemSimulationSpace.Custom:
|
case ParticleSystemSimulationSpace.Custom:
|
||||||
return Matrix4x4.Translate(_particleSystem.main.customSimulationSpace.position.GetScaled(scale))
|
return Matrix4x4.Translate(_particleSystem.main.customSimulationSpace.position.GetScaled(scale))
|
||||||
@@ -621,6 +632,7 @@ namespace Coffee.UIExtensions
|
|||||||
: main.useUnscaledTime
|
: main.useUnscaledTime
|
||||||
? Time.unscaledDeltaTime
|
? Time.unscaledDeltaTime
|
||||||
: Time.deltaTime;
|
: Time.deltaTime;
|
||||||
|
deltaTime *= _parent.timeScaleMultiplier;
|
||||||
|
|
||||||
// Pre-warm:
|
// Pre-warm:
|
||||||
if (0 < deltaTime && _preWarm)
|
if (0 < deltaTime && _preWarm)
|
||||||
@@ -701,12 +713,12 @@ namespace Coffee.UIExtensions
|
|||||||
if (s_Mpb.isEmpty) return;
|
if (s_Mpb.isEmpty) return;
|
||||||
|
|
||||||
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
|
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
|
||||||
if (!_modifiedMaterial) return;
|
if (!materialForRendering) return;
|
||||||
|
|
||||||
for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++)
|
for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++)
|
||||||
{
|
{
|
||||||
var ap = _parent.m_AnimatableProperties[i];
|
var ap = _parent.m_AnimatableProperties[i];
|
||||||
ap.UpdateMaterialProperties(_modifiedMaterial, s_Mpb);
|
ap.UpdateMaterialProperties(materialForRendering, s_Mpb);
|
||||||
}
|
}
|
||||||
|
|
||||||
s_Mpb.Clear();
|
s_Mpb.Clear();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Coffee.UIParticleExtensions;
|
using Coffee.UIParticleInternal;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
private static readonly List<UIParticle> s_ActiveParticles = new List<UIParticle>();
|
private static readonly List<UIParticle> s_ActiveParticles = new List<UIParticle>();
|
||||||
private static readonly List<UIParticleAttractor> s_ActiveAttractors = new List<UIParticleAttractor>();
|
private static readonly List<UIParticleAttractor> s_ActiveAttractors = new List<UIParticleAttractor>();
|
||||||
private static readonly Dictionary<int, Vector3> s_GroupScales = new Dictionary<int, Vector3>();
|
private static readonly HashSet<int> s_UpdatedGroupIds = new HashSet<int>();
|
||||||
private static int s_FrameCount;
|
private static int s_FrameCount;
|
||||||
|
|
||||||
public static int uiParticleCount => s_ActiveParticles.Count;
|
public static int uiParticleCount => s_ActiveParticles.Count;
|
||||||
@@ -40,31 +40,40 @@ namespace Coffee.UIExtensions
|
|||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
[InitializeOnLoadMethod]
|
[InitializeOnLoadMethod]
|
||||||
#else
|
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
|
||||||
#endif
|
|
||||||
private static void InitializeOnLoad()
|
private static void InitializeOnLoad()
|
||||||
{
|
{
|
||||||
Canvas.willRenderCanvases -= Refresh;
|
UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
|
||||||
Canvas.willRenderCanvases += Refresh;
|
|
||||||
|
EditorApplication.playModeStateChanged += state =>
|
||||||
|
{
|
||||||
|
UIExtraCallbacks.onAfterCanvasRebuild -= Refresh;
|
||||||
|
if (state == PlayModeStateChange.EnteredEditMode || state == PlayModeStateChange.EnteredPlayMode)
|
||||||
|
{
|
||||||
|
UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||||
|
private static void InitializeOnLoad()
|
||||||
|
{
|
||||||
|
UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private static void Refresh()
|
private static void Refresh()
|
||||||
{
|
{
|
||||||
// Do not allow it to be called in the same frame.
|
// Do not allow it to be called in the same frame.
|
||||||
if (s_FrameCount == Time.frameCount) return;
|
if (s_FrameCount == Time.frameCount) return;
|
||||||
s_FrameCount = Time.frameCount;
|
s_FrameCount = Time.frameCount;
|
||||||
s_GroupScales.Clear();
|
|
||||||
|
|
||||||
// Simulate -> Primary
|
// Simulate -> Primary
|
||||||
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
||||||
{
|
{
|
||||||
// Process only primary UIParticles.
|
|
||||||
var uip = s_ActiveParticles[i];
|
var uip = s_ActiveParticles[i];
|
||||||
if (!uip || !uip.canvas || !uip.isPrimary || s_GroupScales.ContainsKey(uip.groupId)) continue;
|
if (!uip || !uip.canvas || !uip.isPrimary || !s_UpdatedGroupIds.Add(uip.groupId)) continue;
|
||||||
|
|
||||||
s_GroupScales.Add(uip.groupId, uip.transform.parent.lossyScale);
|
uip.UpdateTransformScale();
|
||||||
uip.UpdateTransformScale(Vector3.one);
|
|
||||||
uip.UpdateRenderers();
|
uip.UpdateRenderers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,31 +83,20 @@ namespace Coffee.UIExtensions
|
|||||||
var uip = s_ActiveParticles[i];
|
var uip = s_ActiveParticles[i];
|
||||||
if (!uip || !uip.canvas) continue;
|
if (!uip || !uip.canvas) continue;
|
||||||
|
|
||||||
// Case 1: Not using mesh sharing.
|
uip.UpdateTransformScale();
|
||||||
|
|
||||||
if (!uip.useMeshSharing)
|
if (!uip.useMeshSharing)
|
||||||
{
|
{
|
||||||
uip.UpdateTransformScale(Vector3.one);
|
|
||||||
uip.UpdateRenderers();
|
uip.UpdateRenderers();
|
||||||
}
|
}
|
||||||
// Case 2: Using mesh sharing as primary.
|
else if (s_UpdatedGroupIds.Add(uip.groupId))
|
||||||
else if (!s_GroupScales.TryGetValue(uip.groupId, out var groupScale))
|
|
||||||
{
|
{
|
||||||
s_GroupScales.Add(uip.groupId, uip.transform.parent.lossyScale);
|
|
||||||
uip.UpdateTransformScale(Vector3.one);
|
|
||||||
uip.UpdateRenderers();
|
uip.UpdateRenderers();
|
||||||
}
|
}
|
||||||
// Case 3: Using mesh sharing as replica. (Only scaling)
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var parentScale = uip.transform.parent.lossyScale;
|
|
||||||
var ratio = parentScale.IsVisible()
|
|
||||||
? groupScale.GetScaled(parentScale.Inverse())
|
|
||||||
: Vector3.one;
|
|
||||||
ratio = Vector3.one;
|
|
||||||
uip.UpdateTransformScale(ratio);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s_UpdatedGroupIds.Clear();
|
||||||
|
|
||||||
// Attract
|
// Attract
|
||||||
for (var i = 0; i < s_ActiveAttractors.Count; i++)
|
for (var i = 0; i < s_ActiveAttractors.Count; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
8
Packages/src/Runtime/Utilities.meta
Normal file
8
Packages/src/Runtime/Utilities.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 66c42f0f30de84ca4bd8305a1188af85
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,96 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
namespace Coffee.UIParticleExtensions
|
namespace Coffee.UIParticleInternal
|
||||||
{
|
{
|
||||||
public static class Color32Extensions
|
internal static class ParticleSystemExtensions
|
||||||
{
|
|
||||||
private static byte[] s_LinearToGammaLut;
|
|
||||||
|
|
||||||
public static byte LinearToGamma(this byte self)
|
|
||||||
{
|
|
||||||
if (s_LinearToGammaLut == null)
|
|
||||||
{
|
|
||||||
s_LinearToGammaLut = new byte[256];
|
|
||||||
for (var i = 0; i < 256; i++)
|
|
||||||
{
|
|
||||||
s_LinearToGammaLut[i] = (byte)(Mathf.LinearToGammaSpace(i / 255f) * 255f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return s_LinearToGammaLut[self];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Vector3Extensions
|
|
||||||
{
|
|
||||||
public static Vector3 Inverse(this Vector3 self)
|
|
||||||
{
|
|
||||||
self.x = Mathf.Approximately(self.x, 0) ? 1 : 1 / self.x;
|
|
||||||
self.y = Mathf.Approximately(self.y, 0) ? 1 : 1 / self.y;
|
|
||||||
self.z = Mathf.Approximately(self.z, 0) ? 1 : 1 / self.z;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1)
|
|
||||||
{
|
|
||||||
self.Scale(other1);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2)
|
|
||||||
{
|
|
||||||
self.Scale(other1);
|
|
||||||
self.Scale(other2);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2, Vector3 other3)
|
|
||||||
{
|
|
||||||
self.Scale(other1);
|
|
||||||
self.Scale(other2);
|
|
||||||
self.Scale(other3);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsVisible(this Vector3 self)
|
|
||||||
{
|
|
||||||
return 0 < Mathf.Abs(self.x * self.y * self.z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static class SpriteExtensions
|
|
||||||
{
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
private static readonly Type s_SpriteEditorExtensionType =
|
|
||||||
Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
|
|
||||||
?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor");
|
|
||||||
|
|
||||||
private static readonly MethodInfo s_GetActiveAtlasTextureMethodInfo = s_SpriteEditorExtensionType
|
|
||||||
.GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic);
|
|
||||||
|
|
||||||
public static Texture2D GetActualTexture(this Sprite self)
|
|
||||||
{
|
|
||||||
if (!self) return null;
|
|
||||||
|
|
||||||
if (Application.isPlaying) return self.texture;
|
|
||||||
var ret = s_GetActiveAtlasTextureMethodInfo.Invoke(null, new object[] { self }) as Texture2D;
|
|
||||||
return ret
|
|
||||||
? ret
|
|
||||||
: self.texture;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
internal static Texture2D GetActualTexture(this Sprite self)
|
|
||||||
{
|
|
||||||
return self ? self.texture : null;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ParticleSystemExtensions
|
|
||||||
{
|
{
|
||||||
private static ParticleSystem.Particle[] s_TmpParticles = new ParticleSystem.Particle[2048];
|
private static ParticleSystem.Particle[] s_TmpParticles = new ParticleSystem.Particle[2048];
|
||||||
|
|
||||||
@@ -250,59 +165,38 @@ namespace Coffee.UIParticleExtensions
|
|||||||
|
|
||||||
public static void Exec(this List<ParticleSystem> self, Action<ParticleSystem> action)
|
public static void Exec(this List<ParticleSystem> self, Action<ParticleSystem> action)
|
||||||
{
|
{
|
||||||
self.RemoveAll(p => !p);
|
foreach (var p in self)
|
||||||
self.ForEach(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static class Misc
|
|
||||||
{
|
|
||||||
public static void Destroy(Object obj)
|
|
||||||
{
|
|
||||||
if (!obj) return;
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
if (!Application.isPlaying)
|
|
||||||
{
|
{
|
||||||
Object.DestroyImmediate(obj);
|
if (!p) continue;
|
||||||
}
|
action.Invoke(p);
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
Object.Destroy(obj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DestroyImmediate(Object obj)
|
public static ParticleSystem GetMainEmitter(this ParticleSystem self, List<ParticleSystem> list)
|
||||||
{
|
{
|
||||||
if (!obj) return;
|
if (!self || list == null || list.Count == 0) return null;
|
||||||
#if UNITY_EDITOR
|
|
||||||
if (Application.isEditor)
|
|
||||||
{
|
|
||||||
Object.DestroyImmediate(obj);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
Object.Destroy(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !UNITY_2021_2_OR_NEWER && !UNITY_2020_3_45 && !UNITY_2020_3_46 && !UNITY_2020_3_47 && !UNITY_2020_3_48
|
for (var i = 0; i < list.Count; i++)
|
||||||
public static T GetComponentInParent<T>(this Component self, bool includeInactive) where T : Component
|
|
||||||
{
|
|
||||||
if (!self) return null;
|
|
||||||
if (!includeInactive) return self.GetComponentInParent<T>();
|
|
||||||
|
|
||||||
var current = self.transform;
|
|
||||||
while (current)
|
|
||||||
{
|
{
|
||||||
var component = current.GetComponent<T>();
|
var parent = list[i];
|
||||||
if (component) return component;
|
if (parent != self && IsSubEmitterOf(self, parent)) return parent;
|
||||||
current = current.parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
public static bool IsSubEmitterOf(this ParticleSystem self, ParticleSystem parent)
|
||||||
|
{
|
||||||
|
if (!self || !parent) return false;
|
||||||
|
|
||||||
|
var subEmitters = parent.subEmitters;
|
||||||
|
var count = subEmitters.subEmittersCount;
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (subEmitters.GetSubEmitterSystem(i) == self) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e51604bfb810e44519e2710fd1b8af90
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Coffee.UIParticleInternal;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Serialization;
|
using UnityEngine.Serialization;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
@@ -51,11 +52,7 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void EnableAnimations(bool flag)
|
public void EnableAnimations(bool flag)
|
||||||
{
|
{
|
||||||
#if UNITY_2023_1_OR_NEWER
|
foreach (var animator in Misc.FindObjectsOfType<Animator>())
|
||||||
foreach (var animator in FindObjectsByType<Animator>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
|
||||||
#else
|
|
||||||
foreach (var animator in FindObjectsOfType<Animator>())
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
animator.enabled = flag;
|
animator.enabled = flag;
|
||||||
}
|
}
|
||||||
@@ -83,11 +80,7 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void UIParticle_Scale(float scale)
|
public void UIParticle_Scale(float scale)
|
||||||
{
|
{
|
||||||
#if UNITY_2023_1_OR_NEWER
|
foreach (var uip in Misc.FindObjectsOfType<UIParticle>())
|
||||||
foreach (var uip in FindObjectsByType<UIParticle>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
|
||||||
#else
|
|
||||||
foreach (var uip in FindObjectsOfType<UIParticle>())
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
uip.scale = scale;
|
uip.scale = scale;
|
||||||
}
|
}
|
||||||
@@ -95,11 +88,7 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void ParticleSystem_WorldSpaseSimulation(bool flag)
|
public void ParticleSystem_WorldSpaseSimulation(bool flag)
|
||||||
{
|
{
|
||||||
#if UNITY_2023_1_OR_NEWER
|
foreach (var p in Misc.FindObjectsOfType<ParticleSystem>())
|
||||||
foreach (var p in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
|
||||||
#else
|
|
||||||
foreach (var p in FindObjectsOfType<ParticleSystem>())
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
var main = p.main;
|
var main = p.main;
|
||||||
main.simulationSpace = flag
|
main.simulationSpace = flag
|
||||||
@@ -135,11 +124,7 @@ namespace Coffee.UIExtensions.Demo
|
|||||||
|
|
||||||
public void ParticleSystem_SetScale(float scale)
|
public void ParticleSystem_SetScale(float scale)
|
||||||
{
|
{
|
||||||
#if UNITY_2023_1_OR_NEWER
|
foreach (var ps in Misc.FindObjectsOfType<ParticleSystem>())
|
||||||
foreach (var ps in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
|
||||||
#else
|
|
||||||
foreach (var ps in FindObjectsOfType<ParticleSystem>())
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
ps.transform.localScale = new Vector3(scale, scale, scale);
|
ps.transform.localScale = new Vector3(scale, scale, scale);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,10 @@
|
|||||||
Lighting Off
|
Lighting Off
|
||||||
ZWrite Off
|
ZWrite Off
|
||||||
ZTest [unity_GUIZTestMode]
|
ZTest [unity_GUIZTestMode]
|
||||||
Fog { Mode Off }
|
Fog
|
||||||
|
{
|
||||||
|
Mode Off
|
||||||
|
}
|
||||||
Blend One One
|
Blend One One
|
||||||
|
|
||||||
ColorMask [_ColorMask]
|
ColorMask [_ColorMask]
|
||||||
@@ -61,21 +64,21 @@
|
|||||||
|
|
||||||
struct appdata_t
|
struct appdata_t
|
||||||
{
|
{
|
||||||
float4 vertex : POSITION;
|
float4 vertex : POSITION;
|
||||||
float4 color : COLOR;
|
float4 color : COLOR;
|
||||||
float2 texcoord : TEXCOORD0;
|
float2 texcoord : TEXCOORD0;
|
||||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||||
};
|
};
|
||||||
|
|
||||||
struct v2f
|
struct v2f
|
||||||
{
|
{
|
||||||
float4 vertex : SV_POSITION;
|
float4 vertex : SV_POSITION;
|
||||||
fixed4 color : COLOR;
|
fixed4 color : COLOR;
|
||||||
float2 texcoord : TEXCOORD0;
|
float2 texcoord : TEXCOORD0;
|
||||||
float4 worldPosition : TEXCOORD1;
|
float4 worldPosition : TEXCOORD1;
|
||||||
UNITY_VERTEX_OUTPUT_STEREO
|
UNITY_VERTEX_OUTPUT_STEREO
|
||||||
};
|
};
|
||||||
|
|
||||||
fixed4 _Color;
|
fixed4 _Color;
|
||||||
sampler2D _MainTex;
|
sampler2D _MainTex;
|
||||||
float4 _MainTex_ST;
|
float4 _MainTex_ST;
|
||||||
@@ -114,4 +117,4 @@
|
|||||||
ENDCG
|
ENDCG
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "com.coffee.ui-particle",
|
"name": "com.coffee.ui-particle",
|
||||||
"displayName": "UI Particle",
|
"displayName": "UI Particle",
|
||||||
"description": "This package provides a component to render particle effects for uGUI.\nThe particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.",
|
"description": "This package provides a component to render particle effects for uGUI.\nThe particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.",
|
||||||
"version": "4.9.1",
|
"version": "4.11.3",
|
||||||
"unity": "2018.2",
|
"unity": "2018.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
11
ProjectSettings/MinimalResourceSettings.json
Normal file
11
ProjectSettings/MinimalResourceSettings.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"MonoBehaviour": {
|
||||||
|
"m_Enabled": true,
|
||||||
|
"m_EditorHideFlags": 0,
|
||||||
|
"m_Name": "",
|
||||||
|
"m_EditorClassIdentifier": "",
|
||||||
|
"m_OutputDllPaths": [
|
||||||
|
"Packages/com.coffee.ui-particle/Runtime/Coffee.UIParticle.R.dll"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -124,7 +124,7 @@ PlayerSettings:
|
|||||||
bundleVersion: 1.0
|
bundleVersion: 1.0
|
||||||
preloadedAssets:
|
preloadedAssets:
|
||||||
- {fileID: 11400000, guid: 86087a0847f384b538391745dad4565c, type: 2}
|
- {fileID: 11400000, guid: 86087a0847f384b538391745dad4565c, type: 2}
|
||||||
- {fileID: 11400000, guid: be3e05903ef7041d39b3ef8ecdd47f08, type: 2}
|
- {fileID: 11400000, guid: 4b9df7b8a4193489299b8f477348ae0c, type: 2}
|
||||||
metroInputSource: 0
|
metroInputSource: 0
|
||||||
wsaTransparentSwapchain: 0
|
wsaTransparentSwapchain: 0
|
||||||
m_HolographicPauseOnTrackingLoss: 1
|
m_HolographicPauseOnTrackingLoss: 1
|
||||||
|
|||||||
Reference in New Issue
Block a user