summaryrefslogtreecommitdiff
path: root/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2024-12-27 00:56:58 -0500
committerFreya Murphy <freya@freyacat.org>2024-12-27 00:58:02 -0500
commit799e6680d40119dc9c2a9e0b320054a40324bebe (patch)
treedbcd308d59eb6e4f937a5547dd77d9f91d4fec20 /VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem
parentmove to self host (diff)
downloadunityprojects-799e6680d40119dc9c2a9e0b320054a40324bebe.tar.gz
unityprojects-799e6680d40119dc9c2a9e0b320054a40324bebe.tar.bz2
unityprojects-799e6680d40119dc9c2a9e0b320054a40324bebe.zip
VRCSDK3Avatars found!
Diffstat (limited to 'VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem')
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors.meta8
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components.meta8
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/FunctionTimeline.cs651
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/FunctionTimeline.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/TemplateGraph.cs293
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/TemplateGraph.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers.meta8
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/EnablePropertyDrawer.cs30
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/EnablePropertyDrawer.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/FunctionPropertyDrawer.cs32
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/FunctionPropertyDrawer.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ModuleTemplatePropertyDrawer.cs29
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ModuleTemplatePropertyDrawer.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/PropertyAttributeDrawer.cs52
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/PropertyAttributeDrawer.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ShaderPropertyDrawer.cs289
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ShaderPropertyDrawer.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/VariablePropertyDrawer.cs43
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/VariablePropertyDrawer.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements.meta8
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/CodeViewElement.cs104
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/CodeViewElement.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/InspectorList.cs324
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/InspectorList.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/LabelField.cs56
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/LabelField.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/ModuleInspectorList.cs315
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/ModuleInspectorList.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/VariableField.cs30
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/VariableField.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors.meta8
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ModularShaderEditor.cs68
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ModularShaderEditor.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ShaderModuleEditor.cs23
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ShaderModuleEditor.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/TemplateAssetEditor.cs20
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/TemplateAssetEditor.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows.meta8
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/Migrator.cs814
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/Migrator.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/ModularShaderDebugger.cs153
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/ModularShaderDebugger.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/TextPopup.cs20
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/TextPopup.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/LICENSE21
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/LICENSE.meta7
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/MSSConstants.cs21
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/MSSConstants.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ModularShaderSystemDefinition.asmdef15
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ModularShaderSystemDefinition.asmdef.meta7
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources.meta8
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS.meta8
-rwxr-xr-xVRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDeleteIcon.pngbin0 -> 2891 bytes
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDeleteIcon.png.meta104
-rwxr-xr-xVRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDownIcon.pngbin0 -> 1578 bytes
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDownIcon.png.meta104
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements.meta8
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/EnablePropertyDrawer.uxml6
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/EnablePropertyDrawer.uxml.meta10
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionPropertyDrawer.uxml9
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionPropertyDrawer.uxml.meta10
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionTimelineStyle.uss173
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionTimelineStyle.uss.meta3
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionView.uxml9
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionView.uxml.meta10
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/InspectorList.uss139
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/InspectorList.uss.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorDark.uss43
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorDark.uss.meta3
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorLight.uss42
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorLight.uss.meta3
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderDebuggerStyle.uss37
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderDebuggerStyle.uss.meta3
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderEditor.uxml17
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderEditor.uxml.meta10
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModuleTemplatePropertyDrawer.uxml6
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModuleTemplatePropertyDrawer.uxml.meta10
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/PropertyView.uxml6
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/PropertyView.uxml.meta10
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderModuleEditor.uxml16
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderModuleEditor.uxml.meta10
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderPropertyDrawer.uxml9
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderPropertyDrawer.uxml.meta10
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/TemplateGraphStyle.uss15
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/TemplateGraphStyle.uss.meta3
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/VariablePropertyDrawer.uxml5
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/VariablePropertyDrawer.uxml.meta10
-rwxr-xr-xVRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUpIcon.pngbin0 -> 1572 bytes
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUpIcon.png.meta104
-rwxr-xr-xVRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ModularShaderIcon.pngbin0 -> 8796 bytes
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ModularShaderIcon.png.meta104
-rwxr-xr-xVRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/RobotoMono-Regular.ttfbin0 -> 86908 bytes
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/RobotoMono-Regular.ttf.meta3
-rwxr-xr-xVRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ShaderModuleIcon.pngbin0 -> 3518 bytes
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ShaderModuleIcon.png.meta104
-rwxr-xr-xVRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateCollectionIcon.pngbin0 -> 5121 bytes
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateCollectionIcon.png.meta104
-rwxr-xr-xVRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateIcon.pngbin0 -> 1470 bytes
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateIcon.png.meta104
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables.meta8
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/EnableProperty.cs60
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/EnableProperty.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModularShader.cs41
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModularShader.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModuleTemplate.cs19
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModuleTemplate.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Property.cs89
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Property.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderFunction.cs25
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderFunction.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderModule.cs34
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderModule.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAsset.cs48
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAsset.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAssetImporter.cs39
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAssetImporter.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAsset.cs47
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAsset.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAssetImporter.cs86
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAssetImporter.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Variable.cs138
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Variable.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderGenerator.cs930
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderGenerator.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderStringBuilderExtensions.cs103
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderStringBuilderExtensions.cs.meta11
126 files changed, 6898 insertions, 0 deletions
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors.meta
new file mode 100644
index 00000000..6d4a06a0
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4ba88caeb15a1b0469773b278aa26bab
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components.meta
new file mode 100644
index 00000000..1352cc98
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 13fa33428f9f4a84b8e3dc4bfedd6e64
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/FunctionTimeline.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/FunctionTimeline.cs
new file mode 100644
index 00000000..101adaa6
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/FunctionTimeline.cs
@@ -0,0 +1,651 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UIElements;
+using UnityEditor.UIElements;
+using Poiyomi.ModularShaderSystem.UI;
+
+namespace Poiyomi.ModularShaderSystem.Debug
+{
+ public class FunctionTimeline : IModularShaderDebuggerTab
+ {
+ public VisualElement TabContainer { get; set; }
+ public string TabName { get; set; }
+
+ public FunctionTimeline()
+ {
+ TabName = "Function Timeline";
+ TabContainer = new VisualElement();
+
+ var styleSheet = Resources.Load<StyleSheet>(MSSConstants.RESOURCES_FOLDER + "/MSSUIElements/FunctionTimelineStyle");
+ TabContainer.styleSheets.Add(styleSheet);
+ TabContainer.style.flexGrow = 1;
+ }
+
+ public void UpdateTab(ModularShader shader)
+ {
+ TabContainer.Clear();
+ if (shader == null) return;
+ TabContainer.Add(new TimelineContainer(shader));
+ }
+ }
+
+ internal class FunctionItem : VisualElement
+ {
+ public ShaderFunction Function { get; }
+ public TimelineRow Row { get; set; }
+ public int Size { get; }
+ public int Offset { get; }
+
+ private TimelineRoot _root;
+
+ public FunctionItem(TimelineRoot root, ShaderFunction function, int size, int offset)
+ {
+ _root = root;
+ Function = function;
+ Size = size;
+ Offset = offset;
+
+ style.left = Offset;
+ style.width = Size;
+
+ var label = new Label(Function.Name);
+ label.AddToClassList("function-header-name");
+ var queue = new Label("" + Function.Queue);
+ queue.AddToClassList("function-header-queue");
+ Add(label);
+ Add(queue);
+
+ RegisterCallback<MouseUpEvent>(evt =>
+ {
+ if (evt.button != 0) return;
+ _root.SelectedFunction = this;
+ });
+ }
+ }
+
+ internal class TimelineRow : VisualElement
+ {
+ public ShaderModule Module { get; }
+
+ public List<FunctionItem> Functions { get; set; }
+
+ private VisualElement _title;
+ public VisualElement _content;
+ public List<VisualElement> _contentChilden;
+
+ public TimelineRow(ShaderModule module)
+ {
+ Module = module;
+
+ Functions = new List<FunctionItem>();
+ _contentChilden = new List<VisualElement>();
+
+ _title = new VisualElement();
+ _content = new VisualElement();
+ _title.AddToClassList("timeline-title");
+ _content.AddToClassList("timeline-content");
+
+ _title.Add(new Label(Module.Name));
+
+ Add(_content);
+ Add(_title);
+ }
+
+ public void SetContentSize(int size)
+ {
+ _content.style.width = size;
+ }
+
+ public void ApplyFunctionsToTimeline()
+ {
+ _content.Clear();
+ _contentChilden.Clear();
+
+ for (int index = Functions.Count - 1; index >= 0; index--)
+ {
+ FunctionItem function = Functions[index];
+ int counter = 0;
+ bool found = false;
+ var functionStart = function.Offset;
+ var functionEnd = function.Offset + function.Size;
+ while (counter < _contentChilden.Count)
+ {
+ if (!TimelineBusyAt(_contentChilden[counter], functionStart, functionEnd))
+ {
+ _contentChilden[counter].Add(function);
+ function.Row = this;
+ found = true;
+ break;
+ }
+ counter++;
+ }
+ if (found) continue;
+ var newRow = new VisualElement();
+ newRow.AddToClassList("timeline-content-row");
+ _contentChilden.Add(newRow);
+ _content.Add(newRow);
+ newRow.Add(function);
+ function.Row = this;
+ }
+ }
+
+ private static bool TimelineBusyAt(VisualElement content, int functionStart, int functionEnd)
+ {
+ return content.Children().Cast<FunctionItem>().Any(x => functionStart < x.Offset + x.Size && functionStart > x.Offset && functionEnd <= x.Offset + x.Size);
+ }
+
+ public void SetRowsHeight()
+ {
+ foreach (VisualElement element in _contentChilden)
+ element.style.height = element[0].resolvedStyle.height + 8;
+ }
+ }
+
+ internal class TimelineRoot : VisualElement
+ {
+ public List<TimelineRow> Rows { get; set; }
+ public List<FunctionItem> Functions { get; set; }
+
+ public FunctionItem SelectedFunction
+ {
+ get => _selectedFunction;
+ set
+ {
+ _selectedFunction = value;
+ ResetSelectedClass();
+ OnSelectedFunctionChanged?.Invoke(_selectedFunction);
+ }
+ }
+
+ public string Keyword { get; }
+
+ public Action<FunctionItem> OnSelectedFunctionChanged { get; set; }
+ public Action OnTimelineFirstDispatch { get; set; }
+
+ private readonly Dictionary<ShaderFunction, ShaderModule> _moduleByFunction;
+ private FunctionItem _selectedFunction;
+
+ public TimelineRoot(Dictionary<ShaderFunction, ShaderModule> moduleByFunction, List<ShaderFunction> allFunctions, string rootKeyword)
+ {
+ Keyword = rootKeyword;
+ Rows = new List<TimelineRow>();
+ Functions = new List<FunctionItem>();
+ int offset = 0;
+ _moduleByFunction = moduleByFunction;
+ foreach (var fn in allFunctions.Where(x => x.AppendAfter.Equals(rootKeyword)).OrderBy(x => x.Queue))
+ {
+ offset += CreateFunctionHierarchy(allFunctions, fn, offset);
+ }
+
+ foreach (TimelineRow row in Rows)
+ {
+ Add(row);
+ row.SetContentSize(offset + 30);
+ row.ApplyFunctionsToTimeline();
+ }
+
+ RegisterCallback<GeometryChangedEvent>(GeometryChangedCallback);
+ }
+
+ private void GeometryChangedCallback(GeometryChangedEvent evt)
+ {
+ UnregisterCallback<GeometryChangedEvent>(GeometryChangedCallback);
+
+ foreach (TimelineRow row in Rows)
+ {
+ row.SetRowsHeight();
+ }
+
+ OnTimelineFirstDispatch?.Invoke();
+ }
+
+ private int CreateFunctionHierarchy(List<ShaderFunction> functions, ShaderFunction function, int offset)
+ {
+ int size = 0;
+ var module = _moduleByFunction[function];
+ var row = Rows.FirstOrDefault(x => x.Module == module);
+ if (row == null)
+ {
+ row = new TimelineRow(module);
+ Rows.Add(row);
+ }
+
+ foreach (var fn in functions.Where(x => x.AppendAfter.Equals(function.Name)).OrderBy(x => x.Queue))
+ size += CreateFunctionHierarchy(functions, fn, offset + size + 30);
+
+ if (size == 0) size = 224;
+ else size += 30;
+
+ var functionItem = new FunctionItem(this, function, size - 4, offset);
+ row.Functions.Add(functionItem);
+ Functions.Add(functionItem);
+
+ return size;
+ }
+
+ public float GetScrollAdjustment()
+ {
+ float factor = 1.1f;
+ if (Rows.Count <= 0) return factor;
+
+ var width = Rows[0]._content.style.width.value.value;
+ var screenWidth = Rows[0]._content.resolvedStyle.width;
+ factor = screenWidth / width;
+
+ return factor;
+ }
+
+ public void Scroll(float f)
+ {
+ foreach (TimelineRow row in Rows)
+ {
+ var width = row._content.style.width.value.value;
+ var screenWidth = row._content.resolvedStyle.width;
+ if(width > screenWidth)
+ row._content.style.left = -((width- screenWidth) * f);
+ }
+ }
+
+ public void ResetSelectedClass()
+ {
+ foreach (FunctionItem function in Functions)
+ {
+ if (function == SelectedFunction && !function.ClassListContains("selected-function"))
+ function.AddToClassList("selected-function");
+ else if (function != SelectedFunction && function.ClassListContains("selected-function"))
+ function.RemoveFromClassList("selected-function");
+ }
+ }
+ }
+
+ internal class VariablesViewer : VisualElement
+ {
+ public Action<Variable> OnVariableSelected { get; set; }
+
+ private List<VariableField> _variables;
+
+ public VariablesViewer(ModularShader shader)
+ {
+ var variables = shader.BaseModules.Concat(shader.AdditionalModules).SelectMany(x => x.Functions).SelectMany(x => x.UsedVariables).Distinct().OrderBy(x => x.Type).ThenBy(x => x.Name);
+
+ var title = new Label("Variables List");
+ title.AddToClassList("area-title");
+ var content = new ScrollView(ScrollViewMode.Vertical);
+ content.AddToClassList("area-content");
+
+ _variables = new List<VariableField>();
+
+ foreach (Variable variable in variables)
+ {
+ var element = new VariableField(variable);
+ _variables.Add(element);
+ content.Add(element);
+
+ element.RegisterCallback<MouseUpEvent>(evt =>
+ {
+ if (evt.button != 0) return;
+ foreach (VariableField field in _variables)
+ {
+ if (field.ClassListContains("selected-variable-global"))
+ field.RemoveFromClassList("selected-variable-global");
+ }
+
+ element.AddToClassList("selected-variable-global");
+ OnVariableSelected?.Invoke(element.Variable);
+ });
+ }
+
+ Add(title);
+ Add(content);
+ }
+ }
+
+ internal class FunctionViewer : VisualElement
+ {
+ public ShaderFunction SelectedItem
+ {
+ get => _selectedItem;
+ set
+ {
+ _selectedItem = value;
+ _appendAfter.Value = _selectedItem?.AppendAfter;
+ _name.Value = _selectedItem?.Name;
+ _queue.Value = "" + _selectedItem?.Queue;
+
+ _variables.Clear();
+ _variablesFoldout.Clear();
+ _variableKeywordsFoldout.Clear();
+ _codeKeywordsFoldout.Clear();
+ if (_selectedItem == null)
+ {
+ OnVariableSelected?.Invoke(null);
+ return;
+ }
+
+ foreach (Variable variable in _selectedItem.UsedVariables)
+ {
+ var element = new VariableField(variable);
+ _variables.Add(element);
+ _variablesFoldout.Add(element);
+
+ element.RegisterCallback<MouseUpEvent>(evt =>
+ {
+ if (evt.button != 0) return;
+ foreach (VariableField field in _variables)
+ {
+ if (field.ClassListContains("selected-variable"))
+ field.RemoveFromClassList("selected-variable");
+ }
+ element.AddToClassList("selected-variable");
+ OnVariableSelected?.Invoke(element.Variable);
+ });
+ }
+
+
+ foreach (string keyword in _selectedItem.VariableKeywords)
+ _variableKeywordsFoldout.Add(new Label(keyword));
+ if(_variableKeywordsFoldout.childCount == 0)
+ _variableKeywordsFoldout.Add(new Label("None"));
+
+ foreach (string keyword in _selectedItem.CodeKeywords)
+ _codeKeywordsFoldout.Add(new Label(keyword));
+ if(_codeKeywordsFoldout.childCount == 0)
+ _codeKeywordsFoldout.Add(new Label("None"));
+ }
+ }
+
+ public Action<Variable> OnVariableSelected { get; set; }
+
+ private LabelField _appendAfter;
+ private LabelField _name;
+ private LabelField _queue;
+ private ShaderFunction _selectedItem;
+ private Foldout _variablesFoldout;
+ private List<VariableField> _variables;
+ private readonly Foldout _variableKeywordsFoldout;
+ private readonly Foldout _codeKeywordsFoldout;
+
+ public FunctionViewer()
+ {
+ var title = new Label("Selected function information");
+ title.AddToClassList("area-title");
+ var content = new ScrollView(ScrollViewMode.Vertical);
+ content.AddToClassList("area-content");
+
+ _name = new LabelField("Name", "");
+ _appendAfter = new LabelField("Append After", "");
+ _queue = new LabelField("Queue", "");
+
+ _variablesFoldout = new Foldout();
+ _variablesFoldout.text = "Variables";
+ _variables = new List<VariableField>();
+
+ _variableKeywordsFoldout = new Foldout();
+ _variableKeywordsFoldout.text = "Variable Keywords";
+
+ _codeKeywordsFoldout = new Foldout();
+ _codeKeywordsFoldout.text = "Code Keywords";
+
+ Add(title);
+ Add(content);
+ content.Add(_name);
+ content.Add(_appendAfter);
+ content.Add(_queue);
+ content.Add(_variablesFoldout);
+ content.Add(_variableKeywordsFoldout);
+ content.Add(_codeKeywordsFoldout);
+ }
+ }
+
+ internal class ModuleViewer : VisualElement
+ {
+ public ShaderModule SelectedItem
+ {
+ get => _selectedItem;
+ set
+ {
+ _selectedItem = value;
+ if (_selectedItem == null)
+ {
+ _name.Value = null;
+ _id.Value = null;
+ _description.Value =null;
+ _author.Value = null;
+ _version.Value = null;
+ if(_content.Contains(_selectButton)) _content.Remove(_selectButton);
+ return;
+ }
+ _name.Value = _selectedItem.Name;
+ _id.Value = _selectedItem.Id;
+ _description.Value = _selectedItem.Description;
+ _author.Value = _selectedItem.Author;
+ _version.Value = _selectedItem.Version;
+
+ if(!_content.Contains(_selectButton)) _content.Add(_selectButton);
+ }
+ }
+
+ private ShaderModule _selectedItem;
+ private readonly LabelField _name;
+ private readonly LabelField _id;
+ private readonly LabelField _author;
+ private readonly LabelField _description;
+ private readonly LabelField _version;
+ private Button _selectButton;
+ private ScrollView _content;
+
+ public ModuleViewer()
+ {
+ var title = new Label("Function's module base info");
+ title.AddToClassList("area-title");
+ var content = new ScrollView(ScrollViewMode.Vertical);
+ _content = content;
+ _content.AddToClassList("area-content");
+
+ _name = new LabelField("Name", "");
+ _id = new LabelField("Id", "");
+ _author = new LabelField("Author", "");
+ _description = new LabelField("Description", "");
+ _version = new LabelField("Version", "");
+
+ _selectButton = new Button(() =>
+ {
+ if (_selectedItem == null) return;
+ Selection.SetActiveObjectWithContext(_selectedItem,_selectedItem);
+ });
+
+ _selectButton.text = "Select module in inspector";
+
+ Add(title);
+ Add(_content);
+
+ _content.Add(_name);
+ _content.Add(_id);
+ _content.Add(_author);
+ _content.Add(_description);
+ _content.Add(_version);
+ }
+ }
+
+ internal class FunctionTemplateViewer : VisualElement
+ {
+ public string SelectedItem
+ {
+ get => _selectedItem;
+ set
+ {
+ _selectedItem = value;
+ _viewer.Text = _selectedItem;
+ }
+ }
+
+ private CodeViewElement _viewer;
+ private string _selectedItem;
+
+ public FunctionTemplateViewer()
+ {
+ _viewer = new CodeViewElement();
+
+ var title = new Label("Function code template");
+ title.AddToClassList("area-title");
+
+ Add(title);
+ Add(_viewer);
+ }
+ }
+
+ internal class TimelineContainer : VisualElement
+ {
+ private List<TimelineRoot> _roots;
+ private PopupField<TimelineRoot> _popup;
+
+ public TimelineContainer(ModularShader shader)
+ {
+ var left = new VisualElement();
+ var right = new VisualElement();
+ var bot = new VisualElement();
+ var templateViewer = new FunctionTemplateViewer();
+ var variablesViewer = new VariablesViewer(shader);
+ var functionViewer = new FunctionViewer();
+ var moduleViewer = new ModuleViewer();
+
+ left.style.flexShrink = 0;
+ left.style.width = new StyleLength(Length.Percent(70));
+ right.style.width = new StyleLength(Length.Percent(30));
+ bot.style.height = new StyleLength(Length.Percent(50));
+ bot.style.flexDirection = FlexDirection.Row;
+ style.flexDirection = FlexDirection.Row;
+ Add(left);
+ Add(right);
+
+ var scroller = new Scroller(0,1,f =>
+ {
+ _popup.value.Scroll(f);
+ }, SliderDirection.Horizontal);
+
+ _roots = new List<TimelineRoot>();
+ var functions = new List<ShaderFunction>();
+ Dictionary<ShaderFunction, ShaderModule> moduleByFunction = new Dictionary<ShaderFunction, ShaderModule>();
+
+ foreach (var module in shader.BaseModules)
+ {
+ functions.AddRange(module.Functions);
+ foreach (var function in module.Functions)
+ if (!moduleByFunction.ContainsKey(function))
+ moduleByFunction.Add(function, module);
+ }
+
+ foreach (var module in shader.AdditionalModules)
+ {
+ functions.AddRange(module.Functions);
+ foreach (var function in module.Functions)
+ if (!moduleByFunction.ContainsKey(function))
+ moduleByFunction.Add(function, module);
+ }
+
+ foreach (var keyword in functions.Select(x => x.AppendAfter).Distinct().Where(x => x.StartsWith("#K#")))
+ {
+ var root = new TimelineRoot(moduleByFunction, functions, keyword);
+ root.OnSelectedFunctionChanged = item =>
+ {
+ functionViewer.SelectedItem = item.Function;
+ moduleViewer.SelectedItem = item.Row.Module;
+ templateViewer.SelectedItem = item.Function.ShaderFunctionCode == null ? null : item.Function.ShaderFunctionCode.Template;
+
+ variablesViewer.OnVariableSelected = variable =>
+ {
+ foreach (FunctionItem f in root.Functions)
+ {
+ bool toHighlight = f.Function.UsedVariables.Any(x => x == variable);
+
+ if(toHighlight && !f.ClassListContains("contains-variable-global"))
+ f.AddToClassList("contains-variable-global");
+ if(!toHighlight && f.ClassListContains("contains-variable-global"))
+ f.RemoveFromClassList("contains-variable-global");
+ }
+ };
+
+ functionViewer.OnVariableSelected = variable =>
+ {
+ foreach (FunctionItem f in root.Functions)
+ {
+ bool toHighlight = f.Function.UsedVariables.Any(x => x == variable);
+
+ if(toHighlight && !f.ClassListContains("contains-variable"))
+ f.AddToClassList("contains-variable");
+ if(!toHighlight && f.ClassListContains("contains-variable"))
+ f.RemoveFromClassList("contains-variable");
+ }
+ };
+
+ foreach (FunctionItem f in root.Functions)
+ {
+ if(f.ClassListContains("contains-variable"))
+ f.RemoveFromClassList("contains-variable");
+ }
+ };
+ root.OnTimelineFirstDispatch = () =>
+ {
+ scroller.Adjust(root.GetScrollAdjustment());
+ };
+ _roots.Add(root);
+ }
+
+ var timelineContent = new VisualElement();
+ if (_roots.Count == 0)
+ {
+ Label label = new Label("No roots found");
+ left.Add(label);
+ return;
+ }
+ timelineContent.Add(_roots[0]);
+
+ variablesViewer.OnVariableSelected = variable =>
+ {
+ foreach (FunctionItem f in _roots[0].Functions)
+ {
+ bool toHighlight = f.Function.UsedVariables.Any(x => x == variable);
+
+ if(toHighlight && !f.ClassListContains("contains-variable-global"))
+ f.AddToClassList("contains-variable-global");
+ if(!toHighlight && f.ClassListContains("contains-variable-global"))
+ f.RemoveFromClassList("contains-variable-global");
+ }
+ };
+
+ var timelineScroll = new ScrollView(ScrollViewMode.Vertical);
+ timelineScroll.AddToClassList("timeline");
+ timelineScroll.style.flexGrow = 1;
+ timelineScroll.Add(timelineContent);
+
+ _popup = new PopupField<TimelineRoot>("Root keywords", _roots, 0, root => { return root.Keyword; }, root => { return root.Keyword; });
+ _popup.RegisterValueChangedCallback(evt =>
+ {
+ timelineContent.Clear();
+ timelineContent.Add(evt.newValue);
+ functionViewer.SelectedItem = evt.newValue?.SelectedFunction?.Function;
+ moduleViewer.SelectedItem = evt.newValue?.SelectedFunction?.Row.Module;
+ templateViewer.SelectedItem = evt.newValue?.SelectedFunction?.Function.ShaderFunctionCode.Template;
+ scroller.Adjust(evt.newValue.GetScrollAdjustment());
+ scroller.value = 0;
+ evt.newValue.Scroll(0);
+ });
+
+ scroller.Adjust(_popup.value.GetScrollAdjustment());
+
+ timelineScroll.Add(timelineContent);
+
+ left.Add(_popup);
+ left.Add(timelineScroll);
+ left.Add(scroller);
+ left.Add(bot);
+ right.Add(templateViewer);
+ bot.Add(variablesViewer);
+ bot.Add(functionViewer);
+ bot.Add(moduleViewer);
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/FunctionTimeline.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/FunctionTimeline.cs.meta
new file mode 100644
index 00000000..0a9be293
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/FunctionTimeline.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c2e7f0b3ef37bf24bb90cfc0bb1c6de0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/TemplateGraph.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/TemplateGraph.cs
new file mode 100644
index 00000000..9bf8b430
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/TemplateGraph.cs
@@ -0,0 +1,293 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor;
+using UnityEditor.Experimental.GraphView;
+using UnityEngine;
+using UnityEngine.UIElements;
+using Poiyomi.ModularShaderSystem.UI;
+
+
+namespace Poiyomi.ModularShaderSystem.Debug
+{
+ public class TemplateGraph : IModularShaderDebuggerTab
+ {
+ public VisualElement TabContainer { get; set; }
+ public string TabName { get; set; }
+
+ internal TemplateGraphView _graph;
+
+ public TemplateGraph()
+ {
+ TabName = "Template graph";
+ TabContainer = new VisualElement();
+ TabContainer.StretchToParentSize();
+ var styleSheet = Resources.Load<StyleSheet>(MSSConstants.RESOURCES_FOLDER + "/MSSUIElements/TemplateGraphStyle");
+ TabContainer.styleSheets.Add(styleSheet);
+ }
+
+ public void UpdateTab(ModularShader shader)
+ {
+ TabContainer.Clear();
+ if (shader == null) return;
+ _graph = new TemplateGraphView(shader);
+
+
+
+ TabContainer.Add(_graph);
+ }
+ }
+
+ internal class TemplateGraphView : GraphView
+ {
+ public List<TemplateNode> Nodes;
+ public List<TemplateNode> BaseNodes;
+
+ private List<ShaderModule> _modules;
+ private ModularShader _shader;
+
+ private static TextPopup _popup;
+
+ public TemplateGraphView(ModularShader shader)
+ {
+ Nodes = new List<TemplateNode>();
+ BaseNodes = new List<TemplateNode>();
+
+ _modules = shader.BaseModules.Concat(shader.AdditionalModules).ToList();
+ _shader = shader;
+
+ SetupZoom(ContentZoomer.DefaultMinScale, ContentZoomer.DefaultMaxScale);
+ this.AddManipulator(new ContentDragger());
+ var grid = new GridBackground();
+
+ Insert(0, grid);
+ grid.StretchToParentSize();
+ this.StretchToParentSize();
+
+ AddBaseTemplateNode("Shader", _shader.ShaderTemplate);
+
+ if (_shader.UseTemplatesForProperties)
+ {
+ var keywords = new []{"#K#" + MSSConstants.TEMPLATE_PROPERTIES_KEYWORD};
+ AddBaseTemplateNode("ShaderPropertiesRoot", new TemplateAsset{ Template = "", Keywords = keywords, name = "Properties Template Root"});
+ if (_shader.ShaderPropertiesTemplate != null) AddTemplateNode("ShaderPropertiesTemplate", _shader.ShaderTemplate, keywords);
+
+ }
+
+ var moduleByTemplate = new Dictionary<ModuleTemplate, ShaderModule>();
+ foreach (var module in _shader.BaseModules.Concat(_shader.AdditionalModules))
+ foreach (var template in module.Templates)
+ moduleByTemplate.Add(template, module);
+
+ foreach (var template in _shader.BaseModules.Concat(_shader.AdditionalModules).SelectMany(x => x.Templates).OrderBy(x => x.Queue))
+ {
+ if (template.Template == null) continue;
+ var module = moduleByTemplate[template];
+ AddTemplateNode(module.Id, template);
+ }
+
+ ScheduleNodesPositionReset();
+ }
+
+ public void AddBaseTemplateNode(string moduleId, TemplateAsset template)
+ {
+ var baseNode = new TemplateNode(moduleId, template, "");
+ AddElement(baseNode);
+ Nodes.Add(baseNode);
+ BaseNodes.Add(baseNode);
+ }
+
+ public void AddTemplateNode(string moduleId, ModuleTemplate template)
+ {
+
+ var tempList = new List<TemplateNode>();
+ foreach ((TemplateNode parent, string key) in Nodes.SelectMany(item => template.Keywords.Where(y => IsKeywordValid(moduleId, item, y)).Select(y => (item, y))).Where(x => !string.IsNullOrEmpty(x.Item2)))
+ {
+ var node = new TemplateNode(moduleId, template, key);
+ AddElement(node);
+ tempList.Add(node);
+ LinkTemplateNodes(parent, node, key);
+ }
+ Nodes.AddRange(tempList);
+ }
+
+ public void AddTemplateNode(string moduleId, TemplateAsset template, string[] keywords)
+ {
+ var tempList = new List<TemplateNode>();
+ foreach ((TemplateNode parent, string key) in Nodes.SelectMany(item => keywords.Where(y => IsKeywordValid(moduleId, item, y)).Select(y => (item, y))).Where(x => !string.IsNullOrEmpty(x.Item2)))
+ {
+ var node = new TemplateNode(moduleId, template, key);
+ AddElement(node);
+ tempList.Add(node);
+ LinkTemplateNodes(parent, node, key);
+ }
+ Nodes.AddRange(tempList);
+ }
+
+ public void ScheduleNodesPositionReset()
+ {
+ RegisterCallback<GeometryChangedEvent>(GeometryChangedCallback);
+ }
+
+ public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
+ {
+ var items = evt.menu.MenuItems();
+ for (int i = 0; i < items.Count; i++)
+ evt.menu.RemoveItemAt(0);
+
+ if (evt.target is TemplateNode node)
+ {
+ evt.menu.InsertAction(0,"View template code", action =>
+ {
+ if (_popup != null) _popup.Close();
+ _popup = ScriptableObject.CreateInstance<TextPopup>();
+ _popup.Text = node.TemplateAsset.Template;
+ var position = GUIUtility.GUIToScreenRect(node.worldBound);
+ int lineCount = _popup.Text == null ? 5 : _popup.Text.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None).Length;
+ _popup.ShowAsDropDown(position, new Vector2(600, Math.Min(lineCount * 16, 800)));
+ });
+ if (node.ModuleId.Equals("Shader") || node.ModuleId.Equals("ShaderPropertiesRoot"))
+ {
+ evt.menu.InsertAction(1, "Select relative modular shader asset", action =>
+ {
+ Selection.SetActiveObjectWithContext(_shader, _shader);
+ });
+ }
+ else
+ {
+ evt.menu.InsertAction(1, "Select relative module asset", action =>
+ {
+ var module = _modules.Find(x => x.Id.Equals(node.ModuleId));
+ if(module != null)
+ Selection.SetActiveObjectWithContext(module, module);
+ });
+ }
+
+ }
+ }
+
+ private void GeometryChangedCallback(GeometryChangedEvent evt)
+ {
+ UnregisterCallback<GeometryChangedEvent>(GeometryChangedCallback);
+
+ if(BaseNodes.Count == 0) return;
+
+ float top = 0;
+ foreach (TemplateNode node in BaseNodes)
+ top += node.Reposition(2, top, 100*(Nodes.Count/70 + 1));
+
+ var newPosition = new Vector3(BaseNodes[0].style.left.value.value + viewport.resolvedStyle.width/2 - BaseNodes[0].resolvedStyle.width/2,
+ -BaseNodes[0].style.top.value.value + viewport.resolvedStyle.height/2 - BaseNodes[0].resolvedStyle.height/2,
+ viewTransform.position.z);
+ viewTransform.position = newPosition;
+ }
+
+ private static bool IsKeywordValid(string moduleId, TemplateNode item, string y)
+ {
+ if (item.ContainsKeyword("#K#"+y)) return true;
+ return item.ContainsKeyword("#KI#"+y) && moduleId.Equals(item.ModuleId);
+ }
+
+ private void LinkTemplateNodes(TemplateNode left, TemplateNode right, string key)
+ {
+ var edge = new Edge
+ {
+ output = left.Outputs[key],
+ input = right.Input
+ };
+
+ edge.input.Connect(edge);
+ edge.output.Connect(edge);
+ edge.SetEnabled(false);
+ Add(edge);
+ }
+ }
+
+ internal sealed class TemplateNode : Node
+ {
+ public TemplateAsset TemplateAsset { get; set; }
+ public string ModuleId { get; set; }
+ public Port Input { get; set; }
+ public Dictionary<string, Port> Outputs { get; set; }
+
+ private ModuleTemplate _template;
+
+ public TemplateNode(string moduleId, ModuleTemplate template, string key) : this (moduleId, template.Template, key)
+ {
+ _template = template;
+
+ if (_template == null) return;
+ var priority = new Label("" +_template.Queue);
+ priority.AddToClassList("node-header-queue");
+ titleContainer.Add(priority);
+ }
+
+ public TemplateNode(string moduleId, TemplateAsset templateAsset, string key)
+ {
+ ModuleId = moduleId;
+ TemplateAsset = templateAsset;
+ title = TemplateAsset.name;
+ var idLabel = new Label($"({ModuleId})");
+ idLabel.AddToClassList("node-header-id");
+ titleContainer.Insert(1, idLabel);
+ Outputs = new Dictionary<string, Port>();
+
+ if (!string.IsNullOrEmpty(key))
+ {
+ Input = InstantiatePort(Orientation.Horizontal, Direction.Input, Port.Capacity.Multi, typeof(string));
+ Input.portName = key;
+ Input.portColor = Color.cyan;
+ Input.edgeConnector.activators.Clear();
+ inputContainer.Add(Input);
+ }
+
+ foreach (string keyword in TemplateAsset.Keywords)
+ {
+ var port = InstantiatePort(Orientation.Horizontal, Direction.Output, Port.Capacity.Multi, typeof(string));
+
+ string sanitizedKeyword = keyword.Replace("#K#", "").Replace("#KI#", "");
+ bool isInternal = keyword.StartsWith("#KI#");
+ port.portName = sanitizedKeyword + (isInternal ? "(i)" : "");
+ port.portColor = Color.cyan;
+ port.edgeConnector.activators.Clear();
+ Outputs.Add(sanitizedKeyword, port);
+ outputContainer.Add(port);
+ }
+
+ RefreshExpandedState();
+ RefreshPorts();
+ }
+
+ public float Reposition(float right, float top, float offset)
+ {
+ float width = resolvedStyle.width;
+ float height = resolvedStyle.height;
+
+ float childrenHeight = 0;
+ float newTop = top;
+
+ foreach (var output in Outputs.Values)
+ {
+ foreach (var edge in output.connections)
+ {
+ var node = edge.input.node as TemplateNode;
+ if (node != null)
+ {
+ childrenHeight += node.Reposition(right + width + offset, newTop, offset);
+ newTop = top + childrenHeight;
+ }
+ }
+ }
+ SetPosition(new Rect(right, top + Math.Max((childrenHeight - height)/2, 0), 100, 100));
+ RefreshExpandedState();
+ RefreshPorts();
+
+ return Math.Max(height, childrenHeight) + 4;
+ }
+
+ public bool ContainsKeyword(string keyword)
+ {
+ return TemplateAsset.Keywords.Contains(keyword);
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/TemplateGraph.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/TemplateGraph.cs.meta
new file mode 100644
index 00000000..e4084c2c
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Components/TemplateGraph.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a58025042953bc1429b3e1a8684be12f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers.meta
new file mode 100644
index 00000000..8c8efc2c
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1a80f0c817257bb43bc624af1073b13f
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/EnablePropertyDrawer.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/EnablePropertyDrawer.cs
new file mode 100644
index 00000000..f33a10cb
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/EnablePropertyDrawer.cs
@@ -0,0 +1,30 @@
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UIElements;
+using UnityEditor.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ [CustomPropertyDrawer(typeof(EnableProperty))]
+ public class EnablePropertyDrawer : PropertyDrawer
+ {
+ private VisualElement _root;
+
+ public override VisualElement CreatePropertyGUI(SerializedProperty property)
+ {
+ _root = new VisualElement();
+
+ var visualTree = Resources.Load<VisualTreeAsset>(MSSConstants.RESOURCES_FOLDER + "/MSSUIElements/EnablePropertyDrawer");
+ VisualElement template = visualTree.CloneTree();
+ var foldout = new Foldout();
+ foldout.text = property.displayName;
+ foldout.RegisterValueChangedCallback((e) => property.isExpanded = e.newValue);
+ foldout.value = property.isExpanded;
+
+ foldout.Add(template);
+ _root.Add(foldout);
+
+ return _root;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/EnablePropertyDrawer.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/EnablePropertyDrawer.cs.meta
new file mode 100644
index 00000000..5f11f5c6
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/EnablePropertyDrawer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ffc75a109a78eb846a6b3708786e1a50
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/FunctionPropertyDrawer.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/FunctionPropertyDrawer.cs
new file mode 100644
index 00000000..d84eb1e4
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/FunctionPropertyDrawer.cs
@@ -0,0 +1,32 @@
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ [CustomPropertyDrawer(typeof(ShaderFunction))]
+ public class FunctionPropertyDrawer : PropertyDrawer
+ {
+ private VisualElement _root;
+
+ public override VisualElement CreatePropertyGUI(SerializedProperty property)
+ {
+ _root = new VisualElement();
+
+ var visualTree = Resources.Load<VisualTreeAsset>(MSSConstants.RESOURCES_FOLDER + "/MSSUIElements/FunctionPropertyDrawer");
+ VisualElement template = visualTree.CloneTree();
+ var foldout = new Foldout();
+ foldout.text = property.displayName;
+ foldout.RegisterValueChangedCallback((e) => property.isExpanded = e.newValue);
+ foldout.value = property.isExpanded;
+
+ var nameField = template.Q<TextField>("Name");
+ nameField.RegisterValueChangedCallback(evt => foldout.text = evt.newValue);
+
+ foldout.Add(template);
+ _root.Add(foldout);
+
+ return _root;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/FunctionPropertyDrawer.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/FunctionPropertyDrawer.cs.meta
new file mode 100644
index 00000000..e8fb2bf6
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/FunctionPropertyDrawer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 24f1782728098f349aee99d57e62f501
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ModuleTemplatePropertyDrawer.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ModuleTemplatePropertyDrawer.cs
new file mode 100644
index 00000000..2d2c77b8
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ModuleTemplatePropertyDrawer.cs
@@ -0,0 +1,29 @@
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UIElements;
+using UnityEditor.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ [CustomPropertyDrawer(typeof(ModuleTemplate))]
+ public class ModuleTemplatePropertyDrawer : PropertyDrawer
+ {
+ private VisualElement _root;
+
+ public override VisualElement CreatePropertyGUI(SerializedProperty property)
+ {
+ _root = new VisualElement();
+
+ var visualTree = Resources.Load<VisualTreeAsset>(MSSConstants.RESOURCES_FOLDER + "/MSSUIElements/ModuleTemplatePropertyDrawer");
+ VisualElement template = visualTree.CloneTree();
+ var foldout = new Foldout();
+ foldout.text = property.displayName;
+ foldout.RegisterValueChangedCallback((e) => property.isExpanded = e.newValue);
+ foldout.value = property.isExpanded;
+ foldout.Add(template);
+ _root.Add(foldout);
+
+ return _root;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ModuleTemplatePropertyDrawer.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ModuleTemplatePropertyDrawer.cs.meta
new file mode 100644
index 00000000..4f655a68
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ModuleTemplatePropertyDrawer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 21bc47d4c53206845ba7ea3ecdada7d0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/PropertyAttributeDrawer.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/PropertyAttributeDrawer.cs
new file mode 100644
index 00000000..2221cd03
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/PropertyAttributeDrawer.cs
@@ -0,0 +1,52 @@
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ public class PropertyAttributeAttribute : PropertyAttribute
+ {
+ }
+ [CustomPropertyDrawer(typeof(PropertyAttributeAttribute))]
+ public class PropertyAttributeDrawer : PropertyDrawer
+ {
+ public override VisualElement CreatePropertyGUI(SerializedProperty property)
+ {
+ var root = new VisualElement();
+
+ var value = new TextField();
+ value.SetValueWithoutNotify(property.stringValue);
+ root.Add(value);
+
+ /*value.RegisterValueChangedCallback(evt =>
+ {
+ property.stringValue = evt.newValue;
+ property.serializedObject.ApplyModifiedProperties();
+ });*/
+ value.RegisterCallback<FocusOutEvent>(evt =>
+ {
+ string v = value.value;
+ if (v[v.Length - 1] == ']')
+ {
+ v = v.Remove(v.Length - 1, 1);
+ }
+ if (v[0] == '[')
+ {
+ v = v.Remove(0, 1);
+ }
+ property.stringValue = v;
+ value.SetValueWithoutNotify(property.stringValue);
+ property.serializedObject.ApplyModifiedProperties();
+ });
+
+ /*customTypeField.style.display = ((VariableType)typeField.value) == VariableType.Custom ? DisplayStyle.Flex : DisplayStyle.None;
+
+ typeField.RegisterValueChangedCallback(e =>
+ {
+ customTypeField.style.display = ((VariableType)e.newValue) == VariableType.Custom ? DisplayStyle.Flex : DisplayStyle.None;
+ });*/
+
+ return root;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/PropertyAttributeDrawer.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/PropertyAttributeDrawer.cs.meta
new file mode 100644
index 00000000..105176a5
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/PropertyAttributeDrawer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3a66ad23d96a7a849ad93d53ea328d0e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ShaderPropertyDrawer.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ShaderPropertyDrawer.cs
new file mode 100644
index 00000000..a41154a4
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ShaderPropertyDrawer.cs
@@ -0,0 +1,289 @@
+using System;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UIElements;
+using UnityEditor.UIElements;
+using UnityEngine.Analytics;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ public enum DefaultTextureValue
+ {
+ White,
+ Black,
+ Gray,
+ Bump,
+ }
+
+ [CustomPropertyDrawer(typeof(Property))]
+ public class ShaderPropertyDrawer : PropertyDrawer
+ {
+ private VisualElement _root;
+
+ public override VisualElement CreatePropertyGUI(SerializedProperty property)
+ {
+ _root = new VisualElement();
+
+ var visualTree = Resources.Load<VisualTreeAsset>(MSSConstants.RESOURCES_FOLDER + "/MSSUIElements/ShaderPropertyDrawer");
+ VisualElement template = visualTree.CloneTree();
+ var foldout = new Foldout();
+ foldout.text = property.displayName;
+ foldout.RegisterValueChangedCallback((e) => property.isExpanded = e.newValue);
+ foldout.value = property.isExpanded;
+
+ var nameField = template.Q<TextField>("Name");
+ nameField.RegisterValueChangedCallback(evt => foldout.text = evt.newValue);
+ var enumField = template.Q<EnumField>("TypeField");
+ var valueContainer = template.Q<VisualElement>("ValueContainer");
+
+ var type = property.FindPropertyRelative("Type");
+ var defaultValue = property.FindPropertyRelative("DefaultValue");
+
+ var propType = GetPropertyTypeFromSerializedProperty(type.stringValue);
+
+ enumField.Init(propType);
+
+ enumField.value = propType;
+
+ enumField.RegisterValueChangedCallback(e =>
+ {
+ SetPropType(type, (PropertyType)e.newValue);
+ SetPropDefaultValue(defaultValue,"");
+ UpdateValueContainer(property, defaultValue, type, (PropertyType)e.newValue, type.stringValue, defaultValue.stringValue, valueContainer);
+ });
+
+ UpdateValueContainer(property, defaultValue, type, propType, type.stringValue, defaultValue.stringValue, valueContainer);
+
+ foldout.Add(template);
+ _root.Add(foldout);
+ return _root;
+ }
+
+ private void SetPropDefaultValue(SerializedProperty defaultValue, string v)
+ {
+ defaultValue.stringValue = v;
+ defaultValue.serializedObject.ApplyModifiedProperties();
+ }
+
+ private void SetPropType(SerializedProperty type, string v)
+ {
+ type.stringValue = v;
+ type.serializedObject.ApplyModifiedProperties();
+ }
+
+ private void SetPropType(SerializedProperty propType, PropertyType type)
+ {
+ string typeString = "";
+ switch (type)
+ {
+ case PropertyType.Int: typeString = "Int"; break;
+ case PropertyType.Float: typeString = "Float"; break;
+ case PropertyType.Range: typeString = "Range(0, 1)"; break;
+ case PropertyType.Vector: typeString = "Vector"; break;
+ case PropertyType.Color: typeString = "Color"; break;
+ case PropertyType.Texture2D: typeString = "2D"; break;
+ case PropertyType.Texture2DArray: typeString = "2DArray"; break;
+ case PropertyType.Cube: typeString = "Cube"; break;
+ case PropertyType.CubeArray: typeString = "CubeArray"; break;
+ case PropertyType.Texture3D: typeString = "3d"; break;
+ }
+
+ propType.stringValue = typeString;
+ propType.serializedObject.ApplyModifiedProperties();
+ }
+
+ private void UpdateValueContainer(SerializedProperty property, SerializedProperty defaultValue, SerializedProperty type, PropertyType propType, string propTypeString, string propValue, VisualElement element)
+ {
+ VisualElement field = null;
+ switch (propType)
+ {
+ case PropertyType.Float:
+ float floatValue = 0;
+ if (float.TryParse(propValue, out float f)) floatValue = f;
+ else SetPropDefaultValue(defaultValue,"" + floatValue);
+ var flfield = new FloatField{ value = floatValue, label = "Default value"};
+ flfield.RegisterValueChangedCallback(e => SetPropDefaultValue(defaultValue, "" + e.newValue));
+ field = flfield;
+ break;
+ case PropertyType.Range:
+
+ field = new VisualElement();
+ var rangeLimits = new Vector2(0, 1);
+ float rangeValue = 0;
+
+ string[] prt = propTypeString.Replace("Range(","").Replace(")","").Split(',');
+ float[] prv = new float[2];
+ bool pfi = true;
+ for (int i = 0; i < 2; i++)
+ {
+ if (float.TryParse(prt[i], out float v))
+ {
+ prv[i] = v;
+ }
+ else
+ {
+ pfi = false;
+ break;
+ }
+ }
+ if (pfi) rangeLimits = new Vector2(prv[0], prv[1]);
+ else SetPropType(type, $"Range({prv[0]}, {prv[1]})");
+
+ var limits = new Vector2Field { label = "Range limits", value = rangeLimits };
+
+ if (float.TryParse(propValue, out float r)) rangeValue = r;
+ else SetPropDefaultValue(defaultValue,"" + rangeValue);
+ var horizontalElement = new VisualElement();
+ horizontalElement.style.flexDirection = FlexDirection.Row;
+
+ var valueSlider = new Slider
+ {
+ value = rangeValue,
+ lowValue = Math.Min(rangeLimits[0], rangeLimits[1]),
+ highValue = Math.Max(rangeLimits[0], rangeLimits[1]),
+
+ label = "Default value"
+ };
+ valueSlider.style.flexGrow = 1;
+ var valueField = new FloatField { value = rangeValue };
+ valueField.style.width = 30;
+
+ limits.RegisterValueChangedCallback(e =>
+ {
+ valueSlider.lowValue = Math.Min(e.newValue[0], e.newValue[1]);
+ valueSlider.highValue = Math.Max(e.newValue[0], e.newValue[1]);
+ SetPropType(type,$"Range({valueSlider.lowValue}, {valueSlider.highValue})");
+ });
+
+ valueField.RegisterValueChangedCallback(e =>
+ {
+ if (e.newValue > valueSlider.highValue || e.newValue < valueSlider.lowValue)
+ {
+ e.StopImmediatePropagation();
+ e.PreventDefault();
+ valueField.SetValueWithoutNotify(e.previousValue);
+ return;
+ }
+ valueSlider.SetValueWithoutNotify(e.newValue);
+ SetPropDefaultValue(defaultValue,"" + e.newValue);
+ });
+ valueSlider.RegisterValueChangedCallback(e =>
+ {
+ valueField.SetValueWithoutNotify(e.newValue);
+ SetPropDefaultValue(defaultValue,"" + e.newValue);
+ });
+
+ field.Add(limits);
+ horizontalElement.Add(valueSlider);
+ horizontalElement.Add(valueField);
+ field.Add(horizontalElement);
+
+ break;
+ case PropertyType.Int:
+ int intValue = 0;
+ if (int.TryParse(propValue, out int iv)) intValue = iv;
+ else SetPropDefaultValue(defaultValue,"" + intValue);
+ var ivfield = new IntegerField{ value = intValue, label = "Default value"};
+ field = ivfield;
+ ivfield.RegisterValueChangedCallback(e => SetPropDefaultValue(defaultValue,"" + e.newValue));
+ break;
+ case PropertyType.Color:
+ Color colorValue = Color.white;
+ string[] clvl = propValue.Replace("(","").Replace(")","").Split(',');
+ float[] fv = new float[4];
+ bool vfi = true;
+ for (int i = 0; i < 4; i++)
+ {
+ if (float.TryParse(clvl[i], out float v))
+ {
+ fv[i] = v;
+ }
+ else
+ {
+ vfi = false;
+ break;
+ }
+ }
+
+ if (vfi) colorValue = new Color(fv[0], fv[1], fv[2], fv[3]);
+ else SetPropDefaultValue(defaultValue,$"({colorValue[0]}, {colorValue[1]}, {colorValue[2]}, {colorValue[3]})");
+ var clfield = new ColorField { value = colorValue, label = "Default value" };
+ field = clfield;
+ clfield.RegisterValueChangedCallback(e => SetPropDefaultValue(defaultValue,$"({e.newValue[0]}, {e.newValue[1]}, {e.newValue[2]}, {e.newValue[3]})"));
+ break;
+ case PropertyType.Vector:
+ Vector4 vectorValue = Vector4.zero;
+ string[] vvl = propValue.Replace("(","").Replace(")","").Split(',');
+ float[] vv = new float[4];
+ bool vvi = true;
+ for (int i = 0; i < 4; i++)
+ {
+ if (float.TryParse(vvl[i], out float v))
+ {
+ vv[i] = v;
+ }
+ else
+ {
+ vvi = false;
+ break;
+ }
+ }
+ if (vvi) vectorValue = new Vector4(vv[0], vv[1], vv[2] ,vv[3]);
+ else SetPropDefaultValue(defaultValue,$"({vv[0]}, {vv[1]}, {vv[2]}, {vv[3]})");
+ var vlfield = new Vector4Field{ value = vectorValue, label = "Default value" };
+ field = vlfield;
+ vlfield.RegisterValueChangedCallback(e => SetPropDefaultValue(defaultValue,$"({e.newValue[0]}, {e.newValue[1]}, {e.newValue[2]}, {e.newValue[3]})"));
+ break;
+ case PropertyType.Texture2D:
+ var texValue = DefaultTextureValue.White;
+ if (propValue.Contains("white")) texValue = DefaultTextureValue.White;
+ if (propValue.Contains("gray")) texValue = DefaultTextureValue.Gray;
+ if (propValue.Contains("black")) texValue = DefaultTextureValue.Black;
+ if (propValue.Contains("bump")) texValue = DefaultTextureValue.Bump;
+ SetPropDefaultValue(defaultValue,$"\"{Enum.GetName(typeof(DefaultTextureValue), texValue)?.ToLower()}\" {{}}");
+ var txfield = new EnumField { label = "Default value" };
+ txfield.Init(texValue);
+ var textureAsset = new PropertyField(property.FindPropertyRelative("DefaultTextureAsset"), "Texture Override");
+ textureAsset.Bind(property.serializedObject);
+ var vl = new VisualElement();
+ vl.Add(txfield);
+ vl.Add(textureAsset);
+ field = vl;
+ txfield.RegisterValueChangedCallback(e => SetPropDefaultValue(defaultValue,$"\"{Enum.GetName(typeof(DefaultTextureValue), e.newValue)?.ToLower()}\" {{}}"));
+ break;
+ case PropertyType.Texture2DArray:
+ case PropertyType.CubeArray:
+ case PropertyType.Texture3D:
+ SetPropDefaultValue(defaultValue,"\"\"{}");
+ break;
+ case PropertyType.Cube:
+ SetPropDefaultValue(defaultValue,"\"\"{}");
+ var textureCubeAsset = new PropertyField(property.FindPropertyRelative("DefaultTextureAsset"), "Texture Override");
+ textureCubeAsset.Bind(property.serializedObject);
+ field = textureCubeAsset;
+ break;
+ }
+
+ element.Clear();
+ if (field != null) element.Add(field);
+ }
+
+ private static PropertyType GetPropertyTypeFromSerializedProperty(string propType)
+ {
+ switch (propType.Trim())
+ {
+ case "Float": return PropertyType.Float;
+ case "Int": return PropertyType.Int;
+ case "Color": return PropertyType.Color;
+ case "Vector": return PropertyType.Vector;
+ case "2D": return PropertyType.Texture2D;
+ case "3D": return PropertyType.Texture3D;
+ case "Cube": return PropertyType.Cube;
+ case "2DArray": return PropertyType.Texture2DArray;
+ case "CubeArray": return PropertyType.CubeArray;
+ default: return propType.Trim().StartsWith("Range") ? PropertyType.Range : PropertyType.Float;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ShaderPropertyDrawer.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ShaderPropertyDrawer.cs.meta
new file mode 100644
index 00000000..a638df90
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/ShaderPropertyDrawer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: eef114f99927e5d4b98ba893786d3838
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/VariablePropertyDrawer.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/VariablePropertyDrawer.cs
new file mode 100644
index 00000000..3bdfd831
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/VariablePropertyDrawer.cs
@@ -0,0 +1,43 @@
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UIElements;
+using UnityEditor.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ [CustomPropertyDrawer(typeof(Variable))]
+ public class VariablePropertyDrawer : PropertyDrawer
+ {
+ private VisualElement _root;
+
+ public override VisualElement CreatePropertyGUI(SerializedProperty property)
+ {
+ _root = new VisualElement();
+
+ var visualTree = Resources.Load<VisualTreeAsset>(MSSConstants.RESOURCES_FOLDER + "/MSSUIElements/VariablePropertyDrawer");
+ VisualElement template = visualTree.CloneTree();
+ var foldout = new Foldout();
+ foldout.text = property.displayName;
+ foldout.RegisterValueChangedCallback((e) => property.isExpanded = e.newValue);
+ foldout.value = property.isExpanded;
+ foldout.Add(template);
+ _root.Add(foldout);
+
+ var nameField = template.Q<TextField>("Name");
+ nameField.RegisterValueChangedCallback(evt => foldout.text = evt.newValue);
+ var typeField = template.Q<EnumField>("Type");
+ var customTypeField = template.Q<VisualElement>("CustomType");
+
+ typeField.Init(VariableType.Float);
+
+ customTypeField.style.display = ((VariableType)typeField.value) == VariableType.Custom ? DisplayStyle.Flex : DisplayStyle.None;
+
+ typeField.RegisterValueChangedCallback(e =>
+ {
+ customTypeField.style.display = ((VariableType)e.newValue) == VariableType.Custom ? DisplayStyle.Flex : DisplayStyle.None;
+ });
+
+ return _root;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/VariablePropertyDrawer.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/VariablePropertyDrawer.cs.meta
new file mode 100644
index 00000000..b6b5f0fa
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Drawers/VariablePropertyDrawer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9d92791b337f5ca4984e6d33748e19a3
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements.meta
new file mode 100644
index 00000000..ec87ef6f
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 593f19fde7643b4429fd5f6a8503214b
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/CodeViewElement.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/CodeViewElement.cs
new file mode 100644
index 00000000..3ad05abf
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/CodeViewElement.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Linq;
+using UnityEngine;
+using UnityEngine.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ public class CodeViewElement : VisualElement
+ {
+ private class LineItem : VisualElement
+ {
+ private static Font TextFont
+ {
+ get
+ {
+ if (_font == null)
+ _font = Resources.Load<Font>(MSSConstants.RESOURCES_FOLDER + "/RobotoMono-Regular");
+ return _font;
+ }
+ }
+
+ private static Font _font;
+ private Label _lineNumber;
+ private Label _line;
+ public string Text { get; }
+
+ public LineItem() : this(0, "") {}
+
+ public LineItem(int number, string text, int digits = 0)
+ {
+ Text = text;
+ _lineNumber = new Label("" + number);
+ _lineNumber.style.color = Color.gray;
+ _lineNumber.style.width = digits == 0 ? 30 : digits * 8;
+ _lineNumber.style.unityTextAlign = TextAnchor.MiddleRight;
+ _lineNumber.style.unityFont = TextFont;
+ _lineNumber.style.marginRight = 4;
+ _lineNumber.style.marginLeft = 4;
+
+ _line = new Label(text);
+ _line.style.flexGrow = 1;
+ _line.style.unityFont = TextFont;
+
+ style.flexDirection = FlexDirection.Row;
+ Add(_lineNumber);
+ Add(_line);
+ }
+
+ public void SetText(int i, string textLine, int digits)
+ {
+ _lineNumber.text = "" + i;
+ _lineNumber.style.width = digits == 0 ? 30 : digits * 8;
+ _line.text = textLine;
+ _line.MeasureTextSize(textLine, 0, MeasureMode.Exactly, 0, MeasureMode.Exactly);
+ }
+ }
+
+ public string Text
+ {
+ get => string.Join("\n", _textLines);
+ set
+ {
+ _textLines = value == null ? Array.Empty<string>() : value.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
+ _digits = (int)Math.Floor(Math.Log10(_textLines.Length) + 1);
+ _listView.itemsSource = _textLines;
+
+ float width =((_textLines.Length == 0 ? 0 : _textLines.Max(x => x.Length)) + _digits + 1) * 10;
+ _listView.contentContainer.style.width = width;
+ }
+ }
+
+ public int LineCount => _textLines.Length;
+
+ private Label _templateLabel;
+ private string[] _textLines;
+ private ListView _listView;
+ private int _digits;
+
+ public CodeViewElement()
+ {
+ ScrollView s = new ScrollView(ScrollViewMode.Horizontal);
+ _listView = new ListView();
+ _listView.itemHeight = 15;
+ _listView.AddToClassList("unity-base-text-field__input");
+ _listView.AddToClassList("unity-text-field__input");
+ _listView.AddToClassList("unity-base-field__input");
+ _listView.style.flexGrow = 1;
+ _listView.contentContainer.style.flexGrow = 1;
+
+ Func<VisualElement> makeItem = () => new LineItem();
+ Action<VisualElement, int> bindItem = (e, i) => (e as LineItem).SetText(i+1, _textLines[i], _digits);
+
+ _listView.makeItem = makeItem;
+ _listView.bindItem = bindItem;
+ _listView.selectionType = SelectionType.None;
+ s.Add(_listView);
+ Add(s);
+ s.style.flexGrow = 1;
+ s.contentContainer.style.flexGrow = 1;
+
+ style.flexGrow = 1;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/CodeViewElement.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/CodeViewElement.cs.meta
new file mode 100644
index 00000000..69417247
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/CodeViewElement.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 248ba9991fe7ba44d8ed907de6a5e4d8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/InspectorList.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/InspectorList.cs
new file mode 100644
index 00000000..60eff417
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/InspectorList.cs
@@ -0,0 +1,324 @@
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEditor.UIElements;
+using UnityEngine;
+using UnityEngine.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ public interface IInspectorList
+ {
+ InspectorListItem draggedElement { get; set; }
+ void HighlightDrops();
+ void DeHighlightDrops();
+ }
+
+ public class InspectorList : BindableElement, IInspectorList
+ {
+ Foldout _listContainer;
+ Button _addButton;
+ SerializedProperty _array;
+ private bool _showElementsButtons;
+
+ private bool _hasFoldingBeenForced;
+
+ public InspectorListItem draggedElement { get; set; }
+ public bool _highlightDrops;
+
+ private List<VisualElement> _drops;
+
+ private VisualElement _currentDrop;
+
+ public InspectorList()
+ {
+ _drops = new List<VisualElement>();
+ _listContainer = new Foldout();
+ _listContainer.text = "Unbound List";
+ _listContainer.contentContainer.AddToClassList("inspector-list-container");
+ _listContainer.value = false;
+ _listContainer.RegisterCallback<MouseUpEvent>(e => Drop());
+ _listContainer.RegisterCallback<MouseLeaveEvent>(e => Drop());
+
+ _addButton = new Button(AddItem);
+ _addButton.text = "Add";
+ _addButton.AddToClassList("inspector-list-add-button");
+ Add(_listContainer);
+ if (enabledSelf)
+ _listContainer.Add(_addButton);
+ _listContainer.RegisterValueChangedCallback((e) => _array.isExpanded = e.newValue);
+ var styleSheet = Resources.Load<StyleSheet>(MSSConstants.RESOURCES_FOLDER + "/MSSUIElements/InspectorList");
+ styleSheets.Add(styleSheet);
+ }
+
+ private void Drop()
+ {
+ if (draggedElement == null) return;
+ draggedElement.RemoveFromClassList("inspector-list-drag-enabled");
+
+ if (_highlightDrops)
+ {
+ DeHighlightDrops();
+ int dropIndex = _drops.IndexOf(_currentDrop);
+
+ if (dropIndex == -1)
+ {
+ draggedElement = null;
+ return;
+ }
+
+ if (dropIndex > draggedElement.index) dropIndex--;
+ _array.MoveArrayElement(draggedElement.index, dropIndex);
+ bool expanded = _array.GetArrayElementAtIndex(dropIndex).isExpanded;
+ _array.GetArrayElementAtIndex(dropIndex).isExpanded = _array.GetArrayElementAtIndex(draggedElement.index).isExpanded;
+ _array.GetArrayElementAtIndex(draggedElement.index).isExpanded = expanded;
+ _array.serializedObject.ApplyModifiedProperties();
+ UpdateList();
+ }
+ draggedElement = null;
+ }
+
+ public void HighlightDrops()
+ {
+ foreach (var item in _drops)
+ item.AddToClassList("inspector-list-drop-area-highlight");
+
+ _highlightDrops = true;
+ }
+
+ public void DeHighlightDrops()
+ {
+ foreach (var item in _drops)
+ item.RemoveFromClassList("inspector-list-drop-area-highlight");
+
+ _highlightDrops = false;
+ }
+
+ public override void HandleEvent(EventBase evt)
+ {
+ var type = evt.GetType(); //SerializedObjectBindEvent is internal, so need to use reflection here
+ if ((type.Name == "SerializedPropertyBindEvent") && !string.IsNullOrWhiteSpace(bindingPath))
+ {
+ var obj = type.GetProperty("bindProperty")?.GetValue(evt) as SerializedProperty;
+ _array = obj;
+ if (obj != null)
+ {
+ if (_hasFoldingBeenForced) obj.isExpanded = _listContainer.value;
+ else _listContainer.value = obj.isExpanded;
+ }
+ UpdateList();
+ }
+ base.HandleEvent(evt);
+ }
+
+ public void UpdateList()
+ {
+ _listContainer.Clear();
+ _drops.Clear();
+
+ if (_array == null)
+ return;
+ _listContainer.text = _array.displayName;
+ CreateDrop();
+ for (int i = 0; i < _array.arraySize; i++)
+ {
+ int index = i;
+ var element = new PropertyField(_array.GetArrayElementAtIndex(index));
+ element.Bind(_array.GetArrayElementAtIndex(index).serializedObject);
+ var item = new InspectorListItem(this, element, _array, index, _showElementsButtons);
+ item.removeButton.RegisterCallback<PointerUpEvent>((evt) => RemoveItem(index));
+ item.upButton.RegisterCallback<PointerUpEvent>((evt) => MoveUpItem(index));
+ item.downButton.RegisterCallback<PointerUpEvent>((evt) => MoveDownItem(index));
+ _listContainer.Add(item);
+ CreateDrop();
+ }
+ if (enabledSelf)
+ _listContainer.Add(_addButton);
+ }
+
+ private void CreateDrop()
+ {
+ VisualElement dropArea = new VisualElement();
+ dropArea.AddToClassList("inspector-list-drop-area");
+ dropArea.RegisterCallback<MouseEnterEvent>(e =>
+ {
+ if (_highlightDrops)
+ {
+ dropArea.AddToClassList("inspector-list-drop-area-selected");
+ _currentDrop = dropArea;
+ }
+ });
+ dropArea.RegisterCallback<MouseLeaveEvent>(e =>
+ {
+ if (_highlightDrops)
+ {
+ dropArea.RemoveFromClassList("inspector-list-drop-area-selected");
+ if (_currentDrop == dropArea) _currentDrop = null;
+ }
+ });
+
+ _listContainer.Add(dropArea);
+ _drops.Add(dropArea);
+ }
+
+ public void RemoveItem(int index)
+ {
+ if (_array != null)
+ {
+ if (index < _array.arraySize - 1)
+ _array.GetArrayElementAtIndex(index).isExpanded = _array.GetArrayElementAtIndex(index + 1).isExpanded;
+ _array.DeleteArrayElementAtIndex(index);
+ _array.serializedObject.ApplyModifiedProperties();
+ }
+
+ UpdateList();
+ }
+
+ public void MoveUpItem(int index)
+ {
+ if (_array != null && index > 0)
+ {
+ _array.MoveArrayElement(index, index - 1);
+ bool expanded = _array.GetArrayElementAtIndex(index).isExpanded;
+ _array.GetArrayElementAtIndex(index).isExpanded = _array.GetArrayElementAtIndex(index - 1).isExpanded;
+ _array.GetArrayElementAtIndex(index - 1).isExpanded = expanded;
+ _array.serializedObject.ApplyModifiedProperties();
+ }
+
+ UpdateList();
+ }
+
+ public void MoveDownItem(int index)
+ {
+ if (_array != null && index < _array.arraySize - 1)
+ {
+ _array.MoveArrayElement(index, index + 1);
+ bool expanded = _array.GetArrayElementAtIndex(index).isExpanded;
+ _array.GetArrayElementAtIndex(index).isExpanded = _array.GetArrayElementAtIndex(index + 1).isExpanded;
+ _array.GetArrayElementAtIndex(index + 1).isExpanded = expanded;
+ _array.serializedObject.ApplyModifiedProperties();
+ }
+
+ UpdateList();
+ }
+
+ public void AddItem()
+ {
+ if (_array != null)
+ {
+ _array.InsertArrayElementAtIndex(_array.arraySize);
+ _array.serializedObject.ApplyModifiedProperties();
+ }
+
+ UpdateList();
+ }
+
+ public void SetFoldingState(bool open)
+ {
+ _listContainer.value = open;
+ if (_array != null) _array.isExpanded = open;
+ else _hasFoldingBeenForced = true;
+ }
+
+ public new class UxmlFactory : UxmlFactory<InspectorList, UxmlTraits> { }
+
+ public new class UxmlTraits : BindableElement.UxmlTraits
+ {
+ UxmlBoolAttributeDescription showElements =
+ new UxmlBoolAttributeDescription { name = "show-elements-text", defaultValue = true };
+
+ public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
+ {
+ base.Init(ve, bag, cc);
+
+ if (ve is InspectorList ate) ate._showElementsButtons = showElements.GetValueFromBag(bag, cc);
+ }
+ }
+
+ }
+
+ public class InspectorListItem : VisualElement
+ {
+ public Button removeButton;
+ public Button upButton;
+ public Button downButton;
+
+ public VisualElement dragArea;
+
+ public Vector2 startPosition;
+
+ public int index;
+
+ private IInspectorList _list;
+ public InspectorListItem(IInspectorList list, VisualElement element, SerializedProperty array, int index, bool showButtonsText)
+ {
+ this.index = index;
+ _list = list;
+ AddToClassList("inspector-list-item-container");
+
+ dragArea = new VisualElement();
+ dragArea.AddToClassList("inspector-list-drag-handle");
+
+ dragArea.RegisterCallback<MouseDownEvent>(e =>
+ {
+ if (_list.draggedElement == this)
+ {
+ e.StopImmediatePropagation();
+ return;
+ }
+
+ _list.draggedElement = this;
+ _list.HighlightDrops();
+ AddToClassList("inspector-list-drag-enabled");
+ });
+
+ VisualElement buttonsArea = new VisualElement();
+
+ RegisterCallback<GeometryChangedEvent>(e =>
+ {
+ buttonsArea.ClearClassList();
+ if (e.newRect.height > 60)
+ {
+ buttonsArea.AddToClassList("inspector-list-buttons-container-vertical");
+ buttonsArea.Add(removeButton);
+ buttonsArea.Add(upButton);
+ buttonsArea.Add(downButton);
+ }
+ else
+ {
+ buttonsArea.AddToClassList("inspector-list-buttons-container-horizontal");
+ buttonsArea.Add(upButton);
+ buttonsArea.Add(downButton);
+ buttonsArea.Add(removeButton);
+ }
+ });
+
+ upButton = new Button();
+ upButton.name = "UpInspectorListItem";
+ upButton.AddToClassList("inspector-list-up-button");
+ if (index == 0)
+ upButton.SetEnabled(false);
+ downButton = new Button();
+ downButton.name = "DownInspectorListItem";
+ downButton.AddToClassList("inspector-list-down-button");
+ if (index >= array.arraySize - 1)
+ downButton.SetEnabled(false);
+ removeButton = new Button();
+ removeButton.name = "RemoveInspectorListItem";
+ removeButton.AddToClassList("inspector-list-remove-button");
+
+ if (showButtonsText)
+ {
+ upButton.text = "up";
+ downButton.text = "down";
+ removeButton.text = "-";
+ }
+
+ var property = array.GetArrayElementAtIndex(index);
+ element.AddToClassList("inspector-list-item");
+
+ Add(dragArea);
+ Add(element);
+ Add(buttonsArea);
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/InspectorList.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/InspectorList.cs.meta
new file mode 100644
index 00000000..5839937e
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/InspectorList.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7e402c0aaa42fe944802ceaf7d55be05
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/LabelField.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/LabelField.cs
new file mode 100644
index 00000000..6f2f9955
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/LabelField.cs
@@ -0,0 +1,56 @@
+using UnityEngine.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ public class LabelField : VisualElement
+ {
+ public string Label
+ {
+ get => _label;
+ set
+ {
+ _label = value;
+ _labelField.text = _label;
+ }
+ }
+
+ public string Value
+ {
+ get => _value;
+ set
+ {
+ _value = value;
+ _valueField.text = _value;
+ }
+ }
+
+ private Label _labelField;
+ private Label _valueField;
+ private string _label;
+ private string _value;
+
+ public LabelField(string label, string value)
+ {
+ _label = label;
+ _value = value;
+ _labelField = new Label(label);
+ _valueField = new Label(value);
+
+ AddToClassList("unity-base-field");
+ AddToClassList("unity-base-text-field");
+ AddToClassList("unity-text-field");
+
+ _labelField.AddToClassList("unity-text-element");
+ _labelField.AddToClassList("unity-label");
+ _labelField.AddToClassList("unity-base-field__label");
+ _labelField.AddToClassList("unity-base-text-field__label");
+ _labelField.AddToClassList("unity-text-field__label");
+ _labelField.AddToClassList("label-field-title");
+ _valueField.AddToClassList("label-field-value");
+
+ Add(_labelField);
+ Add(_valueField);
+
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/LabelField.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/LabelField.cs.meta
new file mode 100644
index 00000000..f7dffca5
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/LabelField.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: af8a36edfa0c0a44d971881746edc521
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/ModuleInspectorList.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/ModuleInspectorList.cs
new file mode 100644
index 00000000..7a80493e
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/ModuleInspectorList.cs
@@ -0,0 +1,315 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor;
+using UnityEditor.UIElements;
+using UnityEngine;
+using UnityEngine.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+
+ public class ModuleInspectorList : BindableElement, IInspectorList
+ {
+ Foldout _listContainer;
+ Button _addButton;
+ SerializedProperty _array;
+ private bool _showElementsButtons;
+ private List<string> _loadedModules;
+
+ private bool _hasFoldingBeenForced;
+
+ public InspectorListItem draggedElement { get; set; }
+ public bool _highlightDrops;
+
+ private List<VisualElement> _drops;
+
+ private VisualElement _currentDrop;
+
+ public ModuleInspectorList()
+ {
+ _drops = new List<VisualElement>();
+ _listContainer = new Foldout();
+ _listContainer.text = "Unbound List";
+ _listContainer.contentContainer.AddToClassList("inspector-list-container");
+ _listContainer.value = false;
+ _listContainer.RegisterCallback<MouseUpEvent>(e => Drop());
+ _listContainer.RegisterCallback<MouseLeaveEvent>(e => Drop());
+
+ _addButton = new Button(AddItem);
+ _addButton.text = "Add";
+ _addButton.AddToClassList("inspector-list-add-button");
+ Add(_listContainer);
+ if (enabledSelf)
+ _listContainer.Add(_addButton);
+ _listContainer.RegisterValueChangedCallback((e) => _array.isExpanded = e.newValue);
+ var styleSheet = Resources.Load<StyleSheet>(MSSConstants.RESOURCES_FOLDER + "/MSSUIElements/InspectorList");
+ styleSheets.Add(styleSheet);
+ }
+
+ private void Drop()
+ {
+ if (draggedElement == null) return;
+ draggedElement.RemoveFromClassList("inspector-list-drag-enabled");
+
+ if (_highlightDrops)
+ {
+ DeHighlightDrops();
+ int dropIndex = _drops.IndexOf(_currentDrop);
+
+ if (dropIndex == -1)
+ {
+ draggedElement = null;
+ return;
+ }
+
+ if (dropIndex > draggedElement.index) dropIndex--;
+ _array.MoveArrayElement(draggedElement.index, dropIndex);
+ bool expanded = _array.GetArrayElementAtIndex(dropIndex).isExpanded;
+ _array.GetArrayElementAtIndex(dropIndex).isExpanded = _array.GetArrayElementAtIndex(draggedElement.index).isExpanded;
+ _array.GetArrayElementAtIndex(draggedElement.index).isExpanded = expanded;
+ _array.serializedObject.ApplyModifiedProperties();
+ UpdateList();
+ }
+ draggedElement = null;
+ }
+
+ public void HighlightDrops()
+ {
+ foreach (var item in _drops)
+ item.AddToClassList("inspector-list-drop-area-highlight");
+
+ _highlightDrops = true;
+ }
+
+ public void DeHighlightDrops()
+ {
+ foreach (var item in _drops)
+ item.RemoveFromClassList("inspector-list-drop-area-highlight");
+
+ _highlightDrops = false;
+ }
+
+ public override void HandleEvent(EventBase evt)
+ {
+ var type = evt.GetType(); //SerializedObjectBindEvent is internal, so need to use reflection here
+ if ((type.Name == "SerializedPropertyBindEvent") && !string.IsNullOrWhiteSpace(bindingPath))
+ {
+ var obj = type.GetProperty("bindProperty")?.GetValue(evt) as SerializedProperty;
+ _array = obj;
+ if (obj != null)
+ {
+ if (_hasFoldingBeenForced) obj.isExpanded = _listContainer.value;
+ else _listContainer.value = obj.isExpanded;
+ }
+ UpdateList();
+ }
+ base.HandleEvent(evt);
+ }
+
+ public void UpdateList()
+ {
+ _listContainer.Clear();
+ _drops.Clear();
+
+ if (_array == null)
+ return;
+ _listContainer.text = _array.displayName;
+ CreateDrop();
+
+ _loadedModules = new List<string>();
+ for (int i = 0; i < _array.arraySize; i++)
+ {
+ if (_array.GetArrayElementAtIndex(i).objectReferenceValue != null)
+ _loadedModules.Add(((ShaderModule)_array.GetArrayElementAtIndex(i).objectReferenceValue)?.Id);
+ }
+
+
+
+ for (int i = 0; i < _array.arraySize; i++)
+ {
+ int index = i;
+
+ var moduleItem = new VisualElement();
+ var objectField = new ObjectField();//_array.GetArrayElementAtIndex(index));
+
+ SerializedProperty propertyValue = _array.GetArrayElementAtIndex(index);
+
+ objectField.objectType = typeof(ShaderModule);
+ objectField.bindingPath = propertyValue.propertyPath;
+ objectField.Bind(propertyValue.serializedObject);
+ var infoLabel = new Label();
+ moduleItem.Add(objectField);
+ moduleItem.Add(infoLabel);
+
+ objectField.RegisterCallback<ChangeEvent<Object>>(x =>
+ {
+ var newValue = (ShaderModule)x.newValue;
+ var oldValue = (ShaderModule)x.previousValue;
+
+ if (oldValue != null)
+ _loadedModules.Remove(oldValue.Id);
+ if (newValue != null)
+ _loadedModules.Add(newValue.Id);
+
+ for (int j = 0; j < _array.arraySize; j++)
+ {
+ var element = ((ObjectField)x.target).parent.parent.parent.ElementAt(j*2+1).ElementAt(1);
+ Label label = element.ElementAt(1) as Label;
+ if (index == j)
+ CheckModuleValidity(newValue, label, element);
+ else
+ CheckModuleValidity((ShaderModule)_array.GetArrayElementAtIndex(j).objectReferenceValue, label, element);
+ }
+ });
+
+ var item = new InspectorListItem(this, moduleItem, _array, index, _showElementsButtons);
+ item.removeButton.RegisterCallback<PointerUpEvent>((evt) => RemoveItem(index));
+ item.upButton.RegisterCallback<PointerUpEvent>((evt) => MoveUpItem(index));
+ item.downButton.RegisterCallback<PointerUpEvent>((evt) => MoveDownItem(index));
+ _listContainer.Add(item);
+ CreateDrop();
+
+ CheckModuleValidity((ShaderModule)propertyValue.objectReferenceValue, infoLabel, moduleItem);
+ }
+ if (enabledSelf)
+ _listContainer.Add(_addButton);
+ }
+
+ private void CreateDrop()
+ {
+ VisualElement dropArea = new VisualElement();
+ dropArea.AddToClassList("inspector-list-drop-area");
+ dropArea.RegisterCallback<MouseEnterEvent>(e =>
+ {
+ if (_highlightDrops)
+ {
+ dropArea.AddToClassList("inspector-list-drop-area-selected");
+ _currentDrop = dropArea;
+ }
+ });
+ dropArea.RegisterCallback<MouseLeaveEvent>(e =>
+ {
+ if (_highlightDrops)
+ {
+ dropArea.RemoveFromClassList("inspector-list-drop-area-selected");
+ if (_currentDrop == dropArea) _currentDrop = null;
+ }
+ });
+
+ _listContainer.Add(dropArea);
+ _drops.Add(dropArea);
+ }
+
+ private void CheckModuleValidity(ShaderModule newValue, Label infoLabel, VisualElement moduleItem)
+ {
+
+ List<string> problems = new List<string>();
+
+ if (newValue != null)
+ {
+ var moduleId = newValue.Id;
+ if (_loadedModules.Count(y => y.Equals(moduleId)) > 1)
+ problems.Add("The module is duplicate");
+
+ List<string> missingDependencies = newValue.ModuleDependencies.Where(dependency => _loadedModules.Count(y => y.Equals(dependency)) == 0).ToList();
+ List<string> incompatibilities = newValue.IncompatibleWith.Where(dependency => _loadedModules.Count(y => y.Equals(dependency)) > 0).ToList();
+
+ if (missingDependencies.Count > 0)
+ problems.Add("Missing dependencies: " + string.Join(", ", missingDependencies));
+
+ if (incompatibilities.Count > 0)
+ problems.Add("These incompatible modules are installed: " + string.Join(", ", incompatibilities));
+ }
+
+ infoLabel.text = string.Join("\n", problems);
+
+ if (!string.IsNullOrWhiteSpace(infoLabel.text))
+ {
+ moduleItem.AddToClassList("error-background");
+ infoLabel.visible = true;
+ }
+ else
+ {
+ moduleItem.RemoveFromClassList("error-background");
+ infoLabel.visible = false;
+ }
+ }
+
+ public void RemoveItem(int index)
+ {
+ if (_array != null)
+ {
+ if (index < _array.arraySize - 1)
+ _array.GetArrayElementAtIndex(index).isExpanded = _array.GetArrayElementAtIndex(index + 1).isExpanded;
+ var elementProperty = _array.GetArrayElementAtIndex(index);
+ if (elementProperty.objectReferenceValue != null)
+ elementProperty.objectReferenceValue = null;
+ _array.DeleteArrayElementAtIndex(index);
+ _array.serializedObject.ApplyModifiedProperties();
+ }
+
+ UpdateList();
+ }
+
+ public void MoveUpItem(int index)
+ {
+ if (_array != null && index > 0)
+ {
+ _array.MoveArrayElement(index, index - 1);
+ bool expanded = _array.GetArrayElementAtIndex(index).isExpanded;
+ _array.GetArrayElementAtIndex(index).isExpanded = _array.GetArrayElementAtIndex(index - 1).isExpanded;
+ _array.GetArrayElementAtIndex(index - 1).isExpanded = expanded;
+ _array.serializedObject.ApplyModifiedProperties();
+ }
+
+ UpdateList();
+ }
+
+ public void MoveDownItem(int index)
+ {
+ if (_array != null && index < _array.arraySize - 1)
+ {
+ _array.MoveArrayElement(index, index + 1);
+ bool expanded = _array.GetArrayElementAtIndex(index).isExpanded;
+ _array.GetArrayElementAtIndex(index).isExpanded = _array.GetArrayElementAtIndex(index + 1).isExpanded;
+ _array.GetArrayElementAtIndex(index + 1).isExpanded = expanded;
+ _array.serializedObject.ApplyModifiedProperties();
+ }
+
+ UpdateList();
+ }
+
+ public void AddItem()
+ {
+ if (_array != null)
+ {
+ _array.InsertArrayElementAtIndex(_array.arraySize);
+ _array.serializedObject.ApplyModifiedProperties();
+ }
+
+ UpdateList();
+ }
+
+ public void SetFoldingState(bool open)
+ {
+ _listContainer.value = open;
+ if (_array != null) _array.isExpanded = open;
+ else _hasFoldingBeenForced = true;
+ }
+
+ public new class UxmlFactory : UxmlFactory<ModuleInspectorList, UxmlTraits> { }
+
+ public new class UxmlTraits : BindableElement.UxmlTraits
+ {
+ UxmlBoolAttributeDescription showElements =
+ new UxmlBoolAttributeDescription { name = "show-elements-text", defaultValue = true };
+
+ public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
+ {
+ base.Init(ve, bag, cc);
+
+ if (ve is ModuleInspectorList ate) ate._showElementsButtons = showElements.GetValueFromBag(bag, cc);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/ModuleInspectorList.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/ModuleInspectorList.cs.meta
new file mode 100644
index 00000000..aab66df8
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/ModuleInspectorList.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f9210556d98393149bad9819fb127c5b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/VariableField.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/VariableField.cs
new file mode 100644
index 00000000..73079bd3
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/VariableField.cs
@@ -0,0 +1,30 @@
+using UnityEngine.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ public class VariableField : VisualElement
+ {
+ public Variable Variable { get; set; }
+
+ private string _type;
+
+ public VariableField(Variable variable)
+ {
+ Variable = variable;
+ if(variable.Type == VariableType.Custom)
+ _type = variable.CustomType;
+ else
+ _type = variable.Type.ToString();
+ var nameField = new Label(variable.Name);
+ var typeField = new Label(_type);
+
+ nameField.style.flexGrow = 1;
+ typeField.AddToClassList("variable-type-text");
+ Add(nameField);
+ Add(typeField);
+
+ style.flexDirection = FlexDirection.Row;
+
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/VariableField.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/VariableField.cs.meta
new file mode 100644
index 00000000..476b82a9
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Elements/VariableField.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1d7f89d7e489068458d4c125179d6061
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors.meta
new file mode 100644
index 00000000..6a6b0b87
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e5f27652ec52b1e4abcf40a28dfa2e9c
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ModularShaderEditor.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ModularShaderEditor.cs
new file mode 100644
index 00000000..4da90e07
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ModularShaderEditor.cs
@@ -0,0 +1,68 @@
+using System;
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UIElements;
+using UnityEditor.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ [CustomEditor(typeof(ModularShader))]
+ public class ModularShaderEditor : Editor
+ {
+ private VisualElement _root;
+ private ModularShader _shader;
+
+ public override VisualElement CreateInspectorGUI()
+ {
+ _root = new VisualElement();
+ _shader = (ModularShader)serializedObject.targetObject;
+ var visualTree = Resources.Load<VisualTreeAsset>(MSSConstants.RESOURCES_FOLDER + "/MSSUIElements/ModularShaderEditor");
+ VisualElement template = visualTree.CloneTree();
+
+ _root.Add(template);
+
+ var baseModulesField = _root.Q<ModuleInspectorList>("BaseModulesField");
+ bool areModulesEditable = !_shader.LockBaseModules;
+ bool checkForProperties = _shader.UseTemplatesForProperties;
+ if(!areModulesEditable)
+ baseModulesField.SetFoldingState(true);
+ baseModulesField.SetEnabled(areModulesEditable);
+
+ var templateField = _root.Q<ObjectField>("ShaderTemplateField");
+ templateField.objectType = typeof(TemplateAsset);
+
+ var propertiesTemplateField = _root.Q<ObjectField>("ShaderPropertiesTemplateField");
+ propertiesTemplateField.objectType = typeof(TemplateAsset);
+ propertiesTemplateField.style.display = checkForProperties ? DisplayStyle.Flex : DisplayStyle.None;
+
+ var useTemplatesField = _root.Q<Toggle>("UseTemplatesForPropertiesField");
+ useTemplatesField.RegisterValueChangedCallback(x =>
+ {
+ propertiesTemplateField.style.display = x.newValue ? DisplayStyle.Flex : DisplayStyle.None;
+ });
+
+ var generateButton = _root.Q<Button>("RegenerateShaderButton");
+
+ generateButton.clicked += () =>
+ {
+ var _issues = ShaderGenerator.CheckShaderIssues(_shader);
+ if (_issues.Count > 0)
+ {
+ EditorUtility.DisplayDialog("Error", $"The modular shader has issues that must be resolved before generating the shader:\n {string.Join("\n ", _issues)}", "Ok");
+ return;
+ }
+
+ string path = EditorUtility.OpenFolderPanel("Select folder", "Assets", "");
+ if (path.Length == 0)
+ return;
+
+ string localPath = Environment.CurrentDirectory;
+ localPath = localPath.Replace('\\', '/');
+ path = path.Replace(localPath + "/", "");
+ ShaderGenerator.GenerateShader(path, _shader);
+ };
+
+ return _root;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ModularShaderEditor.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ModularShaderEditor.cs.meta
new file mode 100644
index 00000000..0b65b770
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ModularShaderEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ac6f0c46be6e0b34b81bc6cb1d45b9f2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ShaderModuleEditor.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ShaderModuleEditor.cs
new file mode 100644
index 00000000..1160ac15
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ShaderModuleEditor.cs
@@ -0,0 +1,23 @@
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ [CustomEditor(typeof(ShaderModule))]
+ public class ShaderModuleEditor : Editor
+ {
+ private VisualElement _root;
+
+ public override VisualElement CreateInspectorGUI()
+ {
+ _root = new VisualElement();
+
+ var visualTree = Resources.Load<VisualTreeAsset>(MSSConstants.RESOURCES_FOLDER + "/MSSUIElements/ShaderModuleEditor");
+ VisualElement template = visualTree.CloneTree();
+ _root.Add(template);
+
+ return _root;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ShaderModuleEditor.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ShaderModuleEditor.cs.meta
new file mode 100644
index 00000000..4b45e29f
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/ShaderModuleEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c77ebb1fa33e27c44ac0cb2e2cadf4fe
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/TemplateAssetEditor.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/TemplateAssetEditor.cs
new file mode 100644
index 00000000..a9278df6
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/TemplateAssetEditor.cs
@@ -0,0 +1,20 @@
+using System;
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ [CustomEditor(typeof(TemplateAsset))]
+ public class TemplateAssetEditor : Editor
+ {
+ public override VisualElement CreateInspectorGUI()
+ {
+ CodeViewElement element = new CodeViewElement();
+ element.Text = serializedObject.FindProperty("Template").stringValue;
+ element.style.minHeight = 600;
+ return element;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/TemplateAssetEditor.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/TemplateAssetEditor.cs.meta
new file mode 100644
index 00000000..e37143ba
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Inspectors/TemplateAssetEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1c1a6131e05e6c54e9503e1a9d4529eb
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows.meta
new file mode 100644
index 00000000..ef76597f
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 37d69e6ef5507b4498f9edc7b4d9bcd5
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/Migrator.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/Migrator.cs
new file mode 100644
index 00000000..9389c1c0
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/Migrator.cs
@@ -0,0 +1,814 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UIElements;
+using Object = UnityEngine.Object;
+
+namespace Poiyomi.ModularShaderSystem
+{
+ [Serializable]
+ public class MigratedAssets
+ {
+ public List<MigratedTemplate> templates;
+ public List<MigratedCollection> templateCollections;
+ public List<MigratedShaderModule> shaderModules;
+ public List<MigratedModularShader> modularShaders;
+
+ public MigratedAssets()
+ {
+ templates = new List<MigratedTemplate>();
+ templateCollections = new List<MigratedCollection>();
+ shaderModules = new List<MigratedShaderModule>();
+ modularShaders = new List<MigratedModularShader>();
+ }
+ }
+
+ [Serializable]
+ public class MigratedTemplate
+ {
+ public long id;
+ public string path;
+ public string content;
+ }
+
+ [Serializable]
+ public class MigratedCollection
+ {
+ public long id;
+ public string path;
+ public string content;
+ }
+
+ [Serializable]
+ public class MigratedShaderModule
+ {
+ public long id;
+ public string path;
+ public string moduleId;
+ public string name;
+ public string version;
+ public string author;
+ public string description;
+ public List<EnableProperty> enableProperties;
+ public List<Property> properties;
+ public List<string> moduleDependencies;
+ public List<string> incompatibleWith;
+ public List<MigratedModuleTemplate> templates;
+ public List<MigratedShaderFunction> functions;
+ public string additionalSerializedData;
+ }
+
+ [Serializable]
+ public class MigratedModularShader
+ {
+ public long id;
+ public string path;
+ public string shaderId;
+ public string name;
+ public string version;
+ public string author;
+ public string description;
+ public bool useTemplatesForProperties;
+ public long propertiesTemplateReference;
+ public string propertiesCollectionSubId;
+ public string shaderPath;
+ public long shaderTemplateReference;
+ public string shaderCollectionSubId;
+ public string customEditor;
+ public List<Property> properties;
+ public List<long> baseModules;
+ public List<long> additionalModules;
+ public bool lockBaseModules;
+ public List<Shader> lastGeneratedShaders;
+ public string additionalSerializedData;
+ }
+
+ [Serializable]
+ public class MigratedModuleTemplate
+ {
+ public long templateReference;
+ public string collectionSubId;
+ public List<string> keywords;
+ public bool needsVariant;
+ public int queue;
+ }
+
+ [Serializable]
+ public class MigratedShaderFunction
+ {
+ public string name;
+ public string appendAfter;
+ public short queue;
+ public long templateReference;
+ public string collectionSubId;
+ public List<Variable> usedVariables;
+ public List<string> variableKeywords;
+ public List<string> codeKeywords;
+ }
+
+ public class MigratedItemElement<T> : VisualElement
+ {
+ private bool _isSelected;
+
+ public bool IsSelected
+ {
+ get => _isSelected;
+ set
+ {
+ _isSelected = value;
+ _toggle.SetValueWithoutNotify(_isSelected);
+ }
+ }
+
+
+ private Migrator _window;
+ public T ToggledItem;
+ private string _name;
+ private readonly Toggle _toggle;
+
+ public MigratedItemElement(Migrator window, T toggledItem, string name)
+ {
+ _window = window;
+ _name = name;
+ ToggledItem = toggledItem;
+
+ style.flexDirection = FlexDirection.Row;
+
+ _toggle = new Toggle();
+ _toggle.RegisterValueChangedCallback(evt =>
+ {
+ IsSelected = evt.newValue;
+ _window.CheckRelationshipSelection(toggledItem, IsSelected);
+ });
+ Add(_toggle);
+ Add(new Label(_name));
+ }
+ }
+
+ public class Migrator : EditorWindow
+ {
+ [MenuItem(MSSConstants.WINDOW_PATH + "/Tools/Migrator")]
+ private static void ShowWindow()
+ {
+ var window = GetWindow<Migrator>();
+ window.titleContent = new GUIContent("Migrator");
+ window.Show();
+ }
+
+ private List<MigratedItemElement<ModularShader>> _shaderElements;
+ private List<MigratedItemElement<ShaderModule>> _moduleElements;
+ private List<MigratedItemElement<TemplateAsset>> _templateElements;
+ private List<MigratedItemElement<TemplateCollectionAsset>> _collectionElements;
+
+ private void CreateGUI()
+ {
+ VisualElement root = rootVisualElement;
+
+ var styleSheet = Resources.Load<StyleSheet>(MSSConstants.RESOURCES_FOLDER + (EditorGUIUtility.isProSkin ? "/MSSUIElements/MigratorDark" : "/MSSUIElements/MigratorLight"));
+ root.styleSheets.Add(styleSheet);
+
+ var buttonRow = new VisualElement();
+ buttonRow.AddToClassList("button-tab-area");
+
+ var selectedTab = new VisualElement();
+ selectedTab.style.flexGrow = 1;
+
+ VisualElement exportRoot = new VisualElement();
+ exportRoot.style.flexGrow = 1;
+ SetupExport(exportRoot);
+
+ VisualElement importRoot = new VisualElement();
+ importRoot.style.flexGrow = 1;
+ SetupImport(importRoot);
+
+ var tabButton = new Button();
+ tabButton.text = "Export";
+ tabButton.AddToClassList("button-tab");
+ tabButton.clicked += () =>
+ {
+ foreach (var button in buttonRow.Children())
+ if(button.ClassListContains("button-tab-selected"))
+ button.RemoveFromClassList("button-tab-selected");
+
+ tabButton.AddToClassList("button-tab-selected");
+
+ selectedTab.Clear();
+ selectedTab.Add(exportRoot);
+ };
+ buttonRow.Add(tabButton);
+
+ var secondTabButton = new Button();
+ secondTabButton.text = "Import";
+ secondTabButton.AddToClassList("button-tab");
+ secondTabButton.clicked += () =>
+ {
+ foreach (var button in buttonRow.Children())
+ if(button.ClassListContains("button-tab-selected"))
+ button.RemoveFromClassList("button-tab-selected");
+
+ secondTabButton.AddToClassList("button-tab-selected");
+
+ selectedTab.Clear();
+ selectedTab.Add(importRoot);
+ };
+
+ buttonRow.Add(secondTabButton);
+
+ selectedTab.Add(exportRoot);
+ tabButton.AddToClassList("button-tab-selected");
+ root.Add(buttonRow);
+ root.Add(selectedTab);
+ }
+
+ private void SetupImport(VisualElement importRoot)
+ {
+ MigratedAssets assets = null;
+
+ var scrollView = new ScrollView(ScrollViewMode.Vertical);
+ scrollView.style.flexGrow = 1;
+
+ var importButton = new Button();
+ importButton.text = "Import";
+ importButton.SetEnabled(false);
+ importButton.clicked += () => Import(assets);
+
+ var loadButton = new Button();
+ loadButton.text = "Load file";
+ loadButton.clicked += () =>
+ {
+ string assetPath = EditorUtility.OpenFilePanel("Export", "Assets", "json");
+ if (string.IsNullOrWhiteSpace(assetPath)) return;
+
+ assets = JsonUtility.FromJson<MigratedAssets>(File.ReadAllText(assetPath));
+
+ importButton.SetEnabled(true);
+
+ scrollView.Clear();
+ var label = new Label("Modular Shaders");
+ label.AddToClassList("title");
+ scrollView.Add(label);
+
+ foreach (var shader in assets.modularShaders)
+ scrollView.Add(new Label($"{shader.name} ({shader.shaderId})"));
+
+ label = new Label("Shader Modules");
+ label.AddToClassList("title");
+ scrollView.Add(label);
+
+ foreach (var module in assets.shaderModules)
+ scrollView.Add(new Label($"{module.name} ({module.moduleId})"));
+
+ label = new Label("Template Assets");
+ label.AddToClassList("title");
+ scrollView.Add(label);
+
+ foreach (var template in assets.templates)
+ scrollView.Add(new Label($"{Path.GetFileNameWithoutExtension(template.path)}"));
+
+ label = new Label("Template Collection Assets");
+ label.AddToClassList("title");
+ scrollView.Add(label);
+
+ foreach (var collection in assets.templateCollections)
+ scrollView.Add(new Label($"{Path.GetFileNameWithoutExtension(collection.path)}"));
+ };
+
+ importRoot.Add(loadButton);
+ importRoot.Add(scrollView);
+ importRoot.Add(importButton);
+ }
+
+ private static void Import(MigratedAssets assets)
+ {
+ foreach (var asset in assets.templates)
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(asset.path));
+ File.WriteAllText(Path.ChangeExtension(asset.path, MSSConstants.TEMPLATE_EXTENSION) ?? string.Empty, asset.content);
+ if(File.Exists(asset.path))
+ File.Delete(asset.path);
+ }
+
+ foreach (var asset in assets.templateCollections)
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(asset.path));
+ File.WriteAllText(Path.ChangeExtension(asset.path, MSSConstants.TEMPLATE_COLLECTION_EXTENSION) ?? string.Empty, asset.content);
+ if(File.Exists(asset.path))
+ File.Delete(asset.path);
+ }
+
+ AssetDatabase.Refresh();
+
+ foreach (var asset in assets.shaderModules)
+ {
+ var module = CreateInstance<ShaderModule>();
+ module.Id = asset.moduleId;
+ module.Name = asset.name;
+ module.Description = asset.description;
+ module.Version = asset.version;
+ module.Author = asset.author;
+ module.ModuleDependencies = new List<string>(asset.moduleDependencies);
+ module.IncompatibleWith = new List<string>(asset.incompatibleWith);
+ module.AdditionalSerializedData = asset.additionalSerializedData;
+ module.EnableProperties = new List<EnableProperty>(asset.enableProperties);
+ module.Properties = new List<Property>(asset.properties);
+ module.Templates = asset.templates.Select(x =>
+ {
+ var template = new ModuleTemplate
+ {
+ Keywords = new List<string>(x.keywords),
+ Queue = x.queue,
+ NeedsVariant = x.needsVariant
+ };
+
+ if (string.IsNullOrWhiteSpace(x.collectionSubId))
+ {
+ var t = assets.templates.Find(y => y.id == x.templateReference);
+ if (t == null) return template;
+ var st = AssetDatabase.LoadAssetAtPath<TemplateAsset>(Path.ChangeExtension(t.path, MSSConstants.TEMPLATE_EXTENSION));
+ template.Template = st;
+ }
+ else
+ {
+ var t = assets.templateCollections.Find(y => y.id == x.templateReference);
+ if (t == null) return template;
+ var st = AssetDatabase.LoadAssetAtPath<TemplateCollectionAsset>(Path.ChangeExtension(t.path, MSSConstants.TEMPLATE_COLLECTION_EXTENSION));
+ template.Template = st.Templates.Find(y => x.collectionSubId.Equals(y.name));
+ }
+
+ return template;
+ }).ToList();
+ module.Functions = asset.functions.Select(x =>
+ {
+ var function = new ShaderFunction
+ {
+ Name = x.name,
+ Queue = x.queue,
+ AppendAfter = x.appendAfter,
+ CodeKeywords = new List<string>(x.codeKeywords),
+ UsedVariables = new List<Variable>(x.usedVariables),
+ VariableKeywords = new List<string>(x.variableKeywords)
+ };
+
+ if (string.IsNullOrWhiteSpace(x.collectionSubId))
+ {
+ var t = assets.templates.Find(y => y.id == x.templateReference);
+ if (t == null) return function;
+ var st = AssetDatabase.LoadAssetAtPath<TemplateAsset>(Path.ChangeExtension(t.path, MSSConstants.TEMPLATE_EXTENSION));
+ function.ShaderFunctionCode = st;
+ }
+ else
+ {
+ var t = assets.templateCollections.Find(y => y.id == x.templateReference);
+ if (t == null) return function;
+ var st = AssetDatabase.LoadAssetAtPath<TemplateCollectionAsset>(Path.ChangeExtension(t.path, MSSConstants.TEMPLATE_COLLECTION_EXTENSION));
+ function.ShaderFunctionCode = st.Templates.Find(y => x.collectionSubId.Equals(y.name));
+ }
+
+ return function;
+ }).ToList();
+ Directory.CreateDirectory(Path.GetDirectoryName(asset.path));
+ AssetDatabase.CreateAsset(module, asset.path);
+ }
+
+ AssetDatabase.Refresh();
+
+ foreach (var asset in assets.modularShaders)
+ {
+ var shader = CreateInstance<ModularShader>();
+ shader.Id = asset.shaderId;
+ shader.Name = asset.name;
+ shader.Description = asset.description;
+ shader.Version = asset.version;
+ shader.Author = asset.author;
+ shader.ShaderPath = asset.shaderPath;
+ shader.CustomEditor = asset.customEditor;
+ shader.LockBaseModules = asset.lockBaseModules;
+ shader.UseTemplatesForProperties = asset.useTemplatesForProperties;
+ shader.Properties = new List<Property>(asset.properties);
+ shader.BaseModules = asset.baseModules.Select(x => { return AssetDatabase.LoadAssetAtPath<ShaderModule>(assets.shaderModules.Find(y => y.id == x).path); }).ToList();
+
+ shader.AdditionalModules = asset.additionalModules.Select(x => { return AssetDatabase.LoadAssetAtPath<ShaderModule>(assets.shaderModules.Find(y => y.id == x).path); }).ToList();
+
+ if (string.IsNullOrWhiteSpace(asset.shaderCollectionSubId))
+ {
+ var t = assets.templates.Find(y => y.id == asset.shaderTemplateReference);
+ if (t != null)
+ {
+ var st = AssetDatabase.LoadAssetAtPath<TemplateAsset>(Path.ChangeExtension(t.path, MSSConstants.TEMPLATE_EXTENSION));
+ shader.ShaderTemplate = st;
+ }
+ }
+ else
+ {
+ var t = assets.templateCollections.Find(y => y.id == asset.shaderTemplateReference);
+ if (t != null)
+ {
+ var st = AssetDatabase.LoadAssetAtPath<TemplateCollectionAsset>(Path.ChangeExtension(t.path, MSSConstants.TEMPLATE_COLLECTION_EXTENSION));
+ shader.ShaderTemplate = st.Templates.Find(y => asset.shaderCollectionSubId.Equals(y.name));
+ }
+ }
+
+ if (string.IsNullOrWhiteSpace(asset.propertiesCollectionSubId))
+ {
+ var t = assets.templates.Find(y => y.id == asset.propertiesTemplateReference);
+ if (t != null)
+ {
+ var st = AssetDatabase.LoadAssetAtPath<TemplateAsset>(Path.ChangeExtension(t.path, MSSConstants.TEMPLATE_EXTENSION));
+ shader.ShaderPropertiesTemplate = st;
+ }
+ }
+ else
+ {
+ var t = assets.templateCollections.Find(y => y.id == asset.propertiesTemplateReference);
+ if (t != null)
+ {
+ var st = AssetDatabase.LoadAssetAtPath<TemplateCollectionAsset>(Path.ChangeExtension(t.path, MSSConstants.TEMPLATE_COLLECTION_EXTENSION));
+ shader.ShaderPropertiesTemplate = st.Templates.Find(y => asset.propertiesCollectionSubId.Equals(y.name));
+ }
+ }
+
+ Directory.CreateDirectory(Path.GetDirectoryName(asset.path));
+ AssetDatabase.CreateAsset(shader, asset.path);
+ }
+
+ AssetDatabase.Refresh();
+ }
+
+ private void SetupExport(VisualElement exportRoot)
+ {
+ _shaderElements = new List<MigratedItemElement<ModularShader>>();
+ _moduleElements = new List<MigratedItemElement<ShaderModule>>();
+ _templateElements = new List<MigratedItemElement<TemplateAsset>>();
+ _collectionElements = new List<MigratedItemElement<TemplateCollectionAsset>>();
+
+ var templateAssets = FindAssetsByType<TemplateAsset>().Where(x => !AssetDatabase.IsSubAsset(x)).ToArray();
+ var collectionAssets = FindAssetsByType<TemplateCollectionAsset>();
+ var shaderModules = FindAssetsByType<ShaderModule>();
+ var modularShaders = FindAssetsByType<ModularShader>();
+
+ var scrollView = new ScrollView(ScrollViewMode.Vertical);
+ scrollView.style.flexGrow = 1;
+
+ Foldout shadersFoldout = new Foldout();
+ shadersFoldout.text = "Modular Shaders";
+ foreach (var modularShader in modularShaders)
+ {
+ var element = new MigratedItemElement<ModularShader>(this, modularShader, $"{modularShader.Name} ({modularShader.name})");
+ shadersFoldout.Add(element);
+ _shaderElements.Add(element);
+ }
+
+ Foldout modulesFoldout = new Foldout();
+ modulesFoldout.text = "Shader Modules";
+ foreach (var shaderModule in shaderModules)
+ {
+ var element = new MigratedItemElement<ShaderModule>(this, shaderModule, $"{shaderModule.Name} ({shaderModule.name})");
+ modulesFoldout.Add(element);
+ _moduleElements.Add(element);
+ }
+
+ Foldout templatesFoldout = new Foldout();
+ templatesFoldout.text = "Template Assets";
+ foreach (var template in templateAssets)
+ {
+ var element = new MigratedItemElement<TemplateAsset>(this, template, template.name);
+ templatesFoldout.Add(element);
+ _templateElements.Add(element);
+ }
+
+ Foldout collectionsFoldout = new Foldout();
+ collectionsFoldout.text = "Template Collection Assets";
+ foreach (var collection in collectionAssets)
+ {
+ var element = new MigratedItemElement<TemplateCollectionAsset>(this, collection, collection.name);
+ collectionsFoldout.Add(element);
+ _collectionElements.Add(element);
+ }
+
+ var bottomRow = new VisualElement();
+ bottomRow.style.flexDirection = FlexDirection.Row;
+
+ var b = new Button();
+ b.text = "Select all";
+ b.clicked += () =>
+ {
+ _shaderElements.ForEach(x => x.IsSelected = true);
+ _moduleElements.ForEach(x => x.IsSelected = true);
+ _templateElements.ForEach(x => x.IsSelected = true);
+ _collectionElements.ForEach(x => x.IsSelected = true);
+ };
+ bottomRow.Add(b);
+
+ b = new Button();
+ b.text = "Unselect all";
+ b.clicked += () =>
+ {
+ _shaderElements.ForEach(x => x.IsSelected = false);
+ _moduleElements.ForEach(x => x.IsSelected = false);
+ _templateElements.ForEach(x => x.IsSelected = false);
+ _collectionElements.ForEach(x => x.IsSelected = false);
+ };
+ bottomRow.Add(b);
+ var v = new VisualElement();
+ v.style.flexGrow = 1;
+ bottomRow.Add(v);
+ b = new Button();
+ b.text = "Save";
+ b.clicked += ExportSelected;
+ bottomRow.Add(b);
+
+
+
+ scrollView.Add(shadersFoldout);
+ scrollView.Add(modulesFoldout);
+ scrollView.Add(templatesFoldout);
+ scrollView.Add(collectionsFoldout);
+ exportRoot.Add(scrollView);
+ exportRoot.Add(bottomRow);
+ }
+
+ private void ExportSelected()
+ {
+ var assets = new MigratedAssets();
+
+ string finalPath = EditorUtility.SaveFilePanel("Export", "Assets", "migrationData", "json");
+ if (string.IsNullOrWhiteSpace(finalPath)) return;
+
+ var idByTemplate = new Dictionary<TemplateAsset, long>();
+ var idByCollection = new Dictionary<TemplateAsset, long>();
+ var idByModule = new Dictionary<ShaderModule, long>();
+
+ long currentId = 1;
+ foreach (var asset in _templateElements.Where(x => x.IsSelected).Select(x => x.ToggledItem))
+ {
+ idByTemplate.Add(asset, currentId);
+ string path = AssetDatabase.GetAssetPath(asset);
+ assets.templates.Add(new MigratedTemplate
+ {
+ id = currentId,
+ content = File.ReadAllText(path),
+ path = path
+ });
+ currentId++;
+ }
+ foreach (var asset in _collectionElements.Where(x => x.IsSelected).Select(x => x.ToggledItem))
+ {
+ foreach (var tmp in asset.Templates)
+ {
+ idByCollection.Add(tmp, currentId);
+ }
+ string path = AssetDatabase.GetAssetPath(asset);
+ assets.templateCollections.Add(new MigratedCollection
+ {
+ id = currentId,
+ content = File.ReadAllText(path),
+ path = path
+ });
+ currentId++;
+ }
+ foreach (var asset in _moduleElements.Where(x => x.IsSelected).Select(x => x.ToggledItem))
+ {
+ idByModule.Add(asset, currentId);
+ string path = AssetDatabase.GetAssetPath(asset);
+ assets.shaderModules.Add(new MigratedShaderModule
+ {
+ id = currentId,
+ path = path,
+ moduleId = asset.Id,
+ name = asset.Name,
+ version = asset.Version,
+ author = asset.Author,
+ description = asset.Description,
+ enableProperties = asset.EnableProperties,
+ properties = new List<Property>(asset.Properties),
+ moduleDependencies = new List<string>(asset.ModuleDependencies),
+ incompatibleWith = new List<string>(asset.IncompatibleWith),
+ additionalSerializedData = asset.AdditionalSerializedData,
+ templates = new List<MigratedModuleTemplate>(asset.Templates.Select(x => FromModuleTemplate(x, idByTemplate, idByCollection))),
+ functions = new List<MigratedShaderFunction>(asset.Functions.Select(x => FromModuleFunction(x, idByTemplate, idByCollection)))
+ });
+ currentId++;
+ }
+ foreach (var asset in _shaderElements.Where(x => x.IsSelected).Select(x => x.ToggledItem))
+ {
+ string path = AssetDatabase.GetAssetPath(asset);
+ var shader = new MigratedModularShader
+ {
+ id = currentId,
+ path = path,
+ shaderId = asset.Id,
+ name = asset.Name,
+ version = asset.Version,
+ author = asset.Author,
+ description = asset.Description,
+ properties = new List<Property>(asset.Properties),
+ additionalSerializedData = asset.AdditionalSerializedData,
+ customEditor = asset.CustomEditor,
+ shaderPath = asset.ShaderPath,
+ lockBaseModules = asset.LockBaseModules,
+ useTemplatesForProperties = asset.UseTemplatesForProperties,
+ baseModules = asset.BaseModules.Select(x => idByModule[x]).ToList(),
+ additionalModules = asset.AdditionalModules.Select(x => idByModule[x]).ToList()
+
+ };
+
+ if (asset.ShaderTemplate == null) shader.shaderTemplateReference = 0;
+ else if (idByTemplate.ContainsKey(asset.ShaderTemplate))
+ {
+ shader.shaderTemplateReference = idByTemplate[asset.ShaderTemplate];
+ }
+ else if (idByCollection.ContainsKey(asset.ShaderTemplate))
+ {
+ shader.shaderTemplateReference = idByTemplate[asset.ShaderTemplate];
+ shader.shaderCollectionSubId = asset.ShaderTemplate.name;
+ }
+
+ if (asset.ShaderPropertiesTemplate == null) shader.propertiesTemplateReference = 0;
+ else if (idByTemplate.ContainsKey(asset.ShaderPropertiesTemplate))
+ {
+ shader.propertiesTemplateReference = idByTemplate[asset.ShaderPropertiesTemplate];
+ }
+ else if (idByCollection.ContainsKey(asset.ShaderPropertiesTemplate))
+ {
+ shader.propertiesTemplateReference = idByTemplate[asset.ShaderPropertiesTemplate];
+ shader.propertiesCollectionSubId = asset.ShaderPropertiesTemplate.name;
+ }
+
+ assets.modularShaders.Add(shader);
+
+ currentId++;
+ }
+
+ File.WriteAllText(finalPath, JsonUtility.ToJson(assets));
+ }
+
+ private static MigratedModuleTemplate FromModuleTemplate(ModuleTemplate original, Dictionary<TemplateAsset, long> idByTemplate, Dictionary<TemplateAsset, long> idByCollection)
+ {
+
+ var template = new MigratedModuleTemplate
+ {
+ keywords = new List<string>(original.Keywords),
+ queue = original.Queue,
+ needsVariant = original.NeedsVariant
+ };
+
+ if (original.Template == null) return template;
+
+ if (idByTemplate.ContainsKey(original.Template))
+ {
+ template.templateReference = idByTemplate[original.Template];
+ }
+ else if (idByCollection.ContainsKey(original.Template))
+ {
+ template.templateReference = idByCollection[original.Template];
+ template.collectionSubId = original.Template.name;
+ }
+
+ return template;
+ }
+
+ private static MigratedShaderFunction FromModuleFunction(ShaderFunction original, Dictionary<TemplateAsset, long> idByTemplate, Dictionary<TemplateAsset, long> idByCollection)
+ {
+
+ var template = new MigratedShaderFunction
+ {
+ name = original.Name,
+ queue = original.Queue,
+ appendAfter = original.AppendAfter,
+ usedVariables = original.UsedVariables,
+ codeKeywords = original.CodeKeywords,
+ variableKeywords = original.VariableKeywords,
+ };
+ if (original.ShaderFunctionCode == null) return template;
+
+ if (idByTemplate.ContainsKey(original.ShaderFunctionCode))
+ {
+ template.templateReference = idByTemplate[original.ShaderFunctionCode];
+ }
+ else if (idByCollection.ContainsKey(original.ShaderFunctionCode))
+ {
+ template.templateReference = idByCollection[original.ShaderFunctionCode];
+ template.collectionSubId = original.ShaderFunctionCode.name;
+ }
+
+ return template;
+ }
+
+ internal void CheckRelationshipSelection<T>(T item, bool isToggled)
+ {
+ switch (item)
+ {
+ case ModularShader s:
+ ToggleShaderDependencies(s, isToggled);
+ break;
+ case ShaderModule m:
+ ToggleModuleDependencies(m, isToggled);
+ break;
+ case TemplateAsset t:
+ ToggleTemplateDependencies(t, isToggled);
+ break;
+ case TemplateCollectionAsset c:
+ ToggleCollectionDependencies(c, isToggled);
+ break;
+ }
+ }
+
+ private void ToggleShaderDependencies(ModularShader shader, bool isToggled)
+ {
+ if (!isToggled) return;
+
+ foreach (var element in _moduleElements.Where(x => shader.BaseModules.Concat(shader.AdditionalModules).Contains(x.ToggledItem)))
+ {
+ element.IsSelected = true;
+ ToggleModuleDependencies(element.ToggledItem, true);
+ }
+
+ foreach (var element in _templateElements.Where(x => shader.ShaderTemplate == x.ToggledItem || shader.ShaderPropertiesTemplate == x.ToggledItem))
+ {
+ element.IsSelected = true;
+ }
+
+ foreach (var element in _collectionElements.Where(x => x.ToggledItem.Templates.Contains(shader.ShaderTemplate) || x.ToggledItem.Templates.Contains(shader.ShaderPropertiesTemplate)))
+ {
+ element.IsSelected = true;
+ }
+ }
+
+ private void ToggleModuleDependencies(ShaderModule module, bool isToggled)
+ {
+ if (isToggled)
+ {
+ foreach (var element in _templateElements.Where(x =>
+ module.Templates.Select(y => y.Template).Concat(module.Functions.Select(z => z.ShaderFunctionCode)).Contains(x.ToggledItem)))
+ {
+ element.IsSelected = true;
+ }
+
+ foreach (var element in _collectionElements.Where(x =>
+ module.Templates.Select(y => y.Template).Concat(module.Functions.Select(z => z.ShaderFunctionCode)).Any(y => x.ToggledItem.Templates.Contains(y))))
+ {
+ element.IsSelected = true;
+ }
+ }
+ else
+ {
+ foreach (var element in _shaderElements.Where(x => x.ToggledItem.BaseModules.Concat(x.ToggledItem.AdditionalModules).Contains(module)))
+ {
+ element.IsSelected = false;
+ }
+ }
+ }
+
+ private void ToggleTemplateDependencies(TemplateAsset template, bool isToggled)
+ {
+ if (isToggled) return;
+
+ foreach (var element in _moduleElements.Where(x =>
+ x.ToggledItem.Templates.Select(y => y.Template).Concat(x.ToggledItem.Functions.Select(z => z.ShaderFunctionCode)).Contains(template)))
+ {
+ element.IsSelected = false;
+ ToggleModuleDependencies(element.ToggledItem, false);
+ }
+
+ foreach (var element in _shaderElements.Where(x => x.ToggledItem.ShaderTemplate == template || x.ToggledItem.ShaderPropertiesTemplate == template))
+ {
+ element.IsSelected = false;
+ }
+ }
+
+ private void ToggleCollectionDependencies(TemplateCollectionAsset template, bool isToggled)
+ {
+ if (isToggled) return;
+
+ foreach (var element in _moduleElements.Where(x =>
+ x.ToggledItem.Templates.Select(y => y.Template).Concat(x.ToggledItem.Functions.Select(z => z.ShaderFunctionCode)).Any(y => template.Templates.Contains(y))))
+ {
+ element.IsSelected = false;
+ ToggleModuleDependencies(element.ToggledItem, false);
+ }
+
+ foreach (var element in _shaderElements.Where(x => template.Templates.Contains(x.ToggledItem.ShaderTemplate) ||template.Templates.Contains(x.ToggledItem.ShaderPropertiesTemplate)))
+ {
+ element.IsSelected = false;
+ }
+ }
+
+ private static T[] FindAssetsByType<T>() where T : Object
+ {
+ List<T> assets = new List<T>();
+ AssetDatabase.Refresh();
+ string[] guids = AssetDatabase.FindAssets($"t:{typeof(T).ToString().Replace("UnityEngine.", "")}");
+ for (int i = 0; i < guids.Length; i++)
+ {
+ string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]);
+ T asset = AssetDatabase.LoadAssetAtPath<T>(assetPath);
+ if (asset != null)
+ assets.Add(asset);
+ }
+ return assets.ToArray();
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/Migrator.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/Migrator.cs.meta
new file mode 100644
index 00000000..c7276d4a
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/Migrator.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 905f1d7d180a43f46900ed1f09f40b2e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/ModularShaderDebugger.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/ModularShaderDebugger.cs
new file mode 100644
index 00000000..377b1bef
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/ModularShaderDebugger.cs
@@ -0,0 +1,153 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UIElements;
+using UnityEditor.UIElements;
+
+namespace Poiyomi.ModularShaderSystem.Debug
+{
+ public interface IModularShaderDebuggerTab
+ {
+ VisualElement TabContainer { get; set; }
+
+ string TabName { get; set; }
+
+ void UpdateTab(ModularShader shader);
+ }
+
+ public class ModularShaderDebugger : EditorWindow
+ {
+ [MenuItem(MSSConstants.WINDOW_PATH + "/Modular Shader Debugger")]
+ public static void ShowExample()
+ {
+ ModularShaderDebugger wnd = GetWindow<ModularShaderDebugger>();
+ wnd.titleContent = new GUIContent("Modular Shader Debugger");
+
+ if (wnd.position.width < 400 || wnd.position.height < 400)
+ {
+ Rect size = wnd.position;
+ size.width = 1280;
+ size.height = 720;
+ wnd.position = size;
+ }
+
+ wnd.Show();
+ }
+
+ private ObjectField _modularShaderField;
+ private ModularShader _modularShader;
+ private VisualElement _selectedTab;
+
+ private List<IModularShaderDebuggerTab> _tabs;
+
+ public void CreateGUI()
+ {
+ VisualElement root = rootVisualElement;
+ var styleSheet = Resources.Load<StyleSheet>(MSSConstants.RESOURCES_FOLDER + "/MSSUIElements/ModularShaderDebuggerStyle");
+ var darkThemeStyleSheet = EditorGUIUtility.Load("StyleSheets/Generated/DefaultCommonDark_inter.uss.asset") as StyleSheet;
+ root.styleSheets.Add(darkThemeStyleSheet);
+ root.styleSheets.Add(styleSheet);
+ root.style.backgroundColor = new Color(0.2196079f, 0.2196079f, 0.2196079f, 1);
+ _modularShaderField = new ObjectField("Shader");
+ _modularShaderField.style.flexGrow = 1;
+ _modularShaderField.objectType = typeof(ModularShader);
+ _modularShaderField.RegisterCallback<ChangeEvent<UnityEngine.Object>>(e =>
+ {
+ if (_modularShaderField.value != null)
+ _modularShader = (ModularShader)_modularShaderField.value;
+ else
+ _modularShader = null;
+
+ UpdateTabs();
+ });
+
+ _tabs = new List<IModularShaderDebuggerTab>();
+
+ var topArea = new VisualElement();
+ topArea.AddToClassList("top-area");
+ var refreshButton = new Button();
+ refreshButton.AddToClassList("refresh-button");
+ refreshButton.clicked += () => UpdateTabs();
+
+ var buttonRow = new VisualElement();
+ buttonRow.AddToClassList("button-tab-area");
+
+ _selectedTab = new VisualElement();
+ _selectedTab.style.flexGrow = 1;
+
+ topArea.Add(_modularShaderField);
+ topArea.Add(refreshButton);
+
+ root.Add(topArea);
+ root.Add(buttonRow);
+ root.Add(_selectedTab);
+
+ var tabTypes = AppDomain.CurrentDomain
+ .GetAssemblies()
+ .SelectMany(x => x.GetTypes())
+ .Where(x => x.GetInterface(typeof(IModularShaderDebuggerTab).FullName) != null)
+ .OrderBy(x => x.Name)
+ .ToList();
+
+ foreach (var type in tabTypes)
+ {
+ var tab = Activator.CreateInstance(type) as IModularShaderDebuggerTab;
+
+ var tabButton = new Button();
+ tabButton.text = tab?.TabName;
+ tabButton.AddToClassList("button-tab");
+
+ tabButton.clicked += () =>
+ {
+ foreach (var button in buttonRow.Children())
+ if(button.ClassListContains("button-tab-selected"))
+ button.RemoveFromClassList("button-tab-selected");
+
+ tabButton.AddToClassList("button-tab-selected");
+
+ _selectedTab.Clear();
+ _selectedTab.Add(tab.TabContainer);
+ };
+
+ buttonRow.Add(tabButton);
+ _tabs.Add(tab);
+ }
+
+ if (_tabs.Count == 0) return;
+ var graph = _tabs.FirstOrDefault(x => x.GetType() == typeof(TemplateGraph));
+ var timeline = _tabs.FirstOrDefault(x => x.GetType() == typeof(FunctionTimeline));
+
+ if (timeline != null)
+ {
+ var index = _tabs.IndexOf(timeline);
+ var button = buttonRow[index];
+ _tabs.RemoveAt(index);
+ buttonRow.RemoveAt(index);
+ _tabs.Insert(0, timeline);
+ buttonRow.Insert(0, button);
+ }
+ if (graph != null)
+ {
+ var index = _tabs.IndexOf(graph);
+ var button = buttonRow[index];
+ _tabs.RemoveAt(index);
+ buttonRow.RemoveAt(index);
+ _tabs.Insert(0, graph);
+ buttonRow.Insert(0, button);
+ }
+
+ buttonRow[0].AddToClassList("button-tab-selected");
+ _selectedTab.Add(_tabs[0].TabContainer);
+ }
+
+ private void UpdateTabs()
+ {
+ foreach (IModularShaderDebuggerTab tab in _tabs)
+ {
+ tab.UpdateTab(_modularShader);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/ModularShaderDebugger.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/ModularShaderDebugger.cs.meta
new file mode 100644
index 00000000..7f5ba831
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/ModularShaderDebugger.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: da3cfc39b3d4bbe45baa0af3e383d910
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/TextPopup.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/TextPopup.cs
new file mode 100644
index 00000000..b59a3434
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/TextPopup.cs
@@ -0,0 +1,20 @@
+using UnityEditor;
+using UnityEngine.UIElements;
+using Poiyomi.ModularShaderSystem.Debug;
+
+namespace Poiyomi.ModularShaderSystem.UI
+{
+ public class TextPopup : EditorWindow
+ {
+ public string Text;
+ private void CreateGUI()
+ {
+ var viewer = new CodeViewElement();
+ viewer.Text = Text;
+ viewer.StretchToParentSize();
+ var darkThemeStyleSheet = EditorGUIUtility.Load("StyleSheets/Generated/DefaultCommonDark_inter.uss.asset") as StyleSheet;
+ rootVisualElement.styleSheets.Add(darkThemeStyleSheet);
+ rootVisualElement.Add(viewer);
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/TextPopup.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/TextPopup.cs.meta
new file mode 100644
index 00000000..35db26ed
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Editors/Windows/TextPopup.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b1bc7c24875ba994fbef21ccbc464432
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/LICENSE b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/LICENSE
new file mode 100644
index 00000000..df010af6
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 VRLabs
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/LICENSE.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/LICENSE.meta
new file mode 100644
index 00000000..1776df2f
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/LICENSE.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 9345abea6ea4a104f98ee62ef3577c24
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/MSSConstants.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/MSSConstants.cs
new file mode 100644
index 00000000..96170a78
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/MSSConstants.cs
@@ -0,0 +1,21 @@
+namespace Poiyomi.ModularShaderSystem
+{
+ public static class MSSConstants
+ {
+ public const string DEFAULT_VARIABLES_KEYWORD = "DEFAULT_VARIABLES";
+
+ public const string DEFAULT_CODE_KEYWORD = "DEFAULT_CODE";
+
+ public const string TEMPLATE_PROPERTIES_KEYWORD = "SHADER_PROPERTIES";
+
+ public const string TEMPLATE_EXTENSION = "poiTemplate";
+
+ public const string TEMPLATE_COLLECTION_EXTENSION = "poiTemplateCollection";
+
+ public const string WINDOW_PATH = "Poi/Modular Shader";
+
+ public const string CREATE_PATH = "Poi/Modular Shader";
+
+ public const string RESOURCES_FOLDER = "POIMSS";
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/MSSConstants.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/MSSConstants.cs.meta
new file mode 100644
index 00000000..ed84f617
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/MSSConstants.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 32e6c8471a3b4ad4884a326cb9da981f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ModularShaderSystemDefinition.asmdef b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ModularShaderSystemDefinition.asmdef
new file mode 100644
index 00000000..3fd19588
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ModularShaderSystemDefinition.asmdef
@@ -0,0 +1,15 @@
+{
+ "name": "Poiyomi.ModularShaderSystem",
+ "references": [],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [],
+ "noEngineReferences": false
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ModularShaderSystemDefinition.asmdef.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ModularShaderSystemDefinition.asmdef.meta
new file mode 100644
index 00000000..2a9156f9
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ModularShaderSystemDefinition.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 9a4c6debc6b05b24d87e13b68d68d9a3
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources.meta
new file mode 100644
index 00000000..3f08654e
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: cba1abf74d7028445a195aa6b60110b0
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS.meta
new file mode 100644
index 00000000..652ca8a2
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 764db3030f9396f4a973ccff02a58296
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDeleteIcon.png b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDeleteIcon.png
new file mode 100755
index 00000000..e39af945
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDeleteIcon.png
Binary files differ
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDeleteIcon.png.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDeleteIcon.png.meta
new file mode 100644
index 00000000..19aab98f
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDeleteIcon.png.meta
@@ -0,0 +1,104 @@
+fileFormatVersion: 2
+guid: 6b424ec3a6fbd2a49ae16108e70985d2
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDownIcon.png b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDownIcon.png
new file mode 100755
index 00000000..4c54e8b2
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDownIcon.png
Binary files differ
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDownIcon.png.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDownIcon.png.meta
new file mode 100644
index 00000000..374d0cbc
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSDownIcon.png.meta
@@ -0,0 +1,104 @@
+fileFormatVersion: 2
+guid: 1546637c8c31e674e964e3fcf5f9cd99
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements.meta
new file mode 100644
index 00000000..bfd9da3f
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3a307a323c724f7479aceb95c16479db
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/EnablePropertyDrawer.uxml b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/EnablePropertyDrawer.uxml
new file mode 100644
index 00000000..e013f293
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/EnablePropertyDrawer.uxml
@@ -0,0 +1,6 @@
+<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
+ <ui:TextField picking-mode="Ignore" label="Name" binding-path="Name" />
+ <ui:TextField picking-mode="Ignore" label="Display Name" binding-path="DisplayName" />
+ <uie:IntegerField label="Enable Value" value="0" binding-path="EnableValue" />
+ <Poiyomi.ModularShaderSystem.UI.InspectorList show-elements-text="false" binding-path="Attributes" />
+</ui:UXML> \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/EnablePropertyDrawer.uxml.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/EnablePropertyDrawer.uxml.meta
new file mode 100644
index 00000000..7e3c8b6f
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/EnablePropertyDrawer.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 5b56ea93d2a967a498f809081478ce2f
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionPropertyDrawer.uxml b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionPropertyDrawer.uxml
new file mode 100644
index 00000000..fd50fdc4
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionPropertyDrawer.uxml
@@ -0,0 +1,9 @@
+<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
+ <ui:TextField name="Name" picking-mode="Ignore" label="Name" binding-path="Name" />
+ <ui:TextField picking-mode="Ignore" label="Append After" binding-path="AppendAfter" />
+ <uie:IntegerField label="Queue" value="100" binding-path="Queue" />
+ <uie:PropertyField binding-path="ShaderFunctionCode" label="Function Code" focusable="true" />
+ <Poiyomi.ModularShaderSystem.UI.InspectorList show-elements-text="false" binding-path="UsedVariables" />
+ <Poiyomi.ModularShaderSystem.UI.InspectorList show-elements-text="false" binding-path="VariableKeywords" />
+ <Poiyomi.ModularShaderSystem.UI.InspectorList show-elements-text="false" binding-path="CodeKeywords" />
+</ui:UXML> \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionPropertyDrawer.uxml.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionPropertyDrawer.uxml.meta
new file mode 100644
index 00000000..beefff86
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionPropertyDrawer.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: fa58e90865df1cd42a942fb4d3fd876f
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionTimelineStyle.uss b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionTimelineStyle.uss
new file mode 100644
index 00000000..1c340a40
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionTimelineStyle.uss
@@ -0,0 +1,173 @@
+TimelineContainer
+{
+ flex-grow: 1;
+}
+
+TimelineRoot
+{
+ border-width: 1px;
+ border-color: black;
+ overflow: hidden;
+}
+
+TimelineRow
+{
+ border-width: 1px;
+ border-color: black;
+ flex-direction: row-reverse;
+ background-color: #303030;
+ overflow: hidden;
+}
+
+FunctionItem
+{
+ border-color: black;
+ border-width: 1px;
+ border-radius: 7px;
+ margin: 4px;
+ background-color: darkslategrey;
+ position: absolute;
+ flex-direction: row;
+ align-content: stretch;
+}
+
+CodeViewElement
+{
+ margin: 6px;
+}
+
+.function-header-queue
+{
+ -unity-font-style: italic;
+ color: grey;
+ -unity-text-align: middle-right;
+}
+
+.function-header-name
+{
+ align-self: center;
+ flex-grow: 1;
+ margin: 4px;
+ -unity-text-align: middle-left;
+}
+
+.timeline-title
+{
+ position: initial;
+ width: 200px;
+ border-width: 0 2px 0 0;
+ border-color: black;
+ background-color: #484848;
+ align-content: center;
+ flex-shrink: 0;
+ overflow: hidden;
+}
+.timeline-title>Label
+{
+ flex-grow: 1;
+ -unity-text-align: middle-right;
+ margin: 3px;
+}
+
+.timeline-content
+{
+ flex-grow: 1;
+}
+
+.timeline-content-row
+{
+ flex-direction: row;
+}
+
+VariablesViewer
+{
+ width: 30%;
+ border-width: 2px;
+ border-color: #282828;
+ margin: 2px;
+}
+
+FunctionViewer
+{
+ width: 35%;
+ border-width: 2px;
+ border-color: #282828;
+ margin: 2px;
+}
+
+FunctionTemplateViewer
+{
+ flex-grow: 1;
+ border-width: 2px;
+ border-color: #282828;
+ margin: 2px;
+}
+
+ModuleViewer
+{
+ width: 35%;
+ border-width: 2px;
+ border-color: #282828;
+ margin: 2px;
+}
+
+.contains-variable
+{
+ border-color: yellow;
+}
+
+.contains-variable-global
+{
+ border-color: #ff002f;
+}
+
+.selected-function
+{
+ border-color: aqua;
+}
+
+.area-title
+{
+ margin: 0;
+ padding: 4px;
+ background-color: #282828;
+ -unity-font-style: bold;
+}
+
+Foldout > Toggle
+{
+ margin-left: -11px;
+}
+
+.area-content>VisualElement, .area-content>VisualElement>VisualElement
+{
+ overflow: visible;
+}
+
+.area-content
+{
+ margin: 4px 4px 4px 4px;
+ padding: 0 0 0 11px;
+ overflow: hidden;
+}
+
+.variable-type-text
+{
+ color: grey;
+}
+
+.selected-variable
+{
+ background-color: rgba(255,255,0,0.2);
+}
+
+.selected-variable-global
+{
+ background-color: rgba(255, 0, 0, 0.2);
+}
+
+.label-field-value
+{
+ white-space: normal;
+ flex-shrink: 1;
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionTimelineStyle.uss.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionTimelineStyle.uss.meta
new file mode 100644
index 00000000..e696637e
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionTimelineStyle.uss.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 84cb57f844db60049882743c4f58c815
+timeCreated: 1640810258 \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionView.uxml b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionView.uxml
new file mode 100644
index 00000000..2f98870e
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionView.uxml
@@ -0,0 +1,9 @@
+<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
+ <ui:VisualElement style="margin-top: 1px; margin-bottom: 1px;">
+ <ui:Foldout name="FoldoutArea" class="hierarchy-foldout" />
+ <ui:Label name="FunctionLabel" class="function-label" />
+ <ui:VisualElement style="position: absolute; width: 100%;">
+ <ui:Label name="PriorityLabel" class="priority-label" />
+ </ui:VisualElement>
+ </ui:VisualElement>
+</ui:UXML> \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionView.uxml.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionView.uxml.meta
new file mode 100644
index 00000000..8ddb58bc
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/FunctionView.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: dc46a350bc76b62448079d7bdb177d8d
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/InspectorList.uss b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/InspectorList.uss
new file mode 100644
index 00000000..48ef93d8
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/InspectorList.uss
@@ -0,0 +1,139 @@
+.inspector-list-item-container
+{
+ flex-direction: row;
+}
+
+.inspector-list-buttons-container-horizontal
+{
+ flex-direction: row;
+ background-color: rgba(93,93,93,0.1);
+ border-left-color: rgba(82,82,82,0.4);
+ border-right-color: rgba(0,0,0,0.4);
+ border-top-color: rgba(0,0,0,0.4);
+ border-bottom-color: rgba(0,0,0,0.4);
+ margin-top: 1px;
+ padding-top: 1px;
+ padding-right: 1px;
+ margin-left: -1px;
+ margin-bottom: 1px;
+ border-width: 1px;
+
+ width: 57px;
+ min-width: 57px;
+ max-width: 57px;
+}
+
+.inspector-list-buttons-container-vertical
+{
+ flex-direction: column;
+ height: 56px;
+ background-color: rgba(93,93,93,0.1);
+ border-left-color: rgba(82,82,82,0.4);
+ border-right-color: rgba(0,0,0,0.4);
+ border-top-color: rgba(0,0,0,0.4);
+ border-bottom-color: rgba(0,0,0,0.4);
+ padding-top: 1px;
+ padding-right: 1px;
+ margin-top: 1px;
+ margin-left: -1px;
+ margin-bottom: 1px;
+ border-width: 1px;
+ width: 21px;
+ min-width: 21px;
+ max-width: 21px;
+}
+
+.inspector-list-item
+{
+ flex-grow: 1;
+
+ margin-left: -15px;
+ margin-top: 1px;
+ margin-bottom: 1px;
+ padding-left: 15px;
+ padding-bottom: 0px;
+ background-color: rgba(93,93,93,0.1);
+ border-left-color: rgba(0,0,0,0.4);
+ border-right-color: rgba(0,0,0,0.4);
+ border-top-color: rgba(0,0,0,0.4);
+ border-bottom-color: rgba(0,0,0,0.4);
+ border-width: 1px;
+}
+
+.inspector-list-add-button
+{
+ align-self: flex-end;
+ width: 52px;
+ height: 22px;
+ margin: 1px;
+}
+
+.inspector-list-up-button, .inspector-list-down-button, .inspector-list-remove-button
+{
+ height: 16px;
+ width: 16px;
+ background-color: rgba(0,0,0,0);
+ margin: 1px;
+ border-left-width: 0;
+ border-right-width: 0;
+ border-top-width: 0;
+ border-bottom-width: 0;
+ -unity-background-scale-mode: scale-to-fit;
+}
+.inspector-list-up-button
+{
+ background-image: resource("POIMSS/MSSUpIcon");
+}
+.inspector-list-down-button
+{
+ background-image: resource("POIMSS/MSSDownIcon");
+}
+.inspector-list-remove-button
+{
+ background-image: resource("POIMSS/MSSDeleteIcon");
+}
+
+.inspector-list-drag-handle
+{
+ width: 10px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ margin-right: 17px;
+ padding-right: 2px;
+ background-color: rgba(150,150,150,0.2);
+ border-color: rgba(0,0,0,0.4);
+ border-width: 1px;
+ border-radius: 5px;
+}
+
+.inspector-list-drag-enabled
+{
+ background-color: rgba(100, 100, 150, 0.5);
+}
+
+.inspector-list-drop-area
+{
+ height: 5px;
+ border-radius: 4px;
+
+}
+
+.inspector-list-drop-area-highlight
+{
+ background-color: rgba(128, 128, 190, 0.5);
+}
+
+.inspector-list-drop-area-selected
+{
+ background-color: rgba(160, 160, 220, 0.5);
+}
+
+.error-background
+{
+ background-color: rgba(255,0,0,0.5);
+}
+
+.inspector-list-item > Label
+{
+ white-space: normal;
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/InspectorList.uss.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/InspectorList.uss.meta
new file mode 100644
index 00000000..6568340b
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/InspectorList.uss.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8cf984743d9bb3a46a16e197f1f65b26
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
+ disableValidation: 0
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorDark.uss b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorDark.uss
new file mode 100644
index 00000000..02d0cbef
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorDark.uss
@@ -0,0 +1,43 @@
+Button
+{
+ margin: 2px;
+ padding: 4px;
+ border-radius: 0;
+ background-color: #484848;
+}
+
+.button-tab-area
+{
+ flex-direction: row;
+ margin: 0;
+}
+
+.top-area
+{
+ flex-direction: row;
+ margin: 0;
+}
+
+.button-tab
+{
+ flex-grow: 1;
+ height: 24px;
+ margin: 4px 0 0 0;
+ border-radius: 0;
+ border-width: 1px 0 0 0;
+ background-color: #484848;
+}
+
+.button-tab-selected
+{
+ background-color: #303030;
+}
+
+.title
+{
+ margin-top: 10px;
+ margin-bottom: 3px;
+ -unity-font-style: bold;
+ font-size: 14;
+}
+
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorDark.uss.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorDark.uss.meta
new file mode 100644
index 00000000..638b1003
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorDark.uss.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 2e127f112d7af0444b919f331612c69e
+timeCreated: 1643331247 \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorLight.uss b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorLight.uss
new file mode 100644
index 00000000..60635c2b
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorLight.uss
@@ -0,0 +1,42 @@
+Button
+{
+ margin: 2px;
+ padding: 4px;
+ border-radius: 0;
+ background-color: #989898;
+}
+.button-tab-area
+{
+ flex-direction: row;
+ margin: 0;
+}
+
+.top-area
+{
+ flex-direction: row;
+ margin: 0;
+}
+
+.button-tab
+{
+ flex-grow: 1;
+ height: 24px;
+ margin: 4px 0 0 0;
+ border-radius: 0;
+ border-width: 1px 0 0 0;
+ background-color: #989898;
+}
+
+.button-tab-selected
+{
+ background-color: #808080;
+}
+
+.title
+{
+ margin-top: 10px;
+ margin-bottom: 3px;
+ -unity-font-style: bold;
+ font-size: 14;
+}
+
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorLight.uss.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorLight.uss.meta
new file mode 100644
index 00000000..2dd5b3e9
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/MigratorLight.uss.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: fb76cdb11426ae44380438e0a03ade95
+timeCreated: 1643331277 \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderDebuggerStyle.uss b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderDebuggerStyle.uss
new file mode 100644
index 00000000..8502e863
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderDebuggerStyle.uss
@@ -0,0 +1,37 @@
+.button-tab-area
+{
+ flex-direction: row;
+ margin: 0;
+}
+
+.top-area
+{
+ flex-direction: row;
+ margin: 0;
+}
+
+.refresh-button
+{
+ background-image: resource("Refresh@2X");
+ background-color: transparent;
+ border-width: 0;
+ margin: 2px;
+ width: 18px;
+ height: 18px;
+}
+
+.button-tab
+{
+ flex-grow: 1;
+ height: 24px;
+ margin: 4px 0 0 0;
+ border-radius: 0;
+ border-width: 1px 1px 0 1px;
+ background-color: #484848;
+}
+
+.button-tab-selected
+{
+ background-color: #303030;
+}
+
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderDebuggerStyle.uss.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderDebuggerStyle.uss.meta
new file mode 100644
index 00000000..504a19ab
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderDebuggerStyle.uss.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: f33784aa05700dd4a90531e89c742927
+timeCreated: 1640810258 \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderEditor.uxml b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderEditor.uxml
new file mode 100644
index 00000000..a74eafbb
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderEditor.uxml
@@ -0,0 +1,17 @@
+<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
+ <ui:Label text="Base Information" style="-unity-font-style: bold; font-size: 12px; margin-bottom: 4px;" />
+ <ui:TextField picking-mode="Ignore" label="Id" binding-path="Id" />
+ <ui:TextField label="Name" binding-path="Name" />
+ <ui:TextField label="Author" binding-path="Author" />
+ <ui:TextField label="Version" value="f" binding-path="Version" />
+ <ui:TextField label="Description" binding-path="Description" multiline="true" />
+ <ui:Label text="Settings" style="-unity-font-style: bold; margin-top: 20px; margin-bottom: 4px;" />
+ <uie:ObjectField label="Shader Template" binding-path="ShaderTemplate" name="ShaderTemplateField" allow-scene-objects="false" />
+ <ui:TextField label="Shader Path" value="filler text" text="filler text" binding-path="ShaderPath" />
+ <ui:TextField label="Custom Editor" binding-path="CustomEditor" />
+ <Poiyomi.ModularShaderSystem.UI.InspectorList binding-path="Properties" show-elements-text="false" />
+ <ui:Toggle binding-path="UseTemplatesForProperties" label="Properties from templates" name="UseTemplatesForPropertiesField" />
+ <uie:ObjectField label="Shader Properties Template" binding-path="ShaderPropertiesTemplate" name="ShaderPropertiesTemplateField" allow-scene-objects="false" />
+ <Poiyomi.ModularShaderSystem.UI.ModuleInspectorList name="BaseModulesField" binding-path="BaseModules" show-elements-text="false" />
+ <ui:Button name="RegenerateShaderButton" text="Generate Shader"/>
+</ui:UXML> \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderEditor.uxml.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderEditor.uxml.meta
new file mode 100644
index 00000000..abed4fa2
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModularShaderEditor.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: a481a148a62c4a747adf60dfc10bfcaf
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModuleTemplatePropertyDrawer.uxml b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModuleTemplatePropertyDrawer.uxml
new file mode 100644
index 00000000..082dba3d
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModuleTemplatePropertyDrawer.uxml
@@ -0,0 +1,6 @@
+<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
+ <uie:PropertyField binding-path="Template" label="Template" focusable="true" />
+ <uie:PropertyField binding-path="Queue" label="Queue" focusable="true" />
+ <ui:Toggle binding-path="NeedsVariant" label="Generates variant" />
+ <Poiyomi.ModularShaderSystem.UI.InspectorList show-elements-text="false" binding-path="Keywords" />
+</ui:UXML> \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModuleTemplatePropertyDrawer.uxml.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModuleTemplatePropertyDrawer.uxml.meta
new file mode 100644
index 00000000..3ac04590
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ModuleTemplatePropertyDrawer.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 5d04d7ad3a733a847af648f76ca1c0df
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/PropertyView.uxml b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/PropertyView.uxml
new file mode 100644
index 00000000..b9a2a8e5
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/PropertyView.uxml
@@ -0,0 +1,6 @@
+<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
+ <ui:VisualElement style="flex-direction: row; margin-top: 1px; margin-bottom: 1px;">
+ <ui:Label name="PropertyLabel" class="property-label" />
+ <ui:Label name="TypeLabel" class="type-label" />
+ </ui:VisualElement>
+</ui:UXML> \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/PropertyView.uxml.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/PropertyView.uxml.meta
new file mode 100644
index 00000000..ebe278af
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/PropertyView.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: c761d2a671477b545aeb468b02f489f5
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderModuleEditor.uxml b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderModuleEditor.uxml
new file mode 100644
index 00000000..54cfcd0c
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderModuleEditor.uxml
@@ -0,0 +1,16 @@
+<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
+ <ui:Label text="Base Information" style="margin-bottom: 4px; -unity-font-style: bold;" />
+ <ui:TextField label="Id" binding-path="Id" />
+ <ui:TextField label="Name" binding-path="Name" />
+ <ui:TextField label="Author" binding-path="Author" />
+ <ui:TextField label="Version" binding-path="Version" />
+ <ui:TextField label="Description" binding-path="Description" multiline="true" />
+ <Poiyomi.ModularShaderSystem.UI.InspectorList binding-path="ModuleDependencies" show-elements-text="false" />
+ <Poiyomi.ModularShaderSystem.UI.InspectorList binding-path="IncompatibleWith" show-elements-text="false" />
+
+ <ui:Label text="Settings" style="margin-bottom: 4px; -unity-font-style: bold; margin-top: 20px;" />
+ <Poiyomi.ModularShaderSystem.UI.InspectorList show-elements-text="false" binding-path="EnableProperties" />
+ <Poiyomi.ModularShaderSystem.UI.InspectorList show-elements-text="false" binding-path="Properties" />
+ <Poiyomi.ModularShaderSystem.UI.InspectorList show-elements-text="false" binding-path="Functions" />
+ <Poiyomi.ModularShaderSystem.UI.InspectorList show-elements-text="false" binding-path="Templates" />
+</ui:UXML> \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderModuleEditor.uxml.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderModuleEditor.uxml.meta
new file mode 100644
index 00000000..6f961d02
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderModuleEditor.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: d900d163996ec8749b8db228226070de
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderPropertyDrawer.uxml b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderPropertyDrawer.uxml
new file mode 100644
index 00000000..93887bf4
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderPropertyDrawer.uxml
@@ -0,0 +1,9 @@
+<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
+ <ui:TextField name="Name" label="Name" binding-path="Name" />
+ <ui:TextField label="Display Name" binding-path="DisplayName" />
+ <uie:EnumField name="TypeField" label="Type"/>
+ <ui:VisualElement name="ValueContainer" />
+ <!--<ui:TextField label="Type" binding-path="Type" readonly="true" focusable="false" />
+ <ui:TextField label="Default Value" binding-path="DefaultValue" readonly="true" focusable="false" />-->
+ <Poiyomi.ModularShaderSystem.UI.InspectorList show-elements-text="false" binding-path="Attributes" />
+</ui:UXML> \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderPropertyDrawer.uxml.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderPropertyDrawer.uxml.meta
new file mode 100644
index 00000000..51238959
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/ShaderPropertyDrawer.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 223d0c277c6083d469a9a7d5d7cfa06b
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/TemplateGraphStyle.uss b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/TemplateGraphStyle.uss
new file mode 100644
index 00000000..358dc04c
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/TemplateGraphStyle.uss
@@ -0,0 +1,15 @@
+.node-header-queue
+{
+ -unity-font-style: italic;
+ color: grey;
+ -unity-text-align: middle-right;
+ flex-grow: 1;
+ margin-right: 6px;
+}
+.node-header-id
+{
+ font-size: 8px;
+ -unity-font-style: italic;
+ align-self: center;
+ margin-left: 2px;
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/TemplateGraphStyle.uss.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/TemplateGraphStyle.uss.meta
new file mode 100644
index 00000000..8814c957
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/TemplateGraphStyle.uss.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 763a4f1ad75609444b9e1122f3a2f5b3
+timeCreated: 1640810258 \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/VariablePropertyDrawer.uxml b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/VariablePropertyDrawer.uxml
new file mode 100644
index 00000000..22d69a8a
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/VariablePropertyDrawer.uxml
@@ -0,0 +1,5 @@
+<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
+ <ui:TextField name="Name" picking-mode="Ignore" label="Name" binding-path="Name" />
+ <uie:EnumField name="Type" label="Type" binding-path="Type" />
+ <ui:TextField name="CustomType" picking-mode="Ignore" label="Custom Type" binding-path="CustomType" />
+</ui:UXML> \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/VariablePropertyDrawer.uxml.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/VariablePropertyDrawer.uxml.meta
new file mode 100644
index 00000000..b082f96f
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUIElements/VariablePropertyDrawer.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: a5e6dac95ccea2048b842c3887d1682c
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUpIcon.png b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUpIcon.png
new file mode 100755
index 00000000..6e7af912
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUpIcon.png
Binary files differ
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUpIcon.png.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUpIcon.png.meta
new file mode 100644
index 00000000..1783b652
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/MSSUpIcon.png.meta
@@ -0,0 +1,104 @@
+fileFormatVersion: 2
+guid: afc79e3b73fb4984b80ab888814ebad7
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ModularShaderIcon.png b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ModularShaderIcon.png
new file mode 100755
index 00000000..18f79eeb
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ModularShaderIcon.png
Binary files differ
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ModularShaderIcon.png.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ModularShaderIcon.png.meta
new file mode 100644
index 00000000..300398a5
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ModularShaderIcon.png.meta
@@ -0,0 +1,104 @@
+fileFormatVersion: 2
+guid: d739c8b030a91b04fb8907203fc97376
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/RobotoMono-Regular.ttf b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/RobotoMono-Regular.ttf
new file mode 100755
index 00000000..7c4ce36a
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/RobotoMono-Regular.ttf
Binary files differ
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/RobotoMono-Regular.ttf.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/RobotoMono-Regular.ttf.meta
new file mode 100644
index 00000000..e092400c
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/RobotoMono-Regular.ttf.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 2ffd9d9a0c716334592f4f418795a770
+timeCreated: 1640914271 \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ShaderModuleIcon.png b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ShaderModuleIcon.png
new file mode 100755
index 00000000..20e6070f
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ShaderModuleIcon.png
Binary files differ
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ShaderModuleIcon.png.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ShaderModuleIcon.png.meta
new file mode 100644
index 00000000..19070b88
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/ShaderModuleIcon.png.meta
@@ -0,0 +1,104 @@
+fileFormatVersion: 2
+guid: 768d4dfd2b3ad7d4ca6cfe703c398631
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateCollectionIcon.png b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateCollectionIcon.png
new file mode 100755
index 00000000..03885eb8
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateCollectionIcon.png
Binary files differ
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateCollectionIcon.png.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateCollectionIcon.png.meta
new file mode 100644
index 00000000..972c6a0a
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateCollectionIcon.png.meta
@@ -0,0 +1,104 @@
+fileFormatVersion: 2
+guid: 64d8d3c5a7468a547b7e8cb106f65d0b
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateIcon.png b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateIcon.png
new file mode 100755
index 00000000..0d4ae5b5
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateIcon.png
Binary files differ
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateIcon.png.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateIcon.png.meta
new file mode 100644
index 00000000..cfa8ee31
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Resources/POIMSS/TemplateIcon.png.meta
@@ -0,0 +1,104 @@
+fileFormatVersion: 2
+guid: a4f5b0b9036a57e49866d0e975fede53
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables.meta
new file mode 100644
index 00000000..94f97593
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 948ecb7b3313d0648bc8d0fc3b207943
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/EnableProperty.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/EnableProperty.cs
new file mode 100644
index 00000000..d1b532a3
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/EnableProperty.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+
+namespace Poiyomi.ModularShaderSystem
+{
+ [Serializable]
+ public class EnableProperty : Property, IEquatable<EnableProperty>
+ {
+ public int EnableValue;
+
+ public EnableProperty(string name, string displayName, int enableValue)
+ {
+ Name = name;
+ DisplayName = displayName;
+ Type = "Float";
+ DefaultValue = "0.1";
+ Attributes = new List<string>();
+
+ EnableValue = enableValue;
+ }
+
+ public override Variable ToVariable()
+ {
+ Variable variable = new Variable();
+ variable.Name = Name;
+ variable.Type = VariableType.Float;
+ return variable;
+ }
+
+ public EnableProperty(string name, int enableValue) : this(name, name, enableValue){}
+
+ bool IEquatable<EnableProperty>.Equals(EnableProperty other)
+ {
+ return Equals(other);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Property other)
+ return Name == other.Name;
+
+ return false;
+ }
+
+ public static bool operator == (EnableProperty left, EnableProperty right)
+ {
+ return left?.Equals(right) ?? right is null;
+ }
+
+ public static bool operator !=(EnableProperty left, EnableProperty right)
+ {
+ return !(left == right);
+ }
+
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/EnableProperty.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/EnableProperty.cs.meta
new file mode 100644
index 00000000..072ef649
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/EnableProperty.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2f78beee5aa767f4aaf5b933b0634ec0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModularShader.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModularShader.cs
new file mode 100644
index 00000000..ec6cc473
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModularShader.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Poiyomi.ModularShaderSystem
+{
+ [CreateAssetMenu(fileName = "ModularShader", menuName = MSSConstants.CREATE_PATH + "/Modular Shader", order = 0)]
+ public class ModularShader : ScriptableObject
+ {
+ public string Id;
+
+ public string Name;
+
+ public string Version;
+
+ public string Author;
+
+ public string Description;
+
+ public bool UseTemplatesForProperties;
+
+ public TemplateAsset ShaderPropertiesTemplate;
+
+ public string ShaderPath;
+
+ public TemplateAsset ShaderTemplate;
+
+ public string CustomEditor;
+
+ public List<Property> Properties;
+
+ public List<ShaderModule> BaseModules;
+
+ [HideInInspector] public List<ShaderModule> AdditionalModules;
+
+ public bool LockBaseModules;
+
+ public List<Shader> LastGeneratedShaders;
+
+ [HideInInspector] public string AdditionalSerializedData;
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModularShader.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModularShader.cs.meta
new file mode 100644
index 00000000..0210fef6
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModularShader.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f8aa43eb5c662824699f2379805fb2c0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: d739c8b030a91b04fb8907203fc97376, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModuleTemplate.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModuleTemplate.cs
new file mode 100644
index 00000000..90b97dae
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModuleTemplate.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Serialization;
+
+namespace Poiyomi.ModularShaderSystem
+{
+ [Serializable]
+ public class ModuleTemplate
+ {
+ public TemplateAsset Template;
+
+ [FormerlySerializedAs("Keyword")] public List<string> Keywords;
+
+ [FormerlySerializedAs("IsCGOnly")] public bool NeedsVariant;
+
+ public int Queue = 100;
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModuleTemplate.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModuleTemplate.cs.meta
new file mode 100644
index 00000000..3818c721
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ModuleTemplate.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9d2d3cba893c01945836e28f34ef3502
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Property.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Property.cs
new file mode 100644
index 00000000..55ba6f5e
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Property.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using Poiyomi.ModularShaderSystem.UI;
+
+namespace Poiyomi.ModularShaderSystem
+{
+ public enum PropertyType
+ {
+ Float,
+ Int,
+ Range,
+ Vector,
+ Color,
+ Texture2D,
+ Texture2DArray,
+ Cube,
+ CubeArray,
+ Texture3D
+ }
+
+ [Serializable]
+ public class Property : IEquatable<Property>
+ {
+ public string Name;
+
+ public string DisplayName;
+
+ public string Type;
+
+ public string DefaultValue;
+
+ public Texture DefaultTextureAsset;
+
+ [PropertyAttribute]
+ public List<string> Attributes;
+
+ public virtual Variable ToVariable()
+ {
+ var variable = new Variable();
+ variable.Name = Name;
+
+ switch(Type)
+ {
+ case "Float": variable.Type = VariableType.Float; break;
+ case "Int": variable.Type = VariableType.Float; break;
+ case "Color": variable.Type = VariableType.Float4; break;
+ case "Vector": variable.Type = VariableType.Float4; break;
+ case "2D": variable.Type = VariableType.Texture2D; break;
+ case "3D": variable.Type = VariableType.Texture3D; break;
+ case "Cube": variable.Type = VariableType.TextureCube; break;
+ case "2DArray": variable.Type = VariableType.Texture2DArray; break;
+ case "CubeArray": variable.Type = VariableType.TextureCubeArray; break;
+ default: variable.Type = Type.StartsWith("Range") ? VariableType.Float : VariableType.Custom; break;
+ }
+
+ return variable;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Property other)
+ return Name == other.Name;
+
+ return false;
+ }
+
+ bool IEquatable<Property>.Equals(Property other)
+ {
+ return Equals(other);
+ }
+
+ public static bool operator == (Property left, Property right)
+ {
+ return left?.Equals(right) ?? right is null;
+ }
+
+ public static bool operator !=(Property left, Property right)
+ {
+ return !(left == right);
+ }
+
+ public override int GetHashCode()
+ {
+ int hashCode = (Name != null ? Name.GetHashCode() : 0);
+ return hashCode;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Property.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Property.cs.meta
new file mode 100644
index 00000000..f4722462
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Property.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a3ea212d65d0f404a839a2f2b0a99228
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderFunction.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderFunction.cs
new file mode 100644
index 00000000..c2e9eff7
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderFunction.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Serialization;
+
+namespace Poiyomi.ModularShaderSystem
+{
+ [Serializable]
+ public class ShaderFunction
+ {
+ public string Name;
+
+ public string AppendAfter;
+
+ [FormerlySerializedAs("Priority")] public short Queue = 100;
+
+ public TemplateAsset ShaderFunctionCode;
+
+ public List<Variable> UsedVariables;
+
+ [FormerlySerializedAs("VariableSinkKeywords")] [FormerlySerializedAs("VariableSinkKeyword")] public List<string> VariableKeywords;
+
+ [FormerlySerializedAs("CodeSinkKeywords")] [FormerlySerializedAs("CodeSinkKeyword")] public List<string> CodeKeywords;
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderFunction.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderFunction.cs.meta
new file mode 100644
index 00000000..c528cebc
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderFunction.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d721b76d4a9ecd34c98bf2710f25cecc
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderModule.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderModule.cs
new file mode 100644
index 00000000..d30bb062
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderModule.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Poiyomi.ModularShaderSystem
+{
+ [CreateAssetMenu(fileName = "ShaderModule", menuName = MSSConstants.CREATE_PATH + "/Shader Module", order = 0)]
+ public class ShaderModule : ScriptableObject
+ {
+ public string Id;
+
+ public string Name;
+
+ public string Version;
+
+ public string Author;
+
+ public string Description;
+
+ public List<EnableProperty> EnableProperties;
+
+ public List<Property> Properties;
+
+ public List<string> ModuleDependencies;
+
+ public List<string> IncompatibleWith;
+
+ public List<ModuleTemplate> Templates;
+
+ public List<ShaderFunction> Functions;
+
+ [HideInInspector] public string AdditionalSerializedData;
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderModule.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderModule.cs.meta
new file mode 100644
index 00000000..5d2a860c
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/ShaderModule.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1039f25740a92fc4292bb1d94d07ad19
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 768d4dfd2b3ad7d4ca6cfe703c398631, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAsset.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAsset.cs
new file mode 100644
index 00000000..7c9d2460
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAsset.cs
@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+using System.Reflection;
+using UnityEditor;
+using UnityEditor.ProjectWindowCallback;
+using UnityEngine;
+using Object = UnityEngine.Object;
+
+namespace Poiyomi.ModularShaderSystem
+{
+ public class TemplateAsset : ScriptableObject
+ {
+ public string Template;
+
+ public string[] Keywords;
+
+ public TemplateAsset(string template)
+ {
+ Template = template;
+ }
+ public TemplateAsset() : this("") { }
+
+ [MenuItem("Assets/Create/" + MSSConstants.CREATE_PATH + "/Template", priority = 9)]
+ private static void CreateTemplate()
+ {
+ Type projectWindowUtilType = typeof(ProjectWindowUtil);
+ MethodInfo getActiveFolderPath = projectWindowUtilType.GetMethod("GetActiveFolderPath", BindingFlags.Static | BindingFlags.NonPublic);
+ object obj = getActiveFolderPath.Invoke(null, new object[0]);
+ string pathToCurrentFolder = obj.ToString();
+ string uniquePath = AssetDatabase.GenerateUniqueAssetPath($"{pathToCurrentFolder}/Template.{MSSConstants.TEMPLATE_EXTENSION}");
+
+ ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, ScriptableObject.CreateInstance<DoCreateNewAsset>(), uniquePath, null, (string) null);
+ }
+
+ internal class DoCreateNewAsset : EndNameEditAction
+ {
+ public override void Action(int instanceId, string pathName, string resourceFile)
+ {
+ File.WriteAllText(pathName, "");
+ AssetDatabase.Refresh();
+ Object o = AssetDatabase.LoadAssetAtPath<Object>(pathName);
+ Selection.activeObject = o;
+ }
+
+ public override void Cancelled(int instanceId, string pathName, string resourceFile) => Selection.activeObject = (Object) null;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAsset.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAsset.cs.meta
new file mode 100644
index 00000000..bb13ffbf
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAsset.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c5245566ee65d4b4bbd25c70aee47169
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: a4f5b0b9036a57e49866d0e975fede53, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAssetImporter.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAssetImporter.cs
new file mode 100644
index 00000000..4e7f7ed4
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAssetImporter.cs
@@ -0,0 +1,39 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using UnityEditor.Experimental.AssetImporters;
+using UnityEngine;
+
+namespace Poiyomi.ModularShaderSystem
+{
+
+ [ScriptedImporter(1, MSSConstants.TEMPLATE_EXTENSION)]
+ public class TemplateAssetImporter : ScriptedImporter
+ {
+ public override void OnImportAsset(AssetImportContext ctx)
+ {
+ var subAsset = ScriptableObject.CreateInstance<TemplateAsset>();
+ subAsset.Template = File.ReadAllText(ctx.assetPath);
+
+ MatchCollection mk = Regex.Matches(subAsset.Template, @"#K#\w*", RegexOptions.Multiline);
+ MatchCollection mki = Regex.Matches(subAsset.Template, @"#KI#\w*", RegexOptions.Multiline);
+
+ var mkr = new string[mk.Count + mki.Count];
+ for (var i = 0; i < mk.Count; i++)
+ mkr[i] = mk[i].Value;
+ for (var i = 0; i < mki.Count; i++)
+ mkr[mk.Count + i] = mki[i].Value;
+
+ subAsset.Keywords = mkr.Distinct().ToArray();
+
+ ctx.AddObjectToAsset("Template", subAsset/*, icon*/);
+ ctx.SetMainObject(subAsset);
+ }
+
+ public override bool SupportsRemappedAssetType(Type type)
+ {
+ return type.IsAssignableFrom(typeof(TemplateAsset));
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAssetImporter.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAssetImporter.cs.meta
new file mode 100644
index 00000000..ea57a2e1
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateAssetImporter.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 836627ab161102f4caef6d73aab2391d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAsset.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAsset.cs
new file mode 100644
index 00000000..c8f32504
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAsset.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using UnityEditor;
+using UnityEditor.ProjectWindowCallback;
+using UnityEngine;
+using Object = UnityEngine.Object;
+
+namespace Poiyomi.ModularShaderSystem
+{
+ public class TemplateCollectionAsset : ScriptableObject
+ {
+ public List<TemplateAsset> Templates;
+
+ public TemplateCollectionAsset()
+ {
+ Templates = new List<TemplateAsset>();
+ }
+
+
+ [MenuItem("Assets/Create/" + MSSConstants.CREATE_PATH + "/Template Collection", priority = 9)]
+ private static void CreateTemplate()
+ {
+ Type projectWindowUtilType = typeof(ProjectWindowUtil);
+ MethodInfo getActiveFolderPath = projectWindowUtilType.GetMethod("GetActiveFolderPath", BindingFlags.Static | BindingFlags.NonPublic);
+ object obj = getActiveFolderPath.Invoke(null, new object[0]);
+ string pathToCurrentFolder = obj.ToString();
+ string uniquePath = AssetDatabase.GenerateUniqueAssetPath($"{pathToCurrentFolder}/Template.{MSSConstants.TEMPLATE_COLLECTION_EXTENSION}");
+
+ ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, ScriptableObject.CreateInstance<DoCreateNewAsset>(), uniquePath, null, (string) null);
+ }
+
+ internal class DoCreateNewAsset : EndNameEditAction
+ {
+ public override void Action(int instanceId, string pathName, string resourceFile)
+ {
+ File.WriteAllText(pathName, "");
+ AssetDatabase.Refresh();
+ Object o = AssetDatabase.LoadAssetAtPath<Object>(pathName);
+ Selection.activeObject = o;
+ }
+
+ public override void Cancelled(int instanceId, string pathName, string resourceFile) => Selection.activeObject = (Object) null;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAsset.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAsset.cs.meta
new file mode 100644
index 00000000..f60c5c0d
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAsset.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c670b58f3d80515448cad87058c4e731
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 64d8d3c5a7468a547b7e8cb106f65d0b, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAssetImporter.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAssetImporter.cs
new file mode 100644
index 00000000..a1be0cef
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAssetImporter.cs
@@ -0,0 +1,86 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using UnityEditor.Experimental.AssetImporters;
+using UnityEngine;
+
+namespace Poiyomi.ModularShaderSystem
+{
+ [ScriptedImporter(1, MSSConstants.TEMPLATE_COLLECTION_EXTENSION)]
+ public class TemplateColletionAssetImporter : ScriptedImporter
+ {
+ public override void OnImportAsset(AssetImportContext ctx)
+ {
+ var subAsset = ScriptableObject.CreateInstance<TemplateCollectionAsset>();
+
+
+
+ using (var sr = new StringReader(File.ReadAllText(ctx.assetPath)))
+ {
+ var builder = new StringBuilder();
+ string line;
+ string name = "";
+ bool deleteEmptyLine = false;
+ while ((line = sr.ReadLine()) != null)
+ {
+ if (line.Contains("#T#"))
+ {
+ if (builder.Length > 0 && !string.IsNullOrWhiteSpace(name))
+ SaveSubAsset(ctx, subAsset, builder, name);
+
+ builder = new StringBuilder();
+ name = line.Replace("#T#", "").Trim();
+ continue;
+ }
+
+ if (string.IsNullOrEmpty(line))
+ {
+ if (deleteEmptyLine)
+ continue;
+ deleteEmptyLine = true;
+ }
+ else
+ {
+ deleteEmptyLine = false;
+ }
+
+ builder.AppendLine(line);
+ }
+
+ if (builder.Length > 0 && !string.IsNullOrWhiteSpace(name))
+ SaveSubAsset(ctx, subAsset, builder, name);
+ }
+
+ ctx.AddObjectToAsset("Collection", subAsset);
+ ctx.SetMainObject(subAsset);
+ }
+
+ private static void SaveSubAsset(AssetImportContext ctx, TemplateCollectionAsset asset, StringBuilder builder, string name)
+ {
+ var templateAsset = ScriptableObject.CreateInstance<TemplateAsset>();
+ templateAsset.Template = builder.ToString();
+ templateAsset.name = name;
+
+ MatchCollection mk = Regex.Matches(templateAsset.Template, @"#K#\w*", RegexOptions.Multiline);
+ MatchCollection mki = Regex.Matches(templateAsset.Template, @"#KI#\w*", RegexOptions.Multiline);
+
+ var mkr = new string[mk.Count + mki.Count];
+ for (var i = 0; i < mk.Count; i++)
+ mkr[i] = mk[i].Value;
+ for (var i = 0; i < mki.Count; i++)
+ mkr[mk.Count + i] = mki[i].Value;
+
+ templateAsset.Keywords = mkr.Distinct().ToArray();
+
+ ctx.AddObjectToAsset(name, templateAsset);
+ asset.Templates.Add(templateAsset);
+ }
+
+ public override bool SupportsRemappedAssetType(Type type)
+ {
+ return type.IsAssignableFrom(typeof(TemplateAsset));
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAssetImporter.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAssetImporter.cs.meta
new file mode 100644
index 00000000..00e685b8
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/TemplateCollectionAssetImporter.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b8e1b7bf6f1d9674dbe75fe157540c41
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Variable.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Variable.cs
new file mode 100644
index 00000000..892210bc
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Variable.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Poiyomi.ModularShaderSystem
+{
+ [Serializable]
+ public class Variable : IEquatable<Variable>
+ {
+ public override int GetHashCode()
+ {
+ int hashCode = (Name != null ? Name.GetHashCode() : 0);
+ return hashCode;
+ }
+
+ public string Name;
+ public VariableType Type;
+ public string CustomType;
+
+ public string GetDefinition()
+ {
+ switch (Type)
+ {
+ case VariableType.Half:
+ return $"half {Name};";
+ case VariableType.Half2:
+ return $"half2 {Name};";
+ case VariableType.Half3:
+ return $"half3 {Name};";
+ case VariableType.Half4:
+ return $"half4 {Name};";
+ case VariableType.Float:
+ return $"float {Name};";
+ case VariableType.Float2:
+ return $"float2 {Name};";
+ case VariableType.Float3:
+ return $"float3 {Name};";
+ case VariableType.Float4:
+ return $"float4 {Name};";
+ case VariableType.Sampler2D:
+ return $"sampler2D {Name};";
+ case VariableType.SamplerCUBE:
+ return $"samplerCUBE {Name};";
+ case VariableType.Sampler3D:
+ return $"sampler3D {Name};";
+ case VariableType.Texture2D:
+ return $"Texture2D {Name};";
+ case VariableType.Texture2DArray:
+ return $"Texture2DArray {Name};";
+ case VariableType.Texture2DMS:
+ return $"Texture2DMS {Name};";
+ case VariableType.TextureCube:
+ return $"TextureCube {Name};";
+ case VariableType.TextureCubeArray:
+ return $"TextureCubeArray {Name};";
+ case VariableType.Texture3D:
+ return $"Texture3D {Name};";
+ case VariableType.UnityTex2D:
+ return $"UNITY_DECLARE_TEX2D({Name});";
+ case VariableType.UnityTex2DNoSampler:
+ return $"UNITY_DECLARE_TEX2D_NOSAMPLER({Name});";
+ case VariableType.UnityTexCube:
+ return $"UNITY_DECLARE_TEXCUBE({Name});";
+ case VariableType.UnityTexCubeNoSampler:
+ return $"UNITY_DECLARE_TEXCUBE_NOSAMPLER({Name});";
+ case VariableType.UnityTex3D:
+ return $"UNITY_DECLARE_TEX3D({Name});";
+ case VariableType.UnityTex3DNoSampler:
+ return $"UNITY_DECLARE_TEX3D_NOSAMPLER({Name});";
+ case VariableType.UnityTex2DArray:
+ return $"UNITY_DECLARE_TEX2DARRAY({Name});";
+ case VariableType.UnityTex2DArrayNoSampler:
+ return $"UNITY_DECLARE_TEX2DARRAY_NOSAMPLER({Name});";
+ case VariableType.UnityTexCubeArray:
+ return $"UNITY_DECLARE_TEXCUBEARRAY({Name});";
+ case VariableType.UnityTexCubeArrayNoSampler:
+ return $"UNITY_DECLARE_TEXCUBEARRAY_NOSAMPLER({Name});";
+ case VariableType.Custom:
+ return $"{CustomType} {Name};";
+ }
+
+ return "";
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as Variable);
+ }
+
+ public bool Equals(Variable other)
+ {
+ return other != null &&
+ Name.Equals(other.Name);
+ }
+
+ public static bool operator ==(Variable left, Variable right)
+ {
+ return EqualityComparer<Variable>.Default.Equals(left, right);
+ }
+
+ public static bool operator !=(Variable left, Variable right)
+ {
+ return !(left == right);
+ }
+ }
+
+ public enum VariableType
+ {
+ Half,
+ Half2,
+ Half3,
+ Half4,
+ Float,
+ Float2,
+ Float3,
+ Float4,
+ Sampler2D,
+ SamplerCUBE,
+ Sampler3D,
+ Texture2D,
+ Texture2DArray,
+ Texture2DMS,
+ TextureCube,
+ TextureCubeArray,
+ Texture3D,
+ UnityTex2D,
+ UnityTex2DNoSampler,
+ UnityTexCube,
+ UnityTexCubeNoSampler,
+ UnityTex3D,
+ UnityTex3DNoSampler,
+ UnityTex2DArray,
+ UnityTex2DArrayNoSampler,
+ UnityTexCubeArray,
+ UnityTexCubeArrayNoSampler,
+ Custom = 999
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Variable.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Variable.cs.meta
new file mode 100644
index 00000000..d7b661ef
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/Scriptables/Variable.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 162a71be29039a548960264e20bd6969
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderGenerator.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderGenerator.cs
new file mode 100644
index 00000000..27ffcd14
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderGenerator.cs
@@ -0,0 +1,930 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using UnityEditor;
+using UnityEngine;
+
+namespace Poiyomi.ModularShaderSystem
+{
+ public static class ShaderGenerator
+ {
+ public static void GenerateShader(string path, ModularShader shader, bool hideVariants = false)
+ {
+ GenerateShader(path, shader, null, hideVariants);
+ }
+
+ public static void GenerateShader(string path, ModularShader shader, Action<StringBuilder, ShaderContext> postGeneration, bool hideVariants = false)
+ {
+
+ path = GetPathRelativeToProject(path);
+
+ var modules = FindAllModules(shader);
+
+ var freshAssets = new Dictionary<TemplateAsset, TemplateAsset>();
+
+ freshAssets.AddFreshShaderToList(shader.ShaderTemplate);
+ freshAssets.AddFreshShaderToList(shader.ShaderPropertiesTemplate);
+
+ foreach (var template in modules.SelectMany(x => x.Templates))
+ freshAssets.AddFreshShaderToList(template.Template);
+
+ foreach (var function in modules.SelectMany(x => x.Functions))
+ freshAssets.AddFreshShaderToList(function.ShaderFunctionCode);
+
+
+ var possibleVariants = GetShaderVariants(modules);
+ var contexts = new List<ShaderContext>();
+ var completePropertiesBlock = GetPropertiesBlock(shader, modules, freshAssets);
+
+ foreach (var variant in possibleVariants)
+ {
+ contexts.Add(new ShaderContext
+ {
+ Shader = shader,
+ PostGeneration = postGeneration,
+ ActiveEnablers = variant,
+ FreshAssets = freshAssets,
+ FilePath = path,
+ PropertiesBlock = completePropertiesBlock,
+ AreVariantsHidden = hideVariants
+ });
+ }
+
+ contexts.AsParallel().ForAll(x => x.GenerateShader());
+ try
+ {
+ AssetDatabase.StartAssetEditing();
+
+ foreach (Shader generatedShader in shader.LastGeneratedShaders.Where(x => x != null))
+ {
+ string assetPath = AssetDatabase.GetAssetPath(generatedShader);
+ if(string.IsNullOrWhiteSpace(assetPath))
+ File.Delete(assetPath);
+ }
+
+ shader.LastGeneratedShaders = new List<Shader>();
+
+ foreach (var context in contexts)
+ File.WriteAllText($"{path}/" + context.VariantFileName, context.ShaderFile.ToString());
+ }
+ finally
+ {
+ AssetDatabase.StopAssetEditing();
+ }
+
+ AssetDatabase.Refresh();
+ ApplyDefaultTextures(contexts);
+
+ foreach (var context in contexts)
+ shader.LastGeneratedShaders.Add(AssetDatabase.LoadAssetAtPath<Shader>($"{path}/" + context.VariantFileName));
+ AssetDatabase.Refresh();
+ }
+
+ private static string GetPathRelativeToProject(string path)
+ {
+ if (!Directory.Exists(path))
+ throw new DirectoryNotFoundException($"The folder \"{path}\" is not found");
+
+ if (!path.Contains(Application.dataPath) && !path.StartsWith("Assets"))
+ throw new DirectoryNotFoundException($"The folder \"{path}\" is not part of the unity project");
+
+ if(!path.StartsWith("Assets"))
+ path = path.Replace(Application.dataPath, "Assets");
+
+ return path;
+ }
+
+ public static void GenerateMinimalShader(string path, ModularShader shader, IEnumerable<Material> materials, Action<StringBuilder, ShaderContext> postGeneration = null)
+ {
+ path = GetPathRelativeToProject(path);
+
+ var modules = FindAllModules(shader);
+ var possibleVariants = GetMinimalVariants(modules, materials);
+ var contexts = new List<ShaderContext>();
+
+ foreach (var (variant, variantMaterials) in possibleVariants)
+ {
+ AssetDatabase.TryGetGUIDAndLocalFileIdentifier(variantMaterials[0], out string guid, out long _);
+ contexts.Add(new ShaderContext
+ {
+ Shader = shader,
+ PostGeneration = postGeneration,
+ ActiveEnablers = variant,
+ FilePath = path,
+ OptimizedShader = true,
+ Materials = variantMaterials,
+ Guid = guid
+ });
+ }
+
+ contexts.GenerateMinimalShaders();
+ }
+
+ public static List<ShaderContext> EnqueueShadersToGenerate(string path, ModularShader shader, IEnumerable<Material> materials, Action<StringBuilder, ShaderContext> postGeneration = null)
+ {
+ path = GetPathRelativeToProject(path);
+
+ var modules = FindAllModules(shader);
+ var possibleVariants = GetMinimalVariants(modules, materials);
+ var contexts = new List<ShaderContext>();
+
+ foreach (var (variant, variantMaterials) in possibleVariants)
+ {
+ AssetDatabase.TryGetGUIDAndLocalFileIdentifier(variantMaterials[0], out string guid, out long _);
+ contexts.Add(new ShaderContext
+ {
+ Shader = shader,
+ PostGeneration = postGeneration,
+ ActiveEnablers = variant,
+ FilePath = path,
+ OptimizedShader = true,
+ Materials = variantMaterials,
+ Guid = guid
+ });
+ }
+
+ return contexts;
+ }
+
+ public static void GenerateMinimalShaders(this List<ShaderContext> contexts)
+ {
+ if (contexts == null || contexts.Count == 0) return;
+
+ var alreadyDoneShaders = new List<ModularShader>();
+
+ var freshAssets = new Dictionary<TemplateAsset, TemplateAsset>();
+
+ foreach (var context in contexts)
+ {
+ context.FreshAssets = freshAssets;
+ if (alreadyDoneShaders.Contains(context.Shader)) continue;
+
+ var shader = context.Shader;
+ var modules = FindAllModules(shader);
+
+ freshAssets.AddFreshShaderToList(shader.ShaderTemplate);
+ freshAssets.AddFreshShaderToList(shader.ShaderPropertiesTemplate);
+
+ foreach (var template in modules.SelectMany(x => x.Templates))
+ freshAssets.AddFreshShaderToList(template.Template);
+
+ foreach (var function in modules.SelectMany(x => x.Functions))
+ freshAssets.AddFreshShaderToList(function.ShaderFunctionCode);
+
+ alreadyDoneShaders.Add(shader);
+ }
+
+ EditorUtility.DisplayProgressBar("Generating Optimized Shaders", "generating shader files", 1 / (contexts.Count + 3));
+ contexts.AsParallel().ForAll(x => x.GenerateShader());
+ try
+ {
+ AssetDatabase.StartAssetEditing();
+ int i = 0;
+ foreach (var context in contexts)
+ {
+ EditorUtility.DisplayProgressBar("Generating Optimized Shaders", "Saving " + context.VariantFileName, 1 + i / (contexts.Count + 3));
+ File.WriteAllText($"{context.FilePath}/" + context.VariantFileName, context.ShaderFile.ToString());
+ i++;
+ }
+ }
+ finally
+ {
+ EditorUtility.DisplayProgressBar("Generating Optimized Shaders", "waiting for unity to compile shaders", contexts.Count - 2 / (contexts.Count + 3));
+ AssetDatabase.StopAssetEditing();
+ AssetDatabase.Refresh();
+ }
+
+ ApplyDefaultTextures(contexts);
+
+ EditorUtility.DisplayProgressBar("Generating Optimized Shaders", "applying shaders to materials", contexts.Count - 1 / (contexts.Count + 3));
+ foreach (var context in contexts)
+ {
+ var shader = Shader.Find(context.ShaderName);
+ foreach (var material in context.Materials)
+ {
+ material.shader = shader;
+ }
+ }
+
+ EditorUtility.ClearProgressBar();
+ }
+
+ private static List<Dictionary<string, int>> GetShaderVariants(List<ShaderModule> modules)
+ {
+ var dictionary = new Dictionary<string, List<int>>();
+ foreach (ShaderModule module in modules)
+ {
+ if (module == null) continue;
+ foreach (EnableProperty property in module.EnableProperties)
+ {
+ if (property == null || string.IsNullOrWhiteSpace(property.Name) ||
+ !(module.Templates?.Any(x => x.NeedsVariant) ?? false)) continue;
+
+ if (dictionary.ContainsKey(property.Name))
+ dictionary[property.Name].Add(property.EnableValue);
+ else
+ dictionary.Add(property.Name, new List<int>(new[] { property.EnableValue }));
+ }
+ }
+
+ var keys = dictionary.Keys.ToList();
+
+ foreach (KeyValuePair<string,List<int>> keyValuePair in dictionary)
+ if(!keyValuePair.Value.Contains(0))
+ keyValuePair.Value.Insert(0,0);
+
+ var states = new List<Dictionary<string, int>>();
+ UnrollVariants(states, new Dictionary<string, int>(), dictionary, keys);
+
+ return states;
+ }
+
+ private static List<(Dictionary<string, int>, List<Material>)> GetMinimalVariants(List<ShaderModule> modules, IEnumerable<Material> materials)
+ {
+ var enablers = new List<string>();
+ foreach (ShaderModule module in modules)
+ {
+ if (module == null) continue;
+ foreach (EnableProperty property in module.EnableProperties)
+ {
+ if (property == null || string.IsNullOrWhiteSpace(property.Name)) continue;
+
+ enablers.Add(property.Name);
+ }
+ }
+
+ enablers = enablers.Distinct().ToList();
+
+ var states = new List<(Dictionary<string, int>, List<Material>)>();
+ foreach (Material material in materials)
+ {
+ var state = new Dictionary<string, int>();
+ foreach (string enabler in enablers)
+ state.Add(enabler, (int)material.GetFloat(enabler));
+
+ var equalState = states.Where(x =>
+ {
+ var keys = state.Keys;
+ foreach (string key in keys)
+ if (x.Item1[key] != state[key])
+ return false;
+
+ return true;
+ }).FirstOrDefault();
+
+ if(equalState == (null, null))
+ states.Add((state, new List<Material>(new [] {material})));
+ else
+ equalState.Item2.Add(material);
+ }
+
+ return states;
+ }
+
+ private static void UnrollVariants(ICollection<Dictionary<string, int>> states, Dictionary<string, int> current, IReadOnlyDictionary<string, List<int>> dictionary, IReadOnlyList<string> keys)
+ {
+ if (current.Count == keys.Count)
+ {
+ states.Add(current);
+ return;
+ }
+ foreach (var value in dictionary[keys[current.Count]])
+ {
+ var next = new Dictionary<string, int>(current);
+ next[keys[current.Count]] = value;
+ UnrollVariants(states, next, dictionary, keys);
+ }
+ }
+
+ public static string GetVariantCode(Dictionary<string, int> activeEnablers)
+ {
+ var keys = activeEnablers.Keys.OrderBy(x => x).ToList();
+ bool isAllZeroes = true;
+ var b = new StringBuilder();
+ foreach (string key in keys)
+ {
+ if (activeEnablers[key] != 0) isAllZeroes = false;
+ b.Append($"-{activeEnablers[key]}");
+ }
+
+ return isAllZeroes ? "" : b.ToString();
+ }
+
+ private static void AddFreshShaderToList(this Dictionary<TemplateAsset, TemplateAsset> dictionary, TemplateAsset asset)
+ {
+ if ((object)asset == null) return;
+ if (dictionary.ContainsKey(asset)) return;
+ string assetPath = AssetDatabase.GetAssetPath(asset);
+ var genericAsset = AssetDatabase.LoadMainAssetAtPath(assetPath);
+ TemplateAsset template = null;
+ switch (genericAsset)
+ {
+ case TemplateCollectionAsset collection:
+ template = collection.Templates.FirstOrDefault(x => x.name.Equals(asset.name));
+ break;
+ case TemplateAsset t:
+ template = t;
+ break;
+ }
+ dictionary.Add(asset, template);
+ }
+
+ private static TemplateAsset GetTemplate(this Dictionary<TemplateAsset, TemplateAsset> dictionary, TemplateAsset asset)
+ {
+ if ((object)asset == null) return null;
+ return dictionary.TryGetValue(asset, out TemplateAsset result) ? result : null;
+ }
+
+ public class ShaderContext
+ {
+ public ModularShader Shader;
+ public Dictionary<string, int> ActiveEnablers;
+ public Dictionary<TemplateAsset, TemplateAsset> FreshAssets;
+ public Action<StringBuilder, ShaderContext> PostGeneration;
+ private List<EnableProperty> _liveUpdateEnablers;
+ public string FilePath;
+ public string VariantFileName;
+ public string VariantName;
+ public string ShaderName;
+ public string PropertiesBlock;
+ public bool AreVariantsHidden;
+ public bool OptimizedShader;
+ public List<Material> Materials;
+ public StringBuilder ShaderFile;
+ private List<ShaderModule> _modules;
+ private List<ShaderFunction> _functions;
+ private List<ShaderFunction> _reorderedFunctions;
+ private Dictionary<ShaderFunction, ShaderModule> _modulesByFunctions;
+ public string Guid;
+
+ public List<ShaderModule> Modules => _modules;
+
+ public void GenerateShader()
+ {
+ _modules = FindActiveModules(Shader, ActiveEnablers);
+ GetLiveUpdateEnablers();
+ ShaderFile = new StringBuilder();
+ VariantName = GetVariantCode(ActiveEnablers);
+ VariantFileName = OptimizedShader ?
+ $"{Shader.Name}{(string.IsNullOrEmpty(VariantName) ? "" : $"-g-{Guid}")}.shader" :
+ $"{Shader.Name}{(string.IsNullOrEmpty(VariantName) ? "" : $"-v{VariantName}")}.shader";
+
+ VariantFileName = string.Join("_", VariantFileName.Split(Path.GetInvalidFileNameChars()));
+
+ if (OptimizedShader)
+ ShaderName = $"Hidden/{Shader.ShaderPath}-g-{Guid}";
+ else if (AreVariantsHidden && !string.IsNullOrEmpty(VariantName))
+ ShaderName = $"Hidden/{Shader.ShaderPath}-v{VariantName}";
+ else
+ ShaderName = $"{Shader.ShaderPath}{VariantName}";
+
+ ShaderFile.AppendLine($"Shader \"{ShaderName}\"");
+
+ ShaderFile.AppendLine("{");
+
+ ShaderFile.Append(string.IsNullOrEmpty(PropertiesBlock) ? GetPropertiesBlock(Shader, _modules, FreshAssets, false) : PropertiesBlock);
+
+ WriteShaderSkeleton();
+
+ _functions = new List<ShaderFunction>();
+ _reorderedFunctions = new List<ShaderFunction>();
+ _modulesByFunctions = new Dictionary<ShaderFunction, ShaderModule>();
+ foreach (var module in _modules)
+ {
+ _functions.AddRange(module.Functions);
+ foreach (ShaderFunction function in module.Functions)
+ {
+ _modulesByFunctions.Add(function, module);
+ }
+ }
+
+ WriteVariablesToKeywords();
+ WriteFunctionCallsToKeywords();
+ WriteFunctionsToKeywords();
+
+ if (!string.IsNullOrWhiteSpace(Shader.CustomEditor))
+ ShaderFile.AppendLine($"CustomEditor \"{Shader.CustomEditor}\"");
+ ShaderFile.AppendLine("}");
+
+ PostGeneration?.Invoke(ShaderFile, this);
+
+ RemoveKeywords();
+
+ ShaderFile.Replace("\r\n", "\n");
+
+ ShaderFile = CleanupShaderFile(ShaderFile);
+ }
+
+ private void GetLiveUpdateEnablers()
+ {
+ _liveUpdateEnablers = new List<EnableProperty>();
+ var staticEnablers = ActiveEnablers.Keys.ToList();
+ foreach (var property in _modules.SelectMany(x => x.EnableProperties))
+ {
+ if(property != null && !string.IsNullOrWhiteSpace(property.Name) && !staticEnablers.Contains(property.Name))
+ _liveUpdateEnablers.Add(property);
+ }
+
+ _liveUpdateEnablers = _liveUpdateEnablers.Distinct().ToList();
+ }
+
+ private void WriteFunctionCallsToKeywords()
+ {
+ foreach (var startKeyword in _functions.Where(x => x.AppendAfter?.StartsWith("#K#") ?? false).Select(x => x.AppendAfter).Distinct())
+ {
+ if (!ShaderFile.Contains(startKeyword)) continue;
+
+ var callSequence = new StringBuilder();
+ WriteFunctionCallSequence(callSequence, startKeyword);
+ var m = Regex.Matches(ShaderFile.ToString(), $@"{startKeyword}(\s|$)", RegexOptions.Multiline);
+ for (int i = m.Count - 1; i >= 0; i--)
+ ShaderFile.Insert(m[i].Index, callSequence.ToString());
+ }
+ }
+
+ private void WriteShaderSkeleton()
+ {
+ ShaderFile.AppendLine("SubShader");
+ ShaderFile.AppendLine("{");
+
+ ShaderFile.AppendLine(FreshAssets.GetTemplate(Shader.ShaderTemplate).Template);
+
+ Dictionary<ModuleTemplate, ShaderModule> moduleByTemplate = new Dictionary<ModuleTemplate, ShaderModule>();
+ Dictionary<(string, string), string> convertedKeyword = new Dictionary<(string, string), string>();
+ int instanceCounter = 0;
+
+ foreach (var module in _modules)
+ foreach (var template in module.Templates)
+ moduleByTemplate.Add(template, module);
+
+ foreach (var template in _modules.SelectMany(x => x.Templates).OrderBy(x => x.Queue))
+ {
+ var freshTemplate = FreshAssets.GetTemplate(template.Template);
+ var module = moduleByTemplate[template];
+ if (freshTemplate == null) continue;
+ bool hasEnabler = module.EnableProperties.Any(x => x != null && !string.IsNullOrEmpty(x.Name));
+ bool isFilteredIn = hasEnabler && module.EnableProperties.All(x => (x == null || string.IsNullOrEmpty(x.Name)) || ActiveEnablers.TryGetValue(x.Name, out _));
+ bool needsIf = hasEnabler && !isFilteredIn && !template.NeedsVariant;
+ var tmp = new StringBuilder();
+
+ if (!needsIf)
+ {
+ tmp.AppendLine(freshTemplate.Template);
+ }
+
+ else
+ {
+ string condition = string.Join(" && ", module.EnableProperties
+ .Where(x => (x != null && !string.IsNullOrEmpty(x.Name)) && !ActiveEnablers.TryGetValue(x.Name, out _))
+ .Select(x => $"{x.Name} == {x.EnableValue}"));
+ tmp.AppendLine($"if({condition})");
+ tmp.AppendLine("{");
+ tmp.AppendLine(freshTemplate.Template);
+ tmp.AppendLine("}");
+ }
+
+ MatchCollection mki = Regex.Matches(tmp.ToString(), @"#KI#\S*", RegexOptions.Multiline);
+ for (int i = mki.Count - 1; i >= 0; i--)
+ {
+ string newKeyword;
+ if (convertedKeyword.TryGetValue((module.Id, mki[i].Value), out string replacedKeyword))
+ {
+ newKeyword = replacedKeyword;
+ }
+ else
+ {
+ newKeyword = $"{mki[i].Value}{instanceCounter++}";
+ convertedKeyword.Add((module.Id, mki[i].Value), newKeyword);
+ }
+ tmp.Replace(mki[i].Value, newKeyword);
+ }
+
+ foreach (var keyword in template.Keywords.Count == 0 ? new[] { MSSConstants.DEFAULT_CODE_KEYWORD } : template.Keywords.Where(x => !string.IsNullOrWhiteSpace(x)).ToArray())
+ {
+ MatchCollection m = Regex.Matches(ShaderFile.ToString(), $@"#K#{keyword}(\s|$)", RegexOptions.Multiline);
+ for (int i = m.Count - 1; i >= 0; i--)
+ ShaderFile.Insert(m[i].Index, tmp.ToString());
+
+ if (convertedKeyword.TryGetValue((module.Id, $@"#KI#{keyword}"), out string replacedKeyword))
+ {
+ m = Regex.Matches(ShaderFile.ToString(), $@"{replacedKeyword}(\s|$)", RegexOptions.Multiline);
+ for (int i = m.Count - 1; i >= 0; i--)
+ ShaderFile.Insert(m[i].Index, tmp.ToString());
+ }
+ }
+ }
+ MatchCollection mkr = Regex.Matches(ShaderFile.ToString(), @"#KI#\S*", RegexOptions.Multiline);
+ for (int i = mkr.Count - 1; i >= 0; i--)
+ ShaderFile.Remove(mkr[i].Index, mkr[i].Length);
+
+ ShaderFile.AppendLine("}");
+ }
+
+ private void WriteVariablesToKeywords()
+ {
+ var variableDeclarations = new Dictionary<string,List<Variable>>();
+
+ foreach (ShaderFunction function in _functions)
+ {
+ if (function.VariableKeywords.Count > 0)
+ {
+ foreach (string keyword in function.VariableKeywords)
+ {
+ if (!variableDeclarations.ContainsKey(keyword))
+ variableDeclarations.Add(keyword, new List<Variable>());
+
+ foreach (Variable variable in function.UsedVariables)
+ variableDeclarations[keyword].Add(variable);
+ }
+ }
+ else
+ {
+ if (!variableDeclarations.ContainsKey(MSSConstants.DEFAULT_VARIABLES_KEYWORD))
+ variableDeclarations.Add(MSSConstants.DEFAULT_VARIABLES_KEYWORD, new List<Variable>());
+
+ foreach (Variable variable in function.UsedVariables)
+ variableDeclarations[MSSConstants.DEFAULT_VARIABLES_KEYWORD].Add(variable);
+ }
+ }
+
+ foreach (var declaration in variableDeclarations)
+ {
+ declaration.Value.AddRange(_liveUpdateEnablers.Select(x => x.ToVariable()));
+ var decCode = string.Join("\n", declaration.Value.Distinct().OrderBy(x => x.Type).Select(x => x.GetDefinition())) + "\n\n";
+ MatchCollection m = Regex.Matches(ShaderFile.ToString(), $@"#K#{declaration.Key}\s", RegexOptions.Multiline);
+ for (int i = m.Count - 1; i >= 0; i--)
+ ShaderFile.Insert(m[i].Index, decCode);
+ }
+ }
+
+ private void WriteFunctionsToKeywords()
+ {
+ var keywordedCode = new Dictionary<string,(StringBuilder, List<TemplateAsset>)>();
+
+ foreach (ShaderFunction function in _reorderedFunctions)
+ {
+ var freshAsset = FreshAssets.GetTemplate(function.ShaderFunctionCode);
+ if (function.CodeKeywords.Count > 0)
+ {
+ foreach (string keyword in function.CodeKeywords)
+ {
+ if (!keywordedCode.ContainsKey(keyword))
+ keywordedCode.Add(keyword, (new StringBuilder(), new List<TemplateAsset>()));
+
+ if (freshAsset == null) continue;
+ (StringBuilder builder, List<TemplateAsset> assets) = keywordedCode[keyword];
+ if (assets.Contains(freshAsset)) continue;
+ builder.AppendLine(freshAsset.Template);
+ assets.Add(freshAsset);
+ }
+ }
+ else
+ {
+ if (!keywordedCode.ContainsKey(MSSConstants.DEFAULT_CODE_KEYWORD))
+ keywordedCode.Add(MSSConstants.DEFAULT_CODE_KEYWORD, (new StringBuilder(), new List<TemplateAsset>()));
+
+ if (freshAsset == null) continue;
+ (StringBuilder builder, List<TemplateAsset> assets) = keywordedCode[MSSConstants.DEFAULT_CODE_KEYWORD];
+ if (assets.Contains(freshAsset)) continue;
+ builder.AppendLine(freshAsset.Template);
+ assets.Add(freshAsset);
+ }
+ }
+
+ foreach (var code in keywordedCode)
+ {
+ MatchCollection m = Regex.Matches(ShaderFile.ToString(), $@"#K#{code.Key}\s", RegexOptions.Multiline);
+ for (int i = m.Count - 1; i >= 0; i--)
+ ShaderFile.Insert(m[i].Index, code.Value.Item1.ToString());
+ }
+ }
+
+ private void WriteFunctionCallSequence(StringBuilder callSequence, string appendAfter)
+ {
+ foreach (var function in _functions.Where(x => x.AppendAfter.Equals(appendAfter)).OrderBy(x => x.Queue))
+ {
+ _reorderedFunctions.Add(function);
+ ShaderModule module = _modulesByFunctions[function];
+
+ bool hasEnabler = module.EnableProperties.Any(x => x != null && !string.IsNullOrEmpty(x.Name));
+ bool isFilteredIn = hasEnabler && module.EnableProperties.All(x => (x == null || string.IsNullOrEmpty(x.Name)) || ActiveEnablers.TryGetValue(x.Name, out _));
+ bool needsIf = hasEnabler && !isFilteredIn;
+
+ if (needsIf)
+ {
+ string condition = string.Join(" && ", module.EnableProperties
+ .Where(x => (x != null && !string.IsNullOrEmpty(x.Name)) && !ActiveEnablers.TryGetValue(x.Name, out _))
+ .Select(x => $"{x.Name} == {x.EnableValue}"));
+ callSequence.AppendLine($"if({condition})");
+ callSequence.AppendLine("{");
+ }
+
+ callSequence.AppendLine($"{function.Name}();");
+ WriteFunctionCallSequence(callSequence, function.Name);
+
+ if (needsIf)
+ callSequence.AppendLine("}");
+ }
+ }
+
+ private void RemoveKeywords()
+ {
+ int current = 0;
+
+ while (current < ShaderFile.Length)
+ {
+ if (ShaderFile.Length >= current + 3 && ShaderFile[current] == '#' && ShaderFile[current + 1] == 'K' &&
+ ShaderFile[current + 2] == '#')
+ {
+ int end = current+3;
+ bool stillToRemove = true;
+ while (end < ShaderFile.Length)
+ {
+ if (char.IsWhiteSpace(ShaderFile[end]))
+ {
+ ShaderFile.Remove(current, end - current);
+ stillToRemove = false;
+ break;
+ }
+
+ end++;
+ }
+ if(stillToRemove)
+ ShaderFile.Remove(current, end - current);
+ }
+
+ current++;
+ }
+ }
+
+ private static bool CheckPropertyBlockLine(StringBuilder builder, StringReader reader, string line, ref int tabs, ref bool deleteEmptyLine)
+ {
+ string ln = null;
+ line = line.Trim();
+ if (string.IsNullOrEmpty(line))
+ {
+ if (deleteEmptyLine)
+ return false;
+ deleteEmptyLine = true;
+ }
+ else
+ {
+ deleteEmptyLine = false;
+ }
+
+ if (line.StartsWith("}") && (ln = reader.ReadLine()) != null && ln.Trim().StartsWith("SubShader"))
+ tabs--;
+ builder.AppendLineTabbed(tabs, line);
+
+ if (!string.IsNullOrWhiteSpace(ln))
+ if (CheckPropertyBlockLine(builder, reader, ln, ref tabs, ref deleteEmptyLine))
+ return true;
+
+ if (line.StartsWith("}") && ln != null && ln.Trim().StartsWith("SubShader"))
+ return true;
+ return false;
+ }
+
+ private static StringBuilder CleanupShaderFile(StringBuilder shaderVariant)
+ {
+ var finalFile = new StringBuilder();
+ using (var sr = new StringReader(shaderVariant.ToString()))
+ {
+ string line;
+ int tabs = 0;
+ bool deleteEmptyLine = false;
+ while ((line = sr.ReadLine()) != null)
+ {
+ line = line.Trim();
+
+ if (string.IsNullOrEmpty(line))
+ {
+ if (deleteEmptyLine)
+ continue;
+ deleteEmptyLine = true;
+ }
+ else
+ {
+ deleteEmptyLine = false;
+ }
+
+ if (line.StartsWith("Properties"))
+ {
+ finalFile.AppendLineTabbed(tabs, line);
+ string ln = sr.ReadLine()?.Trim(); // When the previous line is the one containing "Properties" we always know
+ finalFile.AppendLineTabbed(tabs, ln); // that the next line is "{" so we just write it down before increasing the tabs
+ tabs++;
+ while ((ln = sr.ReadLine()) != null) // we should be escaping this loop way before actually meeting the condition, but you never know
+ {
+ if (CheckPropertyBlockLine(finalFile, sr, ln, ref tabs, ref deleteEmptyLine))
+ break;
+ }
+ continue;
+ }
+
+ if (!line.StartsWith("//") && (line.StartsWith("}") || line.EndsWith("}") && !line.Contains("{")))
+ tabs--;
+ finalFile.AppendLineTabbed(tabs, line);
+ if (!line.StartsWith("//") && (line.StartsWith("{") || line.EndsWith("{")))
+ tabs++;
+ }
+ }
+
+ return finalFile;
+ }
+ }
+
+ private static string GetPropertiesBlock(ModularShader shader, List<ShaderModule> modules, Dictionary<TemplateAsset, TemplateAsset> freshAssets, bool includeEnablers = true)
+ {
+ var block = new StringBuilder();
+ block.AppendLine("Properties");
+ block.AppendLine("{");
+
+ if (shader.UseTemplatesForProperties)
+ {
+ var freshTemplate = freshAssets.GetTemplate(shader.ShaderPropertiesTemplate);
+ if (freshTemplate != null)
+ block.AppendLine(freshTemplate.Template);
+
+ block.AppendLine($"#K#{MSSConstants.TEMPLATE_PROPERTIES_KEYWORD}");
+ }
+ else
+ {
+ List<Property> properties = new List<Property>();
+
+ properties.AddRange(shader.Properties.Where(x => !string.IsNullOrWhiteSpace(x.Name) || x.Attributes.Count > 0));
+
+ foreach (var module in modules.Where(x => x != null))
+ {
+ properties.AddRange(module.Properties.Where(x => !string.IsNullOrWhiteSpace(x.Name) || x.Attributes.Count > 0));
+ if (module.EnableProperties.Count > 0 && includeEnablers)
+ properties.AddRange(module.EnableProperties.Where(x => !string.IsNullOrWhiteSpace(x.Name)));
+
+ }
+
+ foreach (var prop in properties.Distinct())
+ {
+ if (string.IsNullOrWhiteSpace(prop.Type) && !string.IsNullOrWhiteSpace(prop.Name))
+ {
+ prop.Type = "Float";
+ prop.DefaultValue = "0.0";
+ }
+
+ string attributes = prop.Attributes.Count == 0 ? "" : $"[{string.Join("][", prop.Attributes)}]";
+ block.AppendLine(string.IsNullOrWhiteSpace(prop.Name) ? attributes : $"{attributes} {prop.Name}(\"{prop.DisplayName}\", {prop.Type}) = {prop.DefaultValue}");
+ }
+ }
+
+ block.AppendLine("}");
+ return block.ToString();
+ }
+
+ private static void ApplyDefaultTextures(List<ShaderContext> contexts)
+ {
+ foreach (var context in contexts)
+ {
+ var importedShader = AssetImporter.GetAtPath($"{context.FilePath}/" + context.VariantFileName) as ShaderImporter;
+ var customTextures = context.Modules.SelectMany(x => x.Properties).Where(x => x.DefaultTextureAsset != null).ToList();
+ if (importedShader != null)
+ {
+ importedShader.SetDefaultTextures(customTextures.Select(x => x.Name).ToArray(), customTextures.Select(x => x.DefaultTextureAsset).ToArray());
+ importedShader.SetNonModifiableTextures(customTextures.Select(x => x.Name).ToArray(), customTextures.Select(x => x.DefaultTextureAsset).ToArray());
+ }
+ AssetDatabase.ImportAsset($"{context.FilePath}/" + context.VariantFileName);
+ }
+ }
+
+ public static List<ShaderModule> FindAllModules(ModularShader shader)
+ {
+ List<ShaderModule> modules = new List<ShaderModule>();
+ if (shader == null) return modules;
+ modules.AddRange(shader.BaseModules.Where(x => x != null));
+ modules.AddRange(shader.AdditionalModules.Where(x => x != null));
+ return modules;
+ }
+
+ public static List<Property> FindAllProperties(ModularShader shader)
+ {
+ List<Property> properties = new List<Property>();
+ if (shader == null) return properties;
+
+ properties.AddRange(shader.Properties.Where(x => !string.IsNullOrWhiteSpace(x.Name) || x.Attributes.Count == 0));
+
+ foreach (var module in shader.BaseModules.Where(x => x != null))
+ {
+ properties.AddRange(module.Properties.Where(x => !string.IsNullOrWhiteSpace(x.Name) || x.Attributes.Count == 0));
+ if (module.EnableProperties.Count > 0)
+ properties.AddRange(module.EnableProperties.Where(x => !string.IsNullOrWhiteSpace(x.Name)));
+ }
+
+ foreach (var module in shader.AdditionalModules.Where(x => x != null))
+ {
+ properties.AddRange(module.Properties.Where(x => !string.IsNullOrWhiteSpace(x.Name) || x.Attributes.Count == 0));
+ if (module.EnableProperties.Count > 0)
+ properties.AddRange(module.EnableProperties.Where(x => !string.IsNullOrWhiteSpace(x.Name)));
+ }
+
+ return properties.Distinct().ToList();
+ }
+
+ public static List<ShaderFunction> FindAllFunctions(ModularShader shader)
+ {
+ var functions = new List<ShaderFunction>();
+ if (shader == null) return functions;
+ foreach (var module in shader.BaseModules)
+ functions.AddRange(module.Functions);
+
+ foreach (var module in shader.AdditionalModules)
+ functions.AddRange(module.Functions);
+ return functions;
+ }
+
+ public static List<ShaderModule> FindActiveModules(ModularShader shader, Dictionary<string, int> activeEnablers)
+ {
+ List<ShaderModule> modules = new List<ShaderModule>();
+ if (shader == null) return modules;
+
+ foreach (var module in shader.BaseModules)
+ {
+ if (module == null) continue;
+ bool hasEnabler = module.EnableProperties.Any(x => x != null && !string.IsNullOrEmpty(x.Name));
+ bool hasKey = hasEnabler && module.EnableProperties.Any(x => activeEnablers.TryGetValue(x.Name, out _));
+ if (!hasEnabler || !hasKey || (module.EnableProperties.All(x =>
+ {
+ if (x.Name == null || string.IsNullOrEmpty(x.Name)) return true;
+ if (!activeEnablers.TryGetValue(x.Name, out int value)) return true;
+ return x.EnableValue == value;
+ })))
+ modules.Add(module);
+ }
+
+ foreach (var module in shader.AdditionalModules)
+ {
+ if (module == null) continue;
+ bool hasEnabler = module.EnableProperties.Any(x => x != null && !string.IsNullOrEmpty(x.Name));
+ bool hasKey = hasEnabler && module.EnableProperties.Any(x => activeEnablers.TryGetValue(x.Name, out _));
+ if (!hasEnabler || !hasKey || (module.EnableProperties.All(x =>
+ {
+ if (x.Name == null || string.IsNullOrEmpty(x.Name)) return true;
+ if (!activeEnablers.TryGetValue(x.Name, out int value)) return true;
+ return x.EnableValue == value;
+ })))
+ modules.Add(module);
+ }
+
+ return modules;
+ }
+
+ public static List<string> CheckShaderIssues(ModularShader shader)
+ {
+ List<string> errors = new List<string>();
+ var modules = FindAllModules(shader);
+
+ for (int i = 0; i < modules.Count; i++)
+ {
+ var dependencies = new List<string>(modules[i].ModuleDependencies);
+ for (int j = 0; j < modules.Count; j++)
+ {
+ if (modules[j].IncompatibleWith.Any(x => x.Equals(modules[i].Id)))
+ errors.Add($"Module \"{modules[j].Name}\" is incompatible with module \"{modules[i].name}\".");
+
+ if (i != j && modules[i].Id.Equals(modules[j].Id))
+ errors.Add($"Module \"{modules[i].Name}\" is duplicate.");
+
+ if (dependencies.Contains(modules[j].Id))
+ dependencies.Remove(modules[j].Id);
+ }
+ foreach (string t in dependencies)
+ errors.Add($"Module \"{modules[i].Name}\" has missing dependency id \"{t}\".");
+ }
+ return errors;
+ }
+
+ public static List<string> CheckShaderIssues(List<ShaderModule> modules)
+ {
+ List<string> errors = new List<string>();
+
+ for (int i = 0; i < modules.Count; i++)
+ {
+ var dependencies = new List<string>(modules[i].ModuleDependencies);
+ for (int j = 0; j < modules.Count; j++)
+ {
+ if (modules[j].IncompatibleWith.Any(x => x.Equals(modules[i].Id)))
+ errors.Add($"Module \"{modules[j].Name}\" is incompatible with module \"{modules[i].name}\".");
+
+ if (i != j && modules[i].Id.Equals(modules[j].Id))
+ errors.Add($"Module \"{modules[i].Name}\" is duplicate.");
+
+ if (dependencies.Contains(modules[j].Id))
+ dependencies.Remove(modules[j].Id);
+ }
+ foreach (string t in dependencies)
+ errors.Add($"Module \"{modules[i].Name}\" has missing dependency id \"{t}\".");
+ }
+ return errors;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderGenerator.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderGenerator.cs.meta
new file mode 100644
index 00000000..e5b304e8
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderGenerator.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 201376915e15b96479a71b836a88f234
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderStringBuilderExtensions.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderStringBuilderExtensions.cs
new file mode 100644
index 00000000..194b79f9
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderStringBuilderExtensions.cs
@@ -0,0 +1,103 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace Poiyomi.ModularShaderSystem
+{
+ public static class ShaderStringBuilderExtensions
+ {
+ public static StringBuilder Prepend(this StringBuilder builder, string value) => builder.Insert(0, value);
+
+ public static StringBuilder PrependLine(this StringBuilder builder, string value) => builder.Prepend(Environment.NewLine).Prepend(value);
+
+ public static StringBuilder AppendLineTabbed(this StringBuilder builder, int tabLevel, string value)
+ {
+ return builder.Append(Tabs(tabLevel)).AppendLine(value);
+ }
+
+ public static StringBuilder PrependLineTabbed(this StringBuilder builder, int tabLevel, string value)
+ {
+ return builder.PrependLine(value).Prepend(Tabs(tabLevel));
+ }
+
+ public static StringBuilder AppendTabbed(this StringBuilder builder, int tabLevel, string value)
+ {
+ return builder.Append(Tabs(tabLevel)).Append(value);
+ }
+
+ public static StringBuilder PrependTabbed(this StringBuilder builder, int tabLevel, string value)
+ {
+ return builder.Prepend(value).Prepend(Tabs(tabLevel));
+ }
+
+ public static StringBuilder AppendMultilineTabbed(this StringBuilder builder, int tabLevel, string value)
+ {
+ var sr = new StringReader(value);
+ string line;
+ while ((line = sr.ReadLine()) != null)
+ builder.AppendLineTabbed(tabLevel, line);
+ return builder;
+ }
+
+ static string Tabs(int n)
+ {
+ if (n < 0) n = 0;
+ return new string('\t', n);
+ }
+
+ public static bool Contains(this StringBuilder haystack, string needle)
+ {
+ return haystack.IndexOf(needle) != -1;
+ }
+
+ public static int IndexOf(this StringBuilder haystack, string needle)
+ {
+ if (haystack == null || needle == null)
+ throw new ArgumentNullException();
+ if (needle.Length == 0)
+ return 0;//empty strings are everywhere!
+ if (needle.Length == 1)//can't beat just spinning through for it
+ {
+ char c = needle[0];
+ for (int idx = 0; idx != haystack.Length; ++idx)
+ if (haystack[idx] == c)
+ return idx;
+ return -1;
+ }
+ int m = 0;
+ int i = 0;
+ int[] T = KmpTable(needle);
+ while (m + i < haystack.Length)
+ {
+ if (needle[i] == haystack[m + i])
+ {
+ if (i == needle.Length - 1)
+ return m == needle.Length ? -1 : m;//match -1 = failure to find conventional in .NET
+ ++i;
+ }
+ else
+ {
+ m = m + i - T[i];
+ i = T[i] > -1 ? T[i] : 0;
+ }
+ }
+ return -1;
+ }
+ private static int[] KmpTable(string sought)
+ {
+ int[] table = new int[sought.Length];
+ int pos = 2;
+ int cnd = 0;
+ table[0] = -1;
+ table[1] = 0;
+ while (pos < table.Length)
+ if (sought[pos - 1] == sought[cnd])
+ table[pos++] = ++cnd;
+ else if (cnd > 0)
+ cnd = table[cnd];
+ else
+ table[pos++] = 0;
+ return table;
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderStringBuilderExtensions.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderStringBuilderExtensions.cs.meta
new file mode 100644
index 00000000..6a04a004
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/ModularShaderSystem/ShaderStringBuilderExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b54ed470e6719864790dc791d7ce05ab
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: