diff --git a/Assets/Examples/Prefabs/OutlineLayers.asset b/Assets/Examples/Prefabs/OutlineLayers.asset deleted file mode 100644 index 5def13d..0000000 --- a/Assets/Examples/Prefabs/OutlineLayers.asset +++ /dev/null @@ -1,22 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 57d0c11168277cf4eb3b4b89706e6aa5, type: 3} - m_Name: OutlineLayers - m_EditorClassIdentifier: - _layers: - - _outlineColor: {r: 1, g: 0, b: 0, a: 1} - _outlineWidth: 7 - _outlineIntensity: 2 - _outlineMode: 1 - - _outlineColor: {r: 0.22794117, g: 0.8455882, b: 0, a: 1} - _outlineWidth: 8 - _outlineIntensity: 2 - _outlineMode: 0 diff --git a/Assets/Examples/Prefabs/TestOutlineLayers.asset b/Assets/Examples/Prefabs/TestOutlineLayers.asset new file mode 100644 index 0000000..4cb159e --- /dev/null +++ b/Assets/Examples/Prefabs/TestOutlineLayers.asset @@ -0,0 +1,33 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 57d0c11168277cf4eb3b4b89706e6aa5, type: 3} + m_Name: TestOutlineLayers + m_EditorClassIdentifier: + _layers: + - _settings: + _outlineSettings: {fileID: 11400000, guid: 45705bbb29366194eb01ca517d80967c, + type: 2} + _outlineColor: {r: 1, g: 0, b: 0, a: 1} + _outlineWidth: 5 + _outlineIntensity: 2 + _outlineMode: 0 + - _settings: + _outlineSettings: {fileID: 0} + _outlineColor: {r: 1, g: 1, b: 0, a: 1} + _outlineWidth: 15 + _outlineIntensity: 2 + _outlineMode: 1 + - _settings: + _outlineSettings: {fileID: 0} + _outlineColor: {r: 1, g: 0, b: 1, a: 1} + _outlineWidth: 4 + _outlineIntensity: 2 + _outlineMode: 0 diff --git a/Assets/Examples/Prefabs/OutlineLayers.asset.meta b/Assets/Examples/Prefabs/TestOutlineLayers.asset.meta similarity index 100% rename from Assets/Examples/Prefabs/OutlineLayers.asset.meta rename to Assets/Examples/Prefabs/TestOutlineLayers.asset.meta diff --git a/Assets/Examples/Prefabs/TestOutlineSettings.asset b/Assets/Examples/Prefabs/TestOutlineSettings.asset new file mode 100644 index 0000000..7d525e8 --- /dev/null +++ b/Assets/Examples/Prefabs/TestOutlineSettings.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b579424fd3338724cba3155ee4d53475, type: 3} + m_Name: TestOutlineSettings + m_EditorClassIdentifier: + _outlineColor: {r: 1, g: 0, b: 0, a: 1} + _outlineWidth: 5 + _outlineIntensity: 2 + _outlineMode: 0 diff --git a/Assets/Examples/Prefabs/TestOutlineSettings.asset.meta b/Assets/Examples/Prefabs/TestOutlineSettings.asset.meta new file mode 100644 index 0000000..253e14e --- /dev/null +++ b/Assets/Examples/Prefabs/TestOutlineSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 45705bbb29366194eb01ca517d80967c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Examples/Scenes/Outline.unity b/Assets/Examples/Scenes/Outline.unity index 3ac0f6a..63a292e 100644 --- a/Assets/Examples/Scenes/Outline.unity +++ b/Assets/Examples/Scenes/Outline.unity @@ -187,8 +187,6 @@ GameObject: m_Component: - component: {fileID: 692811816} - component: {fileID: 692811815} - - component: {fileID: 692811814} - - component: {fileID: 692811813} - component: {fileID: 692811818} - component: {fileID: 692811817} m_Layer: 0 @@ -198,20 +196,6 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!81 &692811813 -AudioListener: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 692811812} - m_Enabled: 1 ---- !u!124 &692811814 -Behaviour: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 692811812} - m_Enabled: 1 --- !u!20 &692811815 Camera: m_ObjectHideFlags: 0 @@ -503,10 +487,12 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _outlineResources: {fileID: 11400000, guid: d28e70f030b1a634db9a6a6d5478ef19, type: 2} - _outlineColor: {r: 0, g: 1, b: 0, a: 1} - _outlineWidth: 12 - _outlineIntensity: 2 - _outlineMode: 1 + _outlineSettings: + _outlineSettings: {fileID: 0} + _outlineColor: {r: 0, g: 1, b: 0, a: 1} + _outlineWidth: 15 + _outlineIntensity: 2 + _outlineMode: 1 --- !u!23 &1789341923 MeshRenderer: m_ObjectHideFlags: 0 diff --git a/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineBehaviourEditor.cs b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineBehaviourEditor.cs index 57a290a..4716161 100644 --- a/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineBehaviourEditor.cs +++ b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineBehaviourEditor.cs @@ -2,9 +2,8 @@ // See the LICENSE.md file in the project root for more information. using System; -using System.Collections; -using System.Collections.Generic; using UnityEditor; +using UnityEditor.SceneManagement; using UnityEngine; namespace UnityFx.Outline @@ -25,6 +24,22 @@ public override void OnInspectorGUI() { base.OnInspectorGUI(); + // 1) Outline settings. + EditorGUI.BeginChangeCheck(); + + OutlineEditorUtility.Render(_effect, _effect); + + if (EditorGUI.EndChangeCheck()) + { + EditorUtility.SetDirty(_effect.gameObject); + + if (!EditorApplication.isPlayingOrWillChangePlaymode) + { + EditorSceneManager.MarkSceneDirty(_effect.gameObject.scene); + } + } + + // 2) Renderers (read-only). _renderersOpened = EditorGUILayout.Foldout(_renderersOpened, "Renderers", true); if (_renderersOpened) @@ -44,6 +59,7 @@ public override void OnInspectorGUI() EditorGUI.EndDisabledGroup(); } + // 3) Cameras (read-only). _camerasOpened = EditorGUILayout.Foldout(_camerasOpened, "Cameras", true); if (_camerasOpened) diff --git a/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs new file mode 100644 index 0000000..6e04ee0 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs @@ -0,0 +1,166 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace UnityFx.Outline +{ + internal static class OutlineEditorUtility + { + public static void RenderDivider(Color color, int thickness = 1, int padding = 5) + { + var r = EditorGUILayout.GetControlRect(GUILayout.Height(padding + thickness)); + + r.height = thickness; + r.y += padding / 2; + r.x -= 2; + r.width += 6; + + EditorGUI.DrawRect(r, color); + } + + public static void Render(IOutlineSettingsEx settings, UnityEngine.Object undoContext) + { + var obj = (OutlineSettings)EditorGUILayout.ObjectField("Outline Settings", settings.OutlineSettings, typeof(OutlineSettings), true); + + if (settings.OutlineSettings != obj) + { + Undo.RecordObject(undoContext, "Settings"); + settings.OutlineSettings = obj; + } + + if (obj) + { + EditorGUI.BeginDisabledGroup(true); + EditorGUI.indentLevel += 1; + + Render((IOutlineSettings)settings, undoContext); + + EditorGUILayout.HelpBox(string.Format("Outline settings are overriden with values from {0}.", obj.name), MessageType.Info, true); + EditorGUI.indentLevel -= 1; + EditorGUI.EndDisabledGroup(); + } + else + { + EditorGUI.indentLevel += 1; + + Render((IOutlineSettings)settings, undoContext); + + EditorGUI.indentLevel -= 1; + } + } + + public static void Render(IOutlineSettings settings, UnityEngine.Object undoContext) + { + var color = EditorGUILayout.ColorField("Color", settings.OutlineColor); + + if (settings.OutlineColor != color) + { + Undo.RecordObject(undoContext, "Color"); + settings.OutlineColor = color; + } + + var width = EditorGUILayout.IntSlider("Width", settings.OutlineWidth, OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); + + if (settings.OutlineWidth != width) + { + Undo.RecordObject(undoContext, "Width"); + settings.OutlineWidth = width; + } + + var blurred = EditorGUILayout.Toggle("Blurred", settings.OutlineMode == OutlineMode.Blurred); + + if (blurred) + { + EditorGUI.indentLevel += 1; + + var i = EditorGUILayout.Slider("Blur Intensity", settings.OutlineIntensity, OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); + + if (!Mathf.Approximately(settings.OutlineIntensity, i)) + { + Undo.RecordObject(undoContext, "Blur Intensity"); + settings.OutlineIntensity = i; + } + + EditorGUI.indentLevel -= 1; + } + + if (blurred != (settings.OutlineMode == OutlineMode.Blurred)) + { + Undo.RecordObject(undoContext, "Blur"); + settings.OutlineMode = blurred ? OutlineMode.Blurred : OutlineMode.Solid; + } + } + + public static void RenderPreview(OutlineLayer layer, int layerIndex, bool showObjects) + { + if (layer != null) + { + var goIndex = 1; + + EditorGUILayout.BeginHorizontal(); + EditorGUI.indentLevel += 1; + EditorGUILayout.PrefixLabel("Layer #" + layerIndex.ToString()); + EditorGUI.indentLevel -= 1; + EditorGUILayout.IntField(layer.OutlineWidth, GUILayout.MaxWidth(100)); + EditorGUILayout.ColorField(layer.OutlineColor, GUILayout.MinWidth(100)); + EditorGUILayout.EndHorizontal(); + + if (showObjects) + { + if (layer.Count > 0) + { + foreach (var go in layer) + { + EditorGUI.indentLevel += 2; + EditorGUILayout.ObjectField("#" + goIndex.ToString(), go, typeof(GameObject), true); + EditorGUI.indentLevel -= 2; + + goIndex++; + } + } + else + { + EditorGUI.indentLevel += 2; + EditorGUILayout.LabelField("No objects."); + EditorGUI.indentLevel -= 2; + } + } + } + else + { + EditorGUILayout.BeginHorizontal(); + EditorGUI.indentLevel += 1; + EditorGUILayout.PrefixLabel("Layer #" + layerIndex.ToString()); + EditorGUI.indentLevel -= 1; + EditorGUILayout.LabelField("Null"); + EditorGUILayout.EndHorizontal(); + } + } + + public static void RenderPreview(IList layers, bool showObjects) + { + EditorGUI.BeginDisabledGroup(true); + + if (layers.Count > 0) + { + for (var i = 0; i < layers.Count; ++i) + { + RenderPreview(layers[i], i, showObjects); + } + } + else + { + EditorGUI.indentLevel += 1; + EditorGUILayout.LabelField("No layers."); + EditorGUI.indentLevel -= 1; + } + + EditorGUI.EndDisabledGroup(); + } + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviourRt.cs.meta b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs.meta similarity index 83% rename from Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviourRt.cs.meta rename to Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs.meta index 753c16f..28953ac 100644 --- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviourRt.cs.meta +++ b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineEditorUtility.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c6ee32bc28cb44c48ae754d73c9d4595 +guid: ba087138029b59d4bbdf0783db0e2606 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineEffectEditor.cs b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineEffectEditor.cs index ac78341..f6fb00d 100644 --- a/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineEffectEditor.cs +++ b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineEffectEditor.cs @@ -10,7 +10,7 @@ namespace UnityFx.Outline { [CustomEditor(typeof(OutlineEffect))] - public class OutlineEffectInspector : Editor + public class OutlineEffectEditor : Editor { private OutlineEffect _effect; private bool _previewOpened; @@ -30,50 +30,7 @@ public override void OnInspectorGUI() if (_previewOpened) { - EditorGUI.BeginDisabledGroup(true); - - if (_effect.OutlineLayers.Count > 0) - { - for (var i = 0; i < _effect.OutlineLayers.Count; ++i) - { - var layer = _effect.OutlineLayers[i]; - var goIndex = 1; - - EditorGUILayout.BeginHorizontal(); - EditorGUI.indentLevel = 1; - EditorGUILayout.PrefixLabel("Layer #" + i.ToString()); - EditorGUI.indentLevel = 0; - EditorGUILayout.IntField(layer.OutlineWidth, GUILayout.MaxWidth(100)); - EditorGUILayout.ColorField(layer.OutlineColor, GUILayout.MinWidth(100)); - EditorGUILayout.EndHorizontal(); - - if (layer.Count > 0) - { - foreach (var go in layer) - { - EditorGUI.indentLevel = 2; - EditorGUILayout.ObjectField("#" + goIndex.ToString(), go, typeof(GameObject), true); - EditorGUI.indentLevel = 0; - - goIndex++; - } - } - else - { - EditorGUI.indentLevel = 2; - EditorGUILayout.LabelField("No objects."); - EditorGUI.indentLevel = 0; - } - } - } - else - { - EditorGUI.indentLevel = 1; - EditorGUILayout.LabelField("No layers."); - EditorGUI.indentLevel = 0; - } - - EditorGUI.EndDisabledGroup(); + OutlineEditorUtility.RenderPreview(_effect.OutlineLayers, true); } } } diff --git a/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs new file mode 100644 index 0000000..a3fc6bb --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs @@ -0,0 +1,96 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace UnityFx.Outline +{ + [CustomEditor(typeof(OutlineLayerCollection))] + public class OutlineLayerCollectionEditor : Editor + { + private readonly GUILayoutOption _layerButtonStyle = GUILayout.ExpandWidth(false); + private OutlineLayerCollection _layers; + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + EditorGUI.BeginChangeCheck(); + + var removeLayer = -1; + + // 1) Layers list. + if (_layers.Count > 0) + { + for (var i = 0; i < _layers.Count; i++) + { + EditorGUILayout.Space(); + var rect = EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel("Layer #" + i.ToString()); + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Remove", _layerButtonStyle)) + { + removeLayer = i; + } + + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + + rect.xMin -= 2; + rect.xMax += 2; + rect.yMin -= 2; + rect.yMax += 2; + + GUI.Box(rect, GUIContent.none); + + OutlineEditorUtility.Render(_layers[i], _layers); + } + } + else + { + EditorGUILayout.HelpBox("The layer collection is empty.", MessageType.Info, true); + } + + // Add/remove processing. + OutlineEditorUtility.RenderDivider(Color.gray); + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Add New", _layerButtonStyle)) + { + Undo.RecordObject(_layers, "Add Layer"); + _layers.Add(new OutlineLayer()); + } + + if (GUILayout.Button("Remove All", _layerButtonStyle)) + { + Undo.RecordObject(_layers, "Remove All Layers"); + _layers.Clear(); + } + + if (removeLayer >= 0) + { + Undo.RecordObject(_layers, "Remove Layer"); + _layers.RemoveAt(removeLayer); + } + + EditorGUILayout.EndHorizontal(); + + if (EditorGUI.EndChangeCheck()) + { + EditorUtility.SetDirty(_layers); + } + } + + private void OnEnable() + { + _layers = (OutlineLayerCollection)target; + } + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs.meta b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs.meta new file mode 100644 index 0000000..528a02e --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineLayerCollectionEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5f4ec5de59e58794b8e34f2ca3c00199 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineSettingsEditor.cs b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineSettingsEditor.cs new file mode 100644 index 0000000..5f6e78c --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineSettingsEditor.cs @@ -0,0 +1,33 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace UnityFx.Outline +{ + [CustomEditor(typeof(OutlineSettings))] + public class OutlineSettingsEditor : Editor + { + private OutlineSettings _settings; + + public override void OnInspectorGUI() + { + EditorGUI.BeginChangeCheck(); + OutlineEditorUtility.Render(_settings, _settings); + + if (EditorGUI.EndChangeCheck()) + { + EditorUtility.SetDirty(_settings); + } + } + + private void OnEnable() + { + _settings = (OutlineSettings)target; + } + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineSettingsEditor.cs.meta b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineSettingsEditor.cs.meta new file mode 100644 index 0000000..2569298 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Editor/Scripts/OutlineSettingsEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 28f2a32d8600f8045a4b9a9916ff8801 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettings.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettings.cs index 8dbf8c6..bf49e44 100644 --- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettings.cs +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettings.cs @@ -2,9 +2,7 @@ // See the LICENSE.md file in the project root for more information. using System; -using System.Collections.Generic; using UnityEngine; -using UnityEngine.Rendering; namespace UnityFx.Outline { @@ -38,10 +36,5 @@ public interface IOutlineSettings /// /// OutlineMode OutlineMode { get; set; } - - /// - /// Forces the settings to be re-applied and the outline to be re-rendered. - /// - void Invalidate(); } } diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs new file mode 100644 index 0000000..032af2a --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs @@ -0,0 +1,19 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using UnityEngine; + +namespace UnityFx.Outline +{ + /// + /// Extended outline settings. + /// + public interface IOutlineSettingsEx : IOutlineSettings + { + /// + /// Gets or sets serializable outline settings. Set this to non- value to share settings with other components. + /// + OutlineSettings OutlineSettings { get; set; } + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs.meta b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs.meta new file mode 100644 index 0000000..73a20da --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/IOutlineSettingsEx.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9d3517d0fef6af540b0b046d3b2421dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.Renderers.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.Renderers.cs new file mode 100644 index 0000000..d2304d6 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.Renderers.cs @@ -0,0 +1,258 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace UnityFx.Outline +{ + partial class OutlineBehaviour + { + #region interface + #endregion + + #region implementation + + [ExecuteInEditMode] + [DisallowMultipleComponent] + private class OutlineRendererHelper : MonoBehaviour + { + private OutlineBehaviour _parent; + + public void SetParent(OutlineBehaviour parent) + { + _parent = parent; + } + + private void OnWillRenderObject() + { + if (isActiveAndEnabled && _parent) + { + _parent.OnWillRenderObject(); + } + } + } + + private sealed class RendererCollection : IList + { + #region data + + private readonly List _renderers = new List(); + private readonly OutlineBehaviour _parent; + private readonly GameObject _go; + + #endregion + + #region interface + + internal RendererCollection(OutlineBehaviour parent) + { + Debug.Assert(parent); + + _parent = parent; + _go = parent.gameObject; + } + + public void Reset() + { + foreach (var r in _renderers) + { + Release(r); + } + + _renderers.Clear(); + _parent.GetComponentsInChildren(true, _renderers); + + foreach (var r in _renderers) + { + Init(r); + } + } + + #endregion + + #region IList + + public Renderer this[int index] + { + get + { + return _renderers[index]; + } + set + { + if (index < 0 || index >= _renderers.Count) + { + throw new ArgumentOutOfRangeException("index"); + } + + Validate(value); + Release(_renderers[index]); + Init(value); + + _renderers[index] = value; + } + } + + public int IndexOf(Renderer renderer) + { + return _renderers.IndexOf(renderer); + } + + public void Insert(int index, Renderer renderer) + { + if (index < 0 || index >= _renderers.Count) + { + throw new ArgumentOutOfRangeException("index"); + } + + Validate(renderer); + Init(renderer); + + _renderers.Insert(index, renderer); + } + + public void RemoveAt(int index) + { + if (index >= 0 && index < _renderers.Count) + { + Release(_renderers[index]); + _renderers.RemoveAt(index); + } + } + + #endregion + + #region ICollection + + public int Count + { + get + { + return _renderers.Count; + } + } + + public bool IsReadOnly + { + get + { + return false; + } + } + + public void Add(Renderer renderer) + { + Validate(renderer); + Init(renderer); + + _renderers.Add(renderer); + } + + public bool Remove(Renderer renderer) + { + if (_renderers.Remove(renderer)) + { + Release(renderer); + return true; + } + + return false; + } + + public void Clear() + { + foreach (var r in _renderers) + { + Release(r); + } + + _renderers.Clear(); + } + + public bool Contains(Renderer renderer) + { + return _renderers.Contains(renderer); + } + + public void CopyTo(Renderer[] array, int arrayIndex) + { + _renderers.CopyTo(array, arrayIndex); + } + + #endregion + + #region IEnumerable + + public IEnumerator GetEnumerator() + { + return _renderers.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _renderers.GetEnumerator(); + } + + #endregion + + #region implementation + + private void Validate(Renderer renderer) + { + if (renderer == null) + { + throw new ArgumentNullException("renderer"); + } + + if (!renderer.transform.IsChildOf(_go.transform)) + { + throw new ArgumentException(string.Format("Only children of the {0} are allowed.", _go.name), "renderer"); + } + } + + private void Init(Renderer r) + { + if (r && r.gameObject != _go) + { + var c = r.GetComponent(); + + if (c == null) + { + c = r.gameObject.AddComponent(); + } + + c.SetParent(_parent); + } + } + + private void Release(Renderer r) + { + if (r) + { + var c = r.GetComponent(); + + if (c) + { + DestroyImmediate(c); + } + } + } + + #endregion + } + + private void CreateRenderersIfNeeded() + { + if (_renderers == null) + { + _renderers = new RendererCollection(this); + _renderers.Reset(); + } + } + + #endregion + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.Renderers.cs.meta b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.Renderers.cs.meta new file mode 100644 index 0000000..02f6567 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.Renderers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e24c24bdabda57c45a4a803464696afc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs index 6a2d934..ad60cec 100644 --- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviour.cs @@ -15,7 +15,7 @@ namespace UnityFx.Outline /// [ExecuteInEditMode] [DisallowMultipleComponent] - public sealed class OutlineBehaviour : MonoBehaviour, IOutlineSettings + public sealed partial class OutlineBehaviour : MonoBehaviour, IOutlineSettingsEx { #region data @@ -23,26 +23,16 @@ public sealed class OutlineBehaviour : MonoBehaviour, IOutlineSettings [SerializeField] private OutlineResources _outlineResources; - [SerializeField] - private Color _outlineColor = Color.green; - [SerializeField] - [Range(OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth)] - private int _outlineWidth = 5; - [SerializeField] - [Range(OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity)] - private float _outlineIntensity = 2; - [SerializeField] - private OutlineMode _outlineMode; + [SerializeField, HideInInspector] + private OutlineSettingsInstance _outlineSettings; #pragma warning restore 0649 - private OutlineMaterialSet _materials; private RendererCollection _renderers; private CommandBuffer _commandBuffer; private Dictionary _cameraMap = new Dictionary(); private float _cameraMapUpdateTimer; - private bool _changed; #endregion @@ -51,6 +41,7 @@ public sealed class OutlineBehaviour : MonoBehaviour, IOutlineSettings /// /// Gets or sets resources used by the effect implementation. /// + /// Thrown if setter argument is . public OutlineResources OutlineResources { get @@ -67,10 +58,7 @@ public OutlineResources OutlineResources if (_outlineResources != value) { _outlineResources = value; - _changed = true; - - _materials = _outlineResources.CreateMaterialSet(); - _materials.Reset(this); + _outlineSettings.SetResources(_outlineResources); } } } @@ -97,9 +85,12 @@ public ICollection Cameras } } - internal void OnWillRenderObjectRt() + /// + /// Detects changes in nested assets and updates outline if needed. The actual update might not be invoked until the next frame. + /// + public void UpdateChanged() { - OnWillRenderObject(); + _outlineSettings.UpdateChanged(); } #endregion @@ -109,21 +100,17 @@ internal void OnWillRenderObjectRt() private void Awake() { CreateRenderersIfNeeded(); - CreateMaterialsIfNeeded(); - CreateCommandBufferIfNeeded(); + CreateSettingsIfNeeded(); } private void OnDestroy() { - if (_commandBuffer != null) - { - _commandBuffer.Dispose(); - _commandBuffer = null; - } + _outlineSettings.SetResources(null); } private void OnEnable() { + CreateCommandBufferIfNeeded(); } private void OnDisable() @@ -137,6 +124,12 @@ private void OnDisable() } _cameraMap.Clear(); + + if (_commandBuffer != null) + { + _commandBuffer.Dispose(); + _commandBuffer = null; + } } private void Update() @@ -149,9 +142,20 @@ private void Update() _cameraMapUpdateTimer = 0; } - if (_changed) +#if UNITY_EDITOR + + UpdateChanged(); + +#endif + + if (_outlineResources != null && _renderers != null && _outlineSettings.IsChanged) { - UpdateCommandBuffer(); + using (var renderer = new OutlineRenderer(_commandBuffer, BuiltinRenderTextureType.CameraTarget)) + { + renderer.RenderSingleObject(_renderers, _outlineSettings.OutlineMaterials); + } + + _outlineSettings.AcceptChanges(); } } @@ -177,14 +181,13 @@ private void OnWillRenderObject() private void OnValidate() { CreateRenderersIfNeeded(); - CreateMaterialsIfNeeded(); CreateCommandBufferIfNeeded(); - - _changed = true; + CreateSettingsIfNeeded(); } private void Reset() { + _outlineSettings.SetResources(_outlineResources); _renderers.Reset(); } @@ -192,300 +195,83 @@ private void Reset() #endregion - #region IOutlineSettings + #region IOutlineSettingsEx - /// - public Color OutlineColor + /// + /// Gets or sets outline settings. Set this to non- value to share settings with other components. + /// + public OutlineSettings OutlineSettings { get { - return _outlineColor; + return _outlineSettings.OutlineSettings; } set { - if (_outlineColor != value) - { - _outlineColor = value; - _changed = true; - - if (_materials != null) - { - _materials.OutlineColor = value; - } - } + _outlineSettings.OutlineSettings = value; } } + #endregion + + #region IOutlineSettings + /// - public int OutlineWidth + public Color OutlineColor { get { - return _outlineWidth; + return _outlineSettings.OutlineColor; } set { - value = Mathf.Clamp(value, OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); - - if (_outlineWidth != value) - { - _outlineWidth = value; - _changed = true; - - if (_materials != null) - { - _materials.OutlineWidth = value; - } - } + _outlineSettings.OutlineColor = value; } } /// - public float OutlineIntensity + public int OutlineWidth { get { - return _outlineIntensity; + return _outlineSettings.OutlineWidth; } set { - value = Mathf.Clamp(value, OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); - - if (_outlineIntensity != value) - { - _outlineIntensity = value; - _changed = true; - - if (_materials != null) - { - _materials.OutlineIntensity = value; - } - } + _outlineSettings.OutlineWidth = value; } } /// - public OutlineMode OutlineMode + public float OutlineIntensity { get { - return _outlineMode; + return _outlineSettings.OutlineIntensity; } set { - if (_outlineMode != value) - { - _outlineMode = value; - _changed = true; - - if (_materials != null) - { - _materials.OutlineMode = value; - } - } + _outlineSettings.OutlineIntensity = value; } } /// - public void Invalidate() + public OutlineMode OutlineMode { - if (_materials != null) + get { - _materials.Reset(this); + return _outlineSettings.OutlineMode; + } + set + { + _outlineSettings.OutlineMode = value; } - - _changed = true; } #endregion #region implementation - private sealed class RendererCollection : IList - { - private readonly List _renderers = new List(); - private readonly OutlineBehaviour _parent; - private readonly GameObject _go; - - public int Count - { - get - { - return _renderers.Count; - } - } - - public bool IsReadOnly - { - get - { - return false; - } - } - - public Renderer this[int index] - { - get - { - return _renderers[index]; - } - set - { - if (index < 0 || index >= _renderers.Count) - { - throw new ArgumentOutOfRangeException("index"); - } - - Validate(value); - Release(_renderers[index]); - Init(value); - - _renderers[index] = value; - } - } - - public RendererCollection(OutlineBehaviour parent) - { - Debug.Assert(parent); - - _parent = parent; - _go = parent.gameObject; - } - - public void Reset() - { - foreach (var r in _renderers) - { - Release(r); - } - - _renderers.Clear(); - _parent.GetComponentsInChildren(true, _renderers); - - foreach (var r in _renderers) - { - Init(r); - } - } - - public void Add(Renderer renderer) - { - Validate(renderer); - Init(renderer); - - _renderers.Add(renderer); - } - - public bool Remove(Renderer renderer) - { - if (_renderers.Remove(renderer)) - { - Release(renderer); - return true; - } - - return false; - } - - public void Clear() - { - foreach (var r in _renderers) - { - Release(r); - } - - _renderers.Clear(); - } - - public bool Contains(Renderer renderer) - { - return _renderers.Contains(renderer); - } - - public int IndexOf(Renderer renderer) - { - return _renderers.IndexOf(renderer); - } - - public void Insert(int index, Renderer renderer) - { - if (index < 0 || index >= _renderers.Count) - { - throw new ArgumentOutOfRangeException("index"); - } - - Validate(renderer); - Init(renderer); - - _renderers.Insert(index, renderer); - } - - public void RemoveAt(int index) - { - if (index >= 0 && index < _renderers.Count) - { - Release(_renderers[index]); - _renderers.RemoveAt(index); - } - } - - public void CopyTo(Renderer[] array, int arrayIndex) - { - _renderers.CopyTo(array, arrayIndex); - } - - public IEnumerator GetEnumerator() - { - return _renderers.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _renderers.GetEnumerator(); - } - - private void Validate(Renderer renderer) - { - if (renderer == null) - { - throw new ArgumentNullException("renderer"); - } - - if (!renderer.transform.IsChildOf(_go.transform)) - { - throw new ArgumentException(string.Format("Only children of the {0} are allowed.", _go.name), "renderer"); - } - } - - private void Init(Renderer r) - { - if (r && r.gameObject != _go) - { - var c = r.GetComponent(); - - if (c == null) - { - c = r.gameObject.AddComponent(); - } - - c.Parent = _parent; - } - } - - private void Release(Renderer r) - { - if (r) - { - var c = r.GetComponent(); - - if (c) - { - Destroy(c); - } - } - } - } - private void RemoveDestroyedCameras() { List camerasToRemove = null; @@ -520,43 +306,17 @@ private void CreateCommandBufferIfNeeded() { _commandBuffer = new CommandBuffer(); _commandBuffer.name = string.Format("{0} - {1}", GetType().Name, name); - _changed = true; - } - } - - private void CreateMaterialsIfNeeded() - { - if (_outlineResources && (_materials == null || _materials.OutlineResources != _outlineResources)) - { - _materials = _outlineResources.CreateMaterialSet(); - } - - if (_materials != null) - { - _materials.Reset(this); } } - private void UpdateCommandBuffer() + private void CreateSettingsIfNeeded() { - if (_outlineResources != null && _renderers != null && _materials != null) + if (_outlineSettings == null) { - using (var renderer = new OutlineRenderer(_commandBuffer, BuiltinRenderTextureType.CameraTarget)) - { - renderer.RenderSingleObject(_renderers, _materials); - } - - _changed = false; + _outlineSettings = new OutlineSettingsInstance(); } - } - private void CreateRenderersIfNeeded() - { - if (_renderers == null) - { - _renderers = new RendererCollection(this); - _renderers.Reset(); - } + _outlineSettings.SetResources(_outlineResources); } #endregion diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviourRt.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviourRt.cs deleted file mode 100644 index 7301e6b..0000000 --- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineBehaviourRt.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. -// See the LICENSE.md file in the project root for more information. - -using System; -using UnityEngine; - -namespace UnityFx.Outline -{ - /// - /// This should be attached to each for to work as expected. - /// - /// - [ExecuteInEditMode] - [DisallowMultipleComponent] - internal class OutlineBehaviourRt : MonoBehaviour - { - public OutlineBehaviour Parent; - - private void OnWillRenderObject() - { - if (isActiveAndEnabled && Parent) - { - Parent.OnWillRenderObjectRt(); - } - } - } -} diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs index c1e5587..a5bfc3f 100644 --- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineEffect.cs @@ -9,14 +9,15 @@ namespace UnityFx.Outline { /// - /// Post-effect script. Should be attached to camera. + /// Renders outlines at specific camera. Should be attached to camera to function. /// /// /// + /// /// [DisallowMultipleComponent] [RequireComponent(typeof(Camera))] - public sealed class OutlineEffect : MonoBehaviour + public sealed partial class OutlineEffect : MonoBehaviour { #region data @@ -25,7 +26,6 @@ public sealed class OutlineEffect : MonoBehaviour [SerializeField] private OutlineLayerCollection _outlineLayers; - private IList _layers; private CommandBuffer _commandBuffer; private bool _changed; @@ -36,6 +36,7 @@ public sealed class OutlineEffect : MonoBehaviour /// /// Gets or sets resources used by the effect implementation. /// + /// Thrown if setter argument is . public OutlineResources OutlineResources { get @@ -58,31 +59,38 @@ public OutlineResources OutlineResources } /// - /// Gets outline layers. + /// Gets or sets outline layers. /// + /// Thrown if setter argument is . /// - public IList OutlineLayers + public OutlineLayerCollection OutlineLayers { get { - if (_layers == null) + if (_outlineLayers == null) { - if (_outlineLayers) - { - _layers = _outlineLayers.Layers; - } - else - { - _layers = new List(); - } + _outlineLayers = ScriptableObject.CreateInstance(); } - return _layers; + return _outlineLayers; + } + set + { + if (value == null) + { + throw new ArgumentNullException("OutlineLayers"); + } + + if (_outlineLayers != value) + { + _outlineLayers = value; + _changed = true; + } } } /// - /// Shares with another instace. + /// Shares with another instance. /// /// Effect to share with. /// @@ -90,43 +98,33 @@ public void ShareLayersWith(OutlineEffect other) { if (other) { - other._layers = OutlineLayers; + if (_outlineLayers == null) + { + _outlineLayers = ScriptableObject.CreateInstance(); + } + other._outlineLayers = _outlineLayers; other._changed = true; } } - #endregion - - #region MonoBehaviour - - private void Awake() + /// + /// Detects changes in nested assets and updates outline if needed. The actual update might not be invoked until the next frame. + /// + public void UpdateChanged() { if (_outlineLayers) { - _layers = _outlineLayers.Layers; + _outlineLayers.UpdateChanged(); } } - private void OnValidate() - { - if (_outlineLayers) - { - _layers = _outlineLayers.Layers; - } - else - { - _layers = null; - } + #endregion - _changed = true; - } + #region MonoBehaviour - private void Reset() + private void Awake() { - _outlineLayers = null; - _layers = null; - _changed = true; } private void OnEnable() @@ -161,33 +159,50 @@ private void OnDisable() private void Update() { - if (_layers != null) +#if UNITY_EDITOR + + UpdateChanged(); + +#endif + + if (_outlineLayers && (_changed || _outlineLayers.IsChanged)) { - if (_changed) - { - FillCommandBuffer(); - } - else - { - var needUpdate = false; + FillCommandBuffer(); + } + } - for (var i = 0; i < _layers.Count; ++i) - { - if (_layers[i] != null && _layers[i].IsChanged) - { - needUpdate = true; - break; - } - } + private void LateUpdate() + { + // TODO: Find a way to do this once per OutlineLayerCollection instance. + if (_outlineLayers) + { + _outlineLayers.AcceptChanges(); + } + } - if (needUpdate) - { - FillCommandBuffer(); - } - } + private void OnDestroy() + { + if (_outlineLayers) + { + _outlineLayers.Reset(); } } +#if UNITY_EDITOR + + private void OnValidate() + { + _changed = true; + } + + private void Reset() + { + _outlineLayers = null; + _changed = true; + } + +#endif + #endregion #region implementation @@ -198,21 +213,26 @@ private void FillCommandBuffer() { using (var renderer = new OutlineRenderer(_commandBuffer, BuiltinRenderTextureType.CameraTarget)) { - for (var i = 0; i < _layers.Count; ++i) + for (var i = 0; i < _outlineLayers.Count; ++i) { - if (_layers[i] != null) + if (_outlineLayers[i] != null) { - _layers[i].Render(renderer, _outlineResources); + _outlineLayers[i].Render(renderer, _outlineResources); } } } - - _changed = false; } else { _commandBuffer.Clear(); } + + _changed = false; + } + + private void OnChanged(object sender, EventArgs args) + { + _changed = true; } #endregion diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs index 522c0df..5fb6bc3 100644 --- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayer.cs @@ -4,56 +4,58 @@ using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using UnityEngine; namespace UnityFx.Outline { /// - /// A collection of instances that share outlining settings. + /// A collection of instances that share outline settings. An + /// can only belong to one at time. /// + /// /// [Serializable] - public sealed class OutlineLayer : ICollection, IOutlineSettings, ISerializationCallbackReceiver + public sealed class OutlineLayer : ICollection, IOutlineSettingsEx, IChangeTracking { #region data - [SerializeField] - private Color _outlineColor = Color.red; - [SerializeField] - [Range(OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth)] - private int _outlineWidth = 4; - [SerializeField] - [Range(OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity)] - private float _outlineIntensity = 2; - [SerializeField] - private OutlineMode _outlineMode; + [SerializeField, HideInInspector] + private OutlineSettingsInstance _settings = new OutlineSettingsInstance(); + private OutlineLayerCollection _parentCollection; private Dictionary _outlineObjects = new Dictionary(); - private OutlineMaterialSet _materials; private bool _changed; #endregion #region interface - internal bool IsChanged + /// + /// Initializes a new instance of the class. + /// + public OutlineLayer() { - get - { - return _changed; - } } /// /// Initializes a new instance of the class. /// - public OutlineLayer() + /// Thrown if is . + public OutlineLayer(OutlineSettings settings) { + if (settings == null) + { + throw new ArgumentNullException("settings"); + } + + _settings.OutlineSettings = settings; } /// /// Adds a new object to the layer. /// + /// Thrown if is . public void Add(GameObject go, int ignoreLayerMask) { if (go == null) @@ -92,151 +94,129 @@ public void Add(GameObject go, int ignoreLayerMask) } } - internal void Render(OutlineRenderer renderer, OutlineResources resources) + #endregion + + #region internals + + internal OutlineLayerCollection ParentCollection + { + get + { + return _parentCollection; + } + } + + internal void Reset() + { + _settings.SetResources(null); + _outlineObjects.Clear(); + } + + internal void UpdateChanged() + { + _settings.UpdateChanged(); + } + + internal void SetCollection(OutlineLayerCollection collection) { - if (_materials == null || _materials.OutlineResources != resources) + if (_parentCollection == null || collection == null || _parentCollection == collection) { - _materials = resources.CreateMaterialSet(); - _materials.Reset(this); + _parentCollection = collection; } + else + { + throw new InvalidOperationException("OutlineLayer can only belong to a single OutlineLayerCollection."); + } + } + + internal void Render(OutlineRenderer renderer, OutlineResources resources) + { + _settings.SetResources(resources); foreach (var kvp in _outlineObjects) { if (kvp.Key) { - renderer.RenderSingleObject(kvp.Value, _materials); + renderer.RenderSingleObject(kvp.Value, _settings.OutlineMaterials); } } - - _changed = false; } #endregion - #region IOutlineSettings + #region IOutlineSettingsEx - /// - public Color OutlineColor + /// + /// Gets or sets outline settings. Set this to non- value to share settings with other components. + /// + public OutlineSettings OutlineSettings { get { - return _outlineColor; + return _settings.OutlineSettings; } set { - if (_outlineColor != value) - { - _outlineColor = value; - _changed = true; - - if (_materials != null) - { - _materials.OutlineColor = value; - } - } + _settings.OutlineSettings = value; } } + #endregion + + #region IOutlineSettings + /// - public int OutlineWidth + public Color OutlineColor { get { - return _outlineWidth; + return _settings.OutlineColor; } set { - value = Mathf.Clamp(value, OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); - - if (_outlineWidth != value) - { - _outlineWidth = value; - _changed = true; - - if (_materials != null) - { - _materials.OutlineWidth = value; - } - } + _settings.OutlineColor = value; } } /// - public float OutlineIntensity + public int OutlineWidth { get { - return _outlineIntensity; + return _settings.OutlineWidth; } set { - value = Mathf.Clamp(value, OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); - - if (_outlineIntensity != value) - { - _outlineIntensity = value; - _changed = true; - - if (_materials != null) - { - _materials.OutlineIntensity = value; - } - } + _settings.OutlineWidth = value; } } /// - public OutlineMode OutlineMode + public float OutlineIntensity { get { - return _outlineMode; + return _settings.OutlineIntensity; } set { - if (_outlineMode != value) - { - _outlineMode = value; - _changed = true; - - if (_materials != null) - { - _materials.OutlineMode = value; - } - } + _settings.OutlineIntensity = value; } } /// - public void Invalidate() + public OutlineMode OutlineMode { - if (_materials != null) + get { - _materials.Reset(this); + return _settings.OutlineMode; } - - _changed = true; - } - - #endregion - - #region ISerializationCallbackReceiver - - void ISerializationCallbackReceiver.OnAfterDeserialize() - { - _outlineWidth = Mathf.Clamp(_outlineWidth, OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); - - if (_outlineColor == Color.clear) + set { - _outlineColor = Color.red; + _settings.OutlineMode = value; } } - void ISerializationCallbackReceiver.OnBeforeSerialize() - { - _changed = true; - } - #endregion #region ICollection @@ -268,9 +248,10 @@ public void Add(GameObject go) /// public bool Remove(GameObject go) { - if (_outlineObjects.Remove(go)) + if (go != null && _outlineObjects.Remove(go)) { _changed = true; + return true; } return false; @@ -279,14 +260,22 @@ public bool Remove(GameObject go) /// public bool Contains(GameObject go) { + if (ReferenceEquals(go, null)) + { + return false; + } + return _outlineObjects.ContainsKey(go); } /// public void Clear() { - _outlineObjects.Clear(); - _changed = true; + if (_outlineObjects.Count > 0) + { + _outlineObjects.Clear(); + _changed = true; + } } /// @@ -299,6 +288,7 @@ public void CopyTo(GameObject[] array, int arrayIndex) #region IEnumerable + /// public IEnumerator GetEnumerator() { return _outlineObjects.Keys.GetEnumerator(); @@ -311,6 +301,26 @@ IEnumerator IEnumerable.GetEnumerator() #endregion + #region IChangeTracking + + /// + public bool IsChanged + { + get + { + return _changed || _settings.IsChanged; + } + } + + /// + public void AcceptChanges() + { + _settings.AcceptChanges(); + _changed = false; + } + + #endregion + #region implementation #endregion } diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs index 0354cca..9722da1 100644 --- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineLayerCollection.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using UnityEngine; namespace UnityFx.Outline @@ -13,28 +14,34 @@ namespace UnityFx.Outline /// /// /// - [CreateAssetMenu(fileName = "OutlineLayerCollection", menuName = "UnityFx/Outline Layer Collection")] - public sealed class OutlineLayerCollection : ScriptableObject, IList + /// + [CreateAssetMenu(fileName = "OutlineLayerCollection", menuName = "UnityFx/Outline/Outline Layer Collection")] + public sealed class OutlineLayerCollection : ScriptableObject, IList, IChangeTracking { #region data - [SerializeField] - private List _layers; + [SerializeField, HideInInspector] + private List _layers = new List(); + + private bool _changed = true; #endregion #region interface - internal IList Layers + internal void Reset() { - get + foreach (var layer in _layers) { - if (_layers == null) - { - _layers = new List(); - } + layer.Reset(); + } + } - return _layers; + internal void UpdateChanged() + { + foreach (var layer in _layers) + { + layer.UpdateChanged(); } } @@ -42,14 +49,11 @@ internal IList Layers #region ScriptableObject - private void OnValidate() + private void OnEnable() { - if (_layers != null) + foreach (var layer in _layers) { - foreach (var layer in _layers) - { - layer.Invalidate(); - } + layer.SetCollection(this); } } @@ -57,11 +61,12 @@ private void OnValidate() #region IList - public OutlineLayer this[int index] + /// + public OutlineLayer this[int layerIndex] { get { - return _layers[index]; + return _layers[layerIndex]; } set { @@ -70,10 +75,23 @@ public OutlineLayer this[int index] throw new ArgumentNullException("layer"); } - _layers[index] = value; + if (layerIndex < 0 || layerIndex >= _layers.Count) + { + throw new ArgumentOutOfRangeException("layerIndex"); + } + + if (_layers[layerIndex] != value) + { + value.SetCollection(this); + + _layers[layerIndex].SetCollection(null); + _layers[layerIndex] = value; + _changed = true; + } } } + /// public int IndexOf(OutlineLayer layer) { if (layer != null) @@ -84,6 +102,7 @@ public int IndexOf(OutlineLayer layer) return -1; } + /// public void Insert(int index, OutlineLayer layer) { if (layer == null) @@ -91,18 +110,31 @@ public void Insert(int index, OutlineLayer layer) throw new ArgumentNullException("layer"); } - _layers.Insert(index, layer); + if (layer.ParentCollection != this) + { + layer.SetCollection(this); + + _layers.Insert(index, layer); + _changed = true; + } } + /// public void RemoveAt(int index) { - _layers.RemoveAt(index); + if (index >= 0 && index < _layers.Count) + { + _layers[index].SetCollection(null); + _layers.RemoveAt(index); + _changed = true; + } } #endregion #region ICollection + /// public int Count { get @@ -111,6 +143,7 @@ public int Count } } + /// public bool IsReadOnly { get @@ -119,6 +152,7 @@ public bool IsReadOnly } } + /// public void Add(OutlineLayer layer) { if (layer == null) @@ -126,19 +160,45 @@ public void Add(OutlineLayer layer) throw new ArgumentNullException("layer"); } - _layers.Add(layer); + if (layer.ParentCollection != this) + { + layer.SetCollection(this); + + _layers.Add(layer); + _changed = true; + } } + /// public bool Remove(OutlineLayer layer) { - return _layers.Remove(layer); + if (_layers.Remove(layer)) + { + layer.SetCollection(null); + + _changed = true; + return true; + } + + return false; } + /// public void Clear() { - _layers.Clear(); + if (_layers.Count > 0) + { + foreach (var layer in _layers) + { + layer.SetCollection(null); + } + + _layers.Clear(); + _changed = true; + } } + /// public bool Contains(OutlineLayer layer) { if (layer == null) @@ -149,6 +209,7 @@ public bool Contains(OutlineLayer layer) return _layers.Contains(layer); } + /// public void CopyTo(OutlineLayer[] array, int arrayIndex) { _layers.CopyTo(array, arrayIndex); @@ -158,6 +219,7 @@ public void CopyTo(OutlineLayer[] array, int arrayIndex) #region IEnumerable + /// public IEnumerator GetEnumerator() { return _layers.GetEnumerator(); @@ -169,5 +231,45 @@ IEnumerator IEnumerable.GetEnumerator() } #endregion + + #region IChangeTracking + + /// + public bool IsChanged + { + get + { + if (_changed) + { + return true; + } + + foreach (var layer in _layers) + { + if (layer.IsChanged) + { + return true; + } + } + + return false; + } + } + + /// + public void AcceptChanges() + { + foreach (var layer in _layers) + { + layer.AcceptChanges(); + } + + _changed = false; + } + + #endregion + + #region implementation + #endregion } } diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineMaterialSet.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineMaterialSet.cs index 2447bb7..e3e8ce7 100644 --- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineMaterialSet.cs +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineMaterialSet.cs @@ -2,7 +2,6 @@ // See the LICENSE.md file in the project root for more information. using System; -using System.Collections.Generic; using UnityEngine; namespace UnityFx.Outline @@ -11,7 +10,7 @@ namespace UnityFx.Outline /// A set of materials needed to render outlines. /// /// - public sealed class OutlineMaterialSet : IOutlineSettings + public sealed class OutlineMaterialSet : IOutlineSettings, IDisposable { #region data @@ -22,9 +21,10 @@ public sealed class OutlineMaterialSet : IOutlineSettings private readonly float[] _gaussSamples = new float[OutlineRenderer.MaxWidth]; private Color _color; - private int _width; - private float _intensity; + private int _width = OutlineRenderer.MinWidth; + private float _intensity = OutlineRenderer.MinIntensity; private OutlineMode _mode; + private bool _disposed; #endregion @@ -119,10 +119,20 @@ public float[] GaussSamples /// public OutlineMaterialSet(OutlineResources resources) { + if (resources == null) + { + throw new ArgumentNullException("resources"); + } + _outlineResources = resources; _renderMaterial = new Material(resources.RenderShader); _hPassMaterial = new Material(resources.HPassShader); _vPassMaterial = new Material(resources.VPassBlendShader); + + _hPassMaterial.SetInt(WidthNameId, _width); + _vPassMaterial.SetInt(WidthNameId, _width); + _vPassMaterial.SetColor(ColorNameId, _color); + _vPassMaterial.SetFloat(IntensityNameId, OutlineRenderer.SolidIntensity); } /// @@ -130,10 +140,19 @@ public OutlineMaterialSet(OutlineResources resources) /// internal OutlineMaterialSet(OutlineResources resources, Material renderMaterial) { + Debug.Assert(resources); + Debug.Assert(resources.IsValid); + Debug.Assert(renderMaterial); + _outlineResources = resources; _renderMaterial = renderMaterial; _hPassMaterial = new Material(resources.HPassShader); _vPassMaterial = new Material(resources.VPassBlendShader); + + _hPassMaterial.SetInt(WidthNameId, _width); + _vPassMaterial.SetInt(WidthNameId, _width); + _vPassMaterial.SetColor(ColorNameId, _color); + _vPassMaterial.SetFloat(IntensityNameId, OutlineRenderer.SolidIntensity); } /// @@ -144,6 +163,13 @@ internal OutlineMaterialSet(OutlineResources resources, Material renderMaterial) /// public void Reset(IOutlineSettings settings) { + ThrowIfDisposed(); + + if (settings == null) + { + throw new ArgumentNullException("settings"); + } + SetColor(settings.OutlineColor); SetIntensity(settings.OutlineIntensity); SetWidth(settings.OutlineWidth); @@ -164,6 +190,7 @@ public Color OutlineColor } set { + ThrowIfDisposed(); SetColor(value); } } @@ -177,8 +204,7 @@ public int OutlineWidth } set { - Debug.Assert(value >= OutlineRenderer.MinWidth); - Debug.Assert(value <= OutlineRenderer.MaxWidth); + ThrowIfDisposed(); if (_width != value) { @@ -197,8 +223,7 @@ public float OutlineIntensity } set { - Debug.Assert(value >= OutlineRenderer.MinIntensity); - Debug.Assert(value <= OutlineRenderer.MaxIntensity); + ThrowIfDisposed(); if (_intensity != value) { @@ -216,6 +241,8 @@ public OutlineMode OutlineMode } set { + ThrowIfDisposed(); + if (_mode != value) { SetMode(value); @@ -223,10 +250,32 @@ public OutlineMode OutlineMode } } + #endregion + + #region IDisposable + /// - public void Invalidate() + public void Dispose() { - Reset(this); + if (!_disposed) + { + _disposed = true; + + if (_renderMaterial) + { + UnityEngine.Object.DestroyImmediate(_renderMaterial); + } + + if (_hPassMaterial) + { + UnityEngine.Object.DestroyImmediate(_hPassMaterial); + } + + if (_vPassMaterial) + { + UnityEngine.Object.DestroyImmediate(_vPassMaterial); + } + } } #endregion @@ -241,16 +290,15 @@ private void SetColor(Color color) private void SetWidth(int width) { - _width = width; - - _hPassMaterial.SetInt(WidthNameId, width); - _vPassMaterial.SetInt(WidthNameId, width); + _width = Mathf.Clamp(width, OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); + _hPassMaterial.SetInt(WidthNameId, _width); + _vPassMaterial.SetInt(WidthNameId, _width); } private void SetIntensity(float intensity) { - _intensity = intensity; - _vPassMaterial.SetFloat(IntensityNameId, intensity); + _intensity = Mathf.Clamp(intensity, OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); + _vPassMaterial.SetFloat(IntensityNameId, _intensity); } private void SetMode(OutlineMode mode) @@ -272,6 +320,14 @@ private void UpdateGaussSamples() OutlineRenderer.GetGaussSamples(_width, _gaussSamples); } + private void ThrowIfDisposed() + { + if (_disposed) + { + throw new ObjectDisposedException(GetType().Name); + } + } + #endregion } } diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs index 9a34ac3..c0bc1e4 100644 --- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineRenderer.cs @@ -13,7 +13,8 @@ namespace UnityFx.Outline /// /// /// This class is used by higher level outline implementations ( and ). - /// It implements to be used inside block as shown in the code sample. + /// It implements to be used inside block as shown in the code sample. Disposing + /// does not dispose the . /// /// /// using (var renderer = new OutlineRenderer(commandBuffer, BuiltinRenderTextureType.CameraTarget)) @@ -31,6 +32,8 @@ public struct OutlineRenderer : IDisposable private readonly RenderTargetIdentifier _renderTarget; private readonly CommandBuffer _commandBuffer; + private bool _disposed; + #endregion #region interface @@ -85,6 +88,7 @@ public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier dst) { Debug.Assert(commandBuffer != null); + _disposed = false; _maskRtId = Shader.PropertyToID("_MaskTex"); _hPassRtId = Shader.PropertyToID("_HPassTex"); _renderTarget = dst; @@ -101,8 +105,15 @@ public OutlineRenderer(CommandBuffer commandBuffer, RenderTargetIdentifier dst) /// public void RenderSingleObject(IList renderers, OutlineMaterialSet materials) { - Debug.Assert(renderers != null); - Debug.Assert(materials != null); + if (renderers == null) + { + throw new ArgumentNullException("renderers"); + } + + if (materials == null) + { + throw new ArgumentNullException("materials"); + } _commandBuffer.SetRenderTarget(_maskRtId); _commandBuffer.ClearRenderTarget(false, true, Color.black); @@ -131,8 +142,15 @@ public void RenderSingleObject(IList renderers, OutlineMaterialSet mat /// public void RenderSingleObject(Renderer renderer, OutlineMaterialSet materials) { - Debug.Assert(renderer != null); - Debug.Assert(materials != null); + if (renderer == null) + { + throw new ArgumentNullException("renderer"); + } + + if (materials == null) + { + throw new ArgumentNullException("materials"); + } _commandBuffer.SetRenderTarget(_maskRtId); _commandBuffer.ClearRenderTarget(false, true, Color.black); @@ -195,9 +213,13 @@ public static float[] GetGaussSamples(int width, float[] samples) /// public void Dispose() { - _commandBuffer.ReleaseTemporaryRT(_hPassRtId); - _commandBuffer.ReleaseTemporaryRT(_maskRtId); - _commandBuffer.EndSample(EffectName); + if (!_disposed) + { + _disposed = true; + _commandBuffer.ReleaseTemporaryRT(_hPassRtId); + _commandBuffer.ReleaseTemporaryRT(_maskRtId); + _commandBuffer.EndSample(EffectName); + } } #endregion diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs index b732118..98cbab0 100644 --- a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineResources.cs @@ -9,7 +9,7 @@ namespace UnityFx.Outline /// /// This asset is used to store references to shaders and other resources needed at runtime without having to use a Resources folder. /// - [CreateAssetMenu(fileName = "OutlineResources", menuName = "UnityFx/Outline Resources")] + [CreateAssetMenu(fileName = "OutlineResources", menuName = "UnityFx/Outline/Outline Resources")] public class OutlineResources : ScriptableObject { private Material _renderMaterial; diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs new file mode 100644 index 0000000..e9e0d76 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs @@ -0,0 +1,88 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using UnityEngine; + +namespace UnityFx.Outline +{ + /// + /// Outline settings. + /// + [CreateAssetMenu(fileName = "OutlineSettings", menuName = "UnityFx/Outline/Outline Settings")] + public sealed class OutlineSettings : ScriptableObject, IOutlineSettings + { + #region data + + // NOTE: There is a custom editor for OutlineSettings, so no need to show these in default inspector. + [SerializeField, HideInInspector] + private Color _outlineColor = Color.red; + [SerializeField, HideInInspector] + private int _outlineWidth = 4; + [SerializeField, HideInInspector] + private float _outlineIntensity = 2; + [SerializeField, HideInInspector] + private OutlineMode _outlineMode; + + #endregion + + #region interface + #endregion + + #region IOutlineSettings + + /// + public Color OutlineColor + { + get + { + return _outlineColor; + } + set + { + _outlineColor = value; + } + } + + /// + public int OutlineWidth + { + get + { + return _outlineWidth; + } + set + { + _outlineWidth = Mathf.Clamp(value, OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); + } + } + + /// + public float OutlineIntensity + { + get + { + return _outlineIntensity; + } + set + { + _outlineIntensity = Mathf.Clamp(value, OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); + } + } + + /// + public OutlineMode OutlineMode + { + get + { + return _outlineMode; + } + set + { + _outlineMode = value; + } + } + + #endregion + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs.meta b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs.meta new file mode 100644 index 0000000..c6de014 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b579424fd3338724cba3155ee4d53475 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs new file mode 100644 index 0000000..cb982da --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs @@ -0,0 +1,254 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.ComponentModel; +using UnityEngine; + +namespace UnityFx.Outline +{ + [Serializable] + internal class OutlineSettingsInstance : IOutlineSettingsEx, IChangeTracking, IDisposable + { + #region data + +#pragma warning disable 0649 + + // NOTE: There are custom editors for public components, so no need to show these in default inspector. + [SerializeField, HideInInspector] + private OutlineSettings _outlineSettings; + [SerializeField, HideInInspector] + private Color _outlineColor = Color.red; + [SerializeField, HideInInspector] + private int _outlineWidth = 4; + [SerializeField, HideInInspector] + private float _outlineIntensity = 2; + [SerializeField, HideInInspector] + private OutlineMode _outlineMode; + +#pragma warning restore 0649 + + private OutlineMaterialSet _materials; + private bool _changed = true; + + #endregion + + #region interface + + public OutlineMaterialSet OutlineMaterials + { + get + { + return _materials; + } + } + + internal void SetResources(OutlineResources resources) + { + if (resources == null) + { + if (_materials != null) + { + _materials.Dispose(); + _materials = null; + } + } + else if (_materials == null || _materials.OutlineResources != resources) + { + _materials = resources.CreateMaterialSet(); + _materials.Reset(this); + _changed = true; + } + } + + internal void UpdateChanged() + { + if (_outlineSettings != null) + { + _outlineColor = _outlineSettings.OutlineColor; + _outlineWidth = _outlineSettings.OutlineWidth; + _outlineIntensity = _outlineSettings.OutlineIntensity; + _outlineMode = _outlineSettings.OutlineMode; + } + + if (_materials != null) + { + if (_outlineColor != _materials.OutlineColor || + _outlineWidth != _materials.OutlineWidth || + _outlineIntensity != _materials.OutlineIntensity || + _outlineMode != _materials.OutlineMode) + { + _materials.Reset(this); + _changed = true; + } + } + } + + #endregion + + #region IOutlineSettingsEx + + public OutlineSettings OutlineSettings + { + get + { + return _outlineSettings; + } + set + { + if (_outlineSettings != value) + { + _outlineSettings = value; + + if (_outlineSettings != null) + { + _outlineColor = _outlineSettings.OutlineColor; + _outlineWidth = _outlineSettings.OutlineWidth; + _outlineIntensity = _outlineSettings.OutlineIntensity; + _outlineMode = _outlineSettings.OutlineMode; + + if (_materials != null) + { + _materials.Reset(this); + } + + _changed = true; + } + } + } + } + + #endregion + + #region IOutlineSettings + + /// + public Color OutlineColor + { + get + { + return _outlineColor; + } + set + { + if (_outlineColor != value) + { + _outlineColor = value; + _changed = true; + + if (_materials != null) + { + _materials.OutlineColor = value; + } + } + } + } + + /// + public int OutlineWidth + { + get + { + return _outlineWidth; + } + set + { + value = Mathf.Clamp(value, OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); + + if (_outlineWidth != value) + { + _outlineWidth = value; + _changed = true; + + if (_materials != null) + { + _materials.OutlineWidth = value; + } + } + } + } + + /// + public float OutlineIntensity + { + get + { + return _outlineIntensity; + } + set + { + value = Mathf.Clamp(value, OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); + + if (_outlineIntensity != value) + { + _outlineIntensity = value; + _changed = true; + + if (_materials != null) + { + _materials.OutlineIntensity = value; + } + } + } + } + + /// + public OutlineMode OutlineMode + { + get + { + return _outlineMode; + } + set + { + if (_outlineMode != value) + { + _outlineMode = value; + _changed = true; + + if (_materials != null) + { + _materials.OutlineMode = value; + } + } + } + } + + #endregion + + #region IChangeTracking + + /// + public bool IsChanged + { + get + { + return _changed; + } + } + + /// + public void AcceptChanges() + { + _changed = false; + } + + #endregion + + #region IDisposable + + public void Dispose() + { + if (_materials != null) + { + _materials.Dispose(); + _materials = null; + } + } + + #endregion + + #region implementation + #endregion + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs.meta b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs.meta new file mode 100644 index 0000000..177c3cb --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Runtime/Scripts/OutlineSettingsInstance.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8ea4c60e473b8ef4790934bb274993cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests.meta b/Assets/Plugins/UnityFx.Outline/Tests.meta new file mode 100644 index 0000000..ac6bd9e --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9c2f662256b33974c94b1b56640a7397 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor.meta b/Assets/Plugins/UnityFx.Outline/Tests/Editor.meta new file mode 100644 index 0000000..f2ff48e --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f2ad07e44abb5204aa73321dbeb58ddd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts.meta b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts.meta new file mode 100644 index 0000000..f055344 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0678297c303e4104896b2beec616a514 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers.meta b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers.meta new file mode 100644 index 0000000..75cfe48 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ecd2c4203d2dee74389ff168d633fe3a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs new file mode 100644 index 0000000..0f38e19 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs @@ -0,0 +1,78 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.ComponentModel; +using UnityEngine; +using UnityEngine.TestTools; +using NUnit.Framework; + +namespace UnityFx.Outline +{ + public abstract class IOutlineSettingsExTests : IOutlineSettingsTests + { + private IOutlineSettingsEx _settings; + private IChangeTracking _changeTracking; + + protected void Init(IOutlineSettingsEx settings) + { + _settings = settings; + _changeTracking = settings as IChangeTracking; + base.Init(settings); + } + + [Test] + public void OutlineSettings_SetsValue() + { + var settings = ScriptableObject.CreateInstance(); + + try + { + _settings.OutlineSettings = settings; + + Assert.AreEqual(settings, _settings.OutlineSettings); + + _settings.OutlineSettings = null; + + Assert.IsNull(_settings.OutlineSettings); + } + finally + { + UnityEngine.Object.DestroyImmediate(settings); + } + } + + [Test] + public void OutlineSettings_SetsChanged() + { + if (_changeTracking != null) + { + var settings = ScriptableObject.CreateInstance(); + + try + { + _changeTracking.AcceptChanges(); + _settings.OutlineSettings = settings; + + Assert.IsTrue(_changeTracking.IsChanged); + } + finally + { + UnityEngine.Object.DestroyImmediate(settings); + } + } + } + + [Test] + public void OutlineSettings_DoesNotSetsChangedOnSameValue() + { + if (_changeTracking != null) + { + _changeTracking.AcceptChanges(); + _settings.OutlineSettings = _settings.OutlineSettings; + + Assert.IsFalse(_changeTracking.IsChanged); + } + } + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs.meta b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs.meta new file mode 100644 index 0000000..eacde42 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers/IOutlineSettingsExTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c7d2cd56d59228e40917059e616e5ee9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs new file mode 100644 index 0000000..eef5dc4 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs @@ -0,0 +1,195 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.ComponentModel; +using UnityEngine; +using UnityEngine.TestTools; +using NUnit.Framework; + +namespace UnityFx.Outline +{ + public abstract class IOutlineSettingsTests + { + private IOutlineSettings _settings; + private IChangeTracking _changeTracking; + + protected void Init(IOutlineSettings settings) + { + _settings = settings; + _changeTracking = settings as IChangeTracking; + } + + [Test] + public void OutlineColor_SetsValue() + { + var color = Color.blue; + _settings.OutlineColor = color; + + Assert.AreEqual(color, _settings.OutlineColor); + } + + [Test] + public void OutlineColor_SetsChanged() + { + if (_changeTracking != null) + { + _changeTracking.AcceptChanges(); + _settings.OutlineColor = Color.blue; + + Assert.IsTrue(_changeTracking.IsChanged); + } + } + + [Test] + public void OutlineColor_DoesNotSetsChangedOnSameValue() + { + if (_changeTracking != null) + { + _changeTracking.AcceptChanges(); + _settings.OutlineColor = _settings.OutlineColor; + + Assert.IsFalse(_changeTracking.IsChanged); + } + } + + [Test] + public void OutlineWidth_DefaultValueIsValid() + { + Assert.LessOrEqual(OutlineRenderer.MinWidth, _settings.OutlineWidth); + Assert.GreaterOrEqual(OutlineRenderer.MaxWidth, _settings.OutlineWidth); + } + + [Test] + public void OutlineWidth_SetsValue() + { + var width = UnityEngine.Random.Range(OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); + _settings.OutlineWidth = width; + + Assert.AreEqual(width, _settings.OutlineWidth); + } + + [Test] + public void OutlineWidth_ClampsValue() + { + _settings.OutlineWidth = 1000; + + Assert.AreEqual(OutlineRenderer.MaxWidth, _settings.OutlineWidth); + + _settings.OutlineWidth = -1000; + + Assert.AreEqual(OutlineRenderer.MinWidth, _settings.OutlineWidth); + } + + [Test] + public void OutlineWidth_SetsChanged() + { + if (_changeTracking != null) + { + _changeTracking.AcceptChanges(); + _settings.OutlineWidth = 10; + + Assert.IsTrue(_changeTracking.IsChanged); + } + } + + [Test] + public void OutlineWidth_DoesNotSetsChangedOnSameValue() + { + if (_changeTracking != null) + { + _changeTracking.AcceptChanges(); + _settings.OutlineWidth = _settings.OutlineWidth; + + Assert.IsFalse(_changeTracking.IsChanged); + } + } + + [Test] + public void OutlineMode_SetsValue() + { + _settings.OutlineMode = OutlineMode.Blurred; + Assert.AreEqual(OutlineMode.Blurred, _settings.OutlineMode); + + _settings.OutlineMode = OutlineMode.Solid; + Assert.AreEqual(OutlineMode.Solid, _settings.OutlineMode); + } + + [Test] + public void OutlineMode_SetsChanged() + { + if (_changeTracking != null) + { + _changeTracking.AcceptChanges(); + _settings.OutlineMode = OutlineMode.Blurred; + + Assert.IsTrue(_changeTracking.IsChanged); + } + } + + [Test] + public void OutlineMode_DoesNotSetsChangedOnSameValue() + { + if (_changeTracking != null) + { + _changeTracking.AcceptChanges(); + _settings.OutlineMode = _settings.OutlineMode; + + Assert.IsFalse(_changeTracking.IsChanged); + } + } + + [Test] + public void OutlineIntensity_DefaultValueIsValid() + { + Assert.LessOrEqual(OutlineRenderer.MinIntensity, _settings.OutlineIntensity); + Assert.GreaterOrEqual(OutlineRenderer.MaxIntensity, _settings.OutlineIntensity); + } + + [Test] + public void OutlineIntensity_SetsValue() + { + var intensity = UnityEngine.Random.Range(OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); + + _settings.OutlineIntensity = intensity; + + Assert.AreEqual(intensity, _settings.OutlineIntensity); + } + + [Test] + public void OutlineIntensity_ClampsValue() + { + _settings.OutlineIntensity = 1000; + + Assert.AreEqual(OutlineRenderer.MaxIntensity, _settings.OutlineIntensity); + + _settings.OutlineIntensity = -1000; + + Assert.AreEqual(OutlineRenderer.MinIntensity, _settings.OutlineIntensity); + } + + [Test] + public void OutlineIntensity_SetsChanged() + { + if (_changeTracking != null) + { + _changeTracking.AcceptChanges(); + _settings.OutlineIntensity = 21; + + Assert.IsTrue(_changeTracking.IsChanged); + } + } + + [Test] + public void OutlineIntensity_DoesNotSetsChangedOnSameValue() + { + if (_changeTracking != null) + { + _changeTracking.AcceptChanges(); + _settings.OutlineIntensity = _settings.OutlineIntensity; + + Assert.IsFalse(_changeTracking.IsChanged); + } + } + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs.meta b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs.meta new file mode 100644 index 0000000..57016ed --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/Helpers/IOutlineSettingsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 504f7cf5606c25a4a8eeea06598d8cd0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineBehaviourTests.cs b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineBehaviourTests.cs new file mode 100644 index 0000000..80be2ca --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineBehaviourTests.cs @@ -0,0 +1,33 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.TestTools; +using NUnit.Framework; + +namespace UnityFx.Outline +{ + [Category("OutlineBehaviour"), TestOf(typeof(OutlineBehaviour))] + public class OutlineBehaviourTests : IOutlineSettingsExTests, IDisposable + { + private GameObject _go; + private OutlineBehaviour _outlineEffect; + + [SetUp] + public void Init() + { + _go = new GameObject(); + _outlineEffect = _go.AddComponent(); + Init(_outlineEffect); + } + + [TearDown] + public void Dispose() + { + UnityEngine.Object.DestroyImmediate(_go); + } + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineBehaviourTests.cs.meta b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineBehaviourTests.cs.meta new file mode 100644 index 0000000..34a74f0 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineBehaviourTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7ff33caf6306d649ab2176f29f193d6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs new file mode 100644 index 0000000..d3cc51e --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs @@ -0,0 +1,299 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.TestTools; +using NUnit.Framework; + +namespace UnityFx.Outline +{ + [Category("OutlineLayerCollection"), TestOf(typeof(OutlineLayerCollection))] + public class OutlineLayerCollectionTests : IDisposable + { + private OutlineLayerCollection _layerCollection; + + [SetUp] + public void Init() + { + _layerCollection = ScriptableObject.CreateInstance(); + } + + [TearDown] + public void Dispose() + { + UnityEngine.Object.DestroyImmediate(_layerCollection); + } + + [Test] + public void DefaultStateIsValid() + { + Assert.IsTrue(_layerCollection.IsChanged); + Assert.IsFalse(_layerCollection.IsReadOnly); + Assert.IsEmpty(_layerCollection); + Assert.Zero(_layerCollection.Count); + } + + [Test] + public void Add_ThrowsIfArgumentIsNull() + { + Assert.Throws(() => _layerCollection.Add(null)); + } + + [Test] + public void Add_ThrowsIfLayerBelongsToAnotherCollection() + { + var anotherLayerCollection = ScriptableObject.CreateInstance(); + var layer = new OutlineLayer(); + + try + { + anotherLayerCollection.Add(layer); + Assert.Throws(() => _layerCollection.Add(layer)); + } + finally + { + UnityEngine.Object.DestroyImmediate(anotherLayerCollection); + } + } + + [Test] + public void Add_DoesNotSetChangedOnError() + { + _layerCollection.AcceptChanges(); + + try + { + _layerCollection.Add(null); + } + catch + { + } + + Assert.IsFalse(_layerCollection.IsChanged); + } + + [Test] + public void Add_SetsCount() + { + _layerCollection.Add(new OutlineLayer()); + + Assert.AreEqual(1, _layerCollection.Count); + } + + [Test] + public void Add_SetsChanged() + { + _layerCollection.AcceptChanges(); + _layerCollection.Add(new OutlineLayer()); + + Assert.IsTrue(_layerCollection.IsChanged); + } + + [Test] + public void Insert_ThrowsIfArgumentIsNull() + { + Assert.Throws(() => _layerCollection.Insert(0, null)); + } + + [Test] + public void Insert_ThrowsIfLayerBelongsToAnotherCollection() + { + var anotherLayerCollection = ScriptableObject.CreateInstance(); + var layer = new OutlineLayer(); + + try + { + anotherLayerCollection.Add(layer); + Assert.Throws(() => _layerCollection.Insert(0, layer)); + } + finally + { + UnityEngine.Object.DestroyImmediate(anotherLayerCollection); + } + } + + [Test] + public void Insert_DoesNotSetChangedOnError() + { + _layerCollection.AcceptChanges(); + + try + { + _layerCollection.Insert(0, null); + } + catch + { + } + + Assert.IsFalse(_layerCollection.IsChanged); + } + + [Test] + public void Insert_SetsCount() + { + _layerCollection.Insert(0, new OutlineLayer()); + + Assert.AreEqual(1, _layerCollection.Count); + } + + [Test] + public void Insert_SetsChanged() + { + _layerCollection.AcceptChanges(); + _layerCollection.Insert(0, new OutlineLayer()); + + Assert.IsTrue(_layerCollection.IsChanged); + } + + [Test] + public void Remove_DoesNotThrowOnNullArgument() + { + Assert.DoesNotThrow(() => _layerCollection.Remove(null)); + } + + [Test] + public void Remove_DoesNotSetChangedOnError() + { + _layerCollection.AcceptChanges(); + _layerCollection.Remove(null); + + Assert.IsFalse(_layerCollection.IsChanged); + } + + [Test] + public void Remove_DoesNotSetChangedIfNotfound() + { + _layerCollection.AcceptChanges(); + _layerCollection.Remove(new OutlineLayer()); + + Assert.IsFalse(_layerCollection.IsChanged); + } + + [Test] + public void Remove_SetsChanged() + { + var layer = new OutlineLayer(); + + _layerCollection.Add(layer); + _layerCollection.AcceptChanges(); + _layerCollection.Remove(layer); + + Assert.IsTrue(_layerCollection.IsChanged); + } + + [Test] + public void Remove_SetsCount() + { + var layer = new OutlineLayer(); + + _layerCollection.Add(layer); + _layerCollection.Remove(layer); + + Assert.Zero(_layerCollection.Count); + } + + [Test] + public void Clear_ResetsCount() + { + _layerCollection.Add(new OutlineLayer()); + _layerCollection.Clear(); + + Assert.Zero(_layerCollection.Count); + } + + [Test] + public void Clear_SetsChanged() + { + _layerCollection.Add(new OutlineLayer()); + _layerCollection.AcceptChanges(); + _layerCollection.Clear(); + + Assert.IsTrue(_layerCollection.IsChanged); + } + + [Test] + public void Clear_DoesNotSetChangedIfEmpty() + { + _layerCollection.AcceptChanges(); + _layerCollection.Clear(); + + Assert.IsFalse(_layerCollection.IsChanged); + } + + [Test] + public void Contains_DoesNotThrowIfArgumentIsNull() + { + _layerCollection.Contains(null); + } + + [Test] + public void Contains_DoesNotSetChangedOnError() + { + _layerCollection.AcceptChanges(); + + try + { + _layerCollection.Contains(null); + } + catch + { + } + + Assert.IsFalse(_layerCollection.IsChanged); + } + + [Test] + public void Contains_SearchesArgument() + { + var layer = new OutlineLayer(); + + Assert.IsFalse(_layerCollection.Contains(layer)); + + _layerCollection.Add(layer); + + Assert.IsTrue(_layerCollection.Contains(layer)); + } + + [Test] + public void Contains_DoesNotSetChanged() + { + var layer = new OutlineLayer(); + + _layerCollection.AcceptChanges(); + _layerCollection.Contains(layer); + + Assert.IsFalse(_layerCollection.IsChanged); + + _layerCollection.Add(layer); + _layerCollection.AcceptChanges(); + _layerCollection.Contains(layer); + + Assert.IsFalse(_layerCollection.IsChanged); + } + + [Test] + public void IsChanged_TracksLayerChanges() + { + var layer = new OutlineLayer(); + + _layerCollection.Add(layer); + _layerCollection.AcceptChanges(); + + layer.OutlineWidth = 17; + + Assert.IsTrue(_layerCollection.IsChanged); + } + + [Test] + public void AcceptChanges_ResetsChanged() + { + _layerCollection.Add(new OutlineLayer()); + _layerCollection.AcceptChanges(); + + Assert.IsFalse(_layerCollection.IsChanged); + } + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs.meta b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs.meta new file mode 100644 index 0000000..d67e736 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineLayerCollectionTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4a6e8c8f29227c2469990a6168c53b3f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineLayerTests.cs b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineLayerTests.cs new file mode 100644 index 0000000..0e9df7e --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineLayerTests.cs @@ -0,0 +1,212 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.TestTools; +using NUnit.Framework; + +namespace UnityFx.Outline +{ + [Category("OutlineLayer"), TestOf(typeof(OutlineLayer))] + public class OutlineLayerTests : IOutlineSettingsExTests, IDisposable + { + private OutlineLayer _layer; + + [SetUp] + public void Init() + { + _layer = new OutlineLayer(); + Init(_layer); + } + + [TearDown] + public void Dispose() + { + } + + [Test] + public void DefaultStateIsValid() + { + Assert.IsTrue(_layer.IsChanged); + Assert.IsFalse(_layer.IsReadOnly); + Assert.IsEmpty(_layer); + Assert.Zero(_layer.Count); + } + + [Test] + public void Add_ThrowsIfArgumentIsNull() + { + Assert.Throws(() => _layer.Add(null)); + } + + [Test] + public void Add_DoesNotSetChangedOnError() + { + _layer.AcceptChanges(); + + try + { + _layer.Add(null); + } + catch + { + } + + Assert.IsFalse(_layer.IsChanged); + } + + [Test] + public void Add_SetsCount() + { + _layer.Add(new GameObject()); + + Assert.AreEqual(1, _layer.Count); + } + + [Test] + public void Add_SetsChanged() + { + _layer.AcceptChanges(); + _layer.Add(new GameObject()); + + Assert.IsTrue(_layer.IsChanged); + } + + [Test] + public void Remove_DoesNotThrowOnNullArgument() + { + Assert.DoesNotThrow(() => _layer.Remove(null)); + } + + [Test] + public void Remove_DoesNotSetChangedOnError() + { + _layer.AcceptChanges(); + _layer.Remove(null); + + Assert.IsFalse(_layer.IsChanged); + } + + [Test] + public void Remove_DoesNotSetChangedIfNotfound() + { + _layer.AcceptChanges(); + _layer.Remove(new GameObject()); + + Assert.IsFalse(_layer.IsChanged); + } + + [Test] + public void Remove_SetsChanged() + { + var go = new GameObject(); + + _layer.Add(go); + _layer.AcceptChanges(); + _layer.Remove(go); + + Assert.IsTrue(_layer.IsChanged); + } + + [Test] + public void Remove_SetsCount() + { + var go = new GameObject(); + + _layer.Add(go); + _layer.Remove(go); + + Assert.Zero(_layer.Count); + } + + [Test] + public void Clear_ResetsCount() + { + _layer.Add(new GameObject()); + _layer.Clear(); + + Assert.Zero(_layer.Count); + } + + [Test] + public void Clear_SetsChanged() + { + _layer.Add(new GameObject()); + _layer.AcceptChanges(); + _layer.Clear(); + + Assert.IsTrue(_layer.IsChanged); + } + + [Test] + public void Clear_DoesNotSetChangedIfEmpty() + { + _layer.AcceptChanges(); + _layer.Clear(); + + Assert.IsFalse(_layer.IsChanged); + } + + [Test] + public void Contains_DoesNotThrowIfArgumentIsNull() + { + _layer.Contains(null); + } + + [Test] + public void Contains_DoesNotSetChangedOnError() + { + _layer.AcceptChanges(); + + try + { + _layer.Contains(null); + } + catch + { + } + + Assert.IsFalse(_layer.IsChanged); + } + + [Test] + public void Contains_SearchesArgument() + { + var go = new GameObject(); + + Assert.IsFalse(_layer.Contains(go)); + + _layer.Add(go); + + Assert.IsTrue(_layer.Contains(go)); + } + + [Test] + public void Contains_DoesNotSetChanged() + { + var go = new GameObject(); + + _layer.AcceptChanges(); + _layer.Contains(go); + + Assert.IsFalse(_layer.IsChanged); + + _layer.Add(go); + _layer.AcceptChanges(); + _layer.Contains(go); + + Assert.IsFalse(_layer.IsChanged); + } + + [Test] + public void AcceptChanges_ResetsChanged() + { + _layer.AcceptChanges(); + + Assert.IsFalse(_layer.IsChanged); + } + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineLayerTests.cs.meta b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineLayerTests.cs.meta new file mode 100644 index 0000000..5f35914 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineLayerTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6372b061875e8a54bb7ca0dbf1bb3e4b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineMaterialSetTests.cs b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineMaterialSetTests.cs new file mode 100644 index 0000000..c35cf03 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineMaterialSetTests.cs @@ -0,0 +1,133 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using UnityEngine.TestTools; +using NUnit.Framework; + +namespace UnityFx.Outline +{ + [Category("OutlineMaterialSet"), TestOf(typeof(OutlineMaterialSet))] + public class OutlineMaterialSetTests : IOutlineSettingsTests, IDisposable + { + private OutlineResources _resources; + private OutlineMaterialSet _materialSet; + + [SetUp] + public void Init() + { + _resources = ScriptableObject.CreateInstance(); + _materialSet = _resources.CreateMaterialSet(); + Init(_materialSet); + } + + [TearDown] + public void Dispose() + { + _materialSet.Dispose(); + UnityEngine.Object.DestroyImmediate(_resources); + } + + [Test] + public void Dispose_CanBeCalledMultipleTimes() + { + _materialSet.Dispose(); + _materialSet.Dispose(); + } + + [Test] + public void Reset_ThrowsIfDisposed() + { + _materialSet.Dispose(); + + Assert.Throws(() => _materialSet.Reset(_materialSet)); + } + + [Test] + public void Reset_ThrowsIfArgumentIsNull() + { + Assert.Throws(() => _materialSet.Reset(null)); + } + + [Test] + public void Reset_SetsValuesPassed() + { + var settings = ScriptableObject.CreateInstance(); + + try + { + settings.OutlineColor = Color.yellow; + settings.OutlineWidth = 20; + settings.OutlineIntensity = 5; + settings.OutlineMode = OutlineMode.Blurred; + + _materialSet.Reset(settings); + + Assert.AreEqual(settings.OutlineColor, _materialSet.OutlineColor); + Assert.AreEqual(settings.OutlineWidth, _materialSet.OutlineWidth); + Assert.AreEqual(settings.OutlineIntensity, _materialSet.OutlineIntensity); + Assert.AreEqual(settings.OutlineMode, _materialSet.OutlineMode); + } + finally + { + UnityEngine.Object.DestroyImmediate(settings); + } + } + + [Test] + public void OutlineColor_ThrowsIfDisposed() + { + _materialSet.Dispose(); + + Assert.Throws(() => _materialSet.OutlineColor = Color.magenta); + } + + [Test] + public void OutlineColor_SetsMaterialParams() + { + var color = Color.blue; + _materialSet.OutlineColor = color; + + Assert.AreEqual(color, _materialSet.VPassBlendMaterial.GetColor(_materialSet.ColorNameId)); + } + + [Test] + public void OutlineWidth_ThrowsIfDisposed() + { + _materialSet.Dispose(); + + Assert.Throws(() => _materialSet.OutlineWidth = 10); + } + + [Test] + public void OutlineWidth_SetsMaterialParams() + { + var width = UnityEngine.Random.Range(OutlineRenderer.MinWidth, OutlineRenderer.MaxWidth); + _materialSet.OutlineWidth = width; + + Assert.AreEqual(width, _materialSet.HPassMaterial.GetInt(_materialSet.WidthNameId)); + Assert.AreEqual(width, _materialSet.VPassBlendMaterial.GetInt(_materialSet.WidthNameId)); + } + + [Test] + public void OutlineMode_SetsMaterialParams() + { + _materialSet.OutlineMode = OutlineMode.Solid; + Assert.AreEqual(OutlineRenderer.SolidIntensity, _materialSet.VPassBlendMaterial.GetFloat(_materialSet.IntensityNameId)); + } + + [Test] + public void OutlineIntensity_SetsMaterialParams() + { + var intensity = UnityEngine.Random.Range(OutlineRenderer.MinIntensity, OutlineRenderer.MaxIntensity); + + _materialSet.OutlineIntensity = intensity; + + Assert.AreEqual(intensity, _materialSet.VPassBlendMaterial.GetFloat(_materialSet.IntensityNameId)); + } + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineMaterialSetTests.cs.meta b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineMaterialSetTests.cs.meta new file mode 100644 index 0000000..8b04847 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineMaterialSetTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8dd20ed2fbac7544a91b914158581811 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineRendererTests.cs b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineRendererTests.cs new file mode 100644 index 0000000..137c1b1 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineRendererTests.cs @@ -0,0 +1,47 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.TestTools; +using NUnit.Framework; + +namespace UnityFx.Outline +{ + [Category("OutlineRenderer"), TestOf(typeof(OutlineRenderer))] + public class OutlineRendererTests : IDisposable + { + private CommandBuffer _commandBuffer; + private OutlineRenderer _renderer; + + [SetUp] + public void Init() + { + _commandBuffer = new CommandBuffer(); + _renderer = new OutlineRenderer(_commandBuffer, BuiltinRenderTextureType.CameraTarget); + } + + [TearDown] + public void Dispose() + { + _commandBuffer.Dispose(); + } + + [Test] + public void Dispose_CanBeCalledMultipleTimes() + { + _renderer.Dispose(); + _renderer.Dispose(); + } + + [Test] + public void RenderSingleObject_ThrowsIfNullArguments() + { + Assert.Throws(() => _renderer.RenderSingleObject(default(IList), null)); + Assert.Throws(() => _renderer.RenderSingleObject(default(Renderer), null)); + } + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineRendererTests.cs.meta b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineRendererTests.cs.meta new file mode 100644 index 0000000..dce56a7 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineRendererTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c4dcc61e824b6f4f8805dbe543d2997 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineSettingsTests.cs b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineSettingsTests.cs new file mode 100644 index 0000000..7607c81 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineSettingsTests.cs @@ -0,0 +1,32 @@ +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using UnityEngine.TestTools; +using NUnit.Framework; + +namespace UnityFx.Outline +{ + [Category("OutlineSettings"), TestOf(typeof(OutlineSettings))] + public class OutlineSettingsTests : IOutlineSettingsTests, IDisposable + { + private OutlineSettings _settings; + + [SetUp] + public void Init() + { + _settings = ScriptableObject.CreateInstance(); + Init(_settings); + } + + [TearDown] + public void Dispose() + { + UnityEngine.Object.DestroyImmediate(_settings); + } + } +} diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineSettingsTests.cs.meta b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineSettingsTests.cs.meta new file mode 100644 index 0000000..297e458 --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/Scripts/OutlineSettingsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ee681c20e65b7a34085cd5f07a0c03a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/UnityFx.Outline.Editor.Tests.asmdef b/Assets/Plugins/UnityFx.Outline/Tests/Editor/UnityFx.Outline.Editor.Tests.asmdef new file mode 100644 index 0000000..f715ffe --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/UnityFx.Outline.Editor.Tests.asmdef @@ -0,0 +1,19 @@ +{ + "name": "UnityFx.Outline.Editor.Tests", + "references": [ + "UnityFx.Outline", + "UnityFx.Outline.Editor" + ], + "optionalUnityReferences": [ + "TestAssemblies" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [] +} \ No newline at end of file diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Editor/UnityFx.Outline.Editor.Tests.asmdef.meta b/Assets/Plugins/UnityFx.Outline/Tests/Editor/UnityFx.Outline.Editor.Tests.asmdef.meta new file mode 100644 index 0000000..5b4009a --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Editor/UnityFx.Outline.Editor.Tests.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 10ef01f813866564b87fc5ff13123c77 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Runtime.meta b/Assets/Plugins/UnityFx.Outline/Tests/Runtime.meta new file mode 100644 index 0000000..07c5fae --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7f94575f099b1c44893d9feb18c2bc46 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Runtime/UnityFx.Outline.Tests.asmdef b/Assets/Plugins/UnityFx.Outline/Tests/Runtime/UnityFx.Outline.Tests.asmdef new file mode 100644 index 0000000..1108d4a --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Runtime/UnityFx.Outline.Tests.asmdef @@ -0,0 +1,11 @@ +{ + "name": "UnityFx.Outline.Tests", + "references": [ + "UnityFx.Outline" + ], + "optionalUnityReferences": [ + "TestAssemblies" + ], + "includePlatforms": [], + "excludePlatforms": [] +} \ No newline at end of file diff --git a/Assets/Plugins/UnityFx.Outline/Tests/Runtime/UnityFx.Outline.Tests.asmdef.meta b/Assets/Plugins/UnityFx.Outline/Tests/Runtime/UnityFx.Outline.Tests.asmdef.meta new file mode 100644 index 0000000..b868faf --- /dev/null +++ b/Assets/Plugins/UnityFx.Outline/Tests/Runtime/UnityFx.Outline.Tests.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b6f43252634db42458f45f5519ce6f50 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Outline/package.json b/Assets/Plugins/UnityFx.Outline/package.json index 50ce798..006fc6a 100644 --- a/Assets/Plugins/UnityFx.Outline/package.json +++ b/Assets/Plugins/UnityFx.Outline/package.json @@ -1,6 +1,6 @@ { "name": "com.unityfx.outline", - "version": "0.4.0", + "version": "0.5.0", "displayName": "Screen-space outline for Unity", "description": "Configurable per-object and per-camera outlines. Both solid and blurred outline modes are supported (Gauss blur). The outlines can be easily customized either through scripts or with Unity editor (both in edit-time or runtime).", "unity": "2017.2", diff --git a/CHANGELOG.md b/CHANGELOG.md index 2eab22f..f485942 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/); this project adheres to [Semantic Versioning](http://semver.org/). +## [0.5.0] - 2019.09.09 + +Features editor UI and unit tests. + +### Added +- Added `OutlineSettings`, that can be shared between dfferent `OutlineLayer` and `OutlineBehaviour` instances. +- Added custom inspectors for `OutlineSettings`, `OutlineLayerCollection`. +- Added undo/redo support to all custom inspectors. +- Added unit-tests. + +### Changed +- Improved inspectors for `OutlineBehaviour` and `OutlineEffect`. + ## [0.4.0] - 2019.08.31 +Features blurred otulines. + ### Added - Added Gauss blurring to outlines. - Added outline mode parameter (possible values are `Solid` and `Blurred`). diff --git a/Docs/MotusOutline.png b/Docs/MotusOutline.png new file mode 100644 index 0000000..5c12532 Binary files /dev/null and b/Docs/MotusOutline.png differ diff --git a/Docs/OutlineBehaviourInspector.png b/Docs/OutlineBehaviourInspector.png new file mode 100644 index 0000000..27c8703 Binary files /dev/null and b/Docs/OutlineBehaviourInspector.png differ diff --git a/Docs/OutlineEffectInspector.png b/Docs/OutlineEffectInspector.png new file mode 100644 index 0000000..3073192 Binary files /dev/null and b/Docs/OutlineEffectInspector.png differ diff --git a/Docs/OutlineLayerCollectionInspector.png b/Docs/OutlineLayerCollectionInspector.png new file mode 100644 index 0000000..3dead01 Binary files /dev/null and b/Docs/OutlineLayerCollectionInspector.png differ diff --git a/Docs/OutlineSamples.png b/Docs/OutlineSamples.png new file mode 100644 index 0000000..5ec4b39 Binary files /dev/null and b/Docs/OutlineSamples.png differ diff --git a/Docs/OutlineSettingsInspector.png b/Docs/OutlineSettingsInspector.png new file mode 100644 index 0000000..1416267 Binary files /dev/null and b/Docs/OutlineSettingsInspector.png differ diff --git a/MotusOutline.png b/MotusOutline.png deleted file mode 100644 index 962b7f4..0000000 Binary files a/MotusOutline.png and /dev/null differ diff --git a/OutlineSamples.png b/OutlineSamples.png deleted file mode 100644 index 8dc19f6..0000000 Binary files a/OutlineSamples.png and /dev/null differ diff --git a/README.md b/README.md index 02107e6..4fe0304 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ Npm | [![Npm release](https://img.shields.io/npm/v/com.unityfx.outline.svg)](htt **Requires Unity 2017 or higher.** ## Synopsis -![Outline demo](OutlineSamples.png "Outline demo") -![Outline demo](MotusOutline.png "Outline demo") +![Outline demo](Docs/OutlineSamples.png "Outline demo") +![Outline demo](Docs/MotusOutline.png "Outline demo") *UnityFx.Outline* implements configurable per-object and per-camera outlines. Both solid and blurred outline modes are supported (Gauss blur). The outlines can be easily customized either through scripts or with Unity editor (both in edit-time or runtime). @@ -54,7 +54,7 @@ Npm package is available at [npmjs.com](https://www.npmjs.com/package/com.unityf } ], "dependencies": { - "com.unityfx.outline": "0.4.0" + "com.unityfx.outline": "0.5.0" } } ``` @@ -66,6 +66,8 @@ using UnityFx.Outline; ``` ### Per-camera outlines +![Outline demo](Docs/OutlineEffectInspector.png "OutlineEffect Inspector") + Add `OutlineEffect` script to a camera that should render outlines. Then add and configure as many layers as you need: ```csharp var outlineEffect = Camera.main.GetComponent(); @@ -92,6 +94,8 @@ effect1.ShareLayersWith(effect2); ``` ### Per-object outlines +![Outline demo](Docs/OutlineBehaviourInspector.png "OutlineBehaviour Inspector") + Add `OutlineBehaviour` script to objects that should be outlined (in edit mode or in runtime). Make sure `OutlineBehaviour.OutlineResources` is initialized. You can customize outline settings either via Unity inspector or via script. Objects with `OutlineBehaviour` assigned render outlines in all cameras. ```csharp @@ -122,7 +126,7 @@ materials.OutlineColor = Color.blue; using (var renderer = new OutlineRenderer(commandBuffer, BuiltinRenderTextureType.CameraTarget)) { - renderer.RenderSingleObject(renderers, _materials); + renderer.RenderSingleObject(renderers, materials); } myCamera.AddCommandBuffer(OutlineRenderer.RenderEvent, commandBuffer); @@ -141,7 +145,6 @@ Please see the links below for extended information on the product: - [A great outline tutorial](https://willweissman.wordpress.com/tutorials/shaders/unity-shaderlab-object-outlines/). - [Command buffers tutorial](https://lindenreid.wordpress.com/2018/09/13/using-command-buffers-in-unity-selective-bloom/). - [Gaussian blur tutorial](https://www.ronja-tutorials.com/2018/08/27/postprocessing-blur.html). -- [Gaussian blur 2](http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/). ## Contributing Please see [contributing guide](.github/CONTRIBUTING.md) for details.