Repository: hecomi/uShaderTemplate Branch: master Commit: 93f8e8ff750b Files: 96 Total size: 88.4 KB Directory structure: gitextract_rjpfz9kl/ ├── .github/ │ └── workflows/ │ └── main.yml ├── .gitignore ├── Assets/ │ ├── uShaderTemplate/ │ │ ├── Editor/ │ │ │ ├── Resources/ │ │ │ │ ├── uShaderTemplate/ │ │ │ │ │ ├── Constants/ │ │ │ │ │ │ ├── Custom Constants.asset │ │ │ │ │ │ ├── Custom Constants.asset.meta │ │ │ │ │ │ ├── Default Constants.asset │ │ │ │ │ │ └── Default Constants.asset.meta │ │ │ │ │ ├── Constants.meta │ │ │ │ │ ├── Fonts/ │ │ │ │ │ │ ├── LICENSE_OFL.txt │ │ │ │ │ │ ├── LICENSE_OFL.txt.meta │ │ │ │ │ │ └── NotoMono-Regular.ttf.meta │ │ │ │ │ └── Fonts.meta │ │ │ │ └── uShaderTemplate.meta │ │ │ ├── Resources.meta │ │ │ ├── Scripts/ │ │ │ │ ├── CodeEditor.cs │ │ │ │ ├── CodeEditor.cs.meta │ │ │ │ ├── ColorScheme.cs │ │ │ │ ├── ColorScheme.cs.meta │ │ │ │ ├── Common.cs │ │ │ │ ├── Common.cs.meta │ │ │ │ ├── Constants.cs │ │ │ │ ├── Constants.cs.meta │ │ │ │ ├── FileWatcher.cs │ │ │ │ ├── FileWatcher.cs.meta │ │ │ │ ├── Generator.cs │ │ │ │ ├── Generator.cs.meta │ │ │ │ ├── GeneratorEditor.cs │ │ │ │ ├── GeneratorEditor.cs.meta │ │ │ │ ├── MaterialEditor.cs │ │ │ │ ├── MaterialEditor.cs.meta │ │ │ │ ├── ShaderCodeEditor.cs │ │ │ │ ├── ShaderCodeEditor.cs.meta │ │ │ │ ├── ShaderHighlighter.cs │ │ │ │ ├── ShaderHighlighter.cs.meta │ │ │ │ ├── ShaderSyntax.cs │ │ │ │ ├── ShaderSyntax.cs.meta │ │ │ │ ├── ShaderTemplateParser.cs │ │ │ │ ├── ShaderTemplateParser.cs.meta │ │ │ │ ├── ShaderTemplateSelector.cs │ │ │ │ ├── ShaderTemplateSelector.cs.meta │ │ │ │ ├── Utils.cs │ │ │ │ └── Utils.cs.meta │ │ │ ├── Scripts.meta │ │ │ ├── uShaderTemplate.Editor.asmdef │ │ │ └── uShaderTemplate.Editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Examples/ │ │ │ ├── Editor/ │ │ │ │ ├── Generators/ │ │ │ │ │ ├── Surface.asset │ │ │ │ │ ├── Surface.asset.meta │ │ │ │ │ ├── VertFrag.asset │ │ │ │ │ └── VertFrag.asset.meta │ │ │ │ ├── Generators.meta │ │ │ │ ├── Resources/ │ │ │ │ │ ├── ShaderTemplates/ │ │ │ │ │ │ ├── Examples/ │ │ │ │ │ │ │ ├── Surface.txt │ │ │ │ │ │ │ ├── Surface.txt.meta │ │ │ │ │ │ │ ├── VertFrag.txt │ │ │ │ │ │ │ └── VertFrag.txt.meta │ │ │ │ │ │ └── Examples.meta │ │ │ │ │ └── ShaderTemplates.meta │ │ │ │ └── Resources.meta │ │ │ ├── Editor.meta │ │ │ ├── Materials/ │ │ │ │ ├── Surface.mat │ │ │ │ ├── Surface.mat.meta │ │ │ │ ├── VertFrag.mat │ │ │ │ └── VertFrag.mat.meta │ │ │ ├── Materials.meta │ │ │ ├── Shaders/ │ │ │ │ ├── Surface.shader │ │ │ │ ├── Surface.shader.meta │ │ │ │ ├── VertFrag.shader │ │ │ │ └── VertFrag.shader.meta │ │ │ └── Shaders.meta │ │ ├── Examples.meta │ │ ├── package.json │ │ └── package.json.meta │ └── uShaderTemplate.meta ├── LICENSE.md ├── Packages/ │ ├── manifest.json │ └── packages-lock.json ├── ProjectSettings/ │ ├── AudioManager.asset │ ├── ClusterInputManager.asset │ ├── DynamicsManager.asset │ ├── EditorBuildSettings.asset │ ├── EditorSettings.asset │ ├── GraphicsSettings.asset │ ├── InputManager.asset │ ├── NavMeshAreas.asset │ ├── NetworkManager.asset │ ├── PackageManagerSettings.asset │ ├── Physics2DSettings.asset │ ├── PresetManager.asset │ ├── ProjectSettings.asset │ ├── ProjectVersion.txt │ ├── QualitySettings.asset │ ├── TagManager.asset │ ├── TimeManager.asset │ ├── UnityConnectSettings.asset │ ├── VFXManager.asset │ └── VersionControlSettings.asset └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/main.yml ================================================ name: Create UPM branches and run NPM publish on: push: tags: - v* jobs: update: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 with: fetch-depth: 0 - name: Get tag name id: tag run: echo ::set-output name=name::${GITHUB_REF#refs/tags/v} - name: Create UPM Branch uses: hecomi/create-upm-branch-action@main with: git-tag: ${{ steps.tag.outputs.name }} pkg-root-dir-path: Assets/uShaderTemplate main-branch: master samples-dir: Examples - name: Setup node uses: actions/setup-node@v2 with: registry-url: 'https://registry.npmjs.org' - name: NPM publish run: npm publish --access public env: NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} ================================================ FILE: .gitignore ================================================ # This .gitignore file should be placed at the root of your Unity project directory # # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore # /[Ll]ibrary/ /[Tt]emp/ /[Oo]bj/ /[Bb]uild/ /[Bb]uilds/ /[Ll]ogs/ /[Uu]ser[Ss]ettings/ # MemoryCaptures can get excessive in size. # They also could contain extremely sensitive data /[Mm]emoryCaptures/ # Asset meta data should only be ignored when the corresponding asset is also ignored !/[Aa]ssets/**/*.meta # Uncomment this line if you wish to ignore the asset store tools plugin # /[Aa]ssets/AssetStoreTools* # Autogenerated Jetbrains Rider plugin /[Aa]ssets/Plugins/Editor/JetBrains* # Visual Studio cache directory .vs/ .vsconfig # Gradle cache directory .gradle/ # Autogenerated VS/MD/Consulo solution and project files ExportedObj/ .consulo/ *.csproj *.unityproj *.sln *.suo *.tmp *.user *.userprefs *.pidb *.booproj *.svd *.pdb *.mdb *.opendb *.VC.db # Unity3D generated meta files *.pidb.meta *.pdb.meta *.mdb.meta # Unity3D generated file on crash reports sysinfo.txt # Builds *.apk *.aab *.unitypackage # Crashlytics generated file crashlytics-build.properties # Packed Addressables /[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* # Temporary auto-generated Android Assets /[Aa]ssets/[Ss]treamingAssets/aa.meta /[Aa]ssets/[Ss]treamingAssets/aa/* ================================================ FILE: Assets/uShaderTemplate/Editor/Resources/uShaderTemplate/Constants/Custom Constants.asset.meta ================================================ fileFormatVersion: 2 guid: cfee3bf03df3b40c3b654c2cfd4db724 timeCreated: 1495353467 licenseType: Pro NativeFormatImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Resources/uShaderTemplate/Constants/Default Constants.asset.meta ================================================ fileFormatVersion: 2 guid: 9c8b2f5a7a56c4e21bee7ca4ccfc6640 timeCreated: 1495353467 licenseType: Pro NativeFormatImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Resources/uShaderTemplate/Constants.meta ================================================ fileFormatVersion: 2 guid: 0808cee05a22541f1b7c328a1c052f38 folderAsset: yes timeCreated: 1514605650 licenseType: Pro DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Resources/uShaderTemplate/Fonts/LICENSE_OFL.txt ================================================ This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL ----------------------------------------------------------- SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ----------------------------------------------------------- PREAMBLE The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. DEFINITIONS "Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. "Reserved Font Name" refers to any names specified as such after the copyright statement(s). "Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). "Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. "Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. PERMISSION & CONDITIONS Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: 1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. 2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. 3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. 5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. TERMINATION This license becomes null and void if any of the above conditions are not met. DISCLAIMER THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. ================================================ FILE: Assets/uShaderTemplate/Editor/Resources/uShaderTemplate/Fonts/LICENSE_OFL.txt.meta ================================================ fileFormatVersion: 2 guid: e7f1e444a1fa94406a60546cb778466b timeCreated: 1475660344 licenseType: Pro TextScriptImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Resources/uShaderTemplate/Fonts/NotoMono-Regular.ttf.meta ================================================ fileFormatVersion: 2 guid: 278ecf23a382e4292b4a907449fd15f0 timeCreated: 1475660344 licenseType: Pro TrueTypeFontImporter: externalObjects: {} serializedVersion: 4 fontSize: 16 forceTextureCase: -2 characterSpacing: 0 characterPadding: 1 includeFontData: 1 fontName: Noto Mono fontNames: - Noto Mono fallbackFontReferences: - {fileID: 12800000, guid: 9c8d17aeaa1c7bf47805458f830d46cb, type: 3} customCharacters: fontRenderingMode: 0 ascentCalculationMode: 1 useLegacyBoundsCalculation: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Resources/uShaderTemplate/Fonts.meta ================================================ fileFormatVersion: 2 guid: 30a3ca36b7ccf4deb8e21cfe35ca7fd8 folderAsset: yes timeCreated: 1475660340 licenseType: Pro DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Resources/uShaderTemplate.meta ================================================ fileFormatVersion: 2 guid: 9cf019badb8c146e08ad33e26ab9e3a0 folderAsset: yes timeCreated: 1495345278 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Resources.meta ================================================ fileFormatVersion: 2 guid: 22a5a44deb3d648c6abf24801723eca0 folderAsset: yes timeCreated: 1495345065 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/CodeEditor.cs ================================================ using UnityEngine; using UnityEditor; namespace uShaderTemplate { public class CodeEditor { public string controlName { get; set; } public Color backgroundColor { get; set; } public Color textColor { get; set; } public Color cursorColor { get; set; } string cachedCode { get; set; } string cachedHighlightedCode { get; set; } public System.Func highlighter { get; set; } public bool isFocused { get { return GUI.GetNameOfFocusedControl() == controlName; } } public CodeEditor(string controlName) { this.controlName = controlName; backgroundColor = Color.black; textColor = Color.white; highlighter = code => code; } public string Draw(string code, GUIStyle style, params GUILayoutOption[] options) { var preBackgroundColor = GUI.backgroundColor; var preColor = GUI.color; var preCursorColor = GUI.skin.settings.cursorColor; var preCursorFlashSpeed = GUI.skin.settings.cursorFlashSpeed; var backStyle = new GUIStyle(style); backStyle.normal.textColor = Color.clear; backStyle.hover.textColor = Color.clear; backStyle.active.textColor = Color.clear; backStyle.focused.textColor = Color.clear; GUI.backgroundColor = backgroundColor; GUI.color = textColor; GUI.skin.settings.cursorColor = cursorColor; GUI.SetNextControlName(controlName); // IMPORTANT: // Sadly, we cannot use TextEditor with (EditorGUILayout|EditorGUI).TextArea()... X( // And GUILayout.TextArea() cannot handle TAB key... ;_; // GUI.TextArea needs a lot of tasks to implement basic functions... T_T var editedCode = EditorGUILayout.TextArea(code, backStyle, GUILayout.ExpandHeight(true)); // So, this does not work... // var editor = GUIUtility.GetStateObject(typeof(TextEditor), GUIUtility.keyboardControl) as TextEditor; // CheckEvents(editor); if (editedCode != code) { code = editedCode; } if (string.IsNullOrEmpty(cachedHighlightedCode) || (cachedCode != code)) { cachedCode = code; cachedHighlightedCode = highlighter(code); } GUI.backgroundColor = Color.clear; GUI.color = textColor; GUI.skin.settings.cursorColor = Color.clear; var foreStyle = new GUIStyle(style); foreStyle.richText = true; foreStyle.normal.textColor = textColor; foreStyle.hover.textColor = textColor; foreStyle.active.textColor = textColor; foreStyle.focused.textColor = textColor; EditorGUI.TextArea(GUILayoutUtility.GetLastRect(), cachedHighlightedCode, foreStyle); GUI.backgroundColor = preBackgroundColor; GUI.color = preColor; GUI.skin.settings.cursorColor = preCursorColor; return code; } void CheckEvents(TextEditor editor) { // ... } } } ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/CodeEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 62d234cb567694d2789ade8d5cab6a89 timeCreated: 1495345065 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/ColorScheme.cs ================================================ namespace uShaderTemplate { namespace ColorScheme { // http://ethanschoonover.com/solarized public static class Solarized { public const string base03 = "#002b36"; public const string base02 = "#073642"; public const string base01 = "#586e75"; public const string base00 = "#657b83"; public const string base0 = "#839496"; public const string base1 = "#93a1a1"; public const string base2 = "#eee8d5"; public const string base3 = "#fdf6e3"; public const string yellow = "#b58900"; public const string orange = "#cb4b16"; public const string red = "#dc322f"; public const string magenta = "#d33682"; public const string violet = "#6c71c4"; public const string blue = "#268bd2"; public const string cyan = "#2aa198"; public const string green = "#859900"; } } } ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/ColorScheme.cs.meta ================================================ fileFormatVersion: 2 guid: 9cb8608d376b04cab8df8562d02cca44 timeCreated: 1495345065 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/Common.cs ================================================ using uShaderTemplate.ColorScheme; namespace uShaderTemplate { namespace Common { public static class Color { public const string background = Solarized.base03; public const string color = "#ffffff"; public const string cursorColor = "#ffffff"; public const string type = Solarized.yellow; public const string keyword = Solarized.green; public const string symbol = Solarized.base1; public const string digit = Solarized.violet; public const string str = Solarized.violet; public const string comment = Solarized.base01; public const string cgprogram = Solarized.blue; public const string unity = Solarized.magenta; public const string user1 = Solarized.orange; public const string user2 = Solarized.cyan; } public static class Editor { public const string font = "uShaderTemplate/Font/NotoMono-regular"; public const int fontSize = 12; public const bool wordWrap = false; public const int height = 200; } public static class Setting { public const int menuOrder = 1000; public const string menuPlace = "Shader/uShaderTemplate/"; public const string defaultConstants = "uShaderTemplate/Constants/Default Constants"; public const string templateDirectoryPath = "ShaderTemplates"; public const string templateFileExtension = ".txt"; } } } ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/Common.cs.meta ================================================ fileFormatVersion: 2 guid: 4a29e724630f4487cb646107886e433f timeCreated: 1495345065 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/Constants.cs ================================================ using UnityEngine; namespace uShaderTemplate { [System.Serializable] public struct Constant { public string name; public string value; } [CreateAssetMenu( menuName = Common.Setting.menuPlace + "Constants", order = Common.Setting.menuOrder + 1)] public class Constants : ScriptableObject { public Constant[] values; public virtual void OnBeforeConvert() {} public virtual void OnAfterConvert() {} } } ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/Constants.cs.meta ================================================ fileFormatVersion: 2 guid: 0b69f41837370415ab1f75789505044f timeCreated: 1495353387 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/FileWatcher.cs ================================================ using System.IO; using UnityEngine.Events; namespace uShaderTemplate { public class FileWatcher { FileSystemWatcher watcher_; bool hasChanged_ = false; FileSystemEventHandler onChangedHandler_; RenamedEventHandler onRenamedHandler_; public UnityEvent onChanged = new UnityEvent(); public void Start(string path) { watcher_ = new System.IO.FileSystemWatcher(); watcher_.Path = Path.GetDirectoryName(path); watcher_.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; watcher_.Filter = Path.GetFileName(path); onChangedHandler_ = new FileSystemEventHandler(OnChanged); onRenamedHandler_ = new RenamedEventHandler(OnRenamed); watcher_.Changed += onChangedHandler_; watcher_.Created += onChangedHandler_; watcher_.Deleted += onChangedHandler_; watcher_.Renamed += onRenamedHandler_; watcher_.EnableRaisingEvents = true; } public void Stop() { if (watcher_ != null) { watcher_.EnableRaisingEvents = false; watcher_.Changed -= onChangedHandler_; watcher_.Created -= onChangedHandler_; watcher_.Deleted -= onChangedHandler_; watcher_.Renamed -= onRenamedHandler_; } } public void Update() { if (hasChanged_) { hasChanged_ = false; onChanged.Invoke(); } } void OnChanged(object source, FileSystemEventArgs e) { hasChanged_ = true; } void OnRenamed(object source, RenamedEventArgs e) { hasChanged_ = true; } } } ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/FileWatcher.cs.meta ================================================ fileFormatVersion: 2 guid: fc635ea546c084c8291db4721c1d416a timeCreated: 1495345065 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/Generator.cs ================================================ using UnityEngine; using System.Collections.Generic; namespace uShaderTemplate { [System.Serializable] public struct ShaderVariables { public string key; public string value; } [System.Serializable] public struct ShaderCondition { public string key; public bool value; } [System.Serializable] public struct ShaderBlock { public string key; public string value; public bool folded; } [CreateAssetMenu( menuName = Common.Setting.menuPlace + "Generator", order = Common.Setting.menuOrder)] public class Generator : ScriptableObject { public string shaderName = ""; public Shader shaderReference = null; public string shaderTemplate = ""; public List variables = new List(); public List conditions = new List(); public List blocks = new List(); public Constants constants; public bool basicFolded = true; public bool conditionsFolded = false; public bool variablesFolded = false; public bool materialsFolded = false; public bool constantsFolded = false; public virtual void OnBeforeConvert() {} public virtual void OnAfterConvert() {} } } ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/Generator.cs.meta ================================================ fileFormatVersion: 2 guid: 3acd6fe57257048db802c1c4c2b75248 timeCreated: 1495345065 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/GeneratorEditor.cs ================================================ using UnityEngine; using UnityEditor; using System; using System.Collections.Generic; using System.IO; namespace uShaderTemplate { [CustomEditor(typeof(Generator))] public class GeneratorEditor : Editor { SerializedProperty name_; SerializedProperty shader_; SerializedProperty basicFolded_; SerializedProperty materialsFolded_; SerializedProperty conditions_; SerializedProperty conditionsFolded_; SerializedProperty variables_; SerializedProperty variablesFolded_; SerializedProperty constants_; SerializedProperty constantsFolded_; SerializedProperty blocks_; Dictionary editors_ = new Dictionary(); ShaderTemplateSelector template_; ShaderTemplateParser templateParser_; FileWatcher watcher_ = new FileWatcher(); string errorMessage_; Dictionary> toConstFuncs_; bool constVarsFolded_ = false; bool hasShaderReference { get { return shader_.objectReferenceValue != null; } } void OnEnable() { name_ = serializedObject.FindProperty("shaderName"); shader_ = serializedObject.FindProperty("shaderReference"); variables_ = serializedObject.FindProperty("variables"); variablesFolded_ = serializedObject.FindProperty("variablesFolded"); conditions_ = serializedObject.FindProperty("conditions"); conditionsFolded_ = serializedObject.FindProperty("conditionsFolded"); blocks_ = serializedObject.FindProperty("blocks"); basicFolded_ = serializedObject.FindProperty("basicFolded"); materialsFolded_ = serializedObject.FindProperty("materialsFolded"); constants_ = serializedObject.FindProperty("constants"); constantsFolded_ = serializedObject.FindProperty("constantsFolded"); template_ = new ShaderTemplateSelector(serializedObject.FindProperty("shaderTemplate")); template_.onChange.AddListener(OnTemplateChanged); watcher_.onChanged.AddListener(CheckShaderUpdate); if (hasShaderReference) { watcher_.Start(GetShaderPath()); } CheckShaderUpdate(); } void OnDisable() { if (template_ != null) { template_.onChange.RemoveListener(OnTemplateChanged); } if (watcher_ != null) { watcher_.Stop(); watcher_.onChanged.RemoveListener(CheckShaderUpdate); } } public override void OnInspectorGUI() { serializedObject.Update(); watcher_.Update(); HandleKeyEvents(); if (templateParser_ == null) { OnTemplateChanged(); } DrawBasics(); DrawConditions(); DrawVariables(); DrawBlocks(); DrawConstants(); DrawMaterialReferences(); EditorGUILayout.Separator(); DrawButtons(); DrawMessages(); EditorGUILayout.Separator(); serializedObject.ApplyModifiedProperties(); } SerializedProperty FindProperty(SerializedProperty array, string key, string keyName = "key") { for (int i = 0; i < array.arraySize; ++i) { var prop = array.GetArrayElementAtIndex(i); var keyProp = prop.FindPropertyRelative(keyName); if (keyProp.stringValue == key) { return prop; } } return null; } SerializedProperty AddProperty(SerializedProperty array, string key) { var prop = FindProperty(array, key); if (prop != null) return prop; var index = array.arraySize; array.InsertArrayElementAtIndex(index); return array.GetArrayElementAtIndex(index); } void DrawBasics() { basicFolded_.boolValue = Utils.Foldout("Basic", basicFolded_.boolValue); if (basicFolded_.boolValue) { ++EditorGUI.indentLevel; EditorGUILayout.PropertyField(name_); EditorGUILayout.PropertyField(shader_); template_.Draw(); --EditorGUI.indentLevel; } } void DrawConditions() { if (templateParser_.conditions.Count == 0) { return; } conditionsFolded_.boolValue = Utils.Foldout("Conditions", conditionsFolded_.boolValue); if (!conditionsFolded_.boolValue) return; ++EditorGUI.indentLevel; foreach (var kv in templateParser_.conditions) { var prop = FindProperty(conditions_, kv.Key); var value = prop.FindPropertyRelative("value"); var name = Utils.ToSpacedCamel(kv.Key); var isSelected = EditorGUILayout.Toggle(name, value.boolValue); if (value.boolValue != isSelected) { value.boolValue = isSelected; } } --EditorGUI.indentLevel; } void DrawBlocks() { foreach (var kv in templateParser_.blocks) { var prop = FindProperty(blocks_, kv.Key); var value = prop.FindPropertyRelative("value"); var folded = prop.FindPropertyRelative("folded"); var name = Utils.ToSpacedCamel(kv.Key); ShaderCodeEditor editor = null; if (editors_.ContainsKey(name)) { editor = editors_[name]; } else { editor = new ShaderCodeEditor(name, value, folded); editors_.Add(name, editor); } editor.Draw(); } } void DrawVariables() { if (templateParser_.variables.Count == 0) { return; } variablesFolded_.boolValue = Utils.Foldout("Variables", variablesFolded_.boolValue); if (!variablesFolded_.boolValue) return; ++EditorGUI.indentLevel; var constVars = new Dictionary(); foreach (var kv in templateParser_.variables) { var prop = FindProperty(variables_, kv.Key); if (prop == null) continue; var value = prop.FindPropertyRelative("value"); var name = Utils.ToSpacedCamel(kv.Key); var constValue = ToConstVariable(kv.Key); string changedValue; if (constValue != null) { changedValue = constValue; constVars.Add(name, constValue); } else { if (kv.Value.Count <= 1) { changedValue = EditorGUILayout.TextField(name, value.stringValue); } else { var index = kv.Value.IndexOf(value.stringValue); if (index == -1) index = 0; index = EditorGUILayout.Popup(name, index, kv.Value.ToArray()); changedValue = kv.Value[index]; } } if (value.stringValue != changedValue) { value.stringValue = changedValue; } } if (constVars.Count > 0) { constVarsFolded_ = EditorGUILayout.Foldout(constVarsFolded_, "Constants"); if (constVarsFolded_) { ++EditorGUI.indentLevel; foreach (var kv in constVars) { Utils.ReadOnlyTextField(kv.Key, kv.Value); } --EditorGUI.indentLevel; } } --EditorGUI.indentLevel; } void DrawConstants() { constantsFolded_.boolValue = Utils.Foldout("Constants", constantsFolded_.boolValue); if (!constantsFolded_.boolValue) return; ++EditorGUI.indentLevel; EditorGUILayout.BeginHorizontal(); { EditorGUILayout.PropertyField(constants_); if (templateParser_ != null && templateParser_.constants) { var style = new GUIStyle(EditorStyles.miniButtonLeft); style.fixedWidth = 64; if (GUILayout.Button("Use Default", style)) { constants_.objectReferenceValue = templateParser_.constants; } } } EditorGUILayout.EndHorizontal(); --EditorGUI.indentLevel; } void DrawMaterialReferences() { materialsFolded_.boolValue = Utils.Foldout("Material References", materialsFolded_.boolValue); if (!materialsFolded_.boolValue) return; ++EditorGUI.indentLevel; var materials = Utils.FindMaterialsUsingShader(shader_.objectReferenceValue as Shader); if (materials.Count > 0) { foreach (var material in materials) { EditorGUILayout.ObjectField(material, typeof(Material), false); } } else { EditorGUILayout.LabelField("No material using this shader."); } --EditorGUI.indentLevel; } void DrawButtons() { EditorGUILayout.BeginHorizontal(); { var buttonFontSize = GUI.skin.label.fontSize; var buttonPadding = new RectOffset(12, 12, 6, 6); GUILayout.FlexibleSpace(); var style = new GUIStyle(EditorStyles.miniButtonLeft); style.fontSize = buttonFontSize; style.padding = buttonPadding; if (GUILayout.Button("Export (Ctrl+R)", style)) { ExportShaderWithErrorCheck(); } style = new GUIStyle(EditorStyles.miniButtonMid); style.fontSize = buttonFontSize; style.padding = buttonPadding; if (GUILayout.Button("Create Material", style)) { CreateMaterial(); } style = new GUIStyle(EditorStyles.miniButtonMid); style.fontSize = buttonFontSize; style.padding = buttonPadding; if (GUILayout.Button("Reset to Default", style)) { ResetToDefault(); } style = new GUIStyle(EditorStyles.miniButtonMid); style.fontSize = buttonFontSize; style.padding = buttonPadding; if (GUILayout.Button("Update Template", style)) { OnTemplateChanged(); } style = new GUIStyle(EditorStyles.miniButtonRight); style.fontSize = buttonFontSize; style.padding = buttonPadding; if (GUILayout.Button("Reconvert All", style)) { ReconvertAll(); } } EditorGUILayout.EndHorizontal(); } void DrawMessages() { if (!string.IsNullOrEmpty(errorMessage_)) { EditorGUILayout.HelpBox(errorMessage_, MessageType.Error, true); } } string ToConstVariable(string name) { if (name == "Name") { return name_.stringValue; } else if (constants_ != null) { var constants = (Constants)constants_.objectReferenceValue; foreach (var kv in constants.values) { if (kv.name == name) return kv.value; } } return null; } void OnTemplateChanged() { templateParser_ = new ShaderTemplateParser(template_.text); constants_.objectReferenceValue = templateParser_.constants ?? Resources.Load(Common.Setting.defaultConstants); foreach (var kv in templateParser_.conditions) { if (FindProperty(conditions_, kv.Key) != null) continue; var prop = AddProperty(conditions_, kv.Key); prop.FindPropertyRelative("key").stringValue = kv.Key; prop.FindPropertyRelative("value").boolValue = kv.Value; } foreach (var kv in templateParser_.blocks) { if (FindProperty(blocks_, kv.Key) != null) continue; var prop = AddProperty(blocks_, kv.Key); prop.FindPropertyRelative("key").stringValue = kv.Key; prop.FindPropertyRelative("value").stringValue = kv.Value; prop.FindPropertyRelative("folded").boolValue = false; } foreach (var kv in templateParser_.variables) { if (FindProperty(variables_, kv.Key) != null) continue; var prop = AddProperty(variables_, kv.Key); var hasDefaultValue = (kv.Value.Count >= 1); prop.FindPropertyRelative("key").stringValue = kv.Key; prop.FindPropertyRelative("value").stringValue = hasDefaultValue ? kv.Value[0] : ""; } } string GetShaderName() { var name = name_.stringValue; if (string.IsNullOrEmpty(name)) { throw new System.Exception(string.Format("Shader name of \"{0}\" is empty.", target.name)); } return name_.stringValue; } string GetOutputDirPath() { if (hasShaderReference) { return Path.GetDirectoryName(AssetDatabase.GetAssetPath(shader_.objectReferenceValue)); } return Path.GetDirectoryName(AssetDatabase.GetAssetPath(target)); } string GetShaderPath() { return string.Format("{0}/{1}.shader", GetOutputDirPath(), GetShaderName()); } void ReImport() { var outputPath = GetShaderPath(); AssetDatabase.ImportAsset(outputPath); shader_.objectReferenceValue = AssetDatabase.LoadAssetAtPath(outputPath); } void ExportShader() { var info = new ShaderTemplateConvertInfo(); foreach (var kv in templateParser_.conditions) { var prop = FindProperty(conditions_, kv.Key); var value = prop.FindPropertyRelative("value"); info.conditions.Add(kv.Key, value.boolValue); } foreach (var kv in templateParser_.blocks) { var prop = FindProperty(blocks_, kv.Key); var value = prop.FindPropertyRelative("value"); info.blocks.Add(kv.Key, value.stringValue); } foreach (var kv in templateParser_.variables) { var prop = FindProperty(variables_, kv.Key); var value = prop.FindPropertyRelative("value"); var constValue = ToConstVariable(kv.Key); if (constValue != null) { value.stringValue = constValue; } info.variables.Add(kv.Key, value.stringValue); } var code = templateParser_.Convert(info); // rename if generator has a shader reference. if (hasShaderReference) { var shaderFilePath = AssetDatabase.GetAssetPath(shader_.objectReferenceValue); var shaderFileName = Path.GetFileNameWithoutExtension(shaderFilePath); var newFilePath = GetShaderPath(); if (GetShaderName() != shaderFileName) { if (File.Exists(newFilePath)) { throw new System.Exception( string.Format("attempted to rename {0} to {1}, but target file existed.", shaderFilePath, newFilePath)); } AssetDatabase.RenameAsset(shaderFilePath, GetShaderName()); } } using (var writer = new StreamWriter(GetShaderPath())) { writer.Write(code); } ReImport(); if (hasShaderReference) { watcher_.Start(GetShaderPath()); } } void ExportShaderWithErrorCheck() { ClearError(); var generator = target as Generator; generator.OnBeforeConvert(); try { ExportShader(); } catch (Exception e) { AddError(e.Message); } generator.OnAfterConvert(); } void ResetToDefault() { blocks_.ClearArray(); conditions_.ClearArray(); variables_.ClearArray(); OnTemplateChanged(); } public void Reconvert() { CheckShaderUpdate(); OnTemplateChanged(); ExportShaderWithErrorCheck(); } void ReconvertAll() { Debug.LogFormat("Reconvert started.\n------------------------------"); var generators = Utils.FindAllAssets(); foreach (var generator in generators) { try { if (target == generator) { Debug.LogFormat("{0}", GetShaderPath()); Reconvert(); } else { var editor = Editor.CreateEditor(generator) as GeneratorEditor; Debug.LogFormat("{0}", editor.GetShaderPath()); editor.Reconvert(); } } catch (System.Exception e) { Debug.LogFormat("Error: " + e.Message + ""); } } Debug.LogFormat("------------------------------\nReconvert finished."); } void CheckShaderUpdate() { if (!hasShaderReference) return; ClearError(); try { var shaderPath = GetShaderPath(); using (var reader = new StreamReader(shaderPath)) { var code = reader.ReadToEnd(); var parser = new ShaderTemplateParser(code); foreach (var kv in parser.blocks) { var prop = FindProperty(blocks_, kv.Key); if (prop != null) { var value = prop.FindPropertyRelative("value"); value.stringValue = kv.Value; } } } } catch (System.Exception e) { AddError(e.Message); } } void CreateMaterial() { var material = new Material(shader_.objectReferenceValue as Shader); var path = string.Format("{0}/{1}.mat", GetOutputDirPath(), GetShaderName()); ProjectWindowUtil.CreateAsset(material, path); } void HandleKeyEvents() { var e = Event.current; var isKeyPressing = e.type == EventType.KeyUp; if (isKeyPressing && e.control && e.keyCode == KeyCode.R) { ExportShaderWithErrorCheck(); } } void ClearError() { errorMessage_ = ""; } void AddError(string error) { if (!string.IsNullOrEmpty(errorMessage_)) { errorMessage_ += "\n"; } errorMessage_ += error; } } } ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/GeneratorEditor.cs.meta ================================================ fileFormatVersion: 2 guid: f0e7677688d9d41f385006d35eb6ce88 timeCreated: 1495345065 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/MaterialEditor.cs ================================================ using UnityEngine; using UnityEditor; namespace uShaderTemplate { public class MaterialEditor : ShaderGUI { bool folded_ = true; Editor cachedEditor_; override public void OnGUI( UnityEditor.MaterialEditor materialEditor, MaterialProperty[] properties) { if (!cachedEditor_) { var material = materialEditor.target as Material; var shader = material.shader; var generators = Utils.FindAllAssets(); Generator targetGenerator = null; foreach (var generator in generators) { if (generator.shaderReference == shader) { targetGenerator = generator; break; } } if (targetGenerator) { cachedEditor_ = Editor.CreateEditor(targetGenerator); } } if (cachedEditor_) { cachedEditor_.OnInspectorGUI(); EditorGUILayout.Separator(); } folded_ = Utils.Foldout("Material Properties", folded_); if (folded_) { ++EditorGUI.indentLevel; base.OnGUI(materialEditor, properties); --EditorGUI.indentLevel; } } } } ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/MaterialEditor.cs.meta ================================================ fileFormatVersion: 2 guid: b2fe1cb944fe14609899b7870ce5e639 timeCreated: 1495345065 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/ShaderCodeEditor.cs ================================================ using UnityEngine; using UnityEditor; namespace uShaderTemplate { public class ShaderCodeEditor { public string name { get; private set; } public SerializedProperty value { get; private set; } public SerializedProperty folded { get; private set; } CodeEditor editor_; Vector2 scrollPos_; Font font_; public string code { get { return value != null ? value.stringValue : ""; } private set { this.value.stringValue = value; } } public ShaderCodeEditor(string name, SerializedProperty value, SerializedProperty folded) { this.name = name; this.value = value; this.folded = folded; font_ = Resources.Load(Common.Editor.font); Color color, bgColor, cursorColor; ColorUtility.TryParseHtmlString(Common.Color.background, out bgColor); ColorUtility.TryParseHtmlString(Common.Color.color, out color); ColorUtility.TryParseHtmlString(Common.Color.cursorColor, out cursorColor); editor_ = new CodeEditor(name); editor_.backgroundColor = bgColor; editor_.textColor = color; editor_.cursorColor = cursorColor; editor_.highlighter = ShaderHighlighter.Highlight; } public void Draw() { var preFolded = folded.boolValue; folded.boolValue = Utils.Foldout(name, folded.boolValue); if (!folded.boolValue) { if (preFolded) { GUI.FocusControl(""); } return; } if (!preFolded) { GUI.FocusControl(name); } var height = GUILayout.Height(Common.Editor.height); scrollPos_ = EditorGUILayout.BeginScrollView(scrollPos_, height); { var style = new GUIStyle(GUI.skin.textArea); style.padding = new RectOffset(6, 6, 6, 6); style.font = font_; style.fontSize = Common.Editor.fontSize; style.wordWrap = Common.Editor.wordWrap; var editedCode = editor_.Draw(code, style, GUILayout.ExpandHeight(true)); if (editedCode != code) { code = editedCode; } } EditorGUILayout.EndScrollView(); EditorGUILayout.Space(); } } } ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/ShaderCodeEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 79cc0d829733b429c9476e482f714b82 timeCreated: 1495345065 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/ShaderHighlighter.cs ================================================ using System.Text.RegularExpressions; using System.Collections.Generic; namespace uShaderTemplate { public static class ShaderHighlighter { static Regex regex; static MatchEvaluator evaluator; static Dictionary colorTable = new Dictionary { { "symbol", Common.Color.symbol }, { "digit", Common.Color.digit }, { "str", Common.Color.str }, { "comment", Common.Color.comment }, { "type", Common.Color.type }, { "keyword", Common.Color.keyword }, { "cgprogram", Common.Color.cgprogram }, { "user1", Common.Color.user1 }, { "user2", Common.Color.user2 }, { "unity", Common.Color.unity }, }; static string ToColoredCode(string code, string color) { return "" + code + ""; } [UnityEditor.InitializeOnLoadMethod] static void Init() { var forwardSeparator = "(?({1}))"; var pattern2 = string.Format("(?<{0}>{2}({1}){3})", "{0}", "{1}", forwardSeparator, backwardSeparator); var patterns = new string[] { string.Format(pattern1, "comment", string.Join("|", ShaderSyntax.comment)), string.Format(pattern2, "type", string.Join("|", ShaderSyntax.type)), string.Format(pattern2, "keyword", string.Join("|", ShaderSyntax.keyword)), string.Format(pattern2, "user1", string.Join("|", ShaderSyntax.user1)), string.Format(pattern2, "user2", string.Join("|", ShaderSyntax.user2)), string.Format(pattern2, "cgprogram", string.Join("|", ShaderSyntax.cgprogram)), string.Format(pattern2, "unity", string.Join("|", ShaderSyntax.unity)), string.Format(pattern1, "str", string.Join("|", ShaderSyntax.str)), string.Format(pattern1, "digit", string.Join("|", ShaderSyntax.digit)), string.Format(pattern1, "symbol", string.Join("|", ShaderSyntax.symbol)), }; var combinedPattern = "(" + string.Join("|", patterns) + ")"; regex = new Regex(combinedPattern, RegexOptions.Compiled); evaluator = new MatchEvaluator(match => { foreach (var pair in colorTable) { if (match.Groups[pair.Key].Success) { return ToColoredCode(match.Value, pair.Value); } } return match.Value; }); } public static string Highlight(string code) { return regex.Replace(code, evaluator); } } } ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/ShaderHighlighter.cs.meta ================================================ fileFormatVersion: 2 guid: 5ac75baca8c8f4d35b934f94decfb6b6 timeCreated: 1495351861 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/ShaderSyntax.cs ================================================ using System.Text.RegularExpressions; using System.Collections.Generic; namespace uShaderTemplate { public static class ShaderSyntax { public static readonly string[] type = new string[] { "void", "fixed", "fixed[1-4]", "fixed[1-4]x[1-4]", "half", "half[1-4]", "half[1-4]x[1-4]", "float", "float[1-4]", "float[1-4]x[1-4]", }; public static readonly string[] keyword = new string[] { "#include", "#define", "return", "out", "inout", "inline", }; public static readonly string[] symbol = new string[] { @"[{}()=;,+\-*/<>|]+", }; public static readonly string[] digit = new string[] { @"(? conditions = new Dictionary(); public Dictionary blocks = new Dictionary(); public Dictionary variables = new Dictionary(); } public class ShaderTemplateParser { static readonly string conditionPattern = @"@if\s*(?[^:\s\n]+)(?:\s*:\s*)?(?[^\s\n]+)?\s*\n" + @"(?[^@]*?)" + @"((\s*@else\s*)\n" + @"(?[^@]*?))?" + @"\n\s*@endif"; static readonly string blockPattern = @"@block\s*(?[^\s\n]+)\s*\n" + @"(?[\s\S]*?)" + @"\n\s*(:?//\s*)*?@endblock"; static readonly string variablePattern = @"<(?[^=\s\n]+)(?:\s*=\s*(?[^\s\n|>]+)(\s*\|\s*(?[^\s\n|>]+))*)?\s*>"; static readonly string constantsPattern = @"@constants\s*(?[^\n]+)"; public string code { get; set; } public Dictionary conditions { get; private set; } public Dictionary blocks { get; private set; } public Dictionary> variables { get; private set; } public Constants constants { get; private set; } public ShaderTemplateParser(string code) { this.code = code; conditions = new Dictionary(); blocks = new Dictionary(); variables = new Dictionary>(); Parse(); } void Parse() { ParseConstants(); ParseConditions(); ParseBlocks(); ParseVariables(); } public string Convert(ShaderTemplateConvertInfo info) { if (constants != null) { constants.OnBeforeConvert(); } var code = this.code; code = WriteConstants(code); code = WriteConditions(code, info); code = WriteBlocks(code, info); code = WriteVariables(code, info); code = code.Replace("\r\n", "\n"); var regex = new Regex(@"\n\n\n+"); code = regex.Replace(code, "\n\n"); if (constants != null) { constants.OnAfterConvert(); } return code; } void ParseConstants() { var regex = new Regex(constantsPattern); var matches = regex.Matches(code); if (matches.Count > 0) { var path = matches[0].Groups["Path"].Value; constants = UnityEngine.Resources.Load(path); } } string WriteConstants(string code) { var regex = new Regex(constantsPattern); var evaluator = new MatchEvaluator(match => ""); return regex.Replace(code, evaluator); } void ParseConditions() { conditions.Clear(); var regex = new Regex(conditionPattern); var matches = regex.Matches(code); foreach (Match match in matches) { var cond = match.Groups["Cond"].Value; if (conditions.ContainsKey(cond)) continue; bool init = false; if (match.Groups["Init"].Success) { init = bool.Parse(match.Groups["Init"].Value); } conditions.Add(cond, init); } } string WriteConditions(string code, ShaderTemplateConvertInfo info) { var regex = new Regex(conditionPattern); var evaluator = new MatchEvaluator(match => { var cond = match.Groups["Cond"].Value; var trueValue = match.Groups["TrueValue"].Value; var falseValue = match.Groups["FalseValue"].Value; if (!info.conditions.ContainsKey(cond)) { throw new System.Exception(string.Format("The key \"{0}\" is not found in the given conditions.", cond)); } return (info.conditions[cond]) ? trueValue : falseValue; }); var preCode = code; code = regex.Replace(code, evaluator); while (code != preCode) { preCode = code; code = regex.Replace(code, evaluator); } return code; } void ParseBlocks() { blocks.Clear(); var regex = new Regex(blockPattern); var matches = regex.Matches(code); foreach (Match match in matches) { var block = match.Groups["Block"].Value; var value = match.Groups["Value"].Value; blocks.Add(block, value); } } string WriteBlocks(string code, ShaderTemplateConvertInfo info) { var regex = new Regex(blockPattern); var evaluator = new MatchEvaluator(match => { var block = match.Groups["Block"].Value; var value = info.blocks[block]; if (!info.blocks.ContainsKey(block)) { throw new System.Exception(string.Format("The key \"{0}\" is not found in the given blocks.", block)); } return string.Format("// @block {0}\n{1}\n// @endblock", block, value); }); return regex.Replace(code, evaluator); } void ParseVariables() { variables.Clear(); var regex = new Regex(variablePattern); var matches = regex.Matches(code); foreach (Match match in matches) { var variable = match.Groups["Name"].Value; if (!variables.ContainsKey(variable)) { var values = new List(); foreach (Capture capture in match.Groups["Value"].Captures) { values.Add(capture.Value); } variables.Add(variable, values); } } } string WriteVariables(string code, ShaderTemplateConvertInfo info) { var regex = new Regex(variablePattern); var evaluator = new MatchEvaluator(match => { var variable = match.Groups["Name"].Value; if (!info.variables.ContainsKey(variable)) { throw new System.Exception(string.Format("The key \"{0}\" is not found in the given variables.", variable)); } return info.variables[variable]; }); return regex.Replace(code, evaluator); } } } ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/ShaderTemplateParser.cs.meta ================================================ fileFormatVersion: 2 guid: bcb46db3577114bb4aadb54b6309e9e1 timeCreated: 1495345065 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/ShaderTemplateSelector.cs ================================================ using UnityEngine; using UnityEngine.Events; using UnityEditor; using System.Collections.Generic; using System.IO; using System.Linq; namespace uShaderTemplate { public class ShaderTemplateSelector { public SerializedProperty prop { get; private set; } public class OnChangeEventHandler : UnityEvent {} public OnChangeEventHandler onChange = new OnChangeEventHandler(); struct TemplateInfo { public string name; public string path; } List list_ = new List(); public string selected { get { return prop.stringValue; } } public string text { get { if (string.IsNullOrEmpty(prop.stringValue)) { prop.stringValue = list_[0].name; } var dir = Common.Setting.templateDirectoryPath; var asset = Resources.Load(dir + "/" + prop.stringValue); return asset ? asset.text : ""; } } public ShaderTemplateSelector(SerializedProperty prop) { this.prop = prop; var paths = Utils.GetShaderTemplatePathList(); foreach (var path in paths) { if (Path.GetExtension(path) == Common.Setting.templateFileExtension) { var index = path.IndexOf(Common.Setting.templateDirectoryPath); var name = path .Substring(index + Common.Setting.templateDirectoryPath.Length + 1) .Replace(Common.Setting.templateFileExtension, ""); var info = new TemplateInfo() { name = name, path = path, }; list_.Add(info); } } } public void Draw() { var currentIndex = list_.Select(x => x.name).ToList().IndexOf(prop.stringValue); if (currentIndex == -1) currentIndex = 0; EditorGUILayout.BeginHorizontal(); { var selectedIndex = EditorGUILayout.Popup( "Shader Template", currentIndex, list_.Select(x => x.name).ToArray()); var selected = list_[selectedIndex]; var openButtonStyle = EditorStyles.miniButton; openButtonStyle.fixedWidth = 36; if (GUILayout.Button("Edit", openButtonStyle)) { var asset = AssetDatabase.LoadAssetAtPath(selected.path, typeof(Object)); AssetDatabase.OpenAsset(asset); } var pre = prop.stringValue; var cur = selected.name; if (pre != cur) { prop.stringValue = cur; onChange.Invoke(); } } EditorGUILayout.EndHorizontal(); } } } ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/ShaderTemplateSelector.cs.meta ================================================ fileFormatVersion: 2 guid: a8acd5a733ea24db89ac81f30cb3f9d4 timeCreated: 1495345065 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/Utils.cs ================================================ using UnityEngine; using UnityEngine.Assertions; using UnityEditor; using System.IO; using System.Collections.Generic; namespace uShaderTemplate { public static class Utils { public static HashSet GetShaderTemplatePathList() { var files = Resources.LoadAll(Common.Setting.templateDirectoryPath); var list = new HashSet(); foreach (var file in files) { var path = AssetDatabase.GetAssetPath(file); list.Add(path); } return list; } public static bool Foldout(string title, bool display) { var style = new GUIStyle("ShurikenModuleTitle"); style.font = new GUIStyle(EditorStyles.label).font; style.border = new RectOffset(15, 7, 4, 4); style.fixedHeight = 22; style.contentOffset = new Vector2(20f, -2f); var rect = GUILayoutUtility.GetRect(16f, 22f, style); GUI.Box(rect, title, style); var e = Event.current; var toggleRect = new Rect(rect.x + 4f, rect.y + 2f, 13f, 13f); if (e.type == EventType.Repaint) { EditorStyles.foldout.Draw(toggleRect, false, false, display, false); } if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition)) { display = !display; e.Use(); } return display; } public static string ToSpacedCamel(string str) { return System.Text.RegularExpressions.Regex.Replace(str, @"([A-Z][^A-Z]+)", @"$1 "); } public static void ReadOnlyTextField(string label, string text) { EditorGUILayout.BeginHorizontal(); { EditorGUILayout.LabelField(label, GUILayout.Width(EditorGUIUtility.labelWidth - 4)); EditorGUILayout.SelectableLabel(text, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); } EditorGUILayout.EndHorizontal(); } public static List FindAllAssets(string query) where T : Object { var list = new List(); var guids = AssetDatabase.FindAssets(query); foreach (var guid in guids) { var path = AssetDatabase.GUIDToAssetPath(guid); var obj = AssetDatabase.LoadAssetAtPath(path); if (obj) list.Add(obj); } return list; } public static List FindAllAssets() where T : Object { return FindAllAssets("t:" + typeof(T)); } public static List FindMaterialsUsingShader(Shader shader) { var materials = new List(); var allMaterials = FindAllAssets("t:Material"); foreach (var material in allMaterials) { if (material.shader == shader) { materials.Add(material); } } return materials; } } } ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts/Utils.cs.meta ================================================ fileFormatVersion: 2 guid: 925b388b01b594c7698c988bb6d6ae93 timeCreated: 1495345065 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/Scripts.meta ================================================ fileFormatVersion: 2 guid: aa9023223e4924f0b9c0b34c0d3080a1 folderAsset: yes timeCreated: 1495350799 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor/uShaderTemplate.Editor.asmdef ================================================ { "name": "uShaderTemplate.Editor", "rootNamespace": "", "references": [], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: Assets/uShaderTemplate/Editor/uShaderTemplate.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: a0c568dd17c433c488d48cb56a032e0b AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Editor.meta ================================================ fileFormatVersion: 2 guid: 1dc0de322bc9d4c928c2515ca6c0b497 folderAsset: yes timeCreated: 1495345051 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Examples/Editor/Generators/Surface.asset.meta ================================================ fileFormatVersion: 2 guid: 88c90c500f31b4686bae88f3a389e73f timeCreated: 1495458303 licenseType: Pro NativeFormatImporter: mainObjectFileID: 11400000 userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Examples/Editor/Generators/VertFrag.asset.meta ================================================ fileFormatVersion: 2 guid: a0068c12e7d1a4937b32899156d170d1 timeCreated: 1495382657 licenseType: Pro NativeFormatImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Examples/Editor/Generators.meta ================================================ fileFormatVersion: 2 guid: d17285a28a5464c8cb0d2066d7d2560e folderAsset: yes timeCreated: 1495350945 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/uShaderTemplate/Examples/Editor/Resources/ShaderTemplates/Examples/Surface.txt ================================================ Shader "Custom/" { @constants uShaderTemplate/Constants/Custom Constants Properties { _Color("Color", Color) = (1,1,1,1) _MainTex("Albedo (RGB)", 2D) = "white" {} _NormalTex("Normalmap", 2D) = "bump" {} @if UseTesselation : false _DispTex("Disp Texture", 2D) = "gray" {} _Displacement("Displacement", Range(0, 1.0)) = 0.3 _Tess("Tess Factor", Range(1, 32.0)) = 3 @endif _Glossiness("Smoothness", Range(0,1)) = 0.5 _Metallic("Metallic", Range(0,1)) = 0.0 } SubShader { Tags { "RenderType"="Opaque" } LOD CGPROGRAM @if UseTesselation #pragma surface surf addshadow fullforwardshadows vertex:disp tessellate:tessFixed nolightmap