792 lines
32 KiB
C#
Executable file
792 lines
32 KiB
C#
Executable file
// Material/Shader Inspector for Unity 2017/2018
|
|
// Copyright (C) 2019 Thryrallo
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace Thry
|
|
{
|
|
#region Constants
|
|
public class PATH
|
|
{
|
|
public const string TEXTURES_DIR = "Assets/textures";
|
|
public const string RSP_NEEDED_PATH = "Assets/";
|
|
|
|
public const string DELETING_DIR = "Thry/trash";
|
|
|
|
public const string PERSISTENT_DATA = "Thry/persistent_data";
|
|
|
|
public const string GRADIENT_INFO_FILE = "Thry/gradients";
|
|
|
|
public const string LINKED_MATERIALS_FILE = "Thry/linked_materials.json";
|
|
}
|
|
|
|
public class URL
|
|
{
|
|
public const string MODULE_COLLECTION = "https://raw.githubusercontent.com/Thryrallo/ThryEditorStreamedResources/main/packages.json";
|
|
public const string SETTINGS_MESSAGE_URL = "https://raw.githubusercontent.com/Thryrallo/ThryEditorStreamedResources/main/Messages/settingsWindow.json";
|
|
public const string COUNT_PROJECT = "http://thryeditor.thryrallo.de/count_project.php";
|
|
public const string COUNT_USER = "http://thryeditor.thryrallo.de/count_user.php";
|
|
}
|
|
|
|
public class DEFINE_SYMBOLS
|
|
{
|
|
public const string IMAGING_EXISTS = "IMAGING_DLL_EXISTS";
|
|
}
|
|
|
|
public class RESOURCE_GUID
|
|
{
|
|
public const string RECT = "2329f8696fd09a743a5baf2a5f4986af";
|
|
public const string ICON_LINK = "e85fd0a0e4e4fea46bb3fdeab5c3fb07";
|
|
public const string ICON_THRY = "693aa4c2cdc578346a196469a06ddbba";
|
|
}
|
|
#endregion
|
|
|
|
public class DrawingData
|
|
{
|
|
public static TextureProperty CurrentTextureProperty;
|
|
public static Rect LastGuiObjectRect;
|
|
public static Rect LastGuiObjectHeaderRect;
|
|
public static Rect TooltipCheckRect;
|
|
public static bool LastPropertyUsedCustomDrawer;
|
|
public static bool LastPropertyDoesntAllowAnimation;
|
|
public static DrawerType LastPropertyDrawerType;
|
|
public static MaterialPropertyDrawer LastPropertyDrawer;
|
|
public static List<MaterialPropertyDrawer> LastPropertyDecorators = new List<MaterialPropertyDrawer>();
|
|
public static bool IsEnabled = true;
|
|
public static bool IsCollectingProperties = false;
|
|
|
|
public static ShaderPart LastInitiatedPart;
|
|
|
|
public static void ResetLastDrawerData()
|
|
{
|
|
LastPropertyUsedCustomDrawer = false;
|
|
LastPropertyDoesntAllowAnimation = false;
|
|
LastPropertyDrawer = null;
|
|
LastPropertyDrawerType = DrawerType.None;
|
|
LastPropertyDecorators.Clear();
|
|
}
|
|
|
|
public static void RegisterDecorator(MaterialPropertyDrawer drawer)
|
|
{
|
|
if(IsCollectingProperties)
|
|
{
|
|
LastPropertyDecorators.Add(drawer);
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum DrawerType
|
|
{
|
|
None
|
|
}
|
|
|
|
public class GradientData
|
|
{
|
|
public Texture PreviewTexture;
|
|
public Gradient Gradient;
|
|
}
|
|
|
|
public enum TextureDisplayType
|
|
{
|
|
small, big, big_basic
|
|
}
|
|
|
|
//--------------Shader Data Structs--------------------
|
|
|
|
#region In Shader Data
|
|
public class PropertyOptions
|
|
{
|
|
public string tooltip = "";
|
|
public DefineableAction altClick;
|
|
public DefineableAction onClick;
|
|
public DefineableCondition condition_show = new DefineableCondition();
|
|
public string condition_showS;
|
|
public DefineableCondition condition_enable = null;
|
|
public PropertyValueAction[] on_value_actions;
|
|
public string on_value;
|
|
public DefineableAction[] actions;
|
|
public ButtonData button_help;
|
|
public TextureData texture;
|
|
public string[] reference_properties;
|
|
public string reference_property;
|
|
public bool force_texture_options = false;
|
|
public bool is_visible_simple = false;
|
|
public string file_name;
|
|
public string remote_version_url;
|
|
public string generic_string;
|
|
public bool never_lock;
|
|
|
|
public static PropertyOptions Deserialize(string s)
|
|
{
|
|
if(s == null) return new PropertyOptions();
|
|
s = s.Replace("''", "\"");
|
|
PropertyOptions options = Parser.Deserialize<PropertyOptions>(s);
|
|
if (options == null) return new PropertyOptions();
|
|
// The following could be removed since the parser can now handle it. leaving it in for now /shrug
|
|
if (options.condition_showS != null)
|
|
{
|
|
options.condition_show = DefineableCondition.Parse(options.condition_showS);
|
|
}
|
|
if (options.on_value != null)
|
|
{
|
|
options.on_value_actions = PropertyValueAction.ParseToArray(options.on_value);
|
|
}
|
|
return options;
|
|
}
|
|
}
|
|
|
|
public class ButtonData
|
|
{
|
|
public string text = "";
|
|
public TextureData texture = null;
|
|
public DefineableAction action = new DefineableAction();
|
|
public string hover = "";
|
|
public bool center_position = false;
|
|
public DefineableCondition condition_show = new DefineableCondition();
|
|
}
|
|
|
|
public class TextureData
|
|
{
|
|
public string name = null;
|
|
public string guid = null;
|
|
public int width = 128;
|
|
public int height = 128;
|
|
|
|
public char channel = 'r';
|
|
|
|
public int ansioLevel = 1;
|
|
public FilterMode filterMode = FilterMode.Bilinear;
|
|
public TextureWrapMode wrapMode = TextureWrapMode.Repeat;
|
|
public bool center_position = false;
|
|
bool _isLoading;
|
|
|
|
public void ApplyModes(Texture texture)
|
|
{
|
|
texture.filterMode = filterMode;
|
|
texture.wrapMode = wrapMode;
|
|
texture.anisoLevel = ansioLevel;
|
|
}
|
|
public void ApplyModes(string path)
|
|
{
|
|
TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(path);
|
|
importer.filterMode = filterMode;
|
|
importer.wrapMode = wrapMode;
|
|
importer.anisoLevel = ansioLevel;
|
|
importer.SaveAndReimport();
|
|
}
|
|
|
|
static Dictionary<string, Texture> s_loaded_textures = new Dictionary<string, Texture>();
|
|
public Texture loaded_texture
|
|
{
|
|
get
|
|
{
|
|
if(guid != null)
|
|
{
|
|
if(!s_loaded_textures.ContainsKey(guid) || s_loaded_textures[guid] == null)
|
|
{
|
|
string path = AssetDatabase.GUIDToAssetPath(guid);
|
|
if (path != null)
|
|
s_loaded_textures[guid] = AssetDatabase.LoadAssetAtPath<Texture>(path);
|
|
else
|
|
s_loaded_textures[guid] = Texture2D.whiteTexture;
|
|
}
|
|
return s_loaded_textures[guid];
|
|
}else if(name != null)
|
|
{
|
|
if(!s_loaded_textures.ContainsKey(name) || s_loaded_textures[name] == null)
|
|
{
|
|
if(IsUrl())
|
|
{
|
|
if(!_isLoading)
|
|
{
|
|
s_loaded_textures[name] = Texture2D.whiteTexture;
|
|
WebHelper.DownloadBytesASync(name, (byte[] b) =>
|
|
{
|
|
_isLoading = false;
|
|
Texture2D tex = new Texture2D(1,1, TextureFormat.ARGB32, false);
|
|
ImageConversion.LoadImage(tex, b, false);
|
|
s_loaded_textures[name] = tex;
|
|
});
|
|
_isLoading = true;
|
|
}
|
|
}else
|
|
{
|
|
string path = FileHelper.FindFile(name, "texture");
|
|
if (path != null)
|
|
s_loaded_textures[name] = AssetDatabase.LoadAssetAtPath<Texture>(path);
|
|
else
|
|
s_loaded_textures[name] = Texture2D.whiteTexture;
|
|
}
|
|
}
|
|
return s_loaded_textures[name];
|
|
}
|
|
return Texture2D.whiteTexture;
|
|
}
|
|
}
|
|
|
|
private static TextureData ParseForThryParser(string s)
|
|
{
|
|
if(s.StartsWith("{") == false)
|
|
{
|
|
return new TextureData()
|
|
{
|
|
name = s
|
|
};
|
|
}
|
|
return Parser.Deserialize<TextureData>(s);
|
|
}
|
|
|
|
bool IsUrl()
|
|
{
|
|
return name.StartsWith("http") && (name.EndsWith(".jpg") || name.EndsWith(".png"));
|
|
}
|
|
}
|
|
|
|
public class PropertyValueAction
|
|
{
|
|
public string value;
|
|
public DefineableAction[] actions;
|
|
|
|
public bool Execute(MaterialProperty p, Material[] targets)
|
|
{
|
|
if(
|
|
(p.type == MaterialProperty.PropType.Float && p.floatValue.ToString() == value) ||
|
|
(p.type == MaterialProperty.PropType.Range && p.floatValue.ToString() == value) ||
|
|
(p.type == MaterialProperty.PropType.Color && p.colorValue.ToString() == value) ||
|
|
(p.type == MaterialProperty.PropType.Vector && p.vectorValue.ToString() == value) ||
|
|
(p.type == MaterialProperty.PropType.Texture && ((p.textureValue == null) == (value == "0"))) ||
|
|
(p.type == MaterialProperty.PropType.Texture && ((p.textureValue != null) == (value == "1"))) ||
|
|
(p.type == MaterialProperty.PropType.Texture && (p.textureValue != null && p.textureValue.name == value))
|
|
)
|
|
{;
|
|
foreach (DefineableAction a in actions)
|
|
a.Perform(targets);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static PropertyValueAction ParseForThryParser(string s)
|
|
{
|
|
return Parse(s);
|
|
}
|
|
|
|
// value,property1=value1,property2=value2
|
|
public static PropertyValueAction Parse(string s)
|
|
{
|
|
s = s.Trim();
|
|
string[] valueAndActions = s.Split(new string[]{"=>"}, System.StringSplitOptions.RemoveEmptyEntries);
|
|
if (valueAndActions.Length > 1)
|
|
{
|
|
PropertyValueAction propaction = new PropertyValueAction();
|
|
propaction.value = valueAndActions[0];
|
|
List<DefineableAction> actions = new List<DefineableAction>();
|
|
string[] actionStrings = valueAndActions[1].Split(';');
|
|
for (int i = 0; i < actionStrings.Length; i++)
|
|
{
|
|
if(string.IsNullOrWhiteSpace(actionStrings[i]))
|
|
continue;
|
|
actions.Add(DefineableAction.Parse(actionStrings[i]));
|
|
}
|
|
propaction.actions = actions.ToArray();
|
|
return propaction;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static PropertyValueAction[] ParseToArrayForThryParser(string s)
|
|
{
|
|
return ParseToArray(s);
|
|
}
|
|
|
|
public static PropertyValueAction[] ParseToArray(string s)
|
|
{
|
|
//s := 0=>p1=v1;p2=v2;1=>p1=v3...
|
|
List<PropertyValueAction> propactions = new List<PropertyValueAction>();
|
|
string[] valueAndActionMatches = Regex.Matches(s, @"[^;]+=>.+?(?=(;[^;]+=>)|$)", RegexOptions.Multiline).Cast<Match>().Select(m => m.Value).ToArray();
|
|
foreach (string p in valueAndActionMatches)
|
|
{
|
|
PropertyValueAction propertyValueAction = PropertyValueAction.Parse(p);
|
|
if (propertyValueAction != null)
|
|
propactions.Add(propertyValueAction);
|
|
}
|
|
return propactions.ToArray();
|
|
}
|
|
}
|
|
|
|
public class DefineableAction
|
|
{
|
|
public DefineableActionType type = DefineableActionType.NONE;
|
|
public string data = "";
|
|
public void Perform(Material[] targets)
|
|
{
|
|
switch (type)
|
|
{
|
|
case DefineableActionType.URL:
|
|
Application.OpenURL(data);
|
|
break;
|
|
case DefineableActionType.SET_PROPERTY:
|
|
string[] set = Regex.Split(data, @"=");
|
|
if (set.Length > 1)
|
|
MaterialHelper.SetMaterialValue(set[0].Trim(), set[1].Trim());
|
|
break;
|
|
case DefineableActionType.SET_TAG:
|
|
string[] keyValue = Regex.Split(data, @"=");
|
|
foreach (Material m in targets)
|
|
m.SetOverrideTag(keyValue[0].Trim(), keyValue[1].Trim());
|
|
break;
|
|
case DefineableActionType.SET_SHADER:
|
|
Shader shader = Shader.Find(data);
|
|
if (shader != null)
|
|
{
|
|
foreach (Material m in targets)
|
|
m.shader = shader;
|
|
}
|
|
break;
|
|
case DefineableActionType.OPEN_EDITOR:
|
|
System.Type t = Helper.FindTypeByFullName(data);
|
|
if (t != null)
|
|
{
|
|
try
|
|
{
|
|
EditorWindow window = EditorWindow.GetWindow(t);
|
|
window.titleContent = new GUIContent("TPS Setup Wizard");
|
|
window.Show();
|
|
}catch(System.Exception e)
|
|
{
|
|
Debug.LogError("[Thry] Couldn't open Editor Window of type" + data);
|
|
Debug.LogException(e);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private static DefineableAction ParseForThryParser(string s)
|
|
{
|
|
return Parse(s);
|
|
}
|
|
public static DefineableAction Parse(string s)
|
|
{
|
|
s = s.Trim();
|
|
DefineableAction action = new DefineableAction();
|
|
if (s.StartsWith("http", StringComparison.Ordinal) || s.StartsWith("www", StringComparison.Ordinal))
|
|
{
|
|
action.type = DefineableActionType.URL;
|
|
action.data = s;
|
|
}
|
|
else if (s.StartsWith("tag::", StringComparison.Ordinal))
|
|
{
|
|
action.type = DefineableActionType.SET_TAG;
|
|
action.data = s.Replace("tag::", "");
|
|
}
|
|
else if (s.StartsWith("shader=", StringComparison.Ordinal))
|
|
{
|
|
action.type = DefineableActionType.SET_SHADER;
|
|
action.data = s.Replace("shader=", "");
|
|
}
|
|
else if (s.Contains("="))
|
|
{
|
|
action.type = DefineableActionType.SET_PROPERTY;
|
|
action.data = s;
|
|
}
|
|
else if (Regex.IsMatch(s, @"\w+(\.\w+)"))
|
|
{
|
|
action.type = DefineableActionType.OPEN_EDITOR;
|
|
action.data = s;
|
|
}
|
|
return action;
|
|
}
|
|
|
|
public static DefineableAction ParseDrawerParameter(string s)
|
|
{
|
|
s = s.Trim();
|
|
DefineableAction action = new DefineableAction();
|
|
if (s.StartsWith("youtube#", StringComparison.Ordinal))
|
|
{
|
|
action.type = DefineableActionType.URL;
|
|
action.data = "https://www.youtube.com/watch?v="+s.Substring(8);
|
|
}
|
|
return action;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"{{{type},{data}}}";
|
|
}
|
|
}
|
|
|
|
public enum DefineableActionType
|
|
{
|
|
NONE,
|
|
URL,
|
|
SET_PROPERTY,
|
|
SET_SHADER,
|
|
SET_TAG,
|
|
OPEN_EDITOR,
|
|
}
|
|
|
|
public class DefineableCondition
|
|
{
|
|
public DefineableConditionType type = DefineableConditionType.NONE;
|
|
public string data = "";
|
|
public DefineableCondition condition1;
|
|
public DefineableCondition condition2;
|
|
|
|
CompareType _compareType;
|
|
string _obj;
|
|
ShaderProperty _propertyObj;
|
|
Material _materialInsteadOfEditor;
|
|
|
|
string _value;
|
|
float _floatValue;
|
|
|
|
bool _hasConstantValue;
|
|
bool _constantValue;
|
|
|
|
bool _isInit = false;
|
|
public void Init()
|
|
{
|
|
if (_isInit) return;
|
|
_hasConstantValue = true;
|
|
if (type == DefineableConditionType.NONE) { _constantValue = true; }
|
|
else if (type == DefineableConditionType.TRUE) { _constantValue = true; }
|
|
else if (type == DefineableConditionType.FALSE) { _constantValue = false; }
|
|
else
|
|
{
|
|
var (compareType, compareString) = GetComparetor();
|
|
_compareType = compareType;
|
|
|
|
string[] parts = Regex.Split(data, compareString);
|
|
_obj = parts[0].Trim();
|
|
_value = parts[parts.Length - 1].Trim();
|
|
|
|
_floatValue = Parser.ParseFloat(_value);
|
|
if (ShaderEditor.Active != null && ShaderEditor.Active.PropertyDictionary.ContainsKey(_obj))
|
|
_propertyObj = ShaderEditor.Active.PropertyDictionary[_obj];
|
|
|
|
if (type == DefineableConditionType.EDITOR_VERSION) InitEditorVersion();
|
|
else if (type == DefineableConditionType.VRC_SDK_VERSION) InitVRCSDKVersion();
|
|
else _hasConstantValue = false;
|
|
}
|
|
|
|
_isInit = true;
|
|
}
|
|
|
|
void InitEditorVersion()
|
|
{
|
|
int c_ev = Helper.CompareVersions(Config.Singleton.verion, _value);
|
|
if (_compareType == CompareType.EQUAL) _constantValue = c_ev == 0;
|
|
if (_compareType == CompareType.NOT_EQUAL) _constantValue = c_ev != 0;
|
|
if (_compareType == CompareType.SMALLER) _constantValue = c_ev == 1;
|
|
if (_compareType == CompareType.BIGGER) _constantValue = c_ev == -1;
|
|
if (_compareType == CompareType.BIGGER_EQ) _constantValue = c_ev == -1 || c_ev == 0;
|
|
if (_compareType == CompareType.SMALLER_EQ) _constantValue = c_ev == 1 || c_ev == 0;
|
|
}
|
|
|
|
void InitVRCSDKVersion()
|
|
{
|
|
if (VRCInterface.Get().Sdk_information.type == VRCInterface.VRC_SDK_Type.NONE)
|
|
{
|
|
_constantValue = false;
|
|
return;
|
|
}
|
|
int c_vrc = Helper.CompareVersions(VRCInterface.Get().Sdk_information.installed_version, _value);
|
|
if (_compareType == CompareType.EQUAL) _constantValue = c_vrc == 0;
|
|
if (_compareType == CompareType.NOT_EQUAL) _constantValue = c_vrc != 0;
|
|
if (_compareType == CompareType.SMALLER) _constantValue = c_vrc == 1;
|
|
if (_compareType == CompareType.BIGGER) _constantValue = c_vrc == -1;
|
|
if (_compareType == CompareType.BIGGER_EQ) _constantValue = c_vrc == -1 || c_vrc == 0;
|
|
if (_compareType == CompareType.SMALLER_EQ) _constantValue = c_vrc == 1 || c_vrc == 0;
|
|
}
|
|
|
|
public bool Test()
|
|
{
|
|
Init();
|
|
if (_hasConstantValue) return _constantValue;
|
|
|
|
MaterialProperty materialProperty = null;
|
|
switch (type)
|
|
{
|
|
case DefineableConditionType.PROPERTY_BOOL:
|
|
materialProperty = GetMaterialProperty();
|
|
if (materialProperty == null) return false;
|
|
if (_compareType == CompareType.NONE) return materialProperty.floatValue == 1;
|
|
if (_compareType == CompareType.EQUAL) return materialProperty.floatValue == _floatValue;
|
|
if (_compareType == CompareType.NOT_EQUAL) return materialProperty.floatValue != _floatValue;
|
|
if (_compareType == CompareType.SMALLER) return materialProperty.floatValue < _floatValue;
|
|
if (_compareType == CompareType.BIGGER) return materialProperty.floatValue > _floatValue;
|
|
if (_compareType == CompareType.BIGGER_EQ) return materialProperty.floatValue >= _floatValue;
|
|
if (_compareType == CompareType.SMALLER_EQ) return materialProperty.floatValue <= _floatValue;
|
|
break;
|
|
case DefineableConditionType.TEXTURE_SET:
|
|
materialProperty = GetMaterialProperty();
|
|
if (materialProperty == null) return false;
|
|
return (materialProperty.textureValue == null) == (_compareType == CompareType.EQUAL);
|
|
case DefineableConditionType.DROPDOWN:
|
|
materialProperty = GetMaterialProperty();
|
|
if (materialProperty == null) return false;
|
|
if (_compareType == CompareType.NONE) return materialProperty.floatValue == 1;
|
|
if (_compareType == CompareType.EQUAL) return "" + materialProperty.floatValue == _value;
|
|
if (_compareType == CompareType.NOT_EQUAL) return "" + materialProperty.floatValue != _value;
|
|
break;
|
|
case DefineableConditionType.PROPERTY_IS_ANIMATED:
|
|
return ShaderOptimizer.IsAnimated(_materialInsteadOfEditor, _obj);
|
|
case DefineableConditionType.PROPERTY_IS_NOT_ANIMATED:
|
|
return !ShaderOptimizer.IsAnimated(_materialInsteadOfEditor, _obj);
|
|
case DefineableConditionType.AND:
|
|
if(condition1!=null&&condition2!=null) return condition1.Test() && condition2.Test();
|
|
break;
|
|
case DefineableConditionType.OR:
|
|
if(condition1 != null && condition2 != null) return condition1.Test() || condition2.Test();
|
|
break;
|
|
case DefineableConditionType.NOT:
|
|
if(condition1 != null) return !condition1.Test();
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private MaterialProperty GetMaterialProperty()
|
|
{
|
|
if(_materialInsteadOfEditor) return MaterialEditor.GetMaterialProperty(new Material[]{_materialInsteadOfEditor}, _obj);
|
|
if(_propertyObj != null) return _propertyObj.MaterialProperty;
|
|
return null;
|
|
}
|
|
private (CompareType,string) GetComparetor()
|
|
{
|
|
if (data.Contains("=="))
|
|
return (CompareType.EQUAL,"==");
|
|
if (data.Contains("!="))
|
|
return (CompareType.NOT_EQUAL,"!=");
|
|
if (data.Contains(">="))
|
|
return (CompareType.BIGGER_EQ,">=");
|
|
if (data.Contains("<="))
|
|
return (CompareType.SMALLER_EQ,"<=");
|
|
if (data.Contains(">"))
|
|
return (CompareType.BIGGER,">");
|
|
if (data.Contains("<"))
|
|
return (CompareType.SMALLER,"<");
|
|
return (CompareType.NONE,"##");
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
switch (type)
|
|
{
|
|
case DefineableConditionType.PROPERTY_BOOL:
|
|
return data;
|
|
case DefineableConditionType.EDITOR_VERSION:
|
|
return "EDITOR_VERSION" + data;
|
|
case DefineableConditionType.VRC_SDK_VERSION:
|
|
return "VRC_SDK_VERSION" + data;
|
|
case DefineableConditionType.TEXTURE_SET:
|
|
return "TEXTURE_SET" + data;
|
|
case DefineableConditionType.DROPDOWN:
|
|
return "DROPDOWN" + data;
|
|
case DefineableConditionType.PROPERTY_IS_ANIMATED:
|
|
return $"isAnimated({data})";
|
|
case DefineableConditionType.PROPERTY_IS_NOT_ANIMATED:
|
|
return $"isNotAnimated({data})";
|
|
case DefineableConditionType.AND:
|
|
if (condition1 != null && condition2 != null) return "("+condition1.ToString() + "&&" + condition2.ToString()+")";
|
|
break;
|
|
case DefineableConditionType.OR:
|
|
if (condition1 != null && condition2 != null) return "("+condition1.ToString()+"||"+condition2.ToString()+")";
|
|
break;
|
|
case DefineableConditionType.NOT:
|
|
if (condition1 != null) return "!"+condition1.ToString();
|
|
break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
private static DefineableCondition ParseForThryParser(string s)
|
|
{
|
|
return Parse(s);
|
|
}
|
|
|
|
private static readonly char[] ComparissionLiteralsToCheckFor = "*><=".ToCharArray();
|
|
public static DefineableCondition Parse(string s, Material useThisMaterialInsteadOfOpenEditor = null, int start = 0, int end = -1)
|
|
{
|
|
if(end == -1) end = s.Length;
|
|
DefineableCondition con;
|
|
|
|
// Debug.Log("Parsing: " + s.Substring(start, end - start));
|
|
|
|
int depth = 0;
|
|
int bracketStart = -1;
|
|
int bracketEnd = -1;
|
|
for(int i = start; i < end; i++)
|
|
{
|
|
char c = s[i];
|
|
if(c == '(')
|
|
{
|
|
depth += 1;
|
|
if(depth == 1)
|
|
{
|
|
bracketStart = i;
|
|
}
|
|
}else if(c == ')')
|
|
{
|
|
if(depth == 1)
|
|
{
|
|
bracketEnd = i;
|
|
}
|
|
depth -= 1;
|
|
}else if(depth == 0)
|
|
{
|
|
if(c == '&')
|
|
{
|
|
con = new DefineableCondition();
|
|
con._materialInsteadOfEditor = useThisMaterialInsteadOfOpenEditor;
|
|
|
|
con.type = DefineableConditionType.AND;
|
|
con.condition1 = Parse(s, useThisMaterialInsteadOfOpenEditor, start, i);
|
|
con.condition2 = Parse(s, useThisMaterialInsteadOfOpenEditor, i + (s[i+1] == '&' ? 2 : 1), end);
|
|
return con;
|
|
}else if(c == '|')
|
|
{
|
|
|
|
con = new DefineableCondition();
|
|
con._materialInsteadOfEditor = useThisMaterialInsteadOfOpenEditor;
|
|
|
|
con.type = DefineableConditionType.OR;
|
|
con.condition1 = Parse(s, useThisMaterialInsteadOfOpenEditor, start, i);
|
|
con.condition2 = Parse(s, useThisMaterialInsteadOfOpenEditor, i + (s[i + 1] == '|' ? 2 : 1), end);
|
|
return con;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool isInverted = IsInverted(s, ref start);
|
|
|
|
// if no AND or OR was found, check for brackets
|
|
if(bracketStart != -1 && bracketEnd != -1)
|
|
{
|
|
con = Parse(s, useThisMaterialInsteadOfOpenEditor, bracketStart + 1, bracketEnd);
|
|
}else
|
|
{
|
|
con = ParseSingle(s.Substring(start, end - start), useThisMaterialInsteadOfOpenEditor);
|
|
}
|
|
|
|
if(isInverted)
|
|
{
|
|
DefineableCondition inverted = new DefineableCondition();
|
|
inverted._materialInsteadOfEditor = useThisMaterialInsteadOfOpenEditor;
|
|
inverted.type = DefineableConditionType.NOT;
|
|
inverted.condition1 = con;
|
|
return inverted;
|
|
}
|
|
|
|
return con;
|
|
}
|
|
|
|
static bool IsInverted(string s, ref int start)
|
|
{
|
|
for(int i = start; i < s.Length; i++)
|
|
{
|
|
if(s[i] == '!')
|
|
{
|
|
start += 1;
|
|
return true;
|
|
}
|
|
if(s[i] != ' ')
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static DefineableCondition ParseSingle(string s, Material useThisMaterialInsteadOfOpenEditor = null)
|
|
{
|
|
// Debug.Log("Parsing single: " + s);
|
|
|
|
DefineableCondition con = new DefineableCondition();
|
|
con._materialInsteadOfEditor = useThisMaterialInsteadOfOpenEditor;
|
|
|
|
if(s.IndexOfAny(ComparissionLiteralsToCheckFor) != -1)
|
|
{
|
|
//is a comparission
|
|
con.data = s;
|
|
con.type = DefineableConditionType.PROPERTY_BOOL;
|
|
if (s.StartsWith("VRCSDK", StringComparison.Ordinal))
|
|
{
|
|
con.type = DefineableConditionType.VRC_SDK_VERSION;
|
|
con.data = s.Replace("VRCSDK", "");
|
|
}else if (s.StartsWith("ThryEditor", StringComparison.Ordinal))
|
|
{
|
|
con.type = DefineableConditionType.EDITOR_VERSION;
|
|
con.data = s.Replace("ThryEditor", "");
|
|
}else if(IsTextureNullComparission(s, useThisMaterialInsteadOfOpenEditor))
|
|
{
|
|
con.type = DefineableConditionType.TEXTURE_SET;
|
|
con.data = s.Replace("TEXTURE_SET", "");
|
|
}
|
|
return con;
|
|
}
|
|
if(s.StartsWith("isNotAnimated(", StringComparison.Ordinal))
|
|
{
|
|
con.type = DefineableConditionType.PROPERTY_IS_NOT_ANIMATED;
|
|
con.data = s.Replace("isNotAnimated(", "").TrimEnd(')');
|
|
return con;
|
|
}
|
|
if(s.StartsWith("isAnimated(", StringComparison.Ordinal))
|
|
{
|
|
con.type = DefineableConditionType.PROPERTY_IS_ANIMATED;
|
|
con.data = s.Replace("isAnimated(", "").TrimEnd(')');
|
|
return con;
|
|
}
|
|
return con;
|
|
}
|
|
|
|
static bool IsTextureNullComparission(string data, Material useThisMaterialInsteadOfOpenEditor = null)
|
|
{
|
|
// Check if property is a texture property && is checking for null
|
|
Material m = GetReferencedMaterial(useThisMaterialInsteadOfOpenEditor);
|
|
if( m == null) return false;
|
|
if(data.Length < 7) return false;
|
|
if(data.EndsWith("null") == false) return false;
|
|
string propertyName = data.Substring(0, data.Length - 6);
|
|
if(m.HasProperty(propertyName) == false) return false;
|
|
MaterialProperty p = MaterialEditor.GetMaterialProperty(new Material[]{m}, propertyName);
|
|
return p.type == MaterialProperty.PropType.Texture;
|
|
}
|
|
|
|
static Material GetReferencedMaterial(Material useThisMaterialInsteadOfOpenEditor = null)
|
|
{
|
|
if( useThisMaterialInsteadOfOpenEditor != null ) return useThisMaterialInsteadOfOpenEditor;
|
|
if( ShaderEditor.Active != null ) return ShaderEditor.Active.Materials[0];
|
|
return null;
|
|
}
|
|
}
|
|
|
|
enum CompareType { NONE,BIGGER,SMALLER,EQUAL,NOT_EQUAL,BIGGER_EQ,SMALLER_EQ }
|
|
|
|
public enum DefineableConditionType
|
|
{
|
|
NONE,
|
|
TRUE,
|
|
FALSE,
|
|
PROPERTY_BOOL,
|
|
PROPERTY_IS_ANIMATED,
|
|
PROPERTY_IS_NOT_ANIMATED,
|
|
EDITOR_VERSION,
|
|
VRC_SDK_VERSION,
|
|
TEXTURE_SET,
|
|
DROPDOWN,
|
|
AND,
|
|
OR,
|
|
NOT
|
|
}
|
|
|
|
#endregion
|
|
} |