1799 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			1799 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|   | using UnityEngine; | |||
|  | using UnityEditor; | |||
|  | using System.Collections.Generic; | |||
|  | 
 | |||
|  | // Cartoon FX Easy Editor | |||
|  | // (c) 2013-2020 - Jean Moreno | |||
|  | 
 | |||
|  | public class CFXEasyEditor : EditorWindow | |||
|  | { | |||
|  | 	static private CFXEasyEditor SingleWindow; | |||
|  | 	 | |||
|  | 	[MenuItem("Tools/Cartoon FX Easy Editor")] | |||
|  | 	static void ShowWindow() | |||
|  | 	{ | |||
|  | 		CFXEasyEditor window = EditorWindow.GetWindow<CFXEasyEditor>(EditorPrefs.GetBool("CFX_ShowAsToolbox", true), "Easy Editor", true); | |||
|  | 		window.minSize = new Vector2(300, 8); | |||
|  | 		window.maxSize = new Vector2(300, 8); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	private int SelectedParticleSystemsCount; | |||
|  | 
 | |||
|  | 	//Change Start Color | |||
|  | 	private bool AffectAlpha = true; | |||
|  | 	private Color ColorValue = Color.white; | |||
|  | 	private Color ColorValue2 = Color.white; | |||
|  | 	 | |||
|  | 	//Scale | |||
|  | 	private float ScalingValue = 2.0f; | |||
|  | 	private float LTScalingValue = 1.0f; | |||
|  | 	 | |||
|  | 	//Delay | |||
|  | 	private float DelayValue = 1.0f; | |||
|  | 	 | |||
|  | 	//Duration | |||
|  | 	private float DurationValue = 5.0f; | |||
|  | 	 | |||
|  | 	//Tint | |||
|  | 	private bool TintStartColor = true; | |||
|  | 	private bool TintColorModule = true; | |||
|  | 	private bool TintColorSpeedModule = true; | |||
|  | 	private bool TintTrailsModule = true; | |||
|  | 	private bool TintCustomData1 = true; | |||
|  | 	private bool TintCustomData2 = true; | |||
|  | 	private bool TintLights = true; | |||
|  | 	private Color TintColorValue = Color.white; | |||
|  | 	private float TintHueShiftValue = 0f; | |||
|  | 	private float SatShiftValue = 0f; | |||
|  | 	private float ValShiftValue = 0f; | |||
|  | 
 | |||
|  | 	//Change Lightness | |||
|  | 	private int LightnessStep = 10; | |||
|  | 	 | |||
|  | 	//Module copying system | |||
|  | 	private ParticleSystem copyModulesSourceParticleSystem; | |||
|  | 
 | |||
|  | 	private class ParticleSystemModule | |||
|  | 	{ | |||
|  | 		public string name; | |||
|  | 		//public bool selected; | |||
|  | 		//public bool enabledInSource; | |||
|  | 		public string serializedPropertyPath; | |||
|  | 
 | |||
|  | 		public ParticleSystemModule(string name, string serializedPropertyPath) | |||
|  | 		{ | |||
|  | 			this.name = " " + name + " "; | |||
|  | 			this.serializedPropertyPath = serializedPropertyPath; | |||
|  | 		} | |||
|  | 
 | |||
|  | 		public bool CheckIfEnabledInSource(SerializedObject serializedSource) | |||
|  | 		{ | |||
|  | 			bool enabled = true; | |||
|  | 			var sp = serializedSource.FindProperty(this.serializedPropertyPath); | |||
|  | 			if(sp != null) | |||
|  | 			{ | |||
|  | 				var enabledSp = sp.FindPropertyRelative("enabled"); | |||
|  | 				if(enabledSp != null) | |||
|  | 				{ | |||
|  | 					enabled = enabledSp.boolValue; | |||
|  | 				} | |||
|  | 			} | |||
|  | 			return enabled; | |||
|  | 		} | |||
|  | 	} | |||
|  | 
 | |||
|  | 	private ParticleSystemModule[] modulesToCopy = null; | |||
|  | 	private List<string> initialModuleExtraProperties = null; | |||
|  | 	private GUIContent[] modulesLabels = null; | |||
|  | 
 | |||
|  | 	private ParticleSystem selectedParticleSystem; | |||
|  | 	private bool[] selectedModules; | |||
|  | 	private bool[] enabledModules; | |||
|  | 	/* | |||
|  | 	private bool[] selectedModulesMutate; | |||
|  | 	private bool[] enabledModulesMutate; | |||
|  | 
 | |||
|  | 	private float mutatePercentage = 0.1f; | |||
|  | 	*/ | |||
|  | 
 | |||
|  | 	//Foldouts | |||
|  | 	bool basicFoldout = false; | |||
|  | 	bool colorFoldout = false; | |||
|  | 	bool copyFoldout = false; | |||
|  | 	//bool mutateFoldout = false; | |||
|  | 	 | |||
|  | 	//Editor Prefs | |||
|  | 	private bool pref_ShowAsToolbox; | |||
|  | 	private bool pref_IncludeChildren; | |||
|  | 	private bool pref_HideDisabledModulesCopy; | |||
|  | 
 | |||
|  | 	void OnEnable() | |||
|  | 	{ | |||
|  | 		//Load Settings | |||
|  | 		pref_ShowAsToolbox = EditorPrefs.GetBool("CFX_ShowAsToolbox", true); | |||
|  | 		pref_IncludeChildren = EditorPrefs.GetBool("CFX_IncludeChildren", true); | |||
|  | 		pref_HideDisabledModulesCopy = EditorPrefs.GetBool("CFX_HideDisabledModulesCopy", true); | |||
|  | 		basicFoldout = EditorPrefs.GetBool("CFX_BasicFoldout", false); | |||
|  | 		colorFoldout = EditorPrefs.GetBool("CFX_ColorFoldout", false); | |||
|  | 		copyFoldout = EditorPrefs.GetBool("CFX_CopyFoldout", false); | |||
|  | 		//mutateFoldout = EditorPrefs.GetBool("CFX_MutateFoldout", false); | |||
|  | 
 | |||
|  | 		ParticleSystem ps = null; | |||
|  | 		if (Selection.activeGameObject != null) | |||
|  | 		{ | |||
|  | 			ps = Selection.activeGameObject.GetComponent<ParticleSystem>(); | |||
|  | 		} | |||
|  | 		if (ps == null && copyModulesSourceParticleSystem != null) | |||
|  | 		{ | |||
|  | 			ps = copyModulesSourceParticleSystem.GetComponent<ParticleSystem>(); | |||
|  | 		} | |||
|  | 		FetchParticleSystemModules(ps); | |||
|  | 		//RefreshCurrentlyEnabledModules(ps, ref enabledModulesMutate); | |||
|  | 
 | |||
|  | 		OnSelectionChange(); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	void OnSelectionChange() | |||
|  | 	{ | |||
|  | 		UpdateSelectionCount(); | |||
|  | 		this.Repaint(); | |||
|  | 
 | |||
|  | 		if (Selection.activeGameObject != null) | |||
|  | 		{ | |||
|  | 			selectedParticleSystem = Selection.activeGameObject.GetComponent<ParticleSystem>(); | |||
|  | 			FetchParticleSystemModules(selectedParticleSystem); | |||
|  | 		} | |||
|  | 	} | |||
|  | 
 | |||
|  | 	void FetchParticleSystemModules(ParticleSystem ps) | |||
|  | 	{ | |||
|  | 		// Fetch the modules list from a Particle System | |||
|  | 		if (modulesToCopy == null && ps != null) | |||
|  | 		{ | |||
|  | 			initialModuleExtraProperties = new List<string>(); | |||
|  | 			var modulesList = new List<ParticleSystemModule>(); | |||
|  | 			var modulesLabelsList = new List<GUIContent>(); | |||
|  | 			var so = new SerializedObject(ps); | |||
|  | 			var sp = so.GetIterator(); | |||
|  | 			sp.Next(true); | |||
|  | 			while (sp.NextVisible(false)) | |||
|  | 			{ | |||
|  | 				if (sp.propertyPath.EndsWith("Module")) | |||
|  | 				{ | |||
|  | 					var module = new ParticleSystemModule(sp.propertyPath.Replace("Module", ""), sp.propertyPath); | |||
|  | 					modulesList.Add(module); | |||
|  | 					modulesLabelsList.Add(new GUIContent(sp.propertyPath.Replace("Module", ""))); | |||
|  | 				} | |||
|  | 				else | |||
|  | 				{ | |||
|  | 					initialModuleExtraProperties.Add(sp.propertyPath); | |||
|  | 				} | |||
|  | 			} | |||
|  | 			modulesToCopy = modulesList.ToArray(); | |||
|  | 
 | |||
|  | 			// add one entry for renderer (not a module but a component) | |||
|  | 			modulesLabelsList.Add(new GUIContent("Renderer")); | |||
|  | 			modulesLabels = modulesLabelsList.ToArray(); | |||
|  | 		} | |||
|  | 	} | |||
|  | 
 | |||
|  | 	void OnDisable() | |||
|  | 	{ | |||
|  | 		//Save Settings | |||
|  | 		EditorPrefs.SetBool("CFX_BasicFoldout", basicFoldout); | |||
|  | 		EditorPrefs.SetBool("CFX_ColorFoldout", colorFoldout); | |||
|  | 		EditorPrefs.SetBool("CFX_CopyFoldout", copyFoldout); | |||
|  | 		//EditorPrefs.SetBool("CFX_MutateFoldout", mutateFoldout); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	void UpdateSelectionCount() | |||
|  | 	{ | |||
|  | 		SelectedParticleSystemsCount = 0; | |||
|  | 		foreach(var go in Selection.gameObjects) | |||
|  | 		{ | |||
|  | 			ParticleSystem[] systems; | |||
|  | 			if(pref_IncludeChildren) | |||
|  | 				systems = go.GetComponentsInChildren<ParticleSystem>(true); | |||
|  | 			else | |||
|  | 				systems = go.GetComponents<ParticleSystem>(); | |||
|  | 
 | |||
|  | 			SelectedParticleSystemsCount += systems.Length; | |||
|  | 		} | |||
|  | 	} | |||
|  | 	 | |||
|  | 	void OnGUI() | |||
|  | 	{ | |||
|  | 		GUILayout.Space(4); | |||
|  | 		 | |||
|  | 		GUILayout.BeginHorizontal(); | |||
|  | 		var rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight, EditorStyles.label); | |||
|  | 		GUI.Label(rect, "Cartoon FX Easy Editor", EditorStyles.boldLabel); | |||
|  | 		var guiColor = GUI.color; | |||
|  | 		GUI.color *= new Color(.8f,.8f,.8f,1f); | |||
|  | 		pref_ShowAsToolbox = GUILayout.Toggle(pref_ShowAsToolbox, new GUIContent("Toolbox", "If enabled, the window will be displayed as an external toolbox.\nElse it will act as a dockable Unity window."), EditorStyles.miniButton, GUILayout.Width(65)); | |||
|  | 		GUI.color = guiColor; | |||
|  | 		if(GUI.changed) | |||
|  | 		{ | |||
|  | 			EditorPrefs.SetBool("CFX_ShowAsToolbox", pref_ShowAsToolbox); | |||
|  | 			this.Close(); | |||
|  | 			CFXEasyEditor.ShowWindow(); | |||
|  | 		} | |||
|  | 		GUILayout.EndHorizontal(); | |||
|  | 		GUILayout.Label("Easily change properties of any Particle System!", EditorStyles.miniLabel); | |||
|  | 		 | |||
|  | 	//---------------------------------------------------------------- | |||
|  | 		 | |||
|  | 		pref_IncludeChildren = GUILayout.Toggle(pref_IncludeChildren, new GUIContent("Include Children", "If checked, changes will affect every Particle Systems from each child of the selected GameObject(s)")); | |||
|  | 		if(GUI.changed) | |||
|  | 		{ | |||
|  | 			EditorPrefs.SetBool("CFX_IncludeChildren", pref_IncludeChildren); | |||
|  | 			UpdateSelectionCount(); | |||
|  | 		} | |||
|  | 
 | |||
|  | 		GUILayout.Label(string.Format("{0} selected Particle System{1}", SelectedParticleSystemsCount, SelectedParticleSystemsCount > 1 ? "s" : ""), EditorStyles.helpBox); | |||
|  | 		 | |||
|  | 		EditorGUILayout.BeginHorizontal(); | |||
|  | 		 | |||
|  | 		GUILayout.Label("Test effect(s):"); | |||
|  | 		using(new EditorGUI.DisabledScope(SelectedParticleSystemsCount <= 0)) | |||
|  | 		{ | |||
|  | 
 | |||
|  | 			if(GUILayout.Button("Play", EditorStyles.miniButtonLeft, GUILayout.Width(50f))) | |||
|  | 			{ | |||
|  | 				foreach(GameObject go in Selection.gameObjects) | |||
|  | 				{ | |||
|  | 					ParticleSystem[] systems = go.GetComponents<ParticleSystem>(); | |||
|  | 					if(systems.Length == 0) continue; | |||
|  | 					foreach(ParticleSystem system in systems) | |||
|  | 						system.Play(pref_IncludeChildren); | |||
|  | 				} | |||
|  | 			} | |||
|  | 			if(GUILayout.Button("Pause", EditorStyles.miniButtonMid, GUILayout.Width(50f))) | |||
|  | 			{ | |||
|  | 				foreach(GameObject go in Selection.gameObjects) | |||
|  | 				{ | |||
|  | 					ParticleSystem[] systems = go.GetComponents<ParticleSystem>(); | |||
|  | 					if(systems.Length == 0) continue; | |||
|  | 					foreach(ParticleSystem system in systems) | |||
|  | 						system.Pause(pref_IncludeChildren); | |||
|  | 				} | |||
|  | 			} | |||
|  | 			if(GUILayout.Button("Stop", EditorStyles.miniButtonMid, GUILayout.Width(50f))) | |||
|  | 			{ | |||
|  | 				foreach(GameObject go in Selection.gameObjects) | |||
|  | 				{ | |||
|  | 					ParticleSystem[] systems = go.GetComponents<ParticleSystem>(); | |||
|  | 					if(systems.Length == 0) continue; | |||
|  | 					foreach(ParticleSystem system in systems) | |||
|  | 						system.Stop(pref_IncludeChildren); | |||
|  | 				} | |||
|  | 			} | |||
|  | 			if(GUILayout.Button("Clear", EditorStyles.miniButtonRight, GUILayout.Width(50f))) | |||
|  | 			{ | |||
|  | 				foreach(GameObject go in Selection.gameObjects) | |||
|  | 				{ | |||
|  | 					ParticleSystem[] systems = go.GetComponents<ParticleSystem>(); | |||
|  | 					if(systems.Length == 0) continue; | |||
|  | 					foreach(ParticleSystem system in systems) | |||
|  | 					{ | |||
|  | 						system.Stop(pref_IncludeChildren); | |||
|  | 						system.Clear(pref_IncludeChildren); | |||
|  | 					} | |||
|  | 				} | |||
|  | 			} | |||
|  | 		} | |||
|  | 		 | |||
|  | 		GUILayout.FlexibleSpace(); | |||
|  | 		EditorGUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 		//---------------------------------------------------------------- | |||
|  | 
 | |||
|  | 		//Separator | |||
|  | 		GUISeparator(); | |||
|  | 		//GUILayout.Box("",GUILayout.Width(this.position.width - 12), GUILayout.Height(3)); | |||
|  | 		 | |||
|  | 		basicFoldout = EditorGUILayout.Foldout(basicFoldout, "QUICK EDIT", true); | |||
|  | 		if(basicFoldout) | |||
|  | 		{ | |||
|  | 			GUILayout.Space(4); | |||
|  | 
 | |||
|  | 			//---------------------------------------------------------------- | |||
|  | 
 | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			if(GUILayout.Button(new GUIContent("Scale Size", "Changes the size of the Particle System(s) and other values accordingly (speed, gravity, etc.)"), GUILayout.Width(120))) | |||
|  | 			{ | |||
|  | 				applyScale(); | |||
|  | 			} | |||
|  | 			GUILayout.Label("Multiplier:",GUILayout.Width(110)); | |||
|  | 			ScalingValue = EditorGUILayout.FloatField(ScalingValue,GUILayout.Width(50)); | |||
|  | 			if(ScalingValue <= 0) ScalingValue = 0.1f; | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 			 | |||
|  | 		//---------------------------------------------------------------- | |||
|  | 			 | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			if(GUILayout.Button(new GUIContent("Set Speed", "Changes the simulation speed of the Particle System(s)\n1 = default speed"), GUILayout.Width(120))) | |||
|  | 			{ | |||
|  | 				applySpeed(); | |||
|  | 			} | |||
|  | 			GUILayout.Label("Speed:",GUILayout.Width(110)); | |||
|  | 			LTScalingValue = EditorGUILayout.FloatField(LTScalingValue,GUILayout.Width(50)); | |||
|  | 			if(LTScalingValue < 0.0f) LTScalingValue = 0.0f; | |||
|  | 			else if(LTScalingValue > 9999) LTScalingValue = 9999; | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 			 | |||
|  | 		//---------------------------------------------------------------- | |||
|  | 			 | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			if(GUILayout.Button(new GUIContent("Set Duration", "Changes the duration of the Particle System(s)"), GUILayout.Width(120))) | |||
|  | 			{ | |||
|  | 				applyDuration(); | |||
|  | 			} | |||
|  | 			GUILayout.Label("Duration (sec):",GUILayout.Width(110)); | |||
|  | 			DurationValue = EditorGUILayout.FloatField(DurationValue,GUILayout.Width(50)); | |||
|  | 			if(DurationValue < 0.1f) DurationValue = 0.1f; | |||
|  | 			else if(DurationValue > 9999) DurationValue = 9999; | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 			 | |||
|  | 		//---------------------------------------------------------------- | |||
|  | 			 | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			if(GUILayout.Button(new GUIContent("Set Delay", "Changes the delay of the Particle System(s)"), GUILayout.Width(120))) | |||
|  | 			{ | |||
|  | 				applyDelay(); | |||
|  | 			} | |||
|  | 			GUILayout.Label("Delay :",GUILayout.Width(110)); | |||
|  | 			DelayValue = EditorGUILayout.FloatField(DelayValue,GUILayout.Width(50)); | |||
|  | 			if(DelayValue < 0.0f) DelayValue = 0.0f; | |||
|  | 			else if(DelayValue > 9999f) DelayValue = 9999f; | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 			 | |||
|  | 		//---------------------------------------------------------------- | |||
|  | 			 | |||
|  | 			GUILayout.Space(2); | |||
|  | 			 | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			if(GUILayout.Button(new GUIContent("Loop", "Loop the effect (might not work properly on some effects such as explosions)"), EditorStyles.miniButtonLeft)) | |||
|  | 			{ | |||
|  | 				loopEffect(true); | |||
|  | 			} | |||
|  | 			if(GUILayout.Button(new GUIContent("Unloop", "Remove looping from the effect"), EditorStyles.miniButtonRight)) | |||
|  | 			{ | |||
|  | 				loopEffect(false); | |||
|  | 			} | |||
|  | 			if(GUILayout.Button(new GUIContent("Prewarm On", "Prewarm the effect (if looped)"), EditorStyles.miniButtonLeft)) | |||
|  | 			{ | |||
|  | 				prewarmEffect(true); | |||
|  | 			} | |||
|  | 			if(GUILayout.Button(new GUIContent("Prewarm Off", "Don't prewarm the effect (if looped)"), EditorStyles.miniButtonRight)) | |||
|  | 			{ | |||
|  | 				prewarmEffect(false); | |||
|  | 			} | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 			 | |||
|  | 			GUILayout.Space(2); | |||
|  | 		 | |||
|  | 	//---------------------------------------------------------------- | |||
|  | 		 | |||
|  | 		} | |||
|  | 
 | |||
|  | 		//Separator | |||
|  | 		GUISeparator(); | |||
|  | 		//GUILayout.Box("",GUILayout.Width(this.position.width - 12), GUILayout.Height(3)); | |||
|  | 		 | |||
|  | 		EditorGUI.BeginChangeCheck(); | |||
|  | 		colorFoldout = EditorGUILayout.Foldout(colorFoldout, "COLOR EDIT", true); | |||
|  | 		if(colorFoldout) | |||
|  | 		{ | |||
|  | 			GUILayout.Space(4); | |||
|  | 
 | |||
|  | 			//---------------------------------------------------------------- | |||
|  | 
 | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			if(GUILayout.Button(new GUIContent("Set Start Color(s)", "Changes the color(s) of the Particle System(s)\nSecond Color is used when Start Color is 'Random Between Two Colors'."),GUILayout.Width(120))) | |||
|  | 			{ | |||
|  | 				applyColor(); | |||
|  | 			} | |||
|  | 			ColorValue = EditorGUILayout.ColorField(ColorValue); | |||
|  | 			ColorValue2 = EditorGUILayout.ColorField(ColorValue2); | |||
|  | 			AffectAlpha = GUILayout.Toggle(AffectAlpha, new GUIContent("Alpha", "If checked, the alpha value will also be changed")); | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 			//---------------------------------------------------------------- | |||
|  | 
 | |||
|  | 			GUILayout.Space(8); | |||
|  | 
 | |||
|  | 			using(new EditorGUI.DisabledScope(!TintStartColor && !TintColorModule && !TintColorSpeedModule && !TintTrailsModule && !TintCustomData1 && !TintCustomData2)) | |||
|  | 			{ | |||
|  | 				GUILayout.BeginHorizontal(); | |||
|  | 				if(GUILayout.Button(new GUIContent("Tint Colors", "Colorize the Particle System(s) to a specific color, including gradients!\n(preserving their saturation and value)"), GUILayout.Width(120))) | |||
|  | 				{ | |||
|  | 					tintColor(); | |||
|  | 				} | |||
|  | 				TintColorValue = EditorGUILayout.ColorField(TintColorValue); | |||
|  | 				TintColorValue = HSLColor.FromRGBA(TintColorValue).VividColor(); | |||
|  | 				GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 				//---------------------------------------------------------------- | |||
|  | 
 | |||
|  | 				GUILayout.BeginHorizontal(); | |||
|  | 				if(GUILayout.Button(new GUIContent("Hue Shift", "Tints the colors of the Particle System(s) by shifting the original hues by a value\n(preserving differences between colors)"), GUILayout.Width(120))) | |||
|  | 				{ | |||
|  | 					hueShift(); | |||
|  | 				} | |||
|  | 				TintHueShiftValue = EditorGUILayout.Slider(TintHueShiftValue, -180f, 180f); | |||
|  | 				GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 				//---------------------------------------------------------------- | |||
|  | 
 | |||
|  | 				GUILayout.BeginHorizontal(); | |||
|  | 				if(GUILayout.Button(new GUIContent("Saturation Shift", "Change the saturation of the colors of the Particle System(s)\n(preserving their hue and value)"), GUILayout.Width(120))) | |||
|  | 				{ | |||
|  | 					satShift(); | |||
|  | 				} | |||
|  | 				SatShiftValue = EditorGUILayout.Slider(SatShiftValue, -1, 1); | |||
|  | 				GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 				//---------------------------------------------------------------- | |||
|  | 
 | |||
|  | 				GUILayout.BeginHorizontal(); | |||
|  | 				if(GUILayout.Button(new GUIContent("Value Shift", "Change the value of the colors of the Particle System(s)\n(preserving their hue and saturation)"), GUILayout.Width(120))) | |||
|  | 				{ | |||
|  | 					valShift(); | |||
|  | 				} | |||
|  | 				ValShiftValue = EditorGUILayout.Slider(ValShiftValue, -1, 1); | |||
|  | 				GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 				//---------------------------------------------------------------- | |||
|  | 
 | |||
|  | 				GUILayout.BeginHorizontal(); | |||
|  | 				if (GUILayout.Button(new GUIContent("Gamma -> Linear", "Converts the colors from Gamma to Linear color space"))) | |||
|  | 				{ | |||
|  | 					gammaToLinear(); | |||
|  | 				} | |||
|  | 				if (GUILayout.Button(new GUIContent("Linear -> Gamma", "Converts the colors from Linear to Gamma color space"))) | |||
|  | 				{ | |||
|  | 					linearToGamma(); | |||
|  | 				} | |||
|  | 				GUILayout.EndHorizontal(); | |||
|  | 			} | |||
|  | 
 | |||
|  | 			GUILayout.Space(4); | |||
|  | 		 | |||
|  | 		//---------------------------------------------------------------- | |||
|  | 			 | |||
|  | 			/* | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			GUILayout.Label("Add/Substract Lightness:"); | |||
|  | 			 | |||
|  | 			LightnessStep = EditorGUILayout.IntField(LightnessStep, GUILayout.Width(30)); | |||
|  | 			if(LightnessStep > 99) LightnessStep = 99; | |||
|  | 			else if(LightnessStep < 1) LightnessStep = 1; | |||
|  | 			GUILayout.Label("%"); | |||
|  | 			 | |||
|  | 			if(GUILayout.Button("-", EditorStyles.miniButtonLeft, GUILayout.Width(22))) | |||
|  | 			{ | |||
|  | 				addLightness(true); | |||
|  | 			} | |||
|  | 			if(GUILayout.Button("+", EditorStyles.miniButtonRight, GUILayout.Width(22))) | |||
|  | 			{ | |||
|  | 				addLightness(false); | |||
|  | 			} | |||
|  | 			GUILayout.FlexibleSpace(); | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 			*/ | |||
|  | 			 | |||
|  | 		//---------------------------------------------------------------- | |||
|  | 			 | |||
|  | 			GUILayout.Label("Color Modules to affect:"); | |||
|  | 			 | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			GUILayout.Space(4); | |||
|  | 			TintStartColor = GUILayout.Toggle(TintStartColor, new GUIContent("Start Color", "If checked, the \"Start Color\" value(s) will be affected."), EditorStyles.toolbarButton); | |||
|  | 			TintColorModule = GUILayout.Toggle(TintColorModule, new GUIContent("Color over Lifetime", "If checked, the \"Color over Lifetime\" value(s) will be affected."), EditorStyles.toolbarButton); | |||
|  | 			TintColorSpeedModule = GUILayout.Toggle(TintColorSpeedModule, new GUIContent("Color by Speed", "If checked, the \"Color by Speed\" value(s) will be affected."), EditorStyles.toolbarButton); | |||
|  | 			GUILayout.Space(4); | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			GUILayout.Space(4); | |||
|  | 			TintTrailsModule = GUILayout.Toggle(TintTrailsModule, new GUIContent("Trails", "If checked, the \"Trails\" value(s) will be affected."), EditorStyles.toolbarButton); | |||
|  | 			TintCustomData1 = GUILayout.Toggle(TintCustomData1, new GUIContent("Custom Data 1", "If checked, the \"Custom Data 1\" value(s) will be affected if they have been set to a color value."), EditorStyles.toolbarButton); | |||
|  | 			TintCustomData2 = GUILayout.Toggle(TintCustomData2, new GUIContent("Custom Data 2", "If checked, the \"Custom Data 2\" value(s) will be affected if they have been set to a color value."), EditorStyles.toolbarButton); | |||
|  | 			GUILayout.Space(4); | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 			TintLights = GUILayout.Toggle(TintLights, new GUIContent(" Tint Lights found in the effect's Hierarchy", "Will search for and tint any Lights found in the effect hierarchy.")); | |||
|  | 
 | |||
|  | 			GUILayout.Space(4); | |||
|  | 			 | |||
|  | 		//---------------------------------------------------------------- | |||
|  | 			 | |||
|  | 		} | |||
|  | 
 | |||
|  | 		GUISeparator(); | |||
|  | 		 | |||
|  | 	//---------------------------------------------------------------- | |||
|  | 		 | |||
|  | 		EditorGUI.BeginChangeCheck(); | |||
|  | 		copyFoldout = EditorGUILayout.Foldout(copyFoldout, "COPY MODULES", true); | |||
|  | 		if(copyFoldout) | |||
|  | 		{ | |||
|  | 			GUILayout.Space(4); | |||
|  | 
 | |||
|  | 			EditorGUILayout.HelpBox("Copy selected modules from a Particle System to others!", MessageType.Info); | |||
|  | 			 | |||
|  | 			GUILayout.Label("Source Particle System to copy from:"); | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			{ | |||
|  | 				EditorGUI.BeginChangeCheck(); | |||
|  | 				copyModulesSourceParticleSystem = (ParticleSystem)EditorGUILayout.ObjectField(copyModulesSourceParticleSystem, typeof(ParticleSystem), true); | |||
|  | 				if (GUILayout.Button("Get Selected", EditorStyles.miniButton)) | |||
|  | 				{ | |||
|  | 					if (Selection.activeGameObject != null) | |||
|  | 					{ | |||
|  | 						var ps = Selection.activeGameObject.GetComponent<ParticleSystem>(); | |||
|  | 						if (ps != null) | |||
|  | 						{ | |||
|  | 							copyModulesSourceParticleSystem = ps; | |||
|  | 						} | |||
|  | 					} | |||
|  | 				} | |||
|  | 				if (EditorGUI.EndChangeCheck()) | |||
|  | 				{ | |||
|  | 					if (copyModulesSourceParticleSystem != null) | |||
|  | 					{ | |||
|  | 						FetchParticleSystemModules(copyModulesSourceParticleSystem); | |||
|  | 						RefreshCurrentlyEnabledModules(copyModulesSourceParticleSystem, ref enabledModules); | |||
|  | 					} | |||
|  | 				} | |||
|  | 			} | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 			 | |||
|  | 			EditorGUILayout.LabelField("Modules to Copy:"); | |||
|  | 			 | |||
|  | 			GUILayout.Space(4); | |||
|  | 
 | |||
|  | 			DrawSelectableModules(ref selectedModules, ref enabledModules, copyModulesSourceParticleSystem); | |||
|  | 
 | |||
|  | 			/* | |||
|  | 
 | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			GUILayout.Space(8f); | |||
|  | 			GUISelectModule(modulesToCopy[0]); | |||
|  | 			GUISelectModule(modulesToCopy[1]); | |||
|  | 			GUISelectModule(modulesToCopy[2]); | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 			SelectModulesSpace(); | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			GUILayout.Space(8f); | |||
|  | #if UNITY_5_4_OR_NEWER | |||
|  | 			GUISelectModule(modulesToCopy[3]); | |||
|  | 			GUISelectModule(modulesToCopy[4]); | |||
|  | 			GUISelectModule(modulesToCopy[16]); | |||
|  | 			GUISelectModule(modulesToCopy[5]); | |||
|  | #else | |||
|  | 			GUISelectModule(modulesToCopy[3]); | |||
|  | 			GUISelectModule(modulesToCopy[4]); | |||
|  | 			GUISelectModule(modulesToCopy[5]); | |||
|  | #endif | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 			SelectModulesSpace(); | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			GUILayout.Space(8f); | |||
|  | 			GUISelectModule(modulesToCopy[6]); | |||
|  | 			GUISelectModule(modulesToCopy[7]); | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 			SelectModulesSpace(); | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			GUILayout.Space(8f); | |||
|  | 			GUISelectModule(modulesToCopy[8]); | |||
|  | 			GUISelectModule(modulesToCopy[9]); | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 			SelectModulesSpace(); | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			GUILayout.Space(8f); | |||
|  | 			GUISelectModule(modulesToCopy[10]); | |||
|  | 			GUISelectModule(modulesToCopy[11]); | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 			SelectModulesSpace(); | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			GUILayout.Space(8f); | |||
|  | 			GUISelectModule(modulesToCopy[12]); | |||
|  | #if UNITY_5_4_OR_NEWER | |||
|  | 			GUISelectModule(modulesToCopy[17]); | |||
|  | #endif | |||
|  | 			GUISelectModule(modulesToCopy[13]); | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 			SelectModulesSpace(); | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			GUILayout.Space(8f); | |||
|  | #if UNITY_5_5_OR_NEWER | |||
|  | 			GUISelectModule(modulesToCopy[20]); | |||
|  | 			GUISelectModule(modulesToCopy[19]); | |||
|  | 			GUISelectModule(modulesToCopy[18]); | |||
|  | #endif | |||
|  | 			GUISelectModule(modulesToCopy[14]); | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 			SelectModulesSpace(); | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			GUILayout.Space(8f); | |||
|  | 			GUISelectModule(modulesToCopy[15]); | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 			GUI.color = guiColor; | |||
|  | 
 | |||
|  | 			SelectModulesSpace(); | |||
|  | 
 | |||
|  | 			*/ | |||
|  | 
 | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			{ | |||
|  | 				GUILayout.FlexibleSpace(); | |||
|  | 				if (GUILayout.Button("Copy properties to\nselected Object(s)", GUILayout.Height(Mathf.Ceil(EditorGUIUtility.singleLineHeight * 2.1f)))) | |||
|  | 				{ | |||
|  | 					bool foundPs = false; | |||
|  | 					foreach (GameObject go in Selection.gameObjects) | |||
|  | 					{ | |||
|  | 						var system = go.GetComponent<ParticleSystem>(); | |||
|  | 						if (system != null) | |||
|  | 						{ | |||
|  | 							foundPs = true; | |||
|  | 							CopyModules(copyModulesSourceParticleSystem, system); | |||
|  | 						} | |||
|  | 					} | |||
|  | 
 | |||
|  | 					if (!foundPs) | |||
|  | 					{ | |||
|  | 						EditorApplication.Beep(); | |||
|  | 						Debug.LogWarning("Cartoon FX Easy Editor: No Particle System found in the selected GameObject(s)!"); | |||
|  | 					} | |||
|  | 				} | |||
|  | 			} | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 		} | |||
|  | 
 | |||
|  | 		/* | |||
|  | 
 | |||
|  | 		GUISeparator(); | |||
|  | 
 | |||
|  | 		// TODO full list of the Properties with saving/loading presets | |||
|  | 
 | |||
|  | 		mutateFoldout = EditorGUILayout.Foldout(mutateFoldout, "MUTATE MODULES", true); | |||
|  | 		if (mutateFoldout) | |||
|  | 		{ | |||
|  | 			GUILayout.Space(4); | |||
|  | 
 | |||
|  | 			DrawSelectableModules(ref selectedModulesMutate, ref enabledModulesMutate, selectedParticleSystem); | |||
|  | 
 | |||
|  | 			EditorGUI.BeginChangeCheck(); | |||
|  | 			float newValue = EditorGUILayout.Slider("<22> percent", Mathf.Floor(mutatePercentage * 100), 0, 100); | |||
|  | 			if (EditorGUI.EndChangeCheck()) | |||
|  | 			{ | |||
|  | 				mutatePercentage = newValue / 100f; | |||
|  | 			} | |||
|  | 
 | |||
|  | 			if (GUILayout.Button("Mutate Modules", GUILayout.Height(EditorGUIUtility.singleLineHeight*2.1f))) | |||
|  | 			{ | |||
|  | 				MutateModules(); | |||
|  | 			} | |||
|  | 		} | |||
|  | 
 | |||
|  | 		*/ | |||
|  | 
 | |||
|  | 		//---------------------------------------------------------------- | |||
|  | 
 | |||
|  | 		GUILayout.Space(8); | |||
|  | 
 | |||
|  | 		//Resize window if needed | |||
|  | 		if (Event.current.type == EventType.Repaint) | |||
|  | 		{ | |||
|  | 			float h = GUILayoutUtility.GetLastRect().yMax; | |||
|  | 			if (lastHeight != h) | |||
|  | 			{ | |||
|  | 				lastHeight = h; | |||
|  | 				this.minSize = new Vector2(300, h); | |||
|  | 				this.maxSize = new Vector2(300, h); | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | 
 | |||
|  | 	float lastHeight = 0; | |||
|  | 
 | |||
|  | 	void DrawSelectableModules(ref bool[] selected, ref bool[] enabled, ParticleSystem target) | |||
|  | 	{ | |||
|  | 		if (modulesToCopy != null) | |||
|  | 		{ | |||
|  | 			if (enabled == null || enabled.Length != modulesToCopy.Length) | |||
|  | 			{ | |||
|  | 				enabled = new bool[modulesToCopy.Length]; | |||
|  | 			} | |||
|  | 
 | |||
|  | 
 | |||
|  | 			// +1 for the Renderer component | |||
|  | 			if (selected == null || selected.Length != (modulesToCopy.Length + 1)) | |||
|  | 			{ | |||
|  | 				selected = new bool[modulesToCopy.Length + 1]; | |||
|  | 			} | |||
|  | 			int renderer = selected.Length - 1; | |||
|  | 
 | |||
|  | 			// quick select: | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			GUILayout.Label("Select:", GUILayout.Width(60)); | |||
|  | 			if (GUILayout.Button(" All ", EditorStyles.miniButton)) | |||
|  | 			{ | |||
|  | 				for (int i = 0; i < modulesToCopy.Length; i++) | |||
|  | 				{ | |||
|  | 					if (!pref_HideDisabledModulesCopy || enabled[i]) | |||
|  | 					{ | |||
|  | 						selected[i] = true; | |||
|  | 					} | |||
|  | 					selected[renderer] = true; | |||
|  | 				} | |||
|  | 			} | |||
|  | 
 | |||
|  | 			var guiColor = GUI.color; | |||
|  | 			GUI.color *= new Color(1.0f, 0.5f, 0.5f); | |||
|  | 			if (GUILayout.Button(" None ", EditorStyles.miniButton)) | |||
|  | 			{ | |||
|  | 				for (int i = 0; i < modulesToCopy.Length; i++) | |||
|  | 				{ | |||
|  | 					selected[i] = false; | |||
|  | 				} | |||
|  | 				selected[renderer] = false; | |||
|  | 			} | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 			GUI.color = guiColor; | |||
|  | 
 | |||
|  | 			GUILayout.BeginHorizontal(); | |||
|  | 			GUILayout.Label(" ", GUILayout.Width(60)); | |||
|  | 			if (GUILayout.Button(" Size ", EditorStyles.miniButton)) | |||
|  | 			{ | |||
|  | 				for (int i = 0; i < modulesToCopy.Length; i++) | |||
|  | 				{ | |||
|  | 					switch (modulesToCopy[i].serializedPropertyPath) | |||
|  | 					{ | |||
|  | 						case "SizeModule": | |||
|  | 						case "SizeBySpeedModule": | |||
|  | 							selected[i] = true; | |||
|  | 							break; | |||
|  | 					} | |||
|  | 				} | |||
|  | 			} | |||
|  | 			if (GUILayout.Button(" Movement ", EditorStyles.miniButton)) | |||
|  | 			{ | |||
|  | 				for (int i = 0; i < modulesToCopy.Length; i++) | |||
|  | 				{ | |||
|  | 					switch (modulesToCopy[i].serializedPropertyPath) | |||
|  | 					{ | |||
|  | 						case "VelocityModule": | |||
|  | 						case "InheritVelocityModule": | |||
|  | 						case "ForceModule": | |||
|  | 						case "ExternalForcesModule": | |||
|  | 						case "ClampVelocityModule": | |||
|  | 						case "NoiseModule": | |||
|  | 						case "CollisionModule": | |||
|  | 							selected[i] = true; | |||
|  | 							break; | |||
|  | 					} | |||
|  | 				} | |||
|  | 			} | |||
|  | 			if (GUILayout.Button(" Color/Appearance ", EditorStyles.miniButton)) | |||
|  | 			{ | |||
|  | 				for (int i = 0; i < modulesToCopy.Length; i++) | |||
|  | 				{ | |||
|  | 					switch (modulesToCopy[i].serializedPropertyPath) | |||
|  | 					{ | |||
|  | 						case "ColorModule": | |||
|  | 						case "ColorBySpeedModule": | |||
|  | 						case "TrailModule": | |||
|  | 						case "LightsModule": | |||
|  | 						case "UVModule": | |||
|  | 							selected[i] = true; | |||
|  | 							break; | |||
|  | 					} | |||
|  | 					selected[renderer] = true; | |||
|  | 				} | |||
|  | 			} | |||
|  | 			GUILayout.EndHorizontal(); | |||
|  | 
 | |||
|  | 			using (new EditorGUI.DisabledScope(target == null)) | |||
|  | 			{ | |||
|  | 				EditorGUI.BeginChangeCheck(); | |||
|  | 				pref_HideDisabledModulesCopy = GUILayout.Toggle(pref_HideDisabledModulesCopy, new GUIContent(" Hide disabled modules", "Will hide modules that are disabled on the current source Particle System")); | |||
|  | 				if (EditorGUI.EndChangeCheck()) | |||
|  | 				{ | |||
|  | 					EditorPrefs.SetBool("CFX_HideDisabledModulesCopy", pref_HideDisabledModulesCopy); | |||
|  | 					RefreshCurrentlyEnabledModules(target, ref enabled); | |||
|  | 				} | |||
|  | 			} | |||
|  | 
 | |||
|  | 			const int row = 4; | |||
|  | 			const int padding = 4; | |||
|  | 			for (int i = 0; i < modulesToCopy.Length; i += row) | |||
|  | 			{ | |||
|  | 				GUILayout.BeginHorizontal(); | |||
|  | 				{ | |||
|  | 					GUILayout.Space(padding); | |||
|  | 					for (int j = 0; j < row; j++) | |||
|  | 					{ | |||
|  | 						if (i+j < modulesLabels.Length) | |||
|  | 						{ | |||
|  | 							var col = GUI.color; | |||
|  | 
 | |||
|  | 							// special case: renderer | |||
|  | 							/* | |||
|  | 							if (i+j == modulesLabels.Length-1) | |||
|  | 							{ | |||
|  | 								if (selectedModuleRenderer) GUI.color *= Color.cyan; | |||
|  | 								selectedModuleRenderer = GUILayout.Toggle(selectedModuleRenderer, modulesLabels[i+j], EditorStyles.toolbarButton); | |||
|  | 							} | |||
|  | 							else | |||
|  | 							*/ | |||
|  | 							{ | |||
|  | 								bool enbl = (i+j) >= enabled.Length ? true : enabled[i+j]; | |||
|  | 								if (pref_HideDisabledModulesCopy && !enbl) | |||
|  | 								{ | |||
|  | 									continue; | |||
|  | 								} | |||
|  | 								if (selected[i+j]) GUI.color *= Color.cyan; | |||
|  | 								selected[i+j] = GUILayout.Toggle(selected[i+j], modulesLabels[i+j], EditorStyles.toolbarButton); | |||
|  | 							} | |||
|  | 							GUI.color = col; | |||
|  | 						} | |||
|  | 					} | |||
|  | 					GUILayout.Space(padding); | |||
|  | 				} | |||
|  | 				GUILayout.EndHorizontal(); | |||
|  | 			} | |||
|  | 		} | |||
|  | 		else | |||
|  | 		{ | |||
|  | 			EditorGUILayout.HelpBox("Select a Particle System to initialize the module list.", MessageType.Info); | |||
|  | 		} | |||
|  | 	} | |||
|  | 
 | |||
|  | 	void RefreshCurrentlyEnabledModules(ParticleSystem source, ref bool[] enabledModules) | |||
|  | 	{ | |||
|  | 		if (modulesToCopy == null) | |||
|  | 		{ | |||
|  | 			return; | |||
|  | 		} | |||
|  | 
 | |||
|  | 		if (enabledModules == null || enabledModules.Length != modulesToCopy.Length) | |||
|  | 		{ | |||
|  | 			// note: no need for extra slot for renderer, consider it always enabled | |||
|  | 			enabledModules = new bool[modulesToCopy.Length]; | |||
|  | 		} | |||
|  | 
 | |||
|  | 		if (source != null) | |||
|  | 		{ | |||
|  | 			var so = new SerializedObject(source); | |||
|  | 			for (int i = 0; i < modulesToCopy.Length; i++) | |||
|  | 			{ | |||
|  | 				enabledModules[i] = modulesToCopy[i].CheckIfEnabledInSource(so); | |||
|  | 			} | |||
|  | 		} | |||
|  | 		else | |||
|  | 		{ | |||
|  | 			for (int i = 0; i < enabledModules.Length; i++) | |||
|  | 			{ | |||
|  | 				enabledModules[i] = true; | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | 
 | |||
|  | 	//Loop effects | |||
|  | 	private void loopEffect(bool setLoop) | |||
|  | 	{ | |||
|  | 		foreach(GameObject go in Selection.gameObjects) | |||
|  | 		{ | |||
|  | 			//Scale Shuriken Particles Values | |||
|  | 			ParticleSystem[] systems; | |||
|  | 			if(pref_IncludeChildren) | |||
|  | 				systems = go.GetComponentsInChildren<ParticleSystem>(true); | |||
|  | 			else | |||
|  | 				systems = go.GetComponents<ParticleSystem>(); | |||
|  | 			 | |||
|  | 			foreach(ParticleSystem ps in systems) | |||
|  | 			{ | |||
|  | 				SerializedObject so = new SerializedObject(ps); | |||
|  | 				so.FindProperty("looping").boolValue = setLoop; | |||
|  | 				so.ApplyModifiedProperties(); | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | 	 | |||
|  | 	//Prewarm effects | |||
|  | 	private void prewarmEffect(bool setPrewarm) | |||
|  | 	{ | |||
|  | 		foreach(GameObject go in Selection.gameObjects) | |||
|  | 		{ | |||
|  | 			//Scale Shuriken Particles Values | |||
|  | 			ParticleSystem[] systems; | |||
|  | 			if(pref_IncludeChildren) | |||
|  | 				systems = go.GetComponentsInChildren<ParticleSystem>(true); | |||
|  | 			else | |||
|  | 				systems = go.GetComponents<ParticleSystem>(); | |||
|  | 			 | |||
|  | 			foreach(ParticleSystem ps in systems) | |||
|  | 			{ | |||
|  | 				SerializedObject so = new SerializedObject(ps); | |||
|  | 				so.FindProperty("prewarm").boolValue = setPrewarm; | |||
|  | 				so.ApplyModifiedProperties(); | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | 	 | |||
|  | 	//Scale Size | |||
|  | 	private void applyScale() | |||
|  | 	{ | |||
|  | 		Undo.IncrementCurrentGroup(); | |||
|  | 		int groupId = Undo.GetCurrentGroup(); | |||
|  | 
 | |||
|  | 		foreach(GameObject go in Selection.gameObjects) | |||
|  | 		{ | |||
|  | 			//Scale Shuriken Particles Values | |||
|  | 			ParticleSystem[] systems; | |||
|  | 			if(pref_IncludeChildren) | |||
|  | 				systems = go.GetComponentsInChildren<ParticleSystem>(true); | |||
|  | 			else | |||
|  | 				systems = go.GetComponents<ParticleSystem>(); | |||
|  | 			 | |||
|  | 			foreach(ParticleSystem ps in systems) | |||
|  | 			{ | |||
|  | 				Undo.RegisterCompleteObjectUndo(ps, "Apply Particle Scale"); | |||
|  | 				Undo.RegisterCompleteObjectUndo(ps.transform, "Apply Particle Scale"); | |||
|  | 				ScaleParticleValues(ps, go); | |||
|  | 			} | |||
|  | 			 | |||
|  | 			//Scale Lights' range | |||
|  | 			Light[] lights = go.GetComponentsInChildren<Light>(); | |||
|  | 			foreach(Light light in lights) | |||
|  | 			{ | |||
|  | 				Undo.RegisterCompleteObjectUndo(light, "Apply Particle Scale"); | |||
|  | 				Undo.RegisterCompleteObjectUndo(light.transform, "Apply Particle Scale"); | |||
|  | 				light.range *= ScalingValue; | |||
|  | 				light.transform.localPosition *= ScalingValue; | |||
|  | 			} | |||
|  | 		} | |||
|  | 
 | |||
|  | 		Undo.CollapseUndoOperations(groupId); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	//Change Color | |||
|  | 	private void applyColor() | |||
|  | 	{ | |||
|  | 		foreach(GameObject go in Selection.gameObjects) | |||
|  | 		{ | |||
|  | 			ParticleSystem[] systems; | |||
|  | 			if(pref_IncludeChildren) | |||
|  | 				systems = go.GetComponentsInChildren<ParticleSystem>(true); | |||
|  | 			else | |||
|  | 				systems = go.GetComponents<ParticleSystem>(); | |||
|  | 			 | |||
|  | 			foreach(ParticleSystem ps in systems) | |||
|  | 			{ | |||
|  | 				SerializedObject psSerial = new SerializedObject(ps); | |||
|  | 				if(!AffectAlpha) | |||
|  | 				{ | |||
|  | 					psSerial.FindProperty("InitialModule.startColor.maxColor").colorValue = new Color(ColorValue.r, ColorValue.g, ColorValue.b, psSerial.FindProperty("InitialModule.startColor.maxColor").colorValue.a); | |||
|  | 					psSerial.FindProperty("InitialModule.startColor.minColor").colorValue = new Color(ColorValue2.r, ColorValue2.g, ColorValue2.b, psSerial.FindProperty("InitialModule.startColor.minColor").colorValue.a); | |||
|  | 				} | |||
|  | 				else | |||
|  | 				{ | |||
|  | 					psSerial.FindProperty("InitialModule.startColor.maxColor").colorValue = ColorValue; | |||
|  | 					psSerial.FindProperty("InitialModule.startColor.minColor").colorValue = ColorValue2; | |||
|  | 				} | |||
|  | 				psSerial.ApplyModifiedProperties(); | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | 	 | |||
|  | 	//TINT COLORS ================================================================================================================================ | |||
|  | 	 | |||
|  | 	private void tintColor() | |||
|  | 	{ | |||
|  | 		float hue = HSLColor.FromRGBA(TintColorValue).h; | |||
|  | 		GenericProcessColors(color => | |||
|  | 		{ | |||
|  | 			return HSLColor.FromRGBA(color).ColorWithHue(hue, false); | |||
|  | 		}); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	private void hueShift() | |||
|  | 	{ | |||
|  | 		GenericProcessColors(color => | |||
|  | 		{ | |||
|  | 			return HSLColor.FromRGBA(color).ColorWithHue(TintHueShiftValue, true); | |||
|  | 		}); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	private void satShift() | |||
|  | 	{ | |||
|  | 		GenericProcessColors(color => | |||
|  | 		{ | |||
|  | 			return HSLColor.FromRGBA(color).ColorWithSaturationOffset(SatShiftValue); | |||
|  | 		}); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	private void valShift() | |||
|  | 	{ | |||
|  | 		GenericProcessColors(color => | |||
|  | 		{ | |||
|  | 			return HSLColor.FromRGBA(color).ColorWithLightnessOffset(ValShiftValue); | |||
|  | 		}); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	private void GenericTintColorProperty(SerializedProperty colorProperty, float hue, bool shift) | |||
|  | 	{ | |||
|  | 		GenericEditColorProperty(colorProperty, color => | |||
|  | 		{ | |||
|  | 			return HSLColor.FromRGBA(color).ColorWithHue(hue, shift); | |||
|  | 		}); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	private void GenericEditGradient(SerializedProperty gradientProperty, System.Func<Color, Color> callback) | |||
|  | 	{ | |||
|  | 		gradientProperty.FindPropertyRelative("key0").colorValue = callback(gradientProperty.FindPropertyRelative("key0").colorValue); | |||
|  | 		gradientProperty.FindPropertyRelative("key1").colorValue = callback(gradientProperty.FindPropertyRelative("key1").colorValue); | |||
|  | 		gradientProperty.FindPropertyRelative("key2").colorValue = callback(gradientProperty.FindPropertyRelative("key2").colorValue); | |||
|  | 		gradientProperty.FindPropertyRelative("key3").colorValue = callback(gradientProperty.FindPropertyRelative("key3").colorValue); | |||
|  | 		gradientProperty.FindPropertyRelative("key4").colorValue = callback(gradientProperty.FindPropertyRelative("key4").colorValue); | |||
|  | 		gradientProperty.FindPropertyRelative("key5").colorValue = callback(gradientProperty.FindPropertyRelative("key5").colorValue); | |||
|  | 		gradientProperty.FindPropertyRelative("key6").colorValue = callback(gradientProperty.FindPropertyRelative("key6").colorValue); | |||
|  | 		gradientProperty.FindPropertyRelative("key7").colorValue = callback(gradientProperty.FindPropertyRelative("key7").colorValue); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	private void gammaToLinear() | |||
|  | 	{ | |||
|  | 		GenericProcessColors(color => | |||
|  | 		{ | |||
|  | 			return color.gamma; | |||
|  | 		}); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	private void linearToGamma() | |||
|  | 	{ | |||
|  | 		GenericProcessColors(color => | |||
|  | 		{ | |||
|  | 			return color.linear; | |||
|  | 		}); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	private void GenericProcessColors(System.Func<Color, Color> callback) | |||
|  | 	{ | |||
|  | 		foreach (GameObject go in Selection.gameObjects) | |||
|  | 		{ | |||
|  | 			ParticleSystem[] systems; | |||
|  | 			if (pref_IncludeChildren) | |||
|  | 				systems = go.GetComponentsInChildren<ParticleSystem>(true); | |||
|  | 			else | |||
|  | 				systems = go.GetComponents<ParticleSystem>(); | |||
|  | 
 | |||
|  | 			foreach (ParticleSystem ps in systems) | |||
|  | 			{ | |||
|  | 				SerializedObject psSerial = new SerializedObject(ps); | |||
|  | 
 | |||
|  | 				if (TintStartColor)					GenericEditColorProperty(psSerial.FindProperty("InitialModule.startColor"), callback); | |||
|  | 				if (TintColorModule)				GenericEditColorProperty(psSerial.FindProperty("ColorModule.gradient"), callback); | |||
|  | 				if (TintColorSpeedModule)			GenericEditColorProperty(psSerial.FindProperty("ColorBySpeedModule.gradient"), callback); | |||
|  | 				if (TintCustomData1)				GenericEditColorProperty(psSerial.FindProperty("CustomDataModule.color0"), callback); | |||
|  | 				if (TintCustomData2)				GenericEditColorProperty(psSerial.FindProperty("CustomDataModule.color1"), callback); | |||
|  | 
 | |||
|  | 				psSerial.ApplyModifiedProperties(); | |||
|  | 			} | |||
|  | 
 | |||
|  | 			if (TintLights) | |||
|  | 			{ | |||
|  | 				var lights = go.GetComponentsInChildren<Light>(); | |||
|  | 				foreach (var light in lights) | |||
|  | 				{ | |||
|  | 					var psLight = new SerializedObject(light); | |||
|  | 					var colorProperty = psLight.FindProperty("m_Color"); | |||
|  | 					colorProperty.colorValue = callback(colorProperty.colorValue); | |||
|  | 					psLight.ApplyModifiedProperties(); | |||
|  | 				} | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | 
 | |||
|  | 	private void GenericEditColorProperty(SerializedProperty colorProperty, System.Func<Color, Color> callback) | |||
|  | 	{ | |||
|  | 		int state = colorProperty.FindPropertyRelative("minMaxState").intValue; | |||
|  | 		switch (state) | |||
|  | 		{ | |||
|  | 			//Constant Color | |||
|  | 			case 0: | |||
|  | 				colorProperty.FindPropertyRelative("maxColor").colorValue = callback(colorProperty.FindPropertyRelative("maxColor").colorValue); | |||
|  | 				break; | |||
|  | 
 | |||
|  | 			//Gradient | |||
|  | 			case 1: | |||
|  | 				GenericEditGradient(colorProperty.FindPropertyRelative("maxGradient"), callback); | |||
|  | 				break; | |||
|  | 
 | |||
|  | 			//Random between 2 Colors | |||
|  | 			case 2: | |||
|  | 				colorProperty.FindPropertyRelative("minColor").colorValue = callback(colorProperty.FindPropertyRelative("minColor").colorValue); | |||
|  | 				colorProperty.FindPropertyRelative("maxColor").colorValue = callback(colorProperty.FindPropertyRelative("maxColor").colorValue); | |||
|  | 				break; | |||
|  | 
 | |||
|  | 			//Random between 2 Gradients | |||
|  | 			case 3: | |||
|  | 				GenericEditGradient(colorProperty.FindPropertyRelative("maxGradient"), callback); | |||
|  | 				GenericEditGradient(colorProperty.FindPropertyRelative("minGradient"), callback); | |||
|  | 				break; | |||
|  | 		} | |||
|  | 	} | |||
|  | 	 | |||
|  | 	//LIGHTNESS OFFSET ================================================================================================================================ | |||
|  | 	 | |||
|  | 	private void addLightness(bool substract) | |||
|  | 	{ | |||
|  | 		if(!TintStartColor && !TintColorModule && !TintColorSpeedModule) | |||
|  | 		{ | |||
|  | 			Debug.LogWarning("Cartoon FX Easy Editor: You must toggle at least one of the three Color Modules to be able to change lightness!"); | |||
|  | 			return; | |||
|  | 		} | |||
|  | 		 | |||
|  | 		float lightness = (float)(LightnessStep/100f); | |||
|  | 		if(substract) | |||
|  | 			lightness *= -1f; | |||
|  | 		 | |||
|  | 		foreach(GameObject go in Selection.gameObjects) | |||
|  | 		{ | |||
|  | 			ParticleSystem[] systems; | |||
|  | 			if(pref_IncludeChildren) | |||
|  | 				systems = go.GetComponentsInChildren<ParticleSystem>(true); | |||
|  | 			else | |||
|  | 				systems = go.GetComponents<ParticleSystem>(); | |||
|  | 			 | |||
|  | 			foreach(ParticleSystem ps in systems) | |||
|  | 			{ | |||
|  | 				SerializedObject psSerial = new SerializedObject(ps); | |||
|  | 				 | |||
|  | 				if(TintStartColor) | |||
|  | 					GenericAddLightness(psSerial.FindProperty("InitialModule.startColor"), lightness); | |||
|  | 				 | |||
|  | 				if(TintColorModule) | |||
|  | 					GenericAddLightness(psSerial.FindProperty("ColorModule.gradient"), lightness); | |||
|  | 				 | |||
|  | 				if(TintColorSpeedModule) | |||
|  | 					GenericAddLightness(psSerial.FindProperty("ColorBySpeedModule.gradient"), lightness); | |||
|  | 				 | |||
|  | 				psSerial.ApplyModifiedProperties(); | |||
|  | 				psSerial.Update(); | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | 	 | |||
|  | 	private void GenericAddLightness(SerializedProperty colorProperty, float lightness) | |||
|  | 	{ | |||
|  | 		int state = colorProperty.FindPropertyRelative("minMaxState").intValue; | |||
|  | 		switch(state) | |||
|  | 		{ | |||
|  | 			//Constant Color | |||
|  | 		case 0: | |||
|  | 			colorProperty.FindPropertyRelative("maxColor").colorValue = HSLColor.FromRGBA(colorProperty.FindPropertyRelative("maxColor").colorValue).ColorWithLightnessOffset(lightness); | |||
|  | 			break; | |||
|  | 			 | |||
|  | 			//Gradient | |||
|  | 		case 1: | |||
|  | 			AddLightnessGradient(colorProperty.FindPropertyRelative("maxGradient"), lightness); | |||
|  | 			break; | |||
|  | 			 | |||
|  | 			//Random between 2 Colors | |||
|  | 		case 2: | |||
|  | 			colorProperty.FindPropertyRelative("minColor").colorValue = HSLColor.FromRGBA(colorProperty.FindPropertyRelative("minColor").colorValue).ColorWithLightnessOffset(lightness); | |||
|  | 			colorProperty.FindPropertyRelative("maxColor").colorValue = HSLColor.FromRGBA(colorProperty.FindPropertyRelative("maxColor").colorValue).ColorWithLightnessOffset(lightness); | |||
|  | 			break; | |||
|  | 			 | |||
|  | 			//Random between 2 Gradients | |||
|  | 		case 3: | |||
|  | 			AddLightnessGradient(colorProperty.FindPropertyRelative("maxGradient"), lightness); | |||
|  | 			AddLightnessGradient(colorProperty.FindPropertyRelative("minGradient"), lightness); | |||
|  | 			break; | |||
|  | 		} | |||
|  | 	} | |||
|  | 	 | |||
|  | 	private void AddLightnessGradient(SerializedProperty gradientProperty, float lightness) | |||
|  | 	{ | |||
|  | 		gradientProperty.FindPropertyRelative("key0").colorValue = HSLColor.FromRGBA(gradientProperty.FindPropertyRelative("key0").colorValue).ColorWithLightnessOffset(lightness); | |||
|  | 		gradientProperty.FindPropertyRelative("key1").colorValue = HSLColor.FromRGBA(gradientProperty.FindPropertyRelative("key1").colorValue).ColorWithLightnessOffset(lightness); | |||
|  | 		gradientProperty.FindPropertyRelative("key2").colorValue = HSLColor.FromRGBA(gradientProperty.FindPropertyRelative("key2").colorValue).ColorWithLightnessOffset(lightness); | |||
|  | 		gradientProperty.FindPropertyRelative("key3").colorValue = HSLColor.FromRGBA(gradientProperty.FindPropertyRelative("key3").colorValue).ColorWithLightnessOffset(lightness); | |||
|  | 		gradientProperty.FindPropertyRelative("key4").colorValue = HSLColor.FromRGBA(gradientProperty.FindPropertyRelative("key4").colorValue).ColorWithLightnessOffset(lightness); | |||
|  | 		gradientProperty.FindPropertyRelative("key5").colorValue = HSLColor.FromRGBA(gradientProperty.FindPropertyRelative("key5").colorValue).ColorWithLightnessOffset(lightness); | |||
|  | 		gradientProperty.FindPropertyRelative("key6").colorValue = HSLColor.FromRGBA(gradientProperty.FindPropertyRelative("key6").colorValue).ColorWithLightnessOffset(lightness); | |||
|  | 		gradientProperty.FindPropertyRelative("key7").colorValue = HSLColor.FromRGBA(gradientProperty.FindPropertyRelative("key7").colorValue).ColorWithLightnessOffset(lightness); | |||
|  | 	} | |||
|  | 	 | |||
|  | 	//RGB / HSL Conversions | |||
|  | 	private struct HSLColor | |||
|  | 	{ | |||
|  | 		public float h; | |||
|  | 		public float s; | |||
|  | 		public float l; | |||
|  | 		public float a; | |||
|  | 		 | |||
|  | 		public HSLColor(float h, float s, float l, float a) | |||
|  | 		{ | |||
|  | 			this.h = h; | |||
|  | 			this.s = s; | |||
|  | 			this.l = l; | |||
|  | 			this.a = a; | |||
|  | 		} | |||
|  | 		 | |||
|  | 		public HSLColor(float h, float s, float l) | |||
|  | 		{ | |||
|  | 			this.h = h; | |||
|  | 			this.s = s; | |||
|  | 			this.l = l; | |||
|  | 			this.a = 1f; | |||
|  | 		} | |||
|  | 		 | |||
|  | 		public HSLColor(Color c) | |||
|  | 		{ | |||
|  | 			HSLColor temp = FromRGBA(c); | |||
|  | 			h = temp.h; | |||
|  | 			s = temp.s; | |||
|  | 			l = temp.l; | |||
|  | 			a = temp.a; | |||
|  | 		} | |||
|  | 		 | |||
|  | 		public static HSLColor FromRGBA(Color c) | |||
|  | 		{ | |||
|  | 			float h, s, l, a; | |||
|  | 			a = c.a; | |||
|  | 			 | |||
|  | 			float cmin = Mathf.Min(Mathf.Min(c.r, c.g), c.b); | |||
|  | 			float cmax = Mathf.Max(Mathf.Max(c.r, c.g), c.b); | |||
|  | 			 | |||
|  | 			l = (cmin + cmax) / 2f; | |||
|  | 			 | |||
|  | 			if (cmin == cmax) | |||
|  | 			{ | |||
|  | 				s = 0; | |||
|  | 				h = 0; | |||
|  | 			} | |||
|  | 			else | |||
|  | 			{ | |||
|  | 				float delta = cmax - cmin; | |||
|  | 				 | |||
|  | 				s = (l <= .5f) ? (delta / (cmax + cmin)) : (delta / (2f - (cmax + cmin))); | |||
|  | 				 | |||
|  | 				h = 0; | |||
|  | 				 | |||
|  | 				if (c.r == cmax) | |||
|  | 				{ | |||
|  | 					h = (c.g - c.b) / delta; | |||
|  | 				} | |||
|  | 				else if (c.g == cmax) | |||
|  | 				{ | |||
|  | 					h = 2f + (c.b - c.r) / delta; | |||
|  | 				} | |||
|  | 				else if (c.b == cmax) | |||
|  | 				{ | |||
|  | 					h = 4f + (c.r - c.g) / delta; | |||
|  | 				} | |||
|  | 				 | |||
|  | 				h = Mathf.Repeat(h * 60f, 360f); | |||
|  | 			} | |||
|  | 			 | |||
|  | 			return new HSLColor(h, s, l, a); | |||
|  | 		} | |||
|  | 		 | |||
|  | 		public Color ToRGBA() | |||
|  | 		{ | |||
|  | 			float r, g, b, a; | |||
|  | 			a = this.a; | |||
|  | 			 | |||
|  | 			float m1, m2; | |||
|  | 			 | |||
|  | 			m2 = (l <= .5f) ? (l * (1f + s)) : (l + s - l * s); | |||
|  | 			m1 = 2f * l - m2; | |||
|  | 			 | |||
|  | 			if (s == 0f) | |||
|  | 			{ | |||
|  | 				r = g = b = l; | |||
|  | 			} | |||
|  | 			else | |||
|  | 			{ | |||
|  | 				r = Value(m1, m2, h + 120f); | |||
|  | 				g = Value(m1, m2, h); | |||
|  | 				b = Value(m1, m2, h - 120f); | |||
|  | 			} | |||
|  | 			 | |||
|  | 			return new Color(r, g, b, a); | |||
|  | 		} | |||
|  | 		 | |||
|  | 		static float Value(float n1, float n2, float hue) | |||
|  | 		{ | |||
|  | 			hue = Mathf.Repeat(hue, 360f); | |||
|  | 			 | |||
|  | 			if (hue < 60f) | |||
|  | 			{ | |||
|  | 				return n1 + (n2 - n1) * hue / 60f; | |||
|  | 			} | |||
|  | 			else if (hue < 180f) | |||
|  | 			{ | |||
|  | 				return n2; | |||
|  | 			} | |||
|  | 			else if (hue < 240f) | |||
|  | 			{ | |||
|  | 				return n1 + (n2 - n1) * (240f - hue) / 60f; | |||
|  | 			} | |||
|  | 			else | |||
|  | 			{ | |||
|  | 				return n1; | |||
|  | 			} | |||
|  | 		} | |||
|  | 		 | |||
|  | 		public Color VividColor() | |||
|  | 		{ | |||
|  | 			this.l = 0.5f; | |||
|  | 			this.s = 1.0f; | |||
|  | 			return this.ToRGBA(); | |||
|  | 		} | |||
|  | 		 | |||
|  | 		public Color ColorWithHue(float hue, bool shift) | |||
|  | 		{ | |||
|  | 			if(shift) | |||
|  | 			{ | |||
|  | 				this.h += hue; | |||
|  | 				while(this.h >= 360f) | |||
|  | 					this.h -= 360f; | |||
|  | 				while(this.h <= -360f) | |||
|  | 					this.h += 360f; | |||
|  | 			} | |||
|  | 			else | |||
|  | 				this.h = hue; | |||
|  | 
 | |||
|  | 			return this.ToRGBA(); | |||
|  | 		} | |||
|  | 
 | |||
|  | 		public Color ColorWithLightnessOffset(float lightness) | |||
|  | 		{ | |||
|  | 			this.l += lightness; | |||
|  | 			if(this.l > 1.0f) this.l = 1.0f; | |||
|  | 			else if(this.l < 0.0f) this.l = 0.0f; | |||
|  | 			 | |||
|  | 			return this.ToRGBA(); | |||
|  | 		} | |||
|  | 
 | |||
|  | 		public Color ColorWithSaturationOffset(float saturation) | |||
|  | 		{ | |||
|  | 			this.s += saturation; | |||
|  | 			if(this.s > 1.0f) this.s = 1.0f; | |||
|  | 			else if(this.s < 0.0f) this.s = 0.0f; | |||
|  | 			 | |||
|  | 			return this.ToRGBA(); | |||
|  | 		} | |||
|  | 		 | |||
|  | 		public static implicit operator HSLColor(Color src) | |||
|  | 		{ | |||
|  | 			return FromRGBA(src); | |||
|  | 		} | |||
|  | 		 | |||
|  | 		public static implicit operator Color(HSLColor src) | |||
|  | 		{ | |||
|  | 			return src.ToRGBA(); | |||
|  | 		} | |||
|  | 	} | |||
|  | 	 | |||
|  | 	//Scale Lifetime only | |||
|  | 	private void applySpeed() | |||
|  | 	{ | |||
|  | 		foreach(GameObject go in Selection.gameObjects) | |||
|  | 		{ | |||
|  | 			ParticleSystem[] systems; | |||
|  | 			if(pref_IncludeChildren) | |||
|  | 				systems = go.GetComponentsInChildren<ParticleSystem>(true); | |||
|  | 			else | |||
|  | 				systems = go.GetComponents<ParticleSystem>(); | |||
|  | 			 | |||
|  | 			//Scale Lifetime | |||
|  | 			foreach(ParticleSystem ps in systems) | |||
|  | 			{ | |||
|  | #if UNITY_5_5_OR_NEWER | |||
|  | 				var main = ps.main; | |||
|  | 				main.simulationSpeed = LTScalingValue; | |||
|  | #else | |||
|  | 				ps.playbackSpeed = LTScalingValue; | |||
|  | #endif | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | 	 | |||
|  | 	//Set Duration | |||
|  | 	private void applyDuration() | |||
|  | 	{ | |||
|  | 		foreach(GameObject go in Selection.gameObjects) | |||
|  | 		{ | |||
|  | 			//Scale Shuriken Particles Values | |||
|  | 			ParticleSystem[] systems; | |||
|  | 			if(pref_IncludeChildren) | |||
|  | 				systems = go.GetComponentsInChildren<ParticleSystem>(true); | |||
|  | 			else | |||
|  | 				systems = go.GetComponents<ParticleSystem>(); | |||
|  | 			 | |||
|  | 			foreach(ParticleSystem ps in systems) | |||
|  | 			{ | |||
|  | 				SerializedObject so = new SerializedObject(ps); | |||
|  | 				so.FindProperty("lengthInSec").floatValue = DurationValue; | |||
|  | 				so.ApplyModifiedProperties(); | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | 	 | |||
|  | 	//Change delay | |||
|  | 	private void applyDelay() | |||
|  | 	{ | |||
|  | 		foreach(GameObject go in Selection.gameObjects) | |||
|  | 		{ | |||
|  | 			ParticleSystem[] systems; | |||
|  | 			if(pref_IncludeChildren) | |||
|  | 				systems = go.GetComponentsInChildren<ParticleSystem>(true); | |||
|  | 			else | |||
|  | 				systems = go.GetComponents<ParticleSystem>(); | |||
|  | 			 | |||
|  | 			//Scale Lifetime | |||
|  | 			foreach(ParticleSystem ps in systems) | |||
|  | 			{ | |||
|  | #if UNITY_5_5_OR_NEWER | |||
|  | 				var main = ps.main; | |||
|  | 				main.startDelay = DelayValue; | |||
|  | #else | |||
|  | 				ps.startDelay = DelayValue; | |||
|  | #endif | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | 	 | |||
|  | 	//Copy Selected Modules | |||
|  | 	private void CopyModules(ParticleSystem source, ParticleSystem dest) | |||
|  | 	{ | |||
|  | 		if(source == null) | |||
|  | 		{ | |||
|  | 			Debug.LogWarning("Cartoon FX Easy Editor: Select a source Particle System to copy properties from first!"); | |||
|  | 			return; | |||
|  | 		} | |||
|  | 		 | |||
|  | 		SerializedObject psSource = new SerializedObject(source); | |||
|  | 		SerializedObject psDest = new SerializedObject(dest); | |||
|  | 
 | |||
|  | 		for (int i = 0; i < modulesToCopy.Length; i++) | |||
|  | 		{ | |||
|  | 			var module = modulesToCopy[i]; | |||
|  | 
 | |||
|  | 			if (!selectedModules[i]) | |||
|  | 			{ | |||
|  | 				continue; | |||
|  | 			} | |||
|  | 
 | |||
|  | 			var sp = psSource.FindProperty(module.serializedPropertyPath); | |||
|  | 			if (sp == null) | |||
|  | 			{ | |||
|  | 				Debug.LogError("Couldn't find module in SerializedObject: " + module.serializedPropertyPath); | |||
|  | 				continue; | |||
|  | 			} | |||
|  | 
 | |||
|  | 			psDest.CopyFromSerializedProperty(sp); | |||
|  | 
 | |||
|  | 			// special case: extra properties for initial module | |||
|  | 			if (i == 0) | |||
|  | 			{ | |||
|  | 				foreach (var path in initialModuleExtraProperties) | |||
|  | 				{ | |||
|  | 					var extraSp = psSource.FindProperty(path); | |||
|  | 					if (extraSp != null) | |||
|  | 					{ | |||
|  | 						psDest.CopyFromSerializedProperty(extraSp); | |||
|  | 					} | |||
|  | 				} | |||
|  | 			} | |||
|  | 
 | |||
|  | 			psDest.ApplyModifiedProperties(); | |||
|  | 		} | |||
|  | 
 | |||
|  | 		//Renderer | |||
|  | 		if (selectedModules[selectedModules.Length-1]) | |||
|  | 		{ | |||
|  | 			ParticleSystemRenderer rendSource = source.GetComponent<ParticleSystemRenderer>(); | |||
|  | 			ParticleSystemRenderer rendDest = dest.GetComponent<ParticleSystemRenderer>(); | |||
|  | 			UnityEditorInternal.ComponentUtility.CopyComponent(rendSource); | |||
|  | 			UnityEditorInternal.ComponentUtility.PasteComponentValues(rendDest); | |||
|  | 		} | |||
|  | 	} | |||
|  | 
 | |||
|  | 	/* | |||
|  | 	private void MutateModules() | |||
|  | 	{ | |||
|  | 		var systems = pref_IncludeChildren ? Selection.activeGameObject.GetComponentsInChildren<ParticleSystem>() : Selection.activeGameObject.GetComponents<ParticleSystem>(); | |||
|  | 		var so = new SerializedObject(systems); | |||
|  | 
 | |||
|  | 		for (int i = 0; i < modulesToCopy.Length; i++) | |||
|  | 		{ | |||
|  | 			if (!selectedModulesMutate[i]) | |||
|  | 			{ | |||
|  | 				continue; | |||
|  | 			} | |||
|  | 
 | |||
|  | 			var sp = so.FindProperty(modulesToCopy[i].serializedPropertyPath); | |||
|  | 			if (sp != null) | |||
|  | 			{ | |||
|  | 				if (sp.FindPropertyRelative("enabled").boolValue) | |||
|  | 				{ | |||
|  | 					GenericMutateProperty(sp); | |||
|  | 					sp.serializedObject.ApplyModifiedProperties(); | |||
|  | 				} | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | 
 | |||
|  | 	private void GenericMutateProperty(SerializedProperty sp, bool recursive = true) | |||
|  | 	{ | |||
|  | 		System.Func<int, int> randomizeInt = intValue => | |||
|  | 		{ | |||
|  | 			return intValue + Mathf.RoundToInt(intValue * Random.Range(-mutatePercentage, +mutatePercentage)); | |||
|  | 		}; | |||
|  | 		System.Func<float, float> randomizeFloat = floatValue => | |||
|  | 		{ | |||
|  | 			return floatValue + (floatValue * Random.Range(-mutatePercentage, +mutatePercentage)); | |||
|  | 		}; | |||
|  | 		System.Func<float, float> randomizeHue = hueValue => | |||
|  | 		{ | |||
|  | 			hueValue = randomizeFloat(hueValue); | |||
|  | 			while (hueValue > 1) hueValue -= 1; | |||
|  | 			while (hueValue < 0) hueValue += 1; | |||
|  | 			return hueValue; | |||
|  | 		}; | |||
|  | 
 | |||
|  | 		//Debug.Log(new string('\t', sp.depth) + sp.name + ": " + sp.type + ", " + sp.propertyType); | |||
|  | 
 | |||
|  | 		switch (sp.type) | |||
|  | 		{ | |||
|  | 			case "MinMaxCurve": | |||
|  | 				GenericMutateProperty(sp.FindPropertyRelative("scalar"), false); | |||
|  | 				GenericMutateProperty(sp.FindPropertyRelative("minScalar"), false); | |||
|  | 				return; | |||
|  | 
 | |||
|  | 			case "MinMaxGradient": | |||
|  | 				GenericEditColorProperty(sp, color => | |||
|  | 				{ | |||
|  | 					float h, s, v; | |||
|  | 					Color.RGBToHSV(color, out h, out s, out v); | |||
|  | 					h = randomizeHue(h); | |||
|  | 					return Color.HSVToRGB(h, s, v); | |||
|  | 				}); | |||
|  | 				return; | |||
|  | 		} | |||
|  | 
 | |||
|  | 		switch (sp.propertyType) | |||
|  | 		{ | |||
|  | 			case SerializedPropertyType.Float: sp.floatValue = randomizeFloat(sp.floatValue); break; | |||
|  | 			case SerializedPropertyType.Integer: sp.intValue = randomizeInt(sp.intValue); break; | |||
|  | 			case SerializedPropertyType.Vector2: sp.vector2Value += new Vector2(randomizeFloat(sp.vector2Value.x), randomizeFloat(sp.vector2Value.y)); break; | |||
|  | 			case SerializedPropertyType.Vector3: sp.vector3Value += new Vector3(randomizeFloat(sp.vector3Value.x), randomizeFloat(sp.vector3Value.y), randomizeFloat(sp.vector3Value.z)); break; | |||
|  | 			case SerializedPropertyType.Vector4: sp.vector4Value += new Vector4(randomizeFloat(sp.vector4Value.x), randomizeFloat(sp.vector4Value.y), randomizeFloat(sp.vector4Value.z), randomizeFloat(sp.vector4Value.w)); break; | |||
|  | 		} | |||
|  | 
 | |||
|  | 		if (recursive && sp.hasVisibleChildren) | |||
|  | 		{ | |||
|  | 			var endProp = sp.GetEndProperty(); | |||
|  | 			while (!SerializedProperty.EqualContents(endProp, sp) && sp.NextVisible(true)) | |||
|  | 			{ | |||
|  | 				GenericMutateProperty(sp, false); | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | 	*/ | |||
|  | 
 | |||
|  | 	//Scale System | |||
|  | 	private void ScaleParticleValues(ParticleSystem ps, GameObject parent) | |||
|  | 	{ | |||
|  | 		//Particle System | |||
|  | 		if (ps.gameObject != parent) | |||
|  | 		{ | |||
|  | 			ps.transform.localPosition *= ScalingValue; | |||
|  | 		} | |||
|  | 
 | |||
|  | 		SerializedObject psSerial = new SerializedObject(ps); | |||
|  | 
 | |||
|  | 		foreach(var path in PropertiesToScale) | |||
|  | 		{ | |||
|  | 			var prop = psSerial.FindProperty(path); | |||
|  | 			if(prop != null) | |||
|  | 			{ | |||
|  | 				if(prop.propertyType == SerializedPropertyType.Float) | |||
|  | 				{ | |||
|  | 					prop.floatValue *= ScalingValue; | |||
|  | 				} | |||
|  | 				else | |||
|  | 				{ | |||
|  | 					Debug.LogWarning("Property in ParticleSystem is not a float: " + path + "\n"); | |||
|  | 				} | |||
|  | 			} | |||
|  | 			else | |||
|  | 			{ | |||
|  | 				Debug.LogWarning("Property doesn't exist in ParticleSystem: " + path + "\n"); | |||
|  | 			} | |||
|  | 		} | |||
|  | 
 | |||
|  | 		//Shape Module special case | |||
|  | 		/* | |||
|  | 		if(psSerial.FindProperty("ShapeModule.enabled").boolValue) | |||
|  | 		{ | |||
|  | 			//(ShapeModule.type 6 == Mesh) | |||
|  | 			if(psSerial.FindProperty("ShapeModule.type").intValue == 6) | |||
|  | 			{ | |||
|  | 				//Unity 4+ : changing the Transform scale will affect the shape Mesh | |||
|  | 				ps.transform.localScale = ps.transform.localScale * ScalingValue; | |||
|  | 				EditorUtility.SetDirty(ps.transform); | |||
|  | 			} | |||
|  | 		} | |||
|  | 		*/ | |||
|  | 		 | |||
|  | 		//Apply Modified Properties | |||
|  | 		psSerial.ApplyModifiedPropertiesWithoutUndo(); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	//Properties to scale, with per-version differences | |||
|  | 	private string[] PropertiesToScale = new string[] | |||
|  | 	{ | |||
|  | 		//Initial | |||
|  | 		"InitialModule.startSize.scalar", | |||
|  | 		"InitialModule.startSpeed.scalar", | |||
|  | #if UNITY_2017_1_OR_NEWER | |||
|  | 		"InitialModule.startSize.minScalar", | |||
|  | 		"InitialModule.startSpeed.minScalar", | |||
|  | 
 | |||
|  | 		"InitialModule.startSizeY.scalar", | |||
|  | 		"InitialModule.startSizeY.minScalar", | |||
|  | 		"InitialModule.startSizeZ.scalar", | |||
|  | 		"InitialModule.startSizeZ.minScalar", | |||
|  | #endif | |||
|  | 		//Size by Speed | |||
|  | 		"SizeBySpeedModule.range.x", | |||
|  | 		"SizeBySpeedModule.range.y", | |||
|  | 		//Velocity over Lifetime | |||
|  | 		"VelocityModule.x.scalar", | |||
|  | 		"VelocityModule.y.scalar", | |||
|  | 		"VelocityModule.z.scalar", | |||
|  | #if UNITY_2017_1_OR_NEWER | |||
|  | 		"VelocityModule.x.minScalar", | |||
|  | 		"VelocityModule.y.minScalar", | |||
|  | 		"VelocityModule.z.minScalar", | |||
|  | 
 | |||
|  | 		"VelocityModule.orbitalX.scalar", | |||
|  | 		"VelocityModule.orbitalX.minScalar", | |||
|  | 		"VelocityModule.orbitalY.scalar", | |||
|  | 		"VelocityModule.orbitalY.minScalar", | |||
|  | 		"VelocityModule.orbitalZ.scalar", | |||
|  | 		"VelocityModule.orbitalZ.minScalar", | |||
|  | 
 | |||
|  | 		"VelocityModule.orbitalOffsetX.scalar", | |||
|  | 		"VelocityModule.orbitalOffsetX.minScalar", | |||
|  | 		"VelocityModule.orbitalOffsetY.scalar", | |||
|  | 		"VelocityModule.orbitalOffsetY.minScalar", | |||
|  | 		"VelocityModule.orbitalOffsetZ.scalar", | |||
|  | 		"VelocityModule.orbitalOffsetZ.minScalar", | |||
|  | 
 | |||
|  | 		"VelocityModule.radial.scalar", | |||
|  | 		"VelocityModule.radial.minScalar", | |||
|  | 
 | |||
|  | 		"VelocityModule.speedModifier.scalar", | |||
|  | 		"VelocityModule.speedModifier.minScalar", | |||
|  | 
 | |||
|  | 		"InheritVelocityModule.m_Curve.scalar", | |||
|  | 		"InheritVelocityModule.m_Curve.minScalar", | |||
|  | 
 | |||
|  | 		"ExternalForcesModule.multiplier", | |||
|  | 
 | |||
|  | 		"NoiseModule.strength.scalar", | |||
|  | 		"NoiseModule.strength.minScalar", | |||
|  | 		"NoiseModule.strengthY.scalar", | |||
|  | 		"NoiseModule.strengthY.minScalar", | |||
|  | 		"NoiseModule.strengthZ.scalar", | |||
|  | 		"NoiseModule.strengthZ.minScalar", | |||
|  | #endif | |||
|  | 		//Limit Velocity over Lifetime | |||
|  | 		"ClampVelocityModule.x.scalar", | |||
|  | 		"ClampVelocityModule.y.scalar", | |||
|  | 		"ClampVelocityModule.z.scalar", | |||
|  | #if UNITY_2017_1_OR_NEWER | |||
|  | 		"ClampVelocityModule.x.minScalar", | |||
|  | 		"ClampVelocityModule.y.minScalar", | |||
|  | 		"ClampVelocityModule.z.minScalar", | |||
|  | #endif | |||
|  | 		"ClampVelocityModule.magnitude.scalar", | |||
|  | 		//Force over Lifetime | |||
|  | 		"ForceModule.x.scalar", | |||
|  | 		"ForceModule.y.scalar", | |||
|  | 		"ForceModule.z.scalar", | |||
|  | #if UNITY_2017_1_OR_NEWER | |||
|  | 		"ForceModule.x.minScalar", | |||
|  | 		"ForceModule.y.minScalar", | |||
|  | 		"ForceModule.z.minScalar", | |||
|  | #endif | |||
|  | 		//Special cases per Unity version | |||
|  | #if UNITY_2017_1_OR_NEWER | |||
|  | 		"ShapeModule.m_Scale.x", | |||
|  | 		"ShapeModule.m_Scale.y", | |||
|  | 		"ShapeModule.m_Scale.z", | |||
|  | #else | |||
|  | 		"ShapeModule.boxX", | |||
|  | 		"ShapeModule.boxY", | |||
|  | 		"ShapeModule.boxZ", | |||
|  | #if UNITY_5_6_OR_NEWER | |||
|  | 		"ShapeModule.radius.value", | |||
|  | #else | |||
|  | 		"ShapeModule.radius", | |||
|  | #endif | |||
|  | #endif | |||
|  | #if UNITY_5_5_OR_NEWER | |||
|  | 		"EmissionModule.rateOverDistance.scalar", | |||
|  | 		"InitialModule.gravityModifier.scalar", | |||
|  | 	#if UNITY_2017_1_OR_NEWER | |||
|  | 		"EmissionModule.rateOverDistance.minScalar", | |||
|  | 		"InitialModule.gravityModifier.minScalar", | |||
|  | 	#endif | |||
|  | #else | |||
|  | 		"InitialModule.gravityModifier", | |||
|  | 		"EmissionModule.rate.scalar", | |||
|  | #endif | |||
|  | 	}; | |||
|  | 
 | |||
|  | 	void GUISeparator() | |||
|  | 	{ | |||
|  | 		GUILayout.Space(4); | |||
|  | 		if(EditorGUIUtility.isProSkin) | |||
|  | 		{ | |||
|  | 			GUILine(new Color(.15f, .15f, .15f), 1); | |||
|  | 			GUILine(new Color(.4f, .4f, .4f), 1); | |||
|  | 		} | |||
|  | 		else | |||
|  | 		{ | |||
|  | 			GUILine(new Color(.3f, .3f, .3f), 1); | |||
|  | 			GUILine(new Color(.9f, .9f, .9f), 1); | |||
|  | 		} | |||
|  | 		GUILayout.Space(4); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	static public void GUILine(Color color, float height = 2f) | |||
|  | 	{ | |||
|  | 		Rect position = GUILayoutUtility.GetRect(0f, float.MaxValue, height, height, LineStyle); | |||
|  | 
 | |||
|  | 		if(Event.current.type == EventType.Repaint) | |||
|  | 		{ | |||
|  | 			Color orgColor = GUI.color; | |||
|  | 			GUI.color = orgColor * color; | |||
|  | 			LineStyle.Draw(position, false, false, false, false); | |||
|  | 			GUI.color = orgColor; | |||
|  | 		} | |||
|  | 	} | |||
|  | 
 | |||
|  | 	static public GUIStyle _LineStyle; | |||
|  | 	static public GUIStyle LineStyle | |||
|  | 	{ | |||
|  | 		get | |||
|  | 		{ | |||
|  | 			if(_LineStyle == null) | |||
|  | 			{ | |||
|  | 				_LineStyle = new GUIStyle(); | |||
|  | 				_LineStyle.normal.background = EditorGUIUtility.whiteTexture; | |||
|  | 				_LineStyle.stretchWidth = true; | |||
|  | 			} | |||
|  | 
 | |||
|  | 			return _LineStyle; | |||
|  | 		} | |||
|  | 	} | |||
|  | } |